Skip to content

Commit 649c623

Browse files
committed
Add bag recorder config and launch file to diagnostics
1 parent bb047e0 commit 649c623

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Software License Agreement (BSD)
2+
#
3+
# @author Luis Camero <lcamero@clearpathrobotics.com>
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+
import yaml
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+
37+
38+
def launch_setup(context, *args, **kwargs):
39+
# Launch Configurations
40+
namespace = str(
41+
LaunchConfiguration('namespace').perform(context))
42+
parameters = str(
43+
LaunchConfiguration('parameters').perform(context))
44+
enable_recorder = bool(
45+
LaunchConfiguration('enable_recorder').perform(context) == 'true')
46+
47+
# Extract Parameters
48+
content = yaml.safe_load(open(parameters))
49+
params = {}
50+
for i in content:
51+
if 'ros__parameters' in content[i]:
52+
params = content[i]['ros__parameters']
53+
found = False
54+
while not found:
55+
if 'ros__parameters' in content:
56+
params = content['ros__parameters']
57+
found = True
58+
else:
59+
content = content.pop(list(content)[0])
60+
if not isinstance(content, dict):
61+
break
62+
if not found:
63+
if enable_recorder:
64+
return [
65+
Node(
66+
package='rosbag2_transport',
67+
executable='recorder',
68+
name='recorder',
69+
output="screen",
70+
namespace=namespace,
71+
parameters=[parameters],
72+
)
73+
]
74+
else:
75+
return []
76+
77+
# Create Timestamp Directory
78+
flat = False
79+
path = None
80+
if 'storage' in params:
81+
if 'uri' in params['storage']:
82+
path = params['storage']['uri']
83+
elif 'storage.uri' in params:
84+
path = params['storage.uri']
85+
flat = True
86+
if not path:
87+
path = '/etc/clearpath/bags'
88+
if not os.path.exists(path):
89+
os.makedirs(path)
90+
timestamp_path = os.path.join(
91+
path, 'rosbag2_' + datetime.datetime.now().strftime('%Y_%m_%d-%H_%M_%S'))
92+
if flat:
93+
params['storage.uri'] = timestamp_path
94+
else:
95+
params['storage']['uri'] = timestamp_path
96+
97+
# Node
98+
node = Node(
99+
package='rosbag2_transport',
100+
executable='recorder',
101+
name='recorder',
102+
output="screen",
103+
namespace=namespace,
104+
parameters=[params],
105+
)
106+
107+
nodes = []
108+
if enable_recorder:
109+
nodes.append(node)
110+
return nodes
111+
112+
113+
def generate_launch_description():
114+
arg_namespace = DeclareLaunchArgument(
115+
'namespace',
116+
default_value='',
117+
description='Robot namespace'
118+
)
119+
120+
arg_parameters = DeclareLaunchArgument(
121+
'parameters',
122+
default_value=PathJoinSubstitution([
123+
FindPackageShare('clearpath_diagnostics'),
124+
'config',
125+
'recorder.yaml'
126+
]),
127+
description='Recorder node parameters'
128+
)
129+
130+
arg_enable_recorder = DeclareLaunchArgument(
131+
'enable_recorder',
132+
default_value='true',
133+
choices=['true', 'false'],
134+
description='Enable recording'
135+
)
136+
137+
ld = LaunchDescription()
138+
ld.add_action(arg_namespace)
139+
ld.add_action(arg_parameters)
140+
ld.add_action(arg_enable_recorder)
141+
ld.add_action(OpaqueFunction(function=launch_setup))
142+
143+
return ld

0 commit comments

Comments
 (0)