Skip to content

Commit af8ef93

Browse files
committed
Move recoder config and launch from robot
1 parent d1d3d6b commit af8ef93

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
recorder:
2+
ros__parameters:
3+
4+
use_sim_time: false
5+
6+
record:
7+
# all_topics: false
8+
# all_services: false
9+
# all_actions: false
10+
# is_discovery_disabled: true
11+
#topics: ["topic", "other_topic"]
12+
#topic_types: ["std_msgs/msg/Header", "geometry_msgs/msg/Pose"]
13+
#exclude_topic_types: ["sensor_msgs/msg/Image"]
14+
#services: ["service", "other_service"]
15+
#actions: ["action", "other_action"]
16+
#rmw_serialization_format: "cdr"
17+
#topic_polling_interval:
18+
# sec: 0
19+
# nsec: 10000000
20+
regex: "(.*)platform|wiferion|robot_description|tf|cmd_vel|imu(.*)"
21+
# add wiferion, tf, tf_static, robot_description, "(.*)platform|wiferion(.*)", imu_data, all cmd_vel
22+
# exclude_regex: "(.*)"
23+
# exclude_topics: ["exclude_topic", "other_exclude_topic"]
24+
# exclude_services: ["exclude_service", "other_exclude_service"]
25+
# exclude_actions: ["exclude_action", "other_exclude_action"]
26+
# node_prefix: "prefix"
27+
# compression_mode: "file"
28+
# compression_format: "zstd"
29+
# compression_queue_size: 10
30+
# compression_threads: 2
31+
# compression_threads_priority: -1
32+
# qos_profile_overrides_path: ""
33+
include_hidden_topics: true
34+
# include_unpublished_topics: true
35+
# ignore_leaf_topics: false
36+
# start_paused: false
37+
# disable_keyboard_controls: true
38+
39+
storage:
40+
uri: /etc/clearpath/bags
41+
# storage_id: "sqlite3"
42+
# storage_config_uri: ""
43+
# max_bagfile_size: 2147483646
44+
max_bagfile_duration: 600
45+
# max_cache_size: 16777216
46+
storage_preset_profile: "zstd_fast"
47+
# snapshot_mode: true
48+
# custom_data: ["key1=value1", "key2=value2"]
49+
# start_time_ns: 0
50+
# end_time_ns: 100000
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Software License Agreement (BSD)
2+
#
3+
# @author Luis Camero <[email protected]>
4+
# @copyright (c) 2025, Clearpath Robotics, Inc., All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions are met:
8+
# * Redistributions of source code must retain the above copyright notice,
9+
# this list of conditions and the following disclaimer.
10+
# * Redistributions in binary form must reproduce the above copyright notice,
11+
# this list of conditions and the following disclaimer in the documentation
12+
# and/or other materials provided with the distribution.
13+
# * Neither the name of Clearpath Robotics nor the names of its contributors
14+
# may be used to endorse or promote products derived from this software
15+
# without specific prior written permission.
16+
#
17+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
# POSSIBILITY OF SUCH DAMAGE.
28+
import datetime
29+
import os
30+
31+
from launch import LaunchDescription
32+
from launch.actions import DeclareLaunchArgument, OpaqueFunction
33+
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
34+
from launch_ros.actions import Node
35+
from launch_ros.substitutions import FindPackageShare
36+
import yaml
37+
38+
39+
def launch_setup(context, *args, **kwargs):
40+
# Launch Configurations
41+
namespace = str(
42+
LaunchConfiguration('namespace').perform(context))
43+
parameters = str(
44+
LaunchConfiguration('parameters').perform(context))
45+
enable_recorder = bool(
46+
LaunchConfiguration('enable_recorder').perform(context) == 'true')
47+
48+
# Extract Parameters
49+
content = yaml.safe_load(open(parameters))
50+
params = {}
51+
for i in content:
52+
if 'ros__parameters' in content[i]:
53+
params = content[i]['ros__parameters']
54+
found = False
55+
while not found:
56+
if 'ros__parameters' in content:
57+
params = content['ros__parameters']
58+
found = True
59+
else:
60+
content = content.pop(list(content)[0])
61+
if not isinstance(content, dict):
62+
break
63+
if not found:
64+
if enable_recorder:
65+
return [
66+
Node(
67+
package='rosbag2_transport',
68+
executable='recorder',
69+
name='recorder',
70+
output='screen',
71+
namespace=namespace,
72+
parameters=[parameters],
73+
)
74+
]
75+
else:
76+
return []
77+
78+
# Create Timestamp Directory
79+
flat = False
80+
path = None
81+
if 'storage' in params:
82+
if 'uri' in params['storage']:
83+
path = params['storage']['uri']
84+
elif 'storage.uri' in params:
85+
path = params['storage.uri']
86+
flat = True
87+
if not path:
88+
path = '/etc/clearpath/bags'
89+
if not os.path.exists(path):
90+
os.makedirs(path)
91+
timestamp_path = os.path.join(
92+
path, 'rosbag2_' + datetime.datetime.now().strftime('%Y_%m_%d-%H_%M_%S'))
93+
if flat:
94+
params['storage.uri'] = timestamp_path
95+
else:
96+
params['storage']['uri'] = timestamp_path
97+
98+
# Node
99+
node = Node(
100+
package='rosbag2_transport',
101+
executable='recorder',
102+
name='recorder',
103+
output='screen',
104+
namespace=namespace,
105+
parameters=[params],
106+
)
107+
108+
nodes = []
109+
if enable_recorder:
110+
nodes.append(node)
111+
return nodes
112+
113+
114+
def generate_launch_description():
115+
arg_namespace = DeclareLaunchArgument(
116+
'namespace',
117+
default_value='',
118+
description='Robot namespace'
119+
)
120+
121+
arg_parameters = DeclareLaunchArgument(
122+
'parameters',
123+
default_value=PathJoinSubstitution([
124+
FindPackageShare('clearpath_diagnostics'),
125+
'config',
126+
'recorder.yaml'
127+
]),
128+
description='Recorder node parameters'
129+
)
130+
131+
arg_enable_recorder = DeclareLaunchArgument(
132+
'enable_recorder',
133+
default_value='true',
134+
choices=['true', 'false'],
135+
description='Enable recording'
136+
)
137+
138+
ld = LaunchDescription()
139+
ld.add_action(arg_namespace)
140+
ld.add_action(arg_parameters)
141+
ld.add_action(arg_enable_recorder)
142+
ld.add_action(OpaqueFunction(function=launch_setup))
143+
144+
return ld

0 commit comments

Comments
 (0)