ros2 / launch Goto Github PK
View Code? Open in Web Editor NEWTools for launching multiple processes and for writing tests involving multiple processes.
License: Apache License 2.0
Tools for launching multiple processes and for writing tests involving multiple processes.
License: Apache License 2.0
Add a way to launch processes on multiple machines using ssh in a fashion similar to the old launch system. Would allow for the launching of more complex systems.
Currently if you provide an instance of an Action to be visited more than once it will be and that breaks the assumption of one time use of some Actions like ExecuteProcess
.
Instead Actions should declare if they're reusable or not (default to not probably) and then get an appropriate error when they are accidentally reused.
Follow up of #90 (comment)
A convenience option to avoid the need to manually create a UnregisterEventHandler
action for "one off" event handlers.
Follow up of #90
Many nodes need configuration or parameters to make it flexible, however I didn't found a good example to show how to load parameters, as rosparam or param do in ROS. I think it's a necessary feature to ROS2.
Similar as rosparam and param in ROS.
Define some keywords in Descriptors, load or parser the parameters and configurations, pass them to node. Node set them through ParameterService.
I'm proposing/requesting a way for roslaunch to detect failures and restart components using reasonable defaults and programmable parameters, and I'm hopeful that this proposal complements the ROS 2 document about node lifecycles nicely, and will perhaps become how such lifecycles are managed.
This idea probably needs some refinement but here is my first pass based on the conversation at:
https://groups.google.com/forum/#!topic/ros-sig-ng-ros/0HzF5J6hu4k
This bears some similarities for roscore in ROS 1, but it is for a different purpose.
Launch files specify expected behavior of the nodes, and roslaunch verifies that those conditions are met. If the conditions are violated the node is automatically killed and relaunched.
For example, a minimum and maximum frequency of messages published on specified topics, and perhaps a heartbeat message that exists and is enabled by default. If the heartbeat fails or publishing rates exceed the max then the node is killed and relaunched.
All nodes would have this behavior integrated and enabled by default with reasonable default parameters that work for 90% of users. Assuming launch files are python (I think this was discussed in the mailing list) when other requirements exist this functionality can be disabled or modified with explicit changes to the launch file code.
Note that the roslaunch command can still be used exactly as it is now by users. The only difference is that when run, a new roslaunch process would look for an existing running daemon and if one exists, it would pass its parameters to the perpetual daemon to perform the actual launching.
The roslaunch daemon is supplied as one of the items to launch at OS boot by default #31
If not by default, I suggest a simple one line command which enables booting at OS launch. This should hopefully be cross platform, i.e. work for ubuntu, linux, mac, and perhaps other OSes.
The roslaunch daemon should detect its own crashes and/or death and automatically restart itself, except when a user runs something such as roslaunch shutdown
which tells it to exit permanently.
This could be done by an extremely simple micro-daemon or script which only manages roslaunch.
I believe it might be wise to separate the description of a process to be executed and its state while running from the Action which executes it.
Currently all of this information is encapsulated in the ExecuteProcess
action, and my proposal would be to replace that with an action called Execute
that takes an Executable
(not an action or launch description entity, just a new kind of class). The Executable
would contain any information needed by Execute
to actually execute the executable described or introspect it. There could be sub classes of both Execute
and Executable
. For instance, a sub class of Executable
might be Node
or LifecycleNode
, and a sub class of Execute
might be ExecuteRemotely
(execute on a different machine).
The reasons for doing this include:
Executable
s (or subclasses thereof) with other actionsExecuteProcess
class is really big now and it would be nice to break into smaller partsExecute(Executable(...))
or Execute(Node(...))
rather than ExecuteProcess(...)
and Node(...)
The first reason is the most impactful, because it allows for a few use cases that aren't currently easy to implement:
Executable
instances and later decide whether to pass to Execute
, ExecuteRemotely
, or ExecuteInDocker
(just ideas)ComponentNode
(possibly a subclass of Executable
which represents a node that can be loaded dynamically) to either Execute()
or ExecuteNodesInSharedProcess()
(name needs work)
ComponentNode
instances and run them all in a single processI still have some design questions in mind, like:
Node
inherit from Executable
Executable
contain process related things like pid
and produce events for stdout and process exit, etc...
Process
that also inherits from Executable
Node
might not be associated with a process, or rather a process might not be associated with a single Node
Executable
and Execute
?
Execute
?The launch library can be used to turn system tests into nosetests. However if the subcomponents of the system tests are either nosetests or gtests their xml output is not captured, only the return code is utilized.
rostest had a specific tag "test" which was aware that the subprocess was going to generate an xunit output passed appropriate flags to the subprocess and gathered up the results of the subprocess. We should support the same functionality to support system tests.
Most of our usage of launch files is in tests, where launch_testing causes signals to be sent. But if you run them manually and ctrl-c them, they hang (for example demo_nodes_cpp
's test_set_and_get_parameters__rmw_fastrtps_cpp_Release.py
). I'm yet to find a launch file that doesn't cause this to happen.
In ros2/demos#175 (comment) @dirk-thomas noted that
The process hangs for me in
launcher.py
on theloop.close()
call. Both subprocesses have beenSIGTERM
ed and the loop is not running anymore. But theclose()
call still hangs forever.
Simple ROS2-agnostic example:
$ cat launch_wait.py
import os
from launch import LaunchDescriptor
from launch.launcher import DefaultLauncher
def main():
launcher = DefaultLauncher()
launch_descriptor = LaunchDescriptor()
if os.name == 'nt':
cmd=['ping', '127.0.0.1', '-n', '60']
else:
cmd=['sleep', '60']
launch_descriptor.add_process(
cmd=cmd,
name='dummy_process',
)
launcher.add_launch_descriptor(launch_descriptor)
rc = launcher.launch()
print('Return code: ' + str(rc))
exit(rc)
if __name__ == '__main__':
main()
Behaviour on linux:
$ python3 launch_wait.py
(dummy_process) pid 13687: ['sleep', '60'] (stderr > stdout, all > console)
^C(dummy_process) signal SIGINT
(dummy_process) rc -2
Return code: 1
Behaviour on windows:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC>python C:\Users\osrf\Downloads\r2b3-testing\overlay\src\launch_nothing.py
(dummy_process) pid 4416: ['ping', '127.0.0.1', '-n', '60'] (stderr > stdout, all > console)
[dummy_process]
[dummy_process] Pinging 127.0.0.1 with 32 bytes of data:
[dummy_process] Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
[dummy_process] Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
[dummy_process] Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
<manually ctrl c>
(dummy_process) signal SIGTERM
(dummy_process) rc 3221225786
<hangs>
Required Info:
$ ros2 launch share/demo_nodes_cpp/launch/topics/talker_listener.launch.py
Let it run for a few seconds, then Ctrl-C:
root@changeling:~/ros2-linux# ros2 launch share/demo_nodes_cpp/launch/topics/talker_listener.launch.py
[INFO] [launch]: process[talker-1]: started with pid [21936]
[INFO] [launch]: process[listener-2]: started with pid [21937]
[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [listener]: I heard: [Hello World: 1]
[INFO] [talker]: Publishing: 'Hello World: 2'
[INFO] [listener]: I heard: [Hello World: 2]
[INFO] [talker]: Publishing: 'Hello World: 3'
[INFO] [listener]: I heard: [Hello World: 3]
^C[WARNING] [launch.LaunchService]: user interrupted with ctrl-c (SIGINT)
signal_handler(2)
signal_handler(2)
[INFO] [launch]: process[talker-1]: process has finished cleanly
[INFO] [launch]: process[listener-2]: process has finished cleanly
It hangs there forever, until the user hits Ctrl-C.
Launch file terminates cleanly on first Ctrl-C
Launch hangs around "forever".
I do not get the option of launch after typing ros2
This is the error msg
invalid choice: 'launch' (choose from 'daemon', 'extension_points', 'extensions', 'lifecycle', 'msg', 'node', 'param', 'pkg', 'run', 'security', 'service', 'srv', 'topic')
How do I use launch command?
Requires #115
At first IncludeLaunchDescription
will require the creator to pass a LaunchDescription
object, but it should also be able to take a path to a .launch.py
file and then interpret it, call generate_launch_description()
from it, and use that LaunchDescription
. This might need a new Action or it could just be a feature of IncludeLaunchDescription
.
The concept of a "Condition" is a predicate that applies to certain kinds of entities like (but not exclusively) launch.Action
.
This is the equivalent of if
and unless
attributes in roslaunch
from ROS 1:
https://wiki.ros.org/roslaunch/XML#if_and_unless_attributes
The proposed launch.Condition
would:
There could be sub classes for convenience like launch.IfCondition
and launch.UnlessCondition
.
Conditions will need to be part of the interface of any entity which can be affected by them (i.e. either Action
or LaunchDescriptionEntity
should have a condition
argument to the constructor.
One thing I haven't decided on is how to combine multiple conditions, the options are:
Substitution
s like launch.substitutions.PythonExpression
Condition
, like CompoundCondition
or AndCondition
/OrCondition
.Using last night's packaging job:
This only happens for rmw_opensplice_cpp:
C:\J\workspace\packaging_windows\ws>ros2 launch demo_nodes_cpp talker_listener.launch.py
[INFO] [launch]: process[talker.EXE-1]: started with pid [800]
[INFO] [launch]: process[listener.EXE-2]: started with pid [6560]
[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [listener]: I heard: [Hello World: 1]
[INFO] [talker]: Publishing: 'Hello World: 2'
[INFO] [listener]: I heard: [Hello World: 2]
ssignal_handler(2)
[WARNING] [launch.LaunchService]: user interrupted with ctrl-c (SIGINT)
--- Logging error ---
Traceback (most recent call last):
File "c:\python36\lib\logging\__init__.py", line 995, in emit
stream.write(self.terminator)
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stderr>'>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\python36\lib\logging\__init__.py", line 995, in emit
stream.write(self.terminator)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\utilities\signal_management.py", line 121, in __on_sigint
__custom_sigint_handler(signum, frame)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\launch_service.py", line 291, in _on_sigint
_logger.warn(base_msg)
File "c:\python36\lib\logging\__init__.py", line 1323, in warn
self.warning(msg, *args, **kwargs)
File "c:\python36\lib\logging\__init__.py", line 1318, in warning
self._log(WARNING, msg, args, **kwargs)
File "c:\python36\lib\logging\__init__.py", line 1442, in _log
self.handle(record)
File "c:\python36\lib\logging\__init__.py", line 1452, in handle
self.callHandlers(record)
File "c:\python36\lib\logging\__init__.py", line 1514, in callHandlers
hdlr.handle(record)
File "c:\python36\lib\logging\__init__.py", line 863, in handle
self.emit(record)
File "c:\python36\lib\logging\__init__.py", line 998, in emit
self.handleError(record)
File "c:\python36\lib\logging\__init__.py", line 915, in handleError
sys.stderr.write('--- Logging error ---\n')
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stderr>'>
Call stack:
File "C:\J\workspace\packaging_windows\ws\install\Scripts\ros2-script.py", line 11, in <module>
load_entry_point('ros2cli==0.4.0', 'console_scripts', 'ros2')()
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\ros2cli\cli.py", line 69, in main
rc = extension.main(parser=parser, args=args)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\ros2launch\command\launch.py", line 78, in main
debug=args.debug
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\ros2launch\api\api.py", line 127, in launch_a_python_launch_file
return launch_service.run()
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\launch_service.py", line 314, in run
self.__loop_from_run_thread.run_until_complete(run_loop_task)
File "c:\python36\lib\asyncio\base_events.py", line 455, in run_until_complete
self.run_forever()
File "c:\python36\lib\asyncio\base_events.py", line 422, in run_forever
self._run_once()
File "c:\python36\lib\asyncio\base_events.py", line 1432, in _run_once
handle._run()
File "c:\python36\lib\asyncio\events.py", line 145, in _run
self._callback(*self._args)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\launch_service.py", line 177, in _process_one_event
await self.__process_event(next_event)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\launch_service.py", line 186, in __process_event
entities = event_handler.handle(event, self.__context)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\event_handlers\on_process_io.py", line 73, in handle
return self.__on_stdout(event)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch_ros\default_launch_description.py", line 57, in _on_process_output
print(text, end='')
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\utilities\signal_management.py", line 121, in __on_sigint
__custom_sigint_handler(signum, frame)
File "C:\J\workspace\packaging_windows\ws\install\Lib\site-packages\launch\launch_service.py", line 291, in _on_sigint
_logger.warn(base_msg)
Message: 'user interrupted with ctrl-c (SIGINT)'
Arguments: ()
ignal_handler(2)
[ERROR] [launch]: process[listener.EXE-2] process has died [pid 6560, exit code 3221225786, cmd 'C:\J\workspace\packaging_windows\ws\install\lib\demo_nodes_cpp\listener.EXE'].
[ERROR] [launch]: process[talker.EXE-1] process has died [pid 800, exit code 3221225786, cmd 'C:\J\workspace\packaging_windows\ws\install\lib\demo_nodes_cpp\talker.EXE'].
Works fine for e.g. connext:
C:\J\workspace\packaging_windows\ws>set RMW_IMPLEMENTATION=rmw_connext_cpp
C:\J\workspace\packaging_windows\ws>ros2 launch demo_nodes_cpp talker_listener.launch.py
RTI Data Distribution Service Evaluation License issued to OSRF (OSRF01) [email protected] For non-production use only.
Expires on 5-Nov-2018 See www.rti.com for more information.
[INFO] [launch]: process[talker.EXE-1]: started with pid [7312]
[INFO] [launch]: process[listener.EXE-2]: started with pid [10856]
RTI Data Distribution Service Evaluation License issued to OSRF (OSRF01) [email protected] For non-production use only.
Expires on 5-Nov-2018 See www.rti.com for more information.
RTI Data Distribution Service Evaluation License issued to OSRF (OSRF01) [email protected] For non-production use only.
Expires on 5-Nov-2018 See www.rti.com for more information.
[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [listener]: I heard: [Hello World: 1]
[INFO] [talker]: Publishing: 'Hello World: 2'
[INFO] [listener]: I heard: [Hello World: 2]
[WARNING] [launch.LaunchService]: user interrupted with ctrl-c (SIGINT)
signal_handler(2)
signal_handler(2)
[INFO] [launch]: process[listener.EXE-2]: process has finished cleanly
[INFO] [launch]: process[talker.EXE-1]: process has finished cleanly
I'm proposing/requesting a way for a launch file or launch command to automatically be run when the computer boots, which is fully integrated and automated via ros2/launch.
Based on conversation at:
https://groups.google.com/forum/#!topic/ros-sig-ng-ros/0HzF5J6hu4k
Here is one proposal for how this could work, although alternative designs are worth considering:
roslaunch <my_params> --add-at-startup
expected behavior:
roslaunch --list-at-startup
expected behavior:
prints a list of commands that run every time the machine starts (perhaps with numeric ids?)
roslaunch --remove-at-startup <id>
expected behavior:
remove the item with id from the startup list.
a tag that goes in .launch files, whenever the launch is run this automatically adds it to the startup list
The idea behind the concept of LaunchArgument
is that it should be something you can declare (perhaps as an Action) in a launch description which indicates some input configurations to the launch description.
If the launch description is included by another launch description then the arguments would be part of that action, but if the launch description is "run" by ros2 launch
it would be possible to pass them as command line arguments.
This is partially equivalent to the <arg>
tag in roslaunch
from ROS 1:
https://wiki.ros.org/roslaunch/XML/arg
It should take a name, optionally a default value, optionally documentation for the argument, and possibly other things commonly associated with command line arguments, like being a flag rather than a key-value option or with special validation logic (is it the right type or in the right range)? Initially it should always have a type of string, and it can be evaluated by the things consuming it.
The result (default value or user provided) would be stored in a LaunchConfiguration
of the same name.
Right now there is a lot of this in the launcher code:
if 'protocol' in dir(p):
do stuff for process
if 'coroutine' in dir(p):
do stuff for coroutine
Does it make sense to do something like this instead:
if isinstance(p, ProcessDescriptor):
do stuff for process
if isinstance(p, CoroutineDescriptor):
do stuff for coroutine
Or does that not canonical python?
This isn't currently supported but it would be convenient; opening for visibility/tracking.
e.g. if I have an ament_python
package, when I swap to installing with symlink, a launch invocation that was otherwise successful then gives:
$ ros2 launch topic_monitor launch_reliability_demo.launch.py
file 'launch_reliability_demo.launch.py' was not found in the share directory of package 'topic_monitor' which is at '/Users/dhood/ros2_ws/install_isolated/topic_monitor/share/topic_monitor'
$ ros2 launch demo_nodes_cpp add_two_ints.launch.py
[INFO] [launch]: process[add_two_ints_server-1]: started with pid [17647]
[INFO] [launch]: process[add_two_ints_client-2]: started with pid [17648]
[INFO] [add_two_ints_server]: Incoming request
a: 2 b: 3
[INFO] [add_two_ints_client]: Result of add_two_ints: 5
[INFO] [launch]: process[add_two_ints_client-2]: process has finished cleanly
[INFO] [launch]: sending signal 'SIGINT' to process[add_two_ints_server-1]
signal_handler(2)
[INFO] [launch]: process[add_two_ints_server-1]: process has finished cleanly
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/base_events.py", line 431, in __del__
File "/usr/lib/python3.5/asyncio/unix_events.py", line 58, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 139, in remove_signal_handler
File "/usr/lib/python3.5/signal.py", line 47, in signal
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
Seems like it's from https://bugs.python.org/issue23548 (you may have fixed this before @wjwwood , you are in the thread ๐ )
Previously I had described a "Group" or "Group of Actions" as a separate entity from "Action", but since then I think we can just have a special Action that yields other actions and optionally does things like pushes/pops the launch configurations and set/unset specific launch configurations.
I believe the action I've described is capable of fulfilling the use cases I originally imagined for groups:
ros_namespace
LaunchConfiguration
that affects only the actions it yields
launch/launch_ros/launch_ros/actions/node.py
Lines 80 to 81 in b78d87f
LaunchContext
to push and pop them
launch/launch/launch/launch_context.py
Lines 146 to 157 in b78d87f
We should also update the design document (ros2/design#163).
While porting some ROS 1 packages to ROS 2 I wanted to also migrate the rostest
s. Currently there is no API yet in launch_testing
(beside the legacy API).
I tried two different approaches - the idea would be to move the "generic" stuff from one of these prototypes into launch_testing
in order to be able to reuse it across tests:
LaunchDescription
as well as the LaunchService
(GT-RAIL/async_web_server_cpp@1dad9c5). In this case the whole launch file uses those custom classes instead of the original ones. The custom description contains the logic for the return code handling and shutting down. The custom service contains the logic to use the return codes from the test actions as the global return code.The downside of this approach is that requires the launch file specifically being written for testing (by using these custom classes).
LaunchTestService
) is used in addition to the normal launch entities and the actions which are tests are being registered at that class and the class also wraps the run
invocation on the "normal" launch service: (GT-RAIL/async_web_server_cpp@fc6f35a)Any kind of feedback is highly appreciated.
Features:
rclcpp_components
] CMake support macros for building Node's as "components"๐ท
rclcpp
] Consolidate node arguments into a single options class to simplify user defined Node classes ๐ท
rclcpp
] Consolidate how arguments are converted into configurations for the node (i.e. command line arguments into remappings and initial parameter values) ๐ทrclcpp_components
] Node component container executable(s)๐ทlaunch_ros
] Define nodes and then specify where they run separately
launch
] consider refactoring ExecuteProcess into Execute and Executable (#114)launch_ros
] add ability to pass parameters to Node actions (#117) โ
Minor Features:
launch
] add new concept for LaunchArgument (#107) โ
launch
] provide default console and filesystem logging for executed processes (#104) ๐ทlaunch
] add concept of Conditions (#105) โ
launch
] add new Action called UnsetLaunchConfiguration (#108) โ
launch
] add new Action called UnregisterEventHandler (#110) โ
launch
] add option to RegisterEventHandler so that it unregisters itself after one event (#111) โ
Technical Enhancements and Bugs:
launch
] improve test coverage for non-core classes (#102) ๐ทlaunch
] prevent launch from hanging when unexpected exceptions occur internally (#112) ๐ทlaunch
] prevent Actions from being reused (#113)Excluded Features:
launch
] Multi-machine Launching (#79)Excluded Technical Enhancements and Bugs:
launch
] refactor introspection system (#103)launch
] check that iterable contains only types in ensure_argument_type() (#109)Anti-goals (things launch should not do itself):
Required Info:
ros2 launch demo_nodes_cpp talker_listener.launch.py
Exits after ctrl-c.
Does not.
Without an action UnregisterEventHandler
you have to use an OpaqueFunction
and the LaunchContext
to manually unregister an event handler, which is not introspectable.
A follow up of #90, where an exception in the default ros launch description caused launch itself to hang, see:
http://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html#variables
causes failures on xenial jobs, e.g.:
from .launch_context import LaunchContext
E File "/home/rosbuild/ci_scripts/ws/install/launch/lib/python3.5/site-packages/launch/launch_context.py", line 45
E self._event_queue: asyncio.Queue = asyncio.Queue()
E ^
E SyntaxError: invalid syntax
Required Info:
Run the following python code
#!/usr/bin/env python
import sys
import time
import threading
from launch import LaunchDescription
from launch import LaunchService
import launch_ros.actions
def main():
ld = LaunchDescription([
launch_ros.actions.Node(
package='demo_nodes_cpp', node_executable='listener', output='screen'),
])
ls = LaunchService()
ls.include_launch_description(ld)
t = threading.Thread(target=ls.run)
t.start()
time.sleep(5) # wait for listener to fully start
ls.shutdown()
t.join()
if __name__=="__main__":
main()
I expect the listener executable to terminate and the python code to exit.
The python script produces the following output but never terminates.
[INFO] [launch]: process[listener-1]: started with pid [20208]
Starting shutdown
[INFO] [launch]: sending signal 'SIGINT' to process[listener-1]
[ERROR] [launch]: process[listener-1] failed to terminate '5' seconds after receiving 'SIGINT', escalating to 'SIGTERM'
[INFO] [launch]: sending signal 'SIGTERM' to process[listener-1]
[ERROR] [launch]: process[listener-1] failed to terminate '10.0' seconds after receiving 'SIGTERM', escalating to 'SIGKILL'
[INFO] [launch]: sending signal 'SIGKILL' to process[listener-1]
The listener executable in fact terminates when the SIGINT is sent and remains as a zombie process.
20208 pts/20 Z+ 0:00 [listener] <defunct>
Currently in launch
an executed process does not have anything printed to the console and nothing is logged to a file.
Some of the examples will create custom event handlers for this:
launch/launch/examples/launch_counters.py
Lines 51 to 62 in b78d87f
The "default launch description" provided by launch_ros
also creates an event handler to cause executed processes to print to the console if configured to do so (with the output=
option to ExecuteProcess
and it's derived classes like Node
):
launch/launch_ros/launch_ros/default_launch_description.py
Lines 49 to 65 in b78d87f
But even this doesn't handle writing process output to a log file:
Ideally, there would be some facility for this built into launch
and launch_ros
could additionally configure it to write files to something like ROS_HOME
where as it might go to ~/.launch_logs
(or something like that) instead. The user could further configure this default event handler if desired.
The user would still be able to provide their own event handler for output from process, to be run along with the default or instead of it.
Hi,
I was trying to find out how to use this launch script. After some googling I found this: https://github.com/ros2/turtlebot2_demo/blob/master/turtlebot2_teleop/launch/turtlebot_joy.py
With the following example:
def launch(launch_descriptor, argv):
ld = launch_descriptor
package = 'turtlebot2_drivers'
ld.add_process(
cmd=[get_executable_path(package_name=package, executable_name='kobuki_node')],
name='kobuki_node',
exit_handler=restart_exit_handler,
)
package = 'teleop_twist_joy'
Is this the final API? It looks quite heavy. The first thing I did was to make my own function:
def add(ld, pkg, name, exit_on_die=True):
if exit_on_die:
handler = restart_exit_handler,
else:
handler = default_exit_handler
ld.add_process(
cmd=[get_executable_path(package_name=pkg, executable_name=name)],
name=name,
exit_handler=handler
)
So this bug request is about two things
1- If this is the expected API/syntax in launch file. Can I update README/Wiki to document it?
2- If this is not the final API, what will it be? What is missing?
Thanks
Printing to stdout from a coroutine does not seem to get captured by the InMemoryHandler defined in launch_testing.
Gist with sample code:
launch/launch/launch/launcher.py
Line 103 in 9d789b3
Nosetests using launch for testing fail because of that.
Inside the https://github.com/ros2/launch/blob/master/launch/launch/exit_handler.py file, all the exit handlers ignore output, restart the program, or run the default_exit_handler, which shuts all the programs down. I want to launch a program and check its return code for failure. If the error code is non-zero, the launch file should tear itself down. Is that in line with the current design?
Required Info:
Launch system for 2 nodes (talker --> lifecycle node and listener --> regular node) with following actions:
from launch import LaunchDescription
import launch
import launch.actions
import launch.events
import launch_ros.actions
import launch_ros.events
import launch_ros.events.lifecycle
import lifecycle_msgs.msg
def generate_launch_description():
lifecycle_talker = launch_ros.actions.LifecycleNode(
node_name = 'talker', package='lifecycle', node_executable='lifecycle_talker', output='screen')
lifecycle_listener = launch_ros.actions.LifecycleNode(
node_name='listener', package='lifecycle', node_executable='lifecycle_listener', output='screen')
# When the talker reaches the 'inactive' state, make it take the 'activate' transition
register_event_handler_for_talker_reaches_inactive_state = launch.actions.RegisterEventHandler(
launch_ros.event_handlers.OnStateTransition(
target_lifecycle_node=lifecycle_talker, goal_state='inactive',
entities=[
launch.actions.LogInfo(
msg="node 'talker' reached the 'inactive' state, 'activating'."),
launch.actions.EmitEvent(event=launch_ros.events.lifecycle.ChangeState(
lifecycle_node_matcher=launch.events.process.matches_action(lifecycle_talker),
transition_id=lifecycle_msgs.msg.Transition.TRANSITION_ACTIVATE,
)),
],
)
)
# When the talker node reaches the 'active' state, log a message and start the listener node.
register_event_handler_for_talker_reaches_active_state = launch.actions.RegisterEventHandler(
launch_ros.event_handlers.OnStateTransition(
target_lifecycle_node=lifecycle_talker, goal_state='active',
entities=[
launch.actions.LogInfo(
msg="node 'talker' reached the 'active' state, launching 'listener'."),
lifecycle_listener,
],
)
)
# Make the talker node take the 'configure' transition.
emit_event_to_request_that_talker_does_configure_transition = launch.actions.EmitEvent(
event=launch_ros.events.lifecycle.ChangeState(
lifecycle_node_matcher=launch.events.process.matches_action(lifecycle_talker),
transition_id=lifecycle_msgs.msg.Transition.TRANSITION_CONFIGURE,
)
)
"""Launch a talker and a listener."""
return LaunchDescription([
register_event_handler_for_talker_reaches_inactive_state,
register_event_handler_for_talker_reaches_active_state,
lifecycle_talker,
emit_event_to_request_that_talker_does_configure_transition
])
Start the launch and when talker node is in Active state, trigger transition to Inactive with
ros2 lifecycle set talker deactivate
Once the talker node is back in the Active state, Ctrl-C
makes the launch to hung with the following error:
^C[WARNING] [launch.LaunchService]: user interrupted with ctrl-c (SIGINT)
signal_handler(2)
signal_handler(2)
[INFO] [launch]: process[lifecycle_talker-1]: process has finished cleanly
[INFO] [launch]: process[lifecycle_listener-3]: process has finished cleanly
[INFO] [launch]: process[lifecycle_listener-2]: process has finished cleanly
[ERROR] [asyncio]: Task exception was never retrieved
future: <Task finished coro=<ExecuteProcess.__execute_process() done, defined at /home/sumanth.nirmal/ros2_ws/install/lib/python3.5/site-packages/launch/actions/execute_process.py:380> exception=InvalidStateError('FINISHED: <Future finished result=None>',)>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "/home/sumanth.nirmal/ros2_ws/install/lib/python3.5/site-packages/launch/actions/execute_process.py", line 424, in __execute_process
self.__cleanup()
File "/home/sumanth.nirmal/ros2_ws/install/lib/python3.5/site-packages/launch/actions/execute_process.py", line 321, in __cleanup
self.__completed_future.set_result(None)
File "/usr/lib/python3.5/asyncio/futures.py", line 329, in set_result
raise InvalidStateError('{}: {!r}'.format(self._state, self))
asyncio.futures.InvalidStateError: FINISHED: <Future finished result=None>
signal_handler(2)
The launch system cleanly exit on Ctrl-C
The launch system hangs on Ctrl-C
with the above launch file
Also every time the talker node reaches Active state it starts a new Listener node.
If you run the pub sub example of the new-style launch files with debug hard-coded to True, after a keyboard interrupt you can see all of the shutdown handling (with fastrtps/connext):
RMW_IMPLEMENTATION=rmw_fastrtps_cpp python3 src/ros2/launch/launch_ros/examples/pub_sub_launch.py
...
[INFO] [talker]: Publishing: 'Hello World: 4'
[DEBUG] [launch]: emitting event synchronously: 'launch.events.process.ProcessStdout'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b1819ef98>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b1819ef98>' โ '<launch.event_handlers.on_process_io.OnProcessIO object at 0x7f0b1b2cf550>'
[INFO] [listener]: I heard: [Hello World: 4]
^C[WARNING] [launch.LaunchService]: user interrupted with ctrl-c (SIGINT)
[INFO] [asyncio]: %r was closed by peer
[INFO] [asyncio]: %r was closed by peer
[DEBUG] [launch]: emitting event: 'launch.events.Shutdown'
[DEBUG] [launch]: emitting event synchronously: 'launch.events.process.ProcessStdout'
[DEBUG] [launch]: emitting event synchronously: 'launch.events.process.ProcessStdout'
[INFO] [asyncio]: %r was closed by peer
[INFO] [asyncio]: %r was closed by peer
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.shutdown.Shutdown object at 0x7f0b19194f98>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.shutdown.Shutdown object at 0x7f0b19194f98>' โ '<launch.event_handlers.on_shutdown.OnShutdown object at 0x7f0b1819e748>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.shutdown.Shutdown object at 0x7f0b19194f98>' โ '<launch.event_handlers.on_shutdown.OnShutdown object at 0x7f0b1819e0b8>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.shutdown.Shutdown object at 0x7f0b19194f98>' โ '<launch.event_handlers.on_shutdown.OnShutdown object at 0x7f0b1b2cfe10>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.shutdown.Shutdown object at 0x7f0b19194f98>' โ '<launch.event_handlers.on_shutdown.OnShutdown object at 0x7f0b1b2cf390>'
[WARNING] [asyncio]: Executing %s took %.3f seconds
[INFO] [asyncio]: %r exited with return code %r
[INFO] [asyncio]: %r exited with return code %r
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b14f3f518>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b14f3f518>' โ '<launch.event_handlers.on_process_io.OnProcessIO object at 0x7f0b1b2cf550>'
signal_handler(2)
[INFO] [launch]: process[talker-1]: process has finished cleanly
[DEBUG] [launch]: emitting event: 'launch.events.process.ProcessExited'
[INFO] [launch]: process[listener-2]: process has finished cleanly
[DEBUG] [launch]: emitting event: 'launch.events.process.ProcessExited'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b14f3f208>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0b14f3f208>' โ '<launch.event_handlers.on_process_io.OnProcessIO object at 0x7f0b1b2cf550>'
signal_handler(2)
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_exited.ProcessExited object at 0x7f0b1b2cf5c0>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_exited.ProcessExited object at 0x7f0b1b2cf5c0>' โ '<launch.event_handler.EventHandler object at 0x7f0b1b2cf4e0>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_exited.ProcessExited object at 0x7f0b14f3f518>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_exited.ProcessExited object at 0x7f0b14f3f518>' โ '<launch.event_handler.EventHandler object at 0x7f0b1b2cf4e0>'
But for Opensplice you get a segfault:
$ RMW_IMPLEMENTATION=rmw_opensplice_cpp python3 src/ros2/launch/launch_ros/examples/pub_sub_launch.py
...
[INFO] [talker]: Publishing: 'Hello World: 2'
[DEBUG] [launch]: emitting event synchronously: 'launch.events.process.ProcessStdout'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0975e89e10>'
[DEBUG] [launch.LaunchService]: processing event: '<launch.events.process.process_stdout.ProcessStdout object at 0x7f0975e89e10>' โ '<launch.event_handlers.on_process_io.OnProcessIO object at 0x7f0978fac5c0>'
[INFO] [listener]: I heard: [Hello World: 2]
^CSegmentation fault (core dumped)
I was not able to produce it with legacy launch but I did notice that it also happens even with only the default ROS launch descriptor included.
In ros2/rcl#198 I tried to add a test that checks for non-zero return codes for a particular process. On windows, the process would have a non-zero return code, but the launch would always have a return code of 0.
I think, using the default exit handler, it's not possible for the return code to ever be set on windows, because this line:
launch/launch/launch/exit_handler.py
Line 43 in a1057c7
combined with the line above that always ensures that context.launch_state.teardown
is True
:
launch/launch/launch/exit_handler.py
Line 36 in a1057c7
means that the branch where the return code of the launch is set can never be entered.
Currently there are minimal tests for some of the core classes like LaunchDescription
, LaunchService
, and Action
, but there's not really any tests for things like:
launch.LaunchInstrospector
launch.Substitution
launch.actions
launch.event_handlers
launch.events
launch.substitutions
launch.utilities
launch_testing
has support for filtering the RTI license output when checking that the received output matches the expected output. If the license output appears and is not being filtered, then the check fails. I think that this is the desired behaviour.
However, this concept seems to be implemented differently for the case when regex_match
is True
. The license output is always ignored, whether or not it was supposed to be. (And any other output that appears that doesn't match the regex)
These non-matching, un-filtered lines are written here and read here, but since self.matched
is True
, the assertion does not fail.
Am I right in interpreting this as a bug that I should fix?
Some effort was already invested to express intent without side-effects in the new launch api, and each entity in a launch description can express itself and related, or "sub" entities. However, the introspection interfaces of various entities (Actions, Event Handlers, Events, Subsitutions, etc...) need to be refined to avoid impassible and opaque boundaries in the description when introspecting.
I have some ideas of what needs to change already, but ran out of time before the bouncy release. The launch.LaunchDescriptionEntity
interfaces for this are the most "mature" and reflect somewhat closely what I'd like to update the other entities (like EventHandler
and Substitution
) to look like in the future:
launch/launch/launch/launch_description_entity.py
Lines 57 to 101 in b78d87f
The above interfaces may also need some work. Additionally, I think that right now the mechanism to "render" an entity during introspection (render to text for printing on the console in the case of launch.LaunchIntrospector
) needs to be placed with or along side the entities themselves. Currently this logic is in the LaunchIntrospector
, which was only done to get something working rapidly:
launch/launch/launch/launch_introspector.py
Lines 72 to 140 in b78d87f
Lastly, specific entities need to implement these interfaces and handle any special logic to make them useful during introspection. Specifically I noticed:
launch.EventHandlers
could report what is yielded when an event is handledlaunch.Action
s (e.g. the ExecuteProcess
action could report more of what it might do in certain situations)A stretch goal of this refactoring would be to add some notion of "details" when introspecting, e.g. you might just want to see that a process is getting run and not all the various and tedious things it might do in every situation, unless you asked for those details, in which case it would show them. Basically some way for an entity to express that some sub entities and parts of its own description are implementation details and not usually important to express.
On my latest Windows job I'm seeing errors like this:
http://ci.ros2.org/job/ros2_batch_ci_windows/299/console
19:09:05 39: ======================================================================
19:09:05 39: ERROR: test_publisher_subscriber_cpp__nested__rmw_connext_dynamic_cpp__rmw_connext_cpp.test_publisher_subscriber
19:09:05 39: ----------------------------------------------------------------------
19:09:05 39: Traceback (most recent call last):
19:09:05 39: File "C:\tools\python\lib\site-packages\nose\case.py", line 198, in runTest
19:09:05 39: self.test(*self.arg)
19:09:05 39: File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\build\test_communication\test_publisher_subscriber_cpp__nested__rmw_connext_dynamic_cpp__rmw_connext_cpp.py", line 22, in test_publisher_subscriber
19:09:05 39: rc = launcher.launch()
19:09:05 39: File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\install\Lib\site-packages\launch\launcher.py", line 57, in launch
19:09:05 39: asyncio.get_event_loop_policy().set_child_watcher(None)
19:09:05 39: File "C:\tools\python\lib\asyncio\events.py", line 486, in set_child_watcher
19:09:05 39: raise NotImplementedError
19:09:05 39: nose.proxy.NotImplementedError:
19:09:05 39: -------------------- >> begin captured stdout << ---------------------
I think it might be related to this change?: 3684223#diff-64876ece93fadad6549af3a8bcb112c7R57
I'm not sure though.
Spawned processes always get the parent's environment even though a specific env parameter is given.
Reproducible example here
Required Info:
> ros2 launch demo_nodes_cpp talker_listener.launch.py
Runs the talker and listener.
Blocks with no output.
I've already been looking into the issue for a while, but I'm going to stop and pick it up tomorrow. Just wanted to open this for visibility.
I'm proposing/requesting a way for a roslaunch daemon to automate software updates
This is dependent on #32, and related to #31.
This idea probably needs some refinement but here is my first pass based on the conversation at:
https://groups.google.com/forum/#!topic/ros-sig-ng-ros/0HzF5J6hu4k
The roslaunch daemon would provide a facility where it receives an update message for a specific component or set of components. The daemon would take down all relevant nodes (or potentially all running nodes), then run a command which downloads/updates packages. (perhaps rosdep update?)
It should be possible to support updates from forks of ros, and provide packages on a local network and/or on a USB stick.
If possible, I would suggest these updates be verified with some sort of signature from the start.
Once the update is completed, which may include updates to the list of roslaunch commands proposed in #31, all nodes which are down should be automatically relaunched.
Currently you can pass remapping arguments to Node as a dict
, but to set parameters in a node from a launch file you need to pass a normal argument which points to an existing .yaml
file.
To pass parameters via the launch file (without predefining them in an external .yaml
file) will ultimately require the ability to pass parameters via the command line one at a time, which as of right now is not implemented yet.
In the meantime, individually specified parameters in a launch file for a node could be written into a temporary .yaml
file by launch
and then passed to the node, deleting the file after the node exits. However, I think this would step on a user specified parameter .yaml
file unless the node can take more than one right now (it was discussed, but I don't know off-hand if it was implemented). In either case, if launch also lets you specify one or more .yaml
files to be used as parameters (in addition to, and at the same time as, individually specified parameters for a node), then launch could just combine all of the yaml files and parameter kay-value pairs into a single .yaml
file, cascading them in order (overwriting keys that appear more than once, with last wins).
It might look something like this:
launch_ros.actions.Node(...,
parameters=[
'/path/to/first_parameter_file.yaml',
launch_ros.actions.node.NodeParameters({
'foo': '1',
// can have substitutions
[LaunchConfiguration('ros_namespace'), '.my_node.executable_location']:
[ExecutableInPackage('my_node', 'my_package')],
...,
},
[PackageShareDir('my_package'), Dir('config') / 'my_config_file.yaml'],
],
)
If two processes are added to a launch descriptor, and one of them launches fine but the other one causes an error, the first one keeps persisting as a zombie process.
Steps to reproduce:
Use this fork with a test that tries to spawn a talker node and a nonexistent fail node: https://github.com/dhood/launch/blob/zombie_nodes/launch_testing/test/test_zombie_nodes.py
$ ament test --isolated --only-packages launch_testing
The talker will start then the test will crash because of the nonexistent node.
======================================================================
ERROR: test_zombie_nodes.test_zombie_nodes
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/dhood/.local/lib/python3.5/site-packages/nose/case.py", line 198, in runTest
self.test(*self.arg)
File "/home/dhood/ros2_ws/src/ros2/launch/launch_testing/test/test_zombie_nodes.py", line 22, in test_zombie_nodes
rc = launcher.launch()
File "/home/dhood/ros2_ws/install_isolated/launch/lib/python3.5/site-packages/launch/launcher.py", line 96, in launch
raise e.exception
File "/home/dhood/ros2_ws/install_isolated/launch/lib/python3.5/site-packages/launch/launcher.py", line 127, in _run
await self._spawn_process(index)
File "/home/dhood/ros2_ws/install_isolated/launch/lib/python3.5/site-packages/launch/launcher.py", line 351, in _spawn_process
**kwargs)
File "/usr/lib/python3.5/asyncio/base_events.py", line 1079, in subprocess_exec
bufsize, **kwargs)
File "/usr/lib/python3.5/asyncio/unix_events.py", line 184, in _make_subprocess_transport
**kwargs)
File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 40, in __init__
stderr=stderr, bufsize=bufsize, **kwargs)
File "/usr/lib/python3.5/asyncio/unix_events.py", line 649, in _start
universal_newlines=False, bufsize=bufsize, **kwargs)
File "/usr/lib/python3.5/subprocess.py", line 947, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.5/subprocess.py", line 1551, in _execute_child
raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'fail'
-------------------- >> begin captured logging << --------------------
asyncio: DEBUG: Using selector: EpollSelector
--------------------- >> end captured logging << ---------------------
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/base_events.py", line 431, in __del__
File "/usr/lib/python3.5/asyncio/unix_events.py", line 58, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 139, in remove_signal_handler
File "/usr/lib/python3.5/signal.py", line 47, in signal
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
Exception ignored in: <bound method BaseSubprocessTransport.__del__ of <_UnixSubprocessTransport closed pid=3339 running stdin=<_UnixWritePipeTransport closing fd=15 open> stdout=<_UnixReadPipeTransport fd=16 open>>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 126, in __del__
File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 101, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 568, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 560, in write_eof
File "/usr/lib/python3.5/asyncio/base_events.py", line 497, in call_soon
File "/usr/lib/python3.5/asyncio/base_events.py", line 506, in _call_soon
File "/usr/lib/python3.5/asyncio/base_events.py", line 334, in _check_closed
RuntimeError: Event loop is closed
Starting a listener you will notice the talker is still alive:
$ listener
I heard: [Hello World: 508]
I heard: [Hello World: 509]
I heard: [Hello World: 510]
The UnsetLaunchConfiguration
action would simply unset a previously set launch configuration (set with the SetLaunchConfiguration
action).
I'm assuming this is related to something new in Python 3.6, since some asyncio stuff changed in that version. This is the new test failure after updating the macOS CI machines:
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/launch/launch/launch/launcher.py", line 411, in run
self.launcher.launch()
File "/Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/launch/launch/launch/launcher.py", line 96, in launch
raise e.exception
File "/Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/launch/launch/launch/launcher.py", line 127, in _run
await self._spawn_process(index)
File "/Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/launch/launch/launch/launcher.py", line 351, in _spawn_process
**kwargs)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 1190, in subprocess_exec
bufsize, **kwargs)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/unix_events.py", line 194, in _make_subprocess_transport
self._child_watcher_callback, transp)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/unix_events.py", line 858, in add_child_handler
"Cannot add child handler, "
RuntimeError: Cannot add child handler, the child watcher does not have a loop attached
I looked into the problem for a while, but I'm not sure why this error is happening. I think the loop (main thread loop) should be attached to the child watcher, but maybe I'm missing something.
@dirk-thomas do you have any idea about this issue?
I have a launch script that starts various ROS 2 nodes. Most times if I kill it with ctrl-c it dies gracefully with no issues. Occassionally (I haven't figured out under what circumstances yet) it gives:
^CTraceback (most recent call last):
File "/home/ubuntu/tb2_demo_ws/build_isolated/launch/launch/launcher.py", line 91, in launch
returncode = loop.run_until_complete(generator)
File "/usr/lib/python3.5/asyncio/base_events.py", line 375, in run_until_complete
self.run_forever()
File "/usr/lib/python3.5/asyncio/base_events.py", line 345, in run_forever
self._run_once()
File "/usr/lib/python3.5/asyncio/base_events.py", line 1276, in _run_once
event_list = self._selector.select(timeout)
File "/usr/lib/python3.5/selectors.py", line 441, in select
fd_event_list = self._epoll.poll(timeout, max_ev)
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/ubuntu/tb2_demo_ws/install_isolated/launch/bin/launch", line 9, in <module>
load_entry_point('launch', 'console_scripts', 'launch')()
File "/home/ubuntu/tb2_demo_ws/build_isolated/launch/launch/main.py", line 47, in main
rc = launcher.launch()
File "/home/ubuntu/tb2_demo_ws/build_isolated/launch/launch/launcher.py", line 99, in launch
loop.run_forever()
File "/usr/lib/python3.5/asyncio/base_events.py", line 345, in run_forever
self._run_once()
File "/usr/lib/python3.5/asyncio/base_events.py", line 1276, in _run_once
event_list = self._selector.select(timeout)
File "/usr/lib/python3.5/selectors.py", line 441, in select
fd_event_list = self._epoll.poll(timeout, max_ev)
KeyboardInterrupt
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/base_events.py", line 431, in __del__
File "/usr/lib/python3.5/asyncio/unix_events.py", line 58, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 139, in remove_signal_handler
File "/usr/lib/python3.5/signal.py", line 47, in signal
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
Exception ignored in: <bound method BaseSubprocessTransport.__del__ of <_UnixSubprocessTransport closed pid=1247 running stdin=<_UnixWritePipeTransport closing fd=23 open> stdout=<_UnixReadPipeTransport fd=24 open>>>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 126, in __del__
File "/usr/lib/python3.5/asyncio/base_subprocess.py", line 101, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 568, in close
File "/usr/lib/python3.5/asyncio/unix_events.py", line 560, in write_eof
File "/usr/lib/python3.5/asyncio/base_events.py", line 497, in call_soon
File "/usr/lib/python3.5/asyncio/base_events.py", line 506, in _call_soon
File "/usr/lib/python3.5/asyncio/base_events.py", line 334, in _check_closed
RuntimeError: Event loop is closed
On at least one occasion this has left one of the nodes running (as was happening in #54 ).
I've seen this issue https://mail.python.org/pipermail/python-bugs-list/2016-January/290450.html that suggests that the output isn't necessarily something to be concerned about, but perhaps in our use case it prevents the remaining nodes from being killed.
I know that this is vague: I will try to add more information about how to reproduce this when I find out.
Already described in the architecture
document:
Basically it will allow you to include another launch description, which is given to the constructor of the new action. You can already do this by emitting an event, launch.events.IncludeLaunchDescription
(https://github.com/ros2/launch/blob/b78d87f31bb995c7226df66826e1a57079ae3a3f/launch/launch/events/include_launch_description.py), so at first this action will be only syntactic sugar but later it should interact with launch arguments (see: #107).
Opening this for visibility
I tried the lifecycle launchfile and the dummy_robot_bringup one and they both crash. If I revert #57 they work.
See: #74 (comment)
On Windows the nosetests have one failure, see generated xml file:
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="launch.nosetests" tests="4" errors="1" failures="0" skip="0">
<testcase classname="test_launch_with_coroutine" name="test_launch_with_coroutine" time="0.031">
<error type="builtins.NotImplementedError" message=" -------------------- >> begin captured logging << -------------------- asyncio: DEBUG: Using selector: SelectSelector --------------------- >> end captured logging << ---------------------">
<![CDATA[ File "C:\tools\python\lib\unittest\case.py", line 58, in testPartExecutor
yield
File "C:\tools\python\lib\unittest\case.py", line 577, in run
testMethod()
File "C:\tools\python\lib\site-packages\nose\case.py", line 198, in runTest
self.test(*self.arg)
File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\src\ros2\launch\launch\test\test_launch_with_coroutine.py", line 55, in test_launch_with_coroutine
rc = default_launcher.launch()
File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\src\ros2\launch\launch\launch\launcher.py", line 49, in launch
returncode = loop.run_until_complete(self._run())
File "C:\tools\python\lib\asyncio\base_events.py", line 316, in run_until_complete
return future.result()
File "C:\tools\python\lib\asyncio\futures.py", line 275, in result
raise self._exception
File "C:\tools\python\lib\asyncio\tasks.py", line 238, in _step
result = next(coro)
File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\src\ros2\launch\launch\launch\launcher.py", line 68, in _run
yield from self._spawn_process(index)
File "C:\Jenkins\workspace\ros2_batch_ci_windows\workspace\src\ros2\launch\launch\launch\launcher.py", line 228, in _spawn_process
**kwargs)
File "C:\tools\python\lib\asyncio\base_events.py", line 944, in subprocess_exec
bufsize, **kwargs)
File "C:\tools\python\lib\asyncio\coroutines.py", line 141, in coro
res = func(*args, **kw)
File "C:\tools\python\lib\asyncio\base_events.py", line 248, in _make_subprocess_transport
raise NotImplementedError
-------------------- >> begin captured logging << --------------------
asyncio: DEBUG: Using selector: SelectSelector
--------------------- >> end captured logging << ---------------------]]>
</error>
<system-err><![CDATA[launch
]]></system-err>
</testcase>
<testcase classname="test_module_level_launch" name="test_one" time="1.000">
<system-out><![CDATA[(foo) pid 1584: ['C:\\tools\\python\\python.exe', '-u', 'C:\\Jenkins\\workspace\\ros2_batch_ci_windows\\workspace\\src\\ros2\\launch\\launch\\test\\counter.py', '--limit', '15', '--sleep', '0.5'] (stderr > stdout, all > file:C:\Windows\TEMP\foo_celvr29w)
]]></system-out>
<system-err><![CDATA[one
]]></system-err>
</testcase>
<testcase classname="test_module_level_launch" name="test_two" time="1.001">
<system-err><![CDATA[two
]]></system-err>
</testcase>
<testcase classname="test_module_level_launch" name="test_three" time="1.016">
<system-err><![CDATA[three
]]></system-err>
</testcase>
</testsuite>
But Jenkins interprets the result as "successful": http://54.183.26.131:8080/view/ros2/job/ros2_batch_ci_windows/166/testReport/(root)/test_launch_with_coroutine/
This might require selecting a different result file type in the Jenkins job.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.