Recording profiles¶
A profile is a named set of topics. Applying one makes the recorder record exactly those topics: it drops what the profile leaves out, adds what it names, and leaves the topics the old and new sets share recording without a gap. It is the one-call way to follow a robot’s operating mode: idle, navigating, inspecting.
With stock ros2 bag record the same change means stopping and restarting, which leaves a hole in
every topic and starts a new bag. Here it is a topic change like any other: the bag stays open, and
the recorder writes a SubscriptionChangeEvent into it for every topic that starts or stops, so the
bag explains its own boundaries.
Declaring profiles¶
Profiles are recorder parameters: a list of names, and one topic list per name.
rosbag2_dynamic_recorder:
ros__parameters:
profile_names: ["idle", "navigation", "inspection"]
profiles:
idle: ["/tf", "/tf_static", "/odom", "/imu"]
navigation: ["/tf", "/tf_static", "/odom", "/imu", "/scan"]
inspection:
- "/tf"
- "/tf_static"
- "/odom"
- "/imu"
- "/scan"
- "/rgbd_camera/image"
- "/rgbd_camera/depth_image"
Only the names in
profile_namesare read. A list underprofileswith no entry inprofile_namesis ignored.The names keep their order: the CLI lists them and the UI draws their buttons in that order.
Each topic list is sorted and de-duplicated when it is read.
A profile with no topics is accepted with a warning at startup. Applying it records nothing.
Entries are plain topic names. There is no type syntax and no regular expression: the type of each topic is read from the graph when the profile is applied.
Profiles are read once, at startup. To change one, edit the file and restart the recorder.
A worked example, written for the TurtleBot 4 simulator’s topics, ships with the package as
config/profiles.example.yaml.
Starting a recorder with profiles¶
Pass the file as params_file:
ros2 launch rosbag2_dynamic_recorder dynamic_recorder.launch.py \
uri:=/tmp/mybag params_file:=profiles.yaml
The browser UI’s launch file takes the same argument:
ros2 launch rosbag2_dynamic_recorder_ui recorder_with_ui.launch.py \
uri:=/tmp/mybag params_file:=profiles.yaml
Without a launch file, give the node the file, or the parameters one by one:
ros2 run rosbag2_dynamic_recorder dynamic_recorder --ros-args \
-p uri:=/tmp/mybag --params-file profiles.yaml
There is no parameter that starts the recorder in a profile. Set topics to the same list as the
profile you want, or apply the profile once the recorder is up. Either way the recorder reports
that profile as active, because it compares what it is recording with each profile’s list.
Switching¶
Every client calls the same ~/set_profile service. A switch is refused while the recorder is
stopped, with the reason, since there is no bag to record into.
Browser UI. Each profile is a button, with the active one highlighted and its topics in the button’s tooltip. Pressing one applies it.
Command line.
ros2 dynrec profiles # list them; the active one is marked *
ros2 dynrec profiles --names # just the names, one per line
ros2 dynrec profile navigation # apply one
ros2 dynrec profile prints what is now recorded, what stopped, and anything it could not
subscribe.
Python.
from dynrec import Recorder
with Recorder() as rec:
change = rec.profile('navigation')
if change.unavailable:
print('not recording yet:', change.unavailable)
print('active profile:', rec.profiles().active)
Service call.
ros2 service call /rosbag2_dynamic_recorder/set_profile \
rosbag2_dynamic_recorder_interfaces/srv/SetProfile "{name: navigation}"
An unknown name is refused, and the reply lists the profiles that are configured.
What a switch does¶
Going from navigation to inspection in the example above:
Topic |
Before |
After |
What happens |
|---|---|---|---|
|
recorded |
recorded |
untouched: no gap, no event |
|
not recorded |
recorded |
subscribed; a |
and back from inspection to idle:
Topic |
Before |
After |
What happens |
|---|---|---|---|
|
recorded |
recorded |
untouched |
|
recorded |
not recorded |
dropped; an |
The recorder drops before it adds, so the expensive topics of the old profile are gone before the new profile’s arrive. Topics added by hand stay only if the new profile names them: applying a profile makes the recorded set equal to the profile, whatever was recorded before.
The events carry the reason service:set_profile:<name>, so reading the bag back shows which
profile caused each channel to start or stop. They are written into the bag unless the recorder
runs with record_subscription_events:=false. The bag is never split by a switch.
Which profile is active¶
The recorder does not remember which profile was applied last. It compares what it is recording with each profile’s list, every time it reports its status, and names the profile that matches exactly, or none.
That keeps the answer true when something else changes the topics. Add one topic by hand and no profile is active any more, even though you started from one. Reach a profile’s exact set by other means and that profile is reported, though it was never applied.
The status carries it as active_profile, ros2 dynrec profiles marks it with *, and the UI
highlights its button and says “The current selection does not match a profile” when none does.
When a topic is not there¶
A topic in the profile that has no publisher when the profile is applied cannot be subscribed: its
type comes from the graph, and the graph does not have it. The same goes for a topic published
under more than one type, since the recorder will not guess which one you meant. The switch still goes through for every
other topic, and the missing ones come back as unavailable. Until they are recorded, the profile
does not match exactly, so none is reported active.
Apply the profile again once the publisher is up. Topics already recorded are untouched, so repeating a switch costs nothing but the missing subscriptions.
If none of a profile’s topics can be subscribed, the call is reported as a failure.
Designing profiles¶
Nest them. Give every profile the core it needs to interpret anything else, such as transforms and odometry, and add to it. Topics shared between profiles are the ones that never get a gap, so a large shared core means fewer seams in the data.
Put the expensive topics in one profile. Cameras and point clouds belong in the profile for the task that needs them, so switching away from it is what saves the bandwidth and the disk.
Name them after what the robot is doing, not after the topics. A supervisor that knows the robot is inspecting should not need to know which topics inspection needs.
Keep the list in version control next to the launch files that use it, since profiles are fixed for the life of the recorder.