Skip to content

Commit 24edb95

Browse files
luis-cameroroni-kreinintonybaltovski
authored
Backports (#16)
* Prefix node names with can interface * Wait for interface to be up before launching node (#7) * Wait for interface to be UP before starting node * Fix: Multiple IncludeLaunchDescription (#9) * Use opaque function * Add import and context * Type performed context * Reattempt transitions on failure (#10) * Reattempt lifecycle transitions on failure * Unique activator node names * Removed namespace from node name * Linting * Use arguments instead of perform(context) (#11) * Fix: Use script instead of OpaqueFunction (#12) * Use script instead of OpaqueFunction * Add missing line * Add license header * Add EOF line * Add retry in the event lifecycle service is not up yet * Fix: Spin Timeout (#13) * Add timeout to spin to prevent script from waiting when node has failed * Update log to match appropriate action * Fixed using a global namespace. --------- Co-authored-by: Roni Kreinin <[email protected]> Co-authored-by: Roni Kreinin <[email protected]> Co-authored-by: Tony Baltovski <[email protected]>
1 parent 4b0d326 commit 24edb95

File tree

6 files changed

+352
-130
lines changed

6 files changed

+352
-130
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ install(
4343
RUNTIME DESTINATION bin
4444
)
4545

46+
install(
47+
PROGRAMS
48+
scripts/activate_lifecycle
49+
DESTINATION lib/${PROJECT_NAME}
50+
)
51+
4652
if(BUILD_TESTING)
4753
find_package(ament_lint_auto REQUIRED)
4854
list(APPEND AMENT_LINT_AUTO_EXCLUDE

launch/receiver.launch.py

Lines changed: 114 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,118 @@
2525
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2626
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2727
# POSSIBILITY OF SUCH DAMAGE.
28+
2829
from launch import LaunchDescription
2930
from launch.actions import (
3031
DeclareLaunchArgument,
31-
EmitEvent,
32+
ExecuteProcess,
33+
OpaqueFunction,
3234
RegisterEventHandler)
33-
from launch.conditions import IfCondition
34-
from launch.event_handlers import OnProcessStart
35-
from launch.events import matches_action
36-
from launch.substitutions import LaunchConfiguration
37-
from launch_ros.actions import LifecycleNode
38-
from launch_ros.event_handlers import OnStateTransition
39-
from launch_ros.events.lifecycle import ChangeState
40-
from lifecycle_msgs.msg import Transition
35+
from launch.event_handlers import OnProcessExit, OnProcessStart
36+
from launch.substitutions import FindExecutable, LaunchConfiguration
37+
from launch_ros.actions import LifecycleNode, Node
4138

4239

40+
def launch_setup(context, *args, **kwargs):
41+
# Apply context and type cast all LaunchConfiguration
42+
namespace = str(
43+
LaunchConfiguration('namespace').perform(context))
4344

44-
def generate_launch_description():
45-
namespace = LaunchConfiguration('namespace')
46-
interface = LaunchConfiguration('interface')
47-
enable_can_fd = LaunchConfiguration('enable_can_fd')
48-
interval_sec = LaunchConfiguration('interval_sec')
49-
use_bus_time = LaunchConfiguration('use_bus_time')
50-
filters = LaunchConfiguration('filters')
51-
auto_configure = LaunchConfiguration('auto_configure')
52-
auto_activate = LaunchConfiguration('auto_activate')
53-
from_can_bus_topic = LaunchConfiguration('from_can_bus_topic')
45+
interface = str(
46+
LaunchConfiguration('interface').perform(context))
47+
48+
enable_can_fd = bool(
49+
LaunchConfiguration('enable_can_fd').perform(context) == 'true')
50+
51+
interval_sec = float(
52+
LaunchConfiguration('interval_sec').perform(context))
53+
54+
use_bus_time = bool(
55+
LaunchConfiguration('use_bus_time').perform(context) == 'true')
56+
57+
filters = str(
58+
LaunchConfiguration('filters').perform(context))
59+
60+
from_can_bus_topic = str(
61+
LaunchConfiguration('from_can_bus_topic').perform(context))
62+
63+
auto_configure = bool(
64+
LaunchConfiguration('auto_configure').perform(context) == 'true')
65+
66+
auto_activate = bool(
67+
LaunchConfiguration('auto_activate').perform(context) == 'true')
68+
69+
timeout = float(
70+
LaunchConfiguration('timeout').perform(context))
71+
72+
transition_attempts = int(
73+
LaunchConfiguration('transition_attempts').perform(context))
74+
75+
name = f'{interface}_socket_can_receiver'
76+
77+
# SocketCAN receiver node
78+
node = LifecycleNode(
79+
package='ros2_socketcan',
80+
executable='socket_can_receiver_node_exe',
81+
name=name,
82+
namespace=namespace,
83+
parameters=[{
84+
'interface': interface,
85+
'enable_can_fd': enable_can_fd == 'true',
86+
'interval_sec': interval_sec,
87+
'filters': filters,
88+
'use_bus_time': use_bus_time == 'true',
89+
}],
90+
remappings=[('from_can_bus', from_can_bus_topic)],
91+
output='screen')
92+
93+
# Wait for interface to be up
94+
wait_for_can_interface_proc = ExecuteProcess(
95+
cmd=[['until ', FindExecutable(name='ip'), ' link show ', interface,
96+
' | ', FindExecutable(name='grep'), ' \"state UP\"', '; do sleep 1; done']],
97+
shell=True
98+
)
99+
100+
# Event to launch node once interface is up
101+
launch_node = RegisterEventHandler(
102+
event_handler=OnProcessExit(
103+
target_action=wait_for_can_interface_proc,
104+
on_exit=node
105+
)
106+
)
107+
108+
# Activate launch
109+
activate_lifecycle_node = Node(
110+
name=f'activate_{name}',
111+
package='clearpath_ros2_socketcan_interface',
112+
executable='activate_lifecycle',
113+
namespace=namespace,
114+
arguments=[
115+
'--namespace', str(namespace),
116+
'--node', str(name),
117+
'--auto_configure', str(auto_configure),
118+
'--auto_activate', str(auto_activate),
119+
'--timeout', str(timeout),
120+
'--transition_attempts', str(transition_attempts)
121+
]
122+
)
123+
124+
# Event to configure and activate node once node is up
125+
configure_event = RegisterEventHandler(
126+
event_handler=OnProcessStart(
127+
target_action=node,
128+
on_start=[activate_lifecycle_node],
129+
),
130+
)
131+
132+
return [
133+
wait_for_can_interface_proc,
134+
launch_node,
135+
configure_event,
136+
]
54137

138+
139+
def generate_launch_description():
55140
arg_namespace = DeclareLaunchArgument(
56141
'namespace',
57142
default_value='')
@@ -88,54 +173,16 @@ def generate_launch_description():
88173
'from_can_bus_topic',
89174
default_value='rx')
90175

91-
node = LifecycleNode(
92-
package='ros2_socketcan',
93-
executable='socket_can_receiver_node_exe',
94-
name='socket_can_receiver',
95-
namespace=namespace,
96-
parameters=[{
97-
'interface': interface,
98-
'enable_can_fd': enable_can_fd,
99-
'interval_sec': interval_sec,
100-
'filters': filters,
101-
'use_bus_time': use_bus_time,
102-
}],
103-
remappings=[('from_can_bus', from_can_bus_topic)],
104-
output='screen')
105-
106-
configure_event = RegisterEventHandler(
107-
event_handler=OnProcessStart(
108-
target_action=node,
109-
on_start=[
110-
EmitEvent(
111-
event=ChangeState(
112-
lifecycle_node_matcher=matches_action(node),
113-
transition_id=Transition.TRANSITION_CONFIGURE,
114-
),
115-
),
116-
],
117-
),
118-
condition=IfCondition(auto_configure),
119-
)
176+
arg_timeout = DeclareLaunchArgument(
177+
'timeout',
178+
default_value='5.0')
120179

121-
activate_event = RegisterEventHandler(
122-
event_handler=OnStateTransition(
123-
target_lifecycle_node=node,
124-
start_state='configuring',
125-
goal_state='inactive',
126-
entities=[
127-
EmitEvent(
128-
event=ChangeState(
129-
lifecycle_node_matcher=matches_action(node),
130-
transition_id=Transition.TRANSITION_ACTIVATE,
131-
),
132-
),
133-
],
134-
),
135-
condition=IfCondition(auto_activate),
136-
)
180+
arg_transition_attempts = DeclareLaunchArgument(
181+
'transition_attempts',
182+
default_value='3')
137183

138184
ld = LaunchDescription()
185+
139186
ld.add_action(arg_namespace)
140187
ld.add_action(arg_interface)
141188
ld.add_action(arg_enable_can_fd)
@@ -145,7 +192,7 @@ def generate_launch_description():
145192
ld.add_action(arg_auto_configure)
146193
ld.add_action(arg_auto_activate)
147194
ld.add_action(arg_from_can_bus_topic)
148-
ld.add_action(node)
149-
ld.add_action(configure_event)
150-
ld.add_action(activate_event)
195+
ld.add_action(arg_timeout)
196+
ld.add_action(arg_transition_attempts)
197+
ld.add_action(OpaqueFunction(function=launch_setup))
151198
return ld

0 commit comments

Comments
 (0)