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, master_logger_level=False):
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 @param master_logger_level: Specify roscore's rosmaster.master logger level, use default if it is False.
105 @type master_logger_level: str or False
106 """
107
108 self.logger = logging.getLogger('roslaunch.parent')
109 self.run_id = run_id
110 self.process_listeners = process_listeners
111
112 self.roslaunch_files = roslaunch_files
113 self.roslaunch_strs = roslaunch_strs
114 self.is_core = is_core
115 self.is_rostest = is_rostest
116 self.port = port
117 self.local_only = local_only
118 self.verbose = verbose
119 self.num_workers = num_workers
120 self.timeout = timeout
121 self.master_logger_level = master_logger_level
122
123
124
125
126 self.force_screen = force_screen
127
128
129 self._shutting_down = False
130
131 self.config = self.runner = self.server = self.pm = self.remote_runner = None
132
141
147
149 """
150 Initialize the roslaunch runner
151 """
152 if self.config is None:
153 raise RLException("config is not initialized")
154 if self.pm is None:
155 raise RLException("pm is not initialized")
156 if self.server is None:
157 raise RLException("server is not initialized")
158 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, master_logger_level=self.master_logger_level)
159
160
161 if self.is_core:
162 print("ros_comm version %s" % (self.config.params['/rosversion'].value))
163
164 print(self.config.summary(local=self.remote_runner is None))
165 if self.config:
166 for err in self.config.config_errors:
167 printerrlog("WARNING: %s"%err)
168
184
186 """
187 Initialize the remote process runner, if required. Subroutine
188 of _start_remote, separated out for easier testing
189 """
190 if self.config is None:
191 raise RLException("config is not initialized")
192 if self.pm is None:
193 raise RLException("pm is not initialized")
194 if self.server is None:
195 raise RLException("server is not initialized")
196
197 if not self.local_only and self.config.has_remote_nodes():
198
199 import roslaunch.remote
200 self.remote_runner = roslaunch.remote.ROSRemoteRunner(self.run_id, self.config, self.pm, self.server)
201 elif self.local_only:
202 printlog_bold("LOCAL\nlocal only launch specified, will not launch remote nodes\nLOCAL\n")
203
205 """
206 Initializes and runs the remote process runner, if required
207 """
208 if self.remote_runner is None:
209 self._init_remote()
210
211 if self.remote_runner is not None:
212
213 self.remote_runner.start_children()
214
216 """
217 load config, start XMLRPC servers and process monitor
218 """
219 if self.config is None:
220 self._load_config()
221
222
223 if self.pm is None:
224 self._start_pm()
225
226
227
228 if self.server is None:
229 self._start_server()
230
231
232
233 self._start_remote()
234
236 """
237 Tear down server and process monitor. Not multithread safe.
238 """
239
240
241
242 if self._shutting_down:
243 return
244 self._shutting_down = True
245
246 if self.server:
247 try:
248 self.server.shutdown("roslaunch parent complete")
249 except:
250
251 pass
252 if self.pm:
253 self.pm.shutdown()
254 self.pm.join()
255
256 - def start(self, auto_terminate=True):
257 """
258 Run the parent roslaunch.
259
260 @param auto_terminate: stop process monitor once there are no
261 more processes to monitor (default True). This defaults to
262 True, which is the command-line behavior of roslaunch. Scripts
263 may wish to set this to False if they wish to keep the
264 roslauch infrastructure up regardless of processes being
265 monitored.
266 """
267 self.logger.info("starting roslaunch parent run")
268
269
270 try:
271 self._start_infrastructure()
272 except:
273
274 self._stop_infrastructure()
275 raise
276
277
278
279 self._init_runner()
280
281
282 self.runner.launch()
283
284
285 if auto_terminate:
286 self.pm.registrations_complete()
287
288 self.logger.info("... roslaunch parent running, waiting for process exit")
289 if self.process_listeners:
290 for l in self.process_listeners:
291 self.runner.pm.add_process_listener(l)
292
293
294 self.server.add_process_listener(l)
295
297 """
298 Run the parent roslaunch event loop once
299 """
300 if self.runner:
301 self.runner.spin_once()
302
304 """
305 Run the parent roslaunch until exit
306 """
307 if not self.runner:
308 raise RLException("parent not started yet")
309 try:
310
311 self.runner.spin()
312 finally:
313 self._stop_infrastructure()
314
316 """
317 Stop the parent roslaunch.
318 """
319 self._stop_infrastructure()
320