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