{"id":13799094,"url":"https://github.com/ros2/rosbag2","last_synced_at":"2025-05-15T08:09:41.495Z","repository":{"id":37390570,"uuid":"127306752","full_name":"ros2/rosbag2","owner":"ros2","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-13T23:54:35.000Z","size":7378,"stargazers_count":317,"open_issues_count":100,"forks_count":268,"subscribers_count":36,"default_branch":"rolling","last_synced_at":"2025-04-14T17:00:03.086Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ros2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-29T14:54:57.000Z","updated_at":"2025-04-14T15:29:58.000Z","dependencies_parsed_at":"2023-10-20T22:53:44.710Z","dependency_job_id":"572ed3e9-3645-418a-8e00-603dc4daadf4","html_url":"https://github.com/ros2/rosbag2","commit_stats":{"total_commits":695,"total_committers":113,"mean_commits":6.150442477876106,"dds":0.8129496402877698,"last_synced_commit":"8216ea22daa78abd3fe8a1607a6fb91351e340e1"},"previous_names":[],"tags_count":91,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ros2%2Frosbag2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ros2%2Frosbag2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ros2%2Frosbag2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ros2%2Frosbag2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ros2","download_url":"https://codeload.github.com/ros2/rosbag2/tar.gz/refs/heads/rolling","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248923721,"owners_count":21183951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:00:58.769Z","updated_at":"2025-05-15T08:09:41.466Z","avatar_url":"https://github.com/ros2.png","language":"C++","funding_links":[],"categories":["Packages","🛡️ Safety \u0026 Testing"],"sub_categories":["Ecosystem"],"readme":"# Rosbag2\n![License](https://img.shields.io/github/license/ros2/rosbag2)\n[![GitHub Action Status](https://github.com/ros2/rosbag2/workflows/Test%20rosbag2/badge.svg)](https://github.com/ros2/rosbag2/actions)\n\nRosbag2 — the tool for recording and playback of communications in ROS 2 systems.\n\nThis is the ROS 2 successor of https://wiki.ros.org/rosbag.\n\nA \"rosbag\" is simply a file full of timestamped messages. The first goal of the tool is efficient recording, to support complex systems in real time. Its second goal is efficent playback, to allow for viewing and using recorded data.\n\nFor historical context, see the original [design article](https://github.com/ros2/design/blob/ros2bags/articles/rosbags.md) that kicked off the project.\n\nThis README has a lot of information. You may want to jump directly to:\n- [Installation](#installation)\n- [Usage](#usage)\n- [Tips and Tricks](#tips-and-tricks)\n\n## Installation\n\n### Debian packages\n\nRosbag2 packages are available via debian packages, and will already be included with any `-ros-base` installation (which is included within `-desktop`)\n\n```\n$ export ROS_DISTRO=humble\n$ sudo apt-get install ros-$ROS_DISTRO-rosbag2\n```\n\n### Other binaries\n\nYou can follow the instructions at http://docs.ros.org/en/humble/Installation/Alternatives/Ubuntu-Install-Binary.html (or for your chosen distro), and Rosbag2 will be included in that installation.\n\n### Build from source\n\nTo build from source, follow the instructions in [DEVELOPING.md](DEVELOPING.md)\n\n## Using rosbag2 \u003ca id=\"usage\"\u003e\u003c/a\u003e\n\nRosbag2 is part of the ROS 2 command line interface as `ros2 bag`.\nThese verbs are available for `ros2 bag`:\n\n* `ros2 bag burst`\n* [`ros2 bag convert`](#convert)\n* [`ros2 bag info`](#info)\n* `ros2 bag list`\n* [`ros2 bag play`](#play)\n* [`ros2 bag record`](#record)\n* `ros2 bag reindex`\n\nFor up-to-date information on the available options for each, use `ros2 bag \u003cverb\u003e --help`.\n\nMoreover, `rosbag2_transport::Player` and `rosbag2_transport::Recorder` components can be instantiated in `rclcpp` component containers, which makes possible to use intra-process communication for greater efficiency.\nSee [composition](#composition) section for details.\n\n\n### Recording data \u003ca id=\"record\"\u003e\u003c/a\u003e\n\nIn order to record all topics currently available in the system:\n\n```\n$ ros2 bag record -a\n```\n\nThe command above will record all available topics and discovers new topics as they appear while recording.\nThis auto-discovery of new topics can be disabled by given the command line argument `--no-discovery`.\n\nTo record a set of predefined topics, one can specify them on the command line explicitly.\n\n```\n$ ros2 bag record \u003ctopic1\u003e \u003ctopic2\u003e … \u003ctopicN\u003e\n```\n\nThe specified topics don't necessarily have to be present at start time.\nThe discovery function will automatically recognize if one of the specified topics appeared.\nIn the same fashion, this auto discovery can be disabled with `--no-discovery`.\n\nIf not further specified, `ros2 bag record` will create a new folder named to the current time stamp and stores all data within this folder.\nA user defined name can be given with `-o, --output`.\n\n#### Simulation time\n\nIn ROS 2, \"simulation time\" refers to publishing a clock value on the `/clock` topic, instead of using the system clock to tell time.\nBy passing `--use-sim-time` argument to `ros2 bag record`, we turn on this option for the recording node.\nMessages written to the bag will use the latest received value of `/clock` for the timestamp of the recorded message.\n\nNote: Until the first `/clock` message is received, the recorder will not write any messages.\nBefore that message is received, the time is 0, which leads to a significant time jump once simulation time begins, making the bag essentially unplayable if messages are written first with time 0 and then time N from `/clock`.\n\n#### Splitting files during recording\n\nRosbag2 offers the capability to split bag files when they reach a maximum size or after a specified duration. By default Rosbag2 will record all data into a single bag file, but this can be changed using the CLI options.\n\n_Splitting by size_: `ros2 bag record -a -b 100000` will split the bag files when they become greater than 100 kilobytes. Note: the batch size's units are in bytes and must be greater than `86016`. This option defaults to `0`, which means data is written to a single file.\n\n_Splitting by time_: `ros2 bag record -a -d 9000` will split the bag files after a duration of `9000` seconds. This option defaults to `0`, which means data is written to a single file.\n\nIf both splitting by size and duration are enabled, the bag will split at whichever threshold is reached first.\n\n#### Recording with compression\n\nBy default Rosbag2 does not record with compression enabled. However, compression can be specified using the following CLI options.\n\nFor example, `ros2 bag record -a --compression-mode file --compression-format zstd` will record all topics and compress each file using the [zstd](https://github.com/facebook/zstd) compressor.\n\nCurrently, the only `compression-format` available is `zstd`. Both the mode and format options default to `none`. To use a compression format, a compression mode must be specified, where the currently supported modes are compress by `file` or compress by `message`.\n\nIt is recommended to use this feature with the splitting options.\n\n**Note**: Some storage plugins may have their own compression methods, which are separate from the Rosbag2 compression specified by the CLI options `--compression-mode` and `--compression-format`. Notably, the MCAP file format offered by the `rosbag2_storage_mcap` storage plugin supports compression in a way that produces files that are still indexable (whereas using the Rosbag2 compression will not). To utilize storage plugin specific compression or other options, see [Recording with a storage configuration](#record-storage-config).\n\n#### Recording with a storage configuration \u003ca id=\"record-storage-config\"\u003e\u003c/a\u003e\n\nStorage configuration can be specified in a YAML file passed through the `--storage-config-file` option.\nThis can be used to optimize performance for specific use cases.\n\nSee storage plugin documentation for more detail:\n* [mcap](rosbag2_storage_mcap/README.md#writer-configuration)\n* [sqlite3](rosbag2_storage_sqlite3/README.md#storage-configuration-file)\n\n#### Controlling recordings via services\n\nThe Rosbag2 recorder provides the following services for remote control, which can be called via `ros2 service` commandline, or from your nodes:\n\n* `~/is_paused [rosbag2_interfaces/srv/IsPaused]`\n  * Returns whether recording is currently paused.\n* `~/pause [rosbag2_interfaces/srv/Pause]`\n  * Pauses recording. All messages that have already arrived will be written, but all messages that arrive after pausing will be discarded. Has no effect if already paused. Takes no arguments.\n* `~/resume [rosbag2_interfaces/srv/Resume]`\n  * Resume recording if paused. Has no effect if not paused. Takes no arguments.\n* `~/split_bagfile [rosbag2_interfaces/srv/SplitBagfile]`\n  * Triggers a split to a new file, even if none of the configured split criteria (such as `--max-bag-size` or `--max-bag-duration`) have been met yet\n* `~/snapshot [rosbag2_interfaces/srv/Snapshot]`\n  * enabled if `--snapshot-mode` is specified. Takes no arguments, triggers a snapshot.\n\n#### Snapshot mode\n\nThe Recorder provides a \"snapshot mode\", enabled via `--snapshot-mode` or `StorageOptions.snapshot_mode`, which does not write messages to disk as they come in, but instead keeps an in-memory circular buffer of size `--max-cache-size`.\nThis entire buffer can be dumped to disk on request, saving data only in specified circumstances such as a detected error condition or point of interest, capturing the \"last N bytes\" of incoming data, therefore making sure that you can trigger snapshot after the fact of the event.\n\nThe snapshot is taken by calling the `~/snapshot` service on the recorder, described previously.\n\n### Replaying data \u003ca id=\"play\"\u003e\u003c/a\u003e\n\nWhen you have a recorded bag, you can use Rosbag2 to play it back:\n\n```\n$ ros2 bag play \u003cbag\u003e\n```\n\nThe bag argument can be a directory containing `metadata.yaml` and one or more storage files, or\nto a single storage file such as `.mcap` or `.db3`.\nThe Player will automatically detect which storage implementation to use for playing.\nA progress bar to track the playback progress will be displayed in the terminal by default.\n\nTo play back multiple bags:\n\n```\n$ ros2 bag play \u003cbag1\u003e -i \u003cbag2\u003e -i \u003cbag3\u003e\n```\n\nMessages from all provided bags will be played in order, based on their original recording\nreception timestamps.\n\nOptions:\n\n* `--topics`:\n  Space-delimited list of topics to play.\n* `--services`:\n  Space-delimited list of services to play.\n* `--actions`:\n  Space-delimited list of actions to play.\n* `-e,--regex`:\n  Play only topics and services matches with regular expression.\n* `-x,--exclude-regex`:\n  Regular expressions to exclude topics and services from replay.\n* `--exclude-topics`:\n  Space-delimited list of topics not to play.\n* `--exclude-services`:\n  Space-delimited list of services not to play.\n* `--exclude-actions`:\n  Space-delimited list of actions not to play.\n* `--message-order {received,sent}`:\n  The reference to use for bag message chronological ordering.\n  Choices: reception timestamp (`received`), publication timestamp (`sent`).\n  Default: reception timestamp.\n* `--progress-bar-update-rate [Hz]`:\n  Print a progress bar for the playback with a specified maximum update rate in times per second\n  (Hz). Negative values mark an update for every published message, while a zero value disables\n  the progress bar. Default is 3 Hz.\n* `--progress-bar-separation-lines`:\n  The number of lines to separate the progress bar from the rest of the playback player output.\n  It prevents mixing external log messages with the progress bar string. Default to 2.\n\nFor more options, run with `--help`.\n\n#### Playback action messages as action client\n\nIf you want Rosbag2 to replay recorded action messages in the role of an action client, you need to specify the --send-actions-as-client parameter.\n```\n$ ros2 bag play --send-actions-as-client \u003cbag\u003e\n```\nRosbag2 will send recorded goal request, cancel request and result request to action server.  \nFor more information, please refer to https://github.com/ros2/rosbag2/blob/rolling/docs/design/rosbag2_record_replay_action.md.\n\n#### Controlling playback via services\n\nThe Rosbag2 player provides the following services for remote control, which can be called via `ros2 service` commandline or from your nodes,\n\n* `~/burst [rosbag2_interfaces/srv/Burst]`\n  * Can only be used while player is paused, publishes `num_messages` in order as fast as possible, moving forward the play head.\n* `~/get_rate [rosbag2_interfaces/srv/GetRate]`\n  * Return the current playback rate.\n* `~/is_paused [rosbag2_interfaces/srv/IsPaused]`\n  * Return whether playback is paused.\n* `~/pause [rosbag2_interfaces/srv/Pause]`\n  * Pause playback. Has no effect if already paused.\n* `~/play [rosbag2_interfaces/srv/Play]`\n  * Play from a starting offset timestamp, either until the end, an ending timestamp or for a set duration. Only works when stopped (not paused).\n* `~/play_next [rosbag2_interfaces/srv/PlayNext]`\n  * Play a single next message from the bag. Only works while paused.\n* `~/resume [rosbag2_interfaces/srv/Resume]`\n  * Resume playback if paused.\n* `~/seek [rosbag2_interfaces/srv/Seek]`\n  * Change the play head to the specified timestamp. Can be forward or backward in time, the next played message is the next immediately after the seeked timestamp.\n* `~/set_rate [rosbag2_interfaces/srv/SetRate]`\n  * Sets the rate of playback, for example 2.0 will play messages twice as fast.\n* `~/stop [rosbag2_interfaces/srv/Stop]`\n  * Stop the player, putting the play head in \"undefined position\" outside the bag. Must call `play` before other operations can be done.\n* `~/toggle_paused [rosbag2_interfaces/srv/TogglePaused]`\n  * Pause if playing, resume if paused.\n\n\n### Analyzing data \u003ca id=\"info\"\u003e\u003c/a\u003e\n\nThe recorded data can be analyzed by displaying some meta information about it:\n\n```\n$ ros2 bag info \u003cbag_file\u003e\n```\n\nYou should see something along these lines:\n\n```\nFiles:             demo_strings.db3\nBag size:          44.5 KiB\nStorage id:        sqlite3\nDuration:          8.501s\nStart:             Nov 28 2018 18:02:18.600 (1543456938.600)\nEnd                Nov 28 2018 18:02:27.102 (1543456947.102)\nMessages:          27\nTopic information: Topic: /chatter | Type: std_msgs/String | Count: 9 | Serialization Format: cdr\n                   Topic: /my_chatter | Type: std_msgs/String | Count: 18 | Serialization Format: cdr\n```\n\n### Converting bags (merge, split, etc.) \u003ca id=\"convert\"\u003e\u003c/a\u003e\n\nRosbag2 provides a tool `ros2 bag convert` (or, `rosbag2_transport::bag_rewrite` in the C++ API).\nThis allows the user to take one or more input bags, and write them out to one or more output bags with new settings.\nThis flexible feature enables the following features:\n* Merge (multiple input bags, one output bag)\n* Split top-level bags (one input bag, multiple output bags)\n* Split internal files (by time or size - one input bag with fewer internal files, one output bag with more, smaller, internal files)\n* Compress/Decompress (output bag(s) with different compression settings than the input(s))\n* Serialization format conversion\n* ... and more!\n\nHere is an example command:\n\n```\nros2 bag convert --input /path/to/bag1 --input /path/to/bag2 storage_id --output-options output_options.yaml\n```\n\nThe `--input` argument may be specified any number of times, and takes 1 or 2 values.\nThe first value is the URI of the input bag.\nIf a second value is supplied, it specifies the storage implementation of the bag.\nIf no storage implementation is specified, Rosbag2 will try to determine it automatically from the bag.\n\nThe `--output-options` argument must point to the URI of a YAML file specifying the full recording configuration for each bag to output (`StorageOptions` + `RecordOptions`).\nThis file must contain a top-level key `output_bags`, which contains a list of these objects.\n\nThe only required value in the output bags is `uri` and `storage_id`. All other values are options (however, if no topic selection is specified, this output bag will be empty!).\n\nThis example notes all fields that can have an effect, with a comment on the required ones.\n\n```\noutput_bags:\n- uri: /output/bag1  # required\n  storage_id: \"\"  # will use the default storage plugin, if unspecified\n  max_bagfile_size: 0\n  max_bagfile_duration: 0\n  storage_preset_profile: \"\"\n  storage_config_uri: \"\"\n  # optional filter for msg time t [nsec since epoch]:  start_time_ns \u003c= t \u003c= end_time_ns\n  # start_time_ns: 1744227144744197147\n  # end_time_ns: 1744227145734665546\n  all_topics: false\n  topics: []\n  topic_types: []\n  all_services: false\n  services: []\n  all_actions: false\n  actions: []\n  rmw_serialization_format: \"\"  # defaults to using the format of the input topic\n  regex: \"\"\n  exclude_regex: \"\"\n  exclude_topics: []\n  exclude_topic_types: []\n  exclude_services: []\n  exclude_actions: []\n  compression_mode: \"\"\n  compression_format: \"\"\n  compression_queue_size: 1\n  compression_threads: 0\n  include_hidden_topics: false\n  include_unpublished_topics: false\n```\n\nExample merge:\n\n```\n$ ros2 bag convert -i bag1 -i bag2 -o out.yaml\n\n# out.yaml\noutput_bags:\n- uri: merged_bag\n  all_topics: true\n  all_services: true\n```\n\nExample split:\n\n```\n$ ros2 bag convert -i bag1 -o out.yaml\n\n# out.yaml\noutput_bags:\n- uri: split1\n  topics: [/topic1, /topic2]\n- uri: split2\n  topics: [/topic3]\n```\n\nExample compress:\n\n```\n$ ros2 bag convert -i bag1 -o out.yaml\n\n# out.yaml\noutput_bags:\n- uri: compressed\n  all_topics: true\n  all_services: true\n  compression_mode: file\n  compression_format: zstd\n```\n\n### Overriding QoS Profiles\n\nWhen starting a recording or playback, you can pass a YAML file that contains QoS profile settings for a specific topic.\nThe YAML schema for the profile overrides is a dictionary of topic names with key/value pairs for each QoS policy.\nBelow is an example profile set to the default ROS2 QoS settings.\n\n```yaml\n/topic_name:\n  history: keep_last\n  depth: 10\n  reliability: reliable\n  durability: volatile\n  deadline:\n    # unspecified/infinity\n    sec: 0\n    nsec: 0\n  lifespan:\n    # unspecified/infinity\n    sec: 0\n    nsec: 0\n  liveliness: system_default\n  liveliness_lease_duration:\n    # unspecified/infinity\n    sec: 0\n    nsec: 0\n  avoid_ros_namespace_conventions: false\n```\n\nYou can then use the override by specifying the `--qos-profile-overrides-path` argument in the CLI:\n\n```sh\n# Record\nros2 bag record --qos-profile-overrides-path override.yaml -a -o my_bag\n# Playback\nros2 bag play --qos-profile-overrides-path override.yaml my_bag\n```\n\nSee [the official QoS override tutorial][qos-override-tutorial] and [\"About QoS Settings\"][about-qos-settings] for more detail.\n\n### Using in launch\n\nWe can invoke the command line tool from a ROS launch script as an *executable* (not a *node* action).\nFor example, to launch the command to record all topics you can use the following launch script:\n\n```xml\n\u003claunch\u003e\n  \u003cexecutable cmd=\"ros2 bag record -a\" output=\"screen\" /\u003e\n\u003c/launch\u003e\n```\n\nHere's the equivalent Python launch script:\n\n```python\nimport launch\n\n\ndef generate_launch_description():\n    return launch.LaunchDescription([\n        launch.actions.ExecuteProcess(\n            cmd=['ros2', 'bag', 'record', '-a'],\n            output='screen'\n        )\n    ])\n```\n\nUse the `ros2 launch` command line tool to launch either of the above launch scripts.\nFor example, if we named the above XML launch script, `record_all.launch.xml`:\n\n```sh\n$ ros2 launch record_all.launch.xml\n```\n\nYou can also invoke the `play` and `record` functionalities provided by `rosbag2_transport` package as nodes.\nThe advantage to use this invocation strategy is that the Python layer handling the `ros2 bag` CLI is completely skipped.\n\n```python\nimport launch\n\ndef generate_launch_description():\n    return launch.LaunchDescription([\n        launch.actions.Node(\n            package='rosbag2_transport',\n            executable='player',\n            name='player',\n            output=\"screen\",\n            parameters=[\"/path/to/params.yaml\"],\n        )\n    ])\n```\n\n### Using recorder and player as composable nodes \u003ca id=\"composition\"\u003e\u003c/a\u003e\n\nPlay and record are fundamental tasks of Rosbag2. However, playing or recording data at high rates may have limitations (e.g. spurious packet drops) due to one of the following:\n- low network bandwidth\n- high CPU load\n- slow mass memory\n- ROS 2 middleware serialization/deserialization delays \u0026 overhead\n\nROS 2 C++ nodes can benefit from intra-process communication to partially or completely bypass network transport of messages between two nodes.\n\nMultiple _components_ can be _composed_, either [statically](https://docs.ros.org/en/rolling/Tutorials/Intermediate/Composition.html#compile-time-composition-with-hardcoded-nodes) or [dynamically](https://docs.ros.org/en/rolling/Tutorials/Intermediate/Composition.html#run-time-composition-using-ros-services-with-a-publisher-and-subscriber): all the composed component will share the same address space because they will be loaded in a single process.\n\nA prerequirement is for each C++ node to be [_composable_](https://docs.ros.org/en/rolling/Concepts/Intermediate/About-Composition.html?highlight=composition) and to follow the [guidelines](https://docs.ros.org/en/rolling/Tutorials/Demos/Intra-Process-Communication.html?highlight=intra) for efficient publishing \u0026 subscription.\n\nWith the above requirements met, the user can:\n- compose multiple nodes together\n- explicitly enable intra-process communication\n\nWhenever a publisher and a subscriber on the same topic belong to the same _composed_ process, and intra-process is enabled for both, `rclcpp` completely bypasses RMW layer and below transport layer (i.e. DDS). Instead, messages are shared via process memory and *potentially* never copied. Some exception hold, so please have a look to the [IPC guidelines](https://docs.ros.org/en/rolling/Tutorials/Demos/Intra-Process-Communication.html?highlight=intra).\n\nHere is an example of Python launchfile composition. Notice that composable container components do not expect YAML files to be directly passed to them: parameters have to be \"dumped\" out from the YAML file (if you have one). A suggestion of possible implementation is offered as a starting point.\n\n```python\nimport launch\nimport launch_ros\nimport yaml\n\n'''\nUsed to load parameters for composable nodes from a standard param file\n'''\ndef dump_params(param_file_path, node_name):\n    with open(param_file_path, 'r') as file:\n        return [yaml.safe_load(file)[node_name]['ros__parameters']]\n\ndef generate_launch_description():\n    return launch.LaunchDescription([\n        launch.actions.ComposableNodeContainer(\n            name='composable_container',\n            package='rclcpp_components',\n            executable='component_container',\n            composable_node_descriptions=[\n                launch_ros.descriptions.ComposableNode(\n                    package='rosbag2_transport',\n                    plugin='rosbag2_transport::Player',\n                    name='player',\n                    parameters=dump_params(\"/path/to/params.yaml\", \"player\"),\n                    extra_arguments=[{'use_intra_process_comms': True}]\n                ),\n                # your other components here\n            ]\n        )\n    ])\n}\n```\n\nHere's an example YAML configuration for both composable player and recorder:\n```yaml\nrecorder:\n  ros__parameters:\n    use_sim_time: false\n    record:\n      all: true\n      is_discovery_disabled: false\n      topic_polling_interval:\n        sec: 0\n        nsec: 10000000\n      include_hidden_topics: true\n      ignore_leaf_topics: false\n      start_paused: false\n\n    storage:\n      uri: \"/path/to/destination/folder\"\n      storage_id: \"sqlite3\"\n      max_cache_size: 20000000\n```\nand\n```yaml\nplayer:\n  ros__parameters:\n    play:\n      read_ahead_queue_size: 1000\n      node_prefix: \"\"\n      rate: 1.0\n      loop: false\n      # Negative timestamps will make the playback to not stop.\n      playback_duration:\n        sec: -1\n        nsec: 00000000\n      start_paused: false\n\n    storage:\n      uri: \"path/to/rosbag/file\"\n      storage_id: \"mcap\"\n      storage_config_uri: \"\"\n```\n\nFor a full list of available parameters, you can refer to [`player`](rosbag2_transport/test/resources/player_node_params.yaml) and [`recorder`](rosbag2_transport/test/resources/recorder_node_params.yaml) configurations from the `test` folder of `rosbag2_transport`.\n\n## Plugin implementation\n\n### Storage format plugin architecture\n\nLooking at the output of the `ros2 bag info` command, we can see a field `Storage id:`.\nRosbag2 was designed to support multiple storage formats to adapt to individual use cases.\nThis repository provides two storage plugins, `mcap` and `sqlite3`.\nThe default is `mcap`, which is provided to code by [`rosbag2_storage::get_default_storage_id()`](rosbag2_storage/include/rosbag2_storage/default_storage_id.hpp) and defined in [`default_storage_id.cpp`](rosbag2_storage/src/rosbag2_storage/default_storage_id.cpp#L21)\n\nIf not specified otherwise, Rosbag2 will write data using the default plugin.\n\nIn order to use a specified (non-default) storage format plugin, Rosbag2 has a command line argument `--storage`:\n\n```\n$ ros2 bag record --storage \u003cstorage_id\u003e\n```\n\nBag reading commands can detect the storage plugin automatically, but if for any reason you want to force a specific plugin to read a bag, you can use the `--storage` option on any `ros2 bag` verb.\n\nTo write your own Rosbag2 storage implementation, refer to [Storage Plugin Development](docs/storage_plugin_development.md)\n\n\n### Serialization format plugin architecture\n\nLooking further at the output of `ros2 bag info`, we can see another field attached to each topic called `Serialization Format`.\nBy design, ROS 2 is middleware agnostic and thus can leverage multiple communication frameworks.\nThe default middleware for ROS 2 is DDS which has `cdr` as its default binary serialization format.\nHowever, other middleware implementation might have different formats.\nIf not specified, `ros2 bag record -a` will record all data in the middleware specific format.\nThis however also means that such a bag file can't easily be replayed with another middleware format.\n\nRosbag2 implements a serialization format plugin architecture which allows the user the specify a certain serialization format.\nWhen specified, Rosbag2 looks for a suitable converter to transform the native middleware protocol to the target format.\nThis also allows to record data in a native format to optimize for speed, but to convert or transform the recorded data into a middleware agnostic serialization format.\n\nBy default, Rosbag2 can convert from and to CDR as it's the default serialization format for ROS 2.\n\n[qos-override-tutorial]: https://docs.ros.org/en/rolling/Guides/Overriding-QoS-Policies-For-Recording-And-Playback.html\n[about-qos-settings]: https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html\n\n## Tips and Tricks\n\n### Record bags to a custom base directory\n\nIf you want to send bagfiles to a different directory than the current working directory, like so\n\n```plaintext\n/my/bag/base_dir\n├── rosbag2_2025_02_21-15_35_35\n|   ├── metadata.yaml\n│   └── rosbag2_2025_02_21-15_35_35_0.mcap\n└── rosbag2_2025_02_21-15_37_17\n    ├── metadata.yaml\n    └── rosbag2_2025_02_21-15_37_17_0.mcap\n```\n\nThis can be accomplished without features in Rosbag2 itself.\n\nIn shell:\n\n```bash\npushd /my/bag/base_dir \u0026\u0026 ros2 bag record ...\n```\n\nIn launch:\n\n```python\nExecuteProcess(\n  cmd=['ros2', 'bag', 'record', ...],\n  cwd=my_base_dir,\n),\n\nYou can fully customize the output bag name, without any Rosbag2 special features.\n\nFor example, you want a timestamp on the bag directory name, but want a custom prefix instead of `rosbag2_`.\n\n```bash\n$ ros2 bag record -a -o mybag_\"$(date +\"%Y_%m_%d-%H_%M_%S\")\"\n... creates e.g. mybag_2025_02_21-15_35_35\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fros2%2Frosbag2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fros2%2Frosbag2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fros2%2Frosbag2/lists"}