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 from rosmaster.master_api import NUM_WORKERS
58
59
60
61
62
63 load_config_default = roslaunch.config.load_config_default
64
66 """
67 ROSLaunchParent represents the main 'parent' roslaunch process. It
68 is responsible for loading the launch files, assigning machines,
69 and then starting up any remote processes. The __main__ method
70 delegates most of runtime to ROSLaunchParent.
71
72 This must be called from the Python Main thread due to signal registration.
73 """
74
75 - def __init__(self, run_id, roslaunch_files, is_core=False, port=None, local_only=False, process_listeners=None,
76 verbose=False, force_screen=False, is_rostest=False, roslaunch_strs=None, num_workers=NUM_WORKERS, timeout=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 is_rostest bool: if True, this launch is a rostest
97 instance. This affects validation checks.
98 @type is_rostest: bool
99 @param num_workers: If this is the core, the number of worker-threads to use.
100 @type num_workers: int
101 @param timeout: If this is the core, the socket-timeout to use.
102 @type timeout: Float or None
103 @throws RLException
104 """
105
106 self.logger = logging.getLogger('roslaunch.parent')
107 self.run_id = run_id
108 self.process_listeners = process_listeners
109
110 self.roslaunch_files = roslaunch_files
111 self.roslaunch_strs = roslaunch_strs
112 self.is_core = is_core
113 self.is_rostest = is_rostest
114 self.port = port
115 self.local_only = local_only
116 self.verbose = verbose
117 self.num_workers = num_workers
118 self.timeout = timeout
119
120
121
122
123 self.force_screen = force_screen
124
125
126 self._shutting_down = False
127
128 self.config = self.runner = self.server = self.pm = self.remote_runner = None
129
138
144
146 """
147 Initialize the roslaunch runner
148 """
149 if self.config is None:
150 raise RLException("config is not initialized")
151 if self.pm is None:
152 raise RLException("pm is not initialized")
153 if self.server is None:
154 raise RLException("server is not initialized")
155 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, num_workers=self.num_workers, timeout=self.timeout)
156
157
158 if self.is_core:
159 print("ros_comm version %s" % (self.config.params['/rosversion'].value))
160
161 print(self.config.summary(local=self.remote_runner is None))
162 if self.config:
163 for err in self.config.config_errors:
164 printerrlog("WARNING: %s"%err)
165
181
183 """
184 Initialize the remote process runner, if required. Subroutine
185 of _start_remote, separated out for easier testing
186 """
187 if self.config is None:
188 raise RLException("config is not initialized")
189 if self.pm is None:
190 raise RLException("pm is not initialized")
191 if self.server is None:
192 raise RLException("server is not initialized")
193
194 if not self.local_only and self.config.has_remote_nodes():
195
196 import roslaunch.remote
197 self.remote_runner = roslaunch.remote.ROSRemoteRunner(self.run_id, self.config, self.pm, self.server)
198 elif self.local_only:
199 printlog_bold("LOCAL\nlocal only launch specified, will not launch remote nodes\nLOCAL\n")
200
202 """
203 Initializes and runs the remote process runner, if required
204 """
205 if self.remote_runner is None:
206 self._init_remote()
207
208 if self.remote_runner is not None:
209
210 self.remote_runner.start_children()
211
213 """
214 load config, start XMLRPC servers and process monitor
215 """
216 if self.config is None:
217 self._load_config()
218
219
220 if self.pm is None:
221 self._start_pm()
222
223
224
225 if self.server is None:
226 self._start_server()
227
228
229
230 self._start_remote()
231
233 """
234 Tear down server and process monitor. Not multithread safe.
235 """
236
237
238
239 if self._shutting_down:
240 return
241 self._shutting_down = True
242
243 if self.server:
244 try:
245 self.server.shutdown("roslaunch parent complete")
246 except:
247
248 pass
249 if self.pm:
250 self.pm.shutdown()
251 self.pm.join()
252
253 - def start(self, auto_terminate=True):
254 """
255 Run the parent roslaunch.
256
257 @param auto_terminate: stop process monitor once there are no
258 more processes to monitor (default True). This defaults to
259 True, which is the command-line behavior of roslaunch. Scripts
260 may wish to set this to False if they wish to keep the
261 roslauch infrastructure up regardless of processes being
262 monitored.
263 """
264 self.logger.info("starting roslaunch parent run")
265
266
267 try:
268 self._start_infrastructure()
269 except:
270
271 self._stop_infrastructure()
272 raise
273
274
275
276 self._init_runner()
277
278
279 self.runner.launch()
280
281
282 if auto_terminate:
283 self.pm.registrations_complete()
284
285 self.logger.info("... roslaunch parent running, waiting for process exit")
286 if self.process_listeners:
287 for l in self.process_listeners:
288 self.runner.pm.add_process_listener(l)
289
290
291 self.server.add_process_listener(l)
292
294 """
295 Run the parent roslaunch event loop once
296 """
297 if self.runner:
298 self.runner.spin_once()
299
301 """
302 Run the parent roslaunch until exit
303 """
304 if not self.runner:
305 raise RLException("parent not started yet")
306 try:
307
308 self.runner.spin()
309 finally:
310 self._stop_infrastructure()
311
313 """
314 Stop the parent roslaunch.
315 """
316 self._stop_infrastructure()
317