1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 """
36 roslaunch.parent providees the L{ROSLaunchParent} implementation,
37 which represents the main 'parent' roslaunch process.
38
39 ROSLaunch has a client/server architecture for running remote
40 processes. When a user runs roslaunch, this creates a "parent"
41 roslaunch process, which is responsible for managing local
42 processes. This parent process will also start "child" processes on
43 remote machines. The parent can then invoke methods on this child
44 process to launch remote processes, and the child can invoke methods
45 on the parent to provide feedback.
46 """
47
48 import logging
49 import sys
50
51 import roslaunch.config
52 from roslaunch.core import printlog_bold, printerrlog, RLException
53 import roslaunch.runner
54 import roslaunch.pmon
55 import roslaunch.server
56 import roslaunch.xmlloader
57
58
59
60
61
62 load_config_default = roslaunch.config.load_config_default
63
65 """
66 ROSLaunchParent represents the main 'parent' roslaunch process. It
67 is responsible for loading the launch files, assigning machines,
68 and then starting up any remote processes. The __main__ method
69 delegates most of runtime to ROSLaunchParent.
70
71 This must be called from the Python Main thread due to signal registration.
72 """
73
74 - def __init__(self, run_id, roslaunch_files, is_core=False, port=None,
75 local_only=False, process_listeners=None, verbose=False,
76 force_screen=False, pm=None):
77 """
78 @param run_id: UUID of roslaunch session
79 @type run_id: str
80 @param roslaunch_files: list of launch configuration
81 files to load
82 @type roslaunch_files: [str]
83 @param is_core bool: if True, this launch is a roscore
84 instance. This affects the error behavior if a master is
85 already running (i.e. it fails).
86 @type is_core: bool
87 @param process_listeners: (optional) list of process listeners
88 to register with process monitor once launch is running
89 @type process_listeners: [L{roslaunch.pmon.ProcessListener}]
90 @param port: (optional) override master port number from what is specified in the master URI.
91 @type port: int
92 @param verbose: (optional) print verbose output
93 @type verbose: boolean
94 @param force_screen: (optional) force output of all nodes to screen
95 @type force_screen: boolean
96 @param pm: Specify process monitor for parent to use
97 @type pm: roslaunch.pmon.ProcessMonitor
98 @throws RLException
99 """
100
101 self.config = self.runner = self.server = self.remote_runner = None
102
103 self.pm = pm
104 self.logger = logging.getLogger('roslaunch.parent')
105 self.run_id = run_id
106 self.process_listeners = process_listeners
107
108 self.roslaunch_files = roslaunch_files
109 self.is_core = is_core
110 self.port = port
111 self.local_only = local_only
112 self.verbose = verbose
113
114
115
116
117 self.force_screen = force_screen
118
119
120 self._shutting_down = False
121
122
124 self.config = roslaunch.config.load_config_default(self.roslaunch_files, self.port, verbose=self.verbose)
125
126
127 if self.force_screen:
128 for n in self.config.nodes:
129 n.output = 'screen'
130
137
139 """
140 Initialize the roslaunch runner
141 """
142 if self.config is None:
143 raise RLException("config is not initialized")
144 if self.pm is None:
145 raise RLException("pm is not initialized")
146 if self.server is None:
147 raise RLException("server is not initialized")
148 self.runner = roslaunch.runner.ROSLaunchRunner(self.run_id, server_uri=self.server.uri, pmon=self.pm, is_core=self.is_core, remote_runner=self.remote_runner)
149
150
151 print self.config.summary(local=self.remote_runner is None)
152 if self.config:
153 for err in self.config.config_errors:
154 printerrlog("WARNING: %s"%err)
155
171
173 """
174 Initialize the remote process runner, if required. Subroutine
175 of _start_remote, separated out for easier testing
176 """
177 if self.config is None:
178 raise RLException("config is not initialized")
179 if self.pm is None:
180 raise RLException("pm is not initialized")
181 if self.server is None:
182 raise RLException("server is not initialized")
183
184 if not self.local_only and self.config.has_remote_nodes():
185
186 import roslaunch.remote
187 self.remote_runner = roslaunch.remote.ROSRemoteRunner(self.run_id, self.config, self.pm, self.server)
188 elif self.local_only:
189 printlog_bold("LOCAL\nlocal only launch specified, will not launch remote nodes\nLOCAL\n")
190
192 """
193 Initializes and runs the remote process runner, if required
194 """
195 if self.remote_runner is None:
196 self._init_remote()
197
198 if self.remote_runner is not None:
199
200 self.remote_runner.start_children()
201
203 """
204 load config, start XMLRPC servers and process monitor
205 """
206 if self.config is None:
207 self._load_config()
208
209
210 if self.pm is None:
211 self._start_pm()
212
213
214
215 if self.server is None:
216 self._start_server()
217
218
219
220 self._start_remote()
221
223 """
224 Tear down server and process monitor. Not multithread safe.
225 """
226
227
228
229 if self._shutting_down:
230 return
231 self._shutting_down = True
232
233 if self.server:
234 try:
235 self.server.shutdown("roslaunch parent complete")
236 except:
237
238 pass
239 if self.pm:
240 self.pm.shutdown()
241 self.pm.join()
242
243 - def start(self, auto_terminate=True):
244 """
245 Run the parent roslaunch.
246
247 @param auto_terminate: stop process monitor once there are no
248 more processes to monitor (default True). This defaults to
249 True, which is the command-line behavior of roslaunch. Scripts
250 may wish to set this to False if they wish to keep the
251 roslauch infrastructure up regardless of processes being
252 monitored.
253 """
254 self.logger.info("starting roslaunch parent run")
255
256
257 try:
258 self._start_infrastructure()
259 except:
260
261 self._stop_infrastructure()
262 raise
263
264
265
266 self._init_runner()
267
268
269 self.runner.launch(self.config)
270
271
272 if auto_terminate:
273 self.pm.registrations_complete()
274
275 self.logger.info("... roslaunch parent running, waiting for process exit")
276 if self.process_listeners:
277 for l in self.process_listeners:
278 self.runner.pm.add_process_listener(l)
279
281 """
282 Run the parent roslaunch event loop once
283 """
284 if self.runner:
285 self.runner.spin_once()
286
288 """
289 Run the parent roslaunch until exit
290 """
291 if not self.runner:
292 raise RLException("parent not started yet")
293 try:
294
295 self.runner.spin()
296 finally:
297 self._stop_infrastructure()
298
300 """
301 Stop the parent roslaunch.
302 """
303 self._stop_infrastructure()
304