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.launch
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, local_only=False, process_listeners=None, verbose=False, force_screen=False):
75 """
76 @param run_id: UUID of roslaunch session
77 @type run_id: str
78 @param roslaunch_files: list of launch configuration
79 files to load
80 @type roslaunch_files: [str]
81 @param is_core bool: if True, this launch is a roscore
82 instance. This affects the error behavior if a master is
83 already running (i.e. it fails).
84 @type is_core: bool
85 @param process_listeners: (optional) list of process listeners
86 to register with process monitor once launch is running
87 @type process_listeners: [L{roslaunch.pmon.ProcessListener}]
88 @param port: (optional) override master port number from what is specified in the master URI.
89 @type port: int
90 @param verbose: (optional) print verbose output
91 @type verbose: boolean
92 @param force_screen: (optional) force output of all nodes to screen
93 @type force_screen: boolean
94 @throws RLException
95 """
96
97 self.logger = logging.getLogger('roslaunch.parent')
98 self.run_id = run_id
99 self.process_listeners = process_listeners
100
101 self.roslaunch_files = roslaunch_files
102 self.is_core = is_core
103 self.port = port
104 self.local_only = local_only
105 self.verbose = verbose
106
107
108
109
110 self.force_screen = force_screen
111
112
113 self._shutting_down = False
114
115 self.config = self.runner = self.server = self.pm = self.remote_runner = None
116
124
130
132 """
133 Initialize the roslaunch runner
134 """
135 if self.config is None:
136 raise RLException("config is not initialized")
137 if self.pm is None:
138 raise RLException("pm is not initialized")
139 if self.server is None:
140 raise RLException("server is not initialized")
141 self.runner = roslaunch.launch.ROSLaunchRunner(self.run_id, self.config, server_uri=self.server.uri, pmon=self.pm, is_core=self.is_core, remote_runner=self.remote_runner)
142
143
144 if self.is_core:
145 print "ros_comm version %s"%(self.config.params['/rosversion'].value)
146
147 print self.config.summary(local=self.remote_runner is None)
148 if self.config:
149 for err in self.config.config_errors:
150 printerrlog("WARNING: %s"%err)
151
167
169 """
170 Initialize the remote process runner, if required. Subroutine
171 of _start_remote, separated out for easier testing
172 """
173 if self.config is None:
174 raise RLException("config is not initialized")
175 if self.pm is None:
176 raise RLException("pm is not initialized")
177 if self.server is None:
178 raise RLException("server is not initialized")
179
180 if not self.local_only and self.config.has_remote_nodes():
181
182 import roslaunch.remote
183 self.remote_runner = roslaunch.remote.ROSRemoteRunner(self.run_id, self.config, self.pm, self.server)
184 elif self.local_only:
185 printlog_bold("LOCAL\nlocal only launch specified, will not launch remote nodes\nLOCAL\n")
186
188 """
189 Initializes and runs the remote process runner, if required
190 """
191 if self.remote_runner is None:
192 self._init_remote()
193
194 if self.remote_runner is not None:
195
196 self.remote_runner.start_children()
197
199 """
200 load config, start XMLRPC servers and process monitor
201 """
202 if self.config is None:
203 self._load_config()
204
205
206 if self.pm is None:
207 self._start_pm()
208
209
210
211 if self.server is None:
212 self._start_server()
213
214
215
216 self._start_remote()
217
219 """
220 Tear down server and process monitor. Not multithread safe.
221 """
222
223
224
225 if self._shutting_down:
226 return
227 self._shutting_down = True
228
229 if self.server:
230 try:
231 self.server.shutdown("roslaunch parent complete")
232 except:
233
234 pass
235 if self.pm:
236 self.pm.shutdown()
237 self.pm.join()
238
239 - def start(self, auto_terminate=True):
240 """
241 Run the parent roslaunch.
242
243 @param auto_terminate: stop process monitor once there are no
244 more processes to monitor (default True). This defaults to
245 True, which is the command-line behavior of roslaunch. Scripts
246 may wish to set this to False if they wish to keep the
247 roslauch infrastructure up regardless of processes being
248 monitored.
249 """
250 self.logger.info("starting roslaunch parent run")
251
252
253 try:
254 self._start_infrastructure()
255 except:
256
257 self._stop_infrastructure()
258 raise
259
260
261
262 self._init_runner()
263
264
265 self.runner.launch()
266
267
268 if auto_terminate:
269 self.pm.registrations_complete()
270
271 self.logger.info("... roslaunch parent running, waiting for process exit")
272 if self.process_listeners:
273 for l in self.process_listeners:
274 self.runner.pm.add_process_listener(l)
275
277 """
278 Run the parent roslaunch event loop once
279 """
280 if self.runner:
281 self.runner.spin_once()
282
284 """
285 Run the parent roslaunch until exit
286 """
287 if not self.runner:
288 raise RLException("parent not started yet")
289 try:
290
291 self.runner.spin()
292 finally:
293 self._stop_infrastructure()
294
296 """
297 Stop the parent roslaunch.
298 """
299 self._stop_infrastructure()
300