-
Notifications
You must be signed in to change notification settings - Fork 191
[feat] Add make_mcap_metadata.py and document it in bag2edex README #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -83,6 +83,34 @@ rosbag_extract_urdf \ | |||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Generating Missing `metadata.yaml` for MCAP Files | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| `make_mcap_metadata.py` regenerates the `metadata.yaml` file that `rosbag2` requires next to an `.mcap` file. Use it when you have a standalone `.mcap` file without its companion `metadata.yaml` — for example, after downloading only the `.mcap` from a recording system or after the metadata file was accidentally deleted. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| **Prerequisites:** `ros2` must be on `PATH` (the script calls `ros2 bag info` internally). | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| **Usage:** | ||||||||||||||||||||||||||||||
| ```sh | ||||||||||||||||||||||||||||||
| ./make_mcap_metadata.py path/to/rosbag.mcap | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The script writes `metadata.yaml` into the same directory as the `.mcap` file. Once generated, the directory can be used with the extraction tools above. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| **Optional argument:** | ||||||||||||||||||||||||||||||
| - `--version <int>` — sets the `rosbag2_bagfile_information.version` field in the metadata (default: `9`). Only change this if you need to match a specific rosbag2 version. | ||||||||||||||||||||||||||||||
|
Comment on lines
+99
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show surrounding README context
sed -n '1,180p' tools/python_tools/cuvslam_tools/bag2edex/README.md
# Find other mentions of rosbag2/version in this area
rg -n --hidden --no-messages "version|rosbag2|Humble|Jazzy" tools/python_tools/cuvslam_tools/bag2edexRepository: nvidia-isaac/cuVSLAM Length of output: 2029 🌐 Web query:
💡 Result: In ROS 2, the Citations:
🌐 Web query:
💡 Result: In ROS 2 Humble, the rosbag2_storage package defines the bag metadata structure with version 5 [1][2]. The BagMetadata structure is primarily used to manage recording information and includes a version field, which is incremented when the structure of the metadata changes to ensure backward compatibility and proper serialization [2]. Specifically, in version 5 of the metadata schema, the structure introduced support for the files field, which contains a vector of FileInformation objects [3][4]. This field allows the system to explicitly track multiple files associated with a single bag, which is critical for storage formats that split recordings across several files [1][4]. The metadata is typically serialized into a metadata.yaml file [5]. When the system reads this file, it uses the version number to decide which fields to parse [3][4]. For instance, the decoding logic in rosbag2_storage specifically checks if the version is 5 or greater to correctly deserialize the files information [3][4]. While version 5 was current for Humble, newer versions of ROS 2 have subsequently introduced higher metadata versions to support additional features, such as custom data maps (version 6) and ROS distribution tracking (version 8) [3][6]. Citations:
🌐 Web query:
💡 Result: In the context of the ROS 2 (Robot Operating System) rosbag2_storage library, the BagMetadata structure includes a version field that is used to track changes to the content of the structure [1]. As of the documentation for rosbag2_storage version 0.15.16, the defined version is 5 [1]. The documentation explicitly notes that this number should be upgraded whenever the content of the struct is changed [1]. Citations: Clarify 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| **Example:** | ||||||||||||||||||||||||||||||
| ```sh | ||||||||||||||||||||||||||||||
|
Comment on lines
+92
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add blank lines around fenced code blocks.
Proposed fix **Usage:**
+
```sh
...
**Example:**
+
```sh📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.23.0)[warning] 93-93: Fenced code blocks should be surrounded by blank lines (MD031, blanks-around-fences) [warning] 103-103: Fenced code blocks should be surrounded by blank lines (MD031, blanks-around-fences) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||||||||
| ./make_mcap_metadata.py /data/bags/my_recording/my_recording_0.mcap | ||||||||||||||||||||||||||||||
| # Wrote: /data/bags/my_recording/metadata.yaml | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| rosbag_extract_edex \ | ||||||||||||||||||||||||||||||
| --config configs/my_config.yaml \ | ||||||||||||||||||||||||||||||
| --rosbag_path /data/bags/my_recording \ | ||||||||||||||||||||||||||||||
| --output_path /data/edex/my_recording | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## License | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. | ||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,109 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # NVIDIA software released under the NVIDIA Community License is intended to be used to enable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the further development of AI and robotics technologies. Such software has been designed, tested, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # and optimized for use with NVIDIA hardware, and this License grants permission to use the software | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # solely with such hardware. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Subject to the terms of this License, NVIDIA confirms that you are free to commercially use, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # modify, and distribute the software with NVIDIA hardware. NVIDIA does not claim ownership of any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # outputs generated using the software or derivative works thereof. Any code contributions that you | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # share with NVIDIA are licensed to NVIDIA as feedback under this License and may be incorporated | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # in future releases without notice or attribution. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # By using, reproducing, modifying, distributing, performing, or displaying any portion or element | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # of the software or derivative works thereof, you agree to be bound by this License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import argparse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import re | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def ns_from_seconds(seconds: str) -> int: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return int(round(float(seconds) * 1_000_000_000)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def ns_from_epoch(sec: str, nsec: str) -> int: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return int(sec) * 1_000_000_000 + int(nsec.ljust(9, "0")[:9]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def main(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser = argparse.ArgumentParser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser.add_argument("mcap", help="Path to .mcap file") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser.add_argument("--version", type=int, default=9) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args = parser.parse_args() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mcap_path = Path(args.mcap).resolve() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bag_dir = mcap_path.parent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata_path = bag_dir / "metadata.yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = subprocess.run( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["ros2", "bag", "info", "--storage", "mcap", str(mcap_path)], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| check=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| capture_output=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text = result.stdout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration = re.search(r"Duration:\s+([0-9.]+)s", text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start = re.search(r"Start:.*\((\d+)\.(\d+)\)", text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages = re.search(r"Messages:\s+(\d+)", text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not duration or not start or not messages: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise RuntimeError("Could not parse ros2 bag info output") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration_ns = ns_from_seconds(duration.group(1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start_ns = ns_from_epoch(start.group(1), start.group(2)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| total_messages = int(messages.group(1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| topic_re = re.compile( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| r"Topic:\s+(.+?)\s+\|\s+Type:\s+(.+?)\s+\|\s+Count:\s+(\d+)\s+\|\s+Serialization Format:\s+(\S+)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| topics = topic_re.findall(text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not topics: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise RuntimeError("No topics found in ros2 bag info output") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rel_file = mcap_path.name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append("rosbag2_bagfile_information:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" version: {args.version}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" storage_identifier: mcap") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" duration:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" nanoseconds: {duration_ns}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" starting_time:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" nanoseconds_since_epoch: {start_ns}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" message_count: {total_messages}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" relative_file_paths:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" - {rel_file}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" files:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" - path: {rel_file}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" starting_time:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" nanoseconds_since_epoch: {start_ns}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" duration:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" nanoseconds: {duration_ns}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" message_count: {total_messages}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" topics_with_message_count:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for name, msg_type, count, serialization in topics: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" - topic_metadata:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" name: {name}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" type: {msg_type}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" serialization_format: {serialization}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(' offered_qos_profiles: ""') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+73
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== File outline ==\n'
ast-grep outline tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py --view expanded || true
printf '\n== Relevant source excerpts ==\n'
sed -n '1,220p' tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py | cat -n
printf '\n== README excerpt ==\n'
sed -n '1,180p' tools/python_tools/cuvslam_tools/bag2edex/README.md | cat -n
printf '\n== Search for type_description_hash / version handling ==\n'
rg -n "type_description_hash|rosbag2_bagfile_information.version|version:" tools/python_tools/cuvslam_tools/bag2edex -SRepository: nvidia-isaac/cuVSLAM Length of output: 2029 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py')
text = p.read_text()
print('HAS type_description_hash:', 'type_description_hash' in text)
print('HAS version 9 literal:', 'version: 9' in text or 'version = 9' in text)
PYRepository: nvidia-isaac/cuVSLAM Length of output: 2029 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the generator and any local documentation for metadata version/schema requirements.
sed -n '1,220p' tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py | cat -n
printf '\n--- README ---\n'
sed -n '1,180p' tools/python_tools/cuvslam_tools/bag2edex/README.md | cat -n
printf '\n--- Search ---\n'
rg -n "type_description_hash|rosbag2_bagfile_information.version|version 9|version 5|Jazzy|Humble" tools/python_tools/cuvslam_tools/bag2edex -SRepository: nvidia-isaac/cuVSLAM Length of output: 2029 🌐 Web query:
💡 Result: The metadata version 9 in Citations:
🌐 Web query:
💡 Result: In ROS 2, rosbag2 metadata files use a versioning system to track changes in the metadata schema [1][2][3]. The specific fields you mentioned are associated with different versions of this schema: The type_description_hash field was introduced to TopicMetadata in metadata version 7 [1][2]. In versions prior to 7, this field is not present or is treated as an empty string [1][2]. Regarding metadata version 9: This version introduced updates to how QoS (Quality of Service) profiles are serialized and handled within the metadata files [2]. Specifically, in versions 9 and later, the offered_qos_profiles field is serialized using YAML::convert rather than being stored as a raw string [2]. For ROS 2 Humble, the metadata version is generally lower than 9 (Humble typically uses version 5 or 6 depending on the specific release patch), meaning it does not support the version 9 metadata schema features such as the updated QoS serialization or the field structures associated with newer ROS 2 distributions [4][1][2]. The type_description_hash field may also be unavailable or handled differently depending on the specific patch version of Humble, as it was added in later development cycles [1][2]. In summary, metadata version 9 is a more recent schema evolution used in newer ROS 2 distributions (such as Rolling or Jazzy), whereas Humble relies on an older version of the schema [4][1][2][5]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
# Find where the metadata file and version flag are used.
rg -n "make_mcap_metadata|--version|metadata.version|topics_with_message_count|type_description_hash" tools/python_tools -S
# Show the script in smaller slices if it is large.
wc -l tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py
sed -n '1,140p' tools/python_tools/cuvslam_tools/bag2edex/make_mcap_metadata.py | cat -nRepository: nvidia-isaac/cuVSLAM Length of output: 2029 🌐 Web query:
💡 Result: In the context of ROS 2 rosbag2 metadata, version 9 is a storage format version that includes the Citations:
Align the metadata schema with the ROS distribution you’re targeting.
📍 Affects 2 files
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(f" message_count: {count}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+69
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Escape all dynamic YAML scalars. The MCAP filename and parsed Proposed fix+import json
...
- yaml.append(f" - {rel_file}")
+ yaml.append(f" - {json.dumps(rel_file)}")
...
- yaml.append(f" - path: {rel_file}")
+ yaml.append(f" - path: {json.dumps(rel_file)}")
...
- yaml.append(f" name: {name}")
- yaml.append(f" type: {msg_type}")
- yaml.append(f" serialization_format: {serialization}")
+ yaml.append(f" name: {json.dumps(name)}")
+ yaml.append(f" type: {json.dumps(msg_type)}")
+ yaml.append(f" serialization_format: {json.dumps(serialization)}")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(' compression_format: ""') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(' compression_mode: ""') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append(" custom_data: {}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml.append("") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata_path.write_text("\n".join(yaml)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win Add regression coverage for the CLI contract. Mock representative 🧰 Tools🪛 ast-grep (0.44.1)[warning] 63-63: XPath query is request-/variable-derived; use parameterized XPath to prevent injection. (xpath-injection-python) 🪛 Ruff (0.15.21)[error] 40-40: (S603) [error] 41-41: Starting a process with a partial executable path (S607) [warning] 54-54: Avoid specifying long messages outside the exception class (TRY003) [warning] 67-67: Avoid specifying long messages outside the exception class (TRY003) 🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Do not silently overwrite existing metadata.
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"Wrote: {metadata_path}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| main() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Document the MCAP storage plugin prerequisite.
ros2on PATH is not enough here; the sourced ROS 2 environment also needs the MCAP storage plugin available forros2 bag info --storage mcap.🤖 Prompt for AI Agents