-
Notifications
You must be signed in to change notification settings - Fork 7
ROS2: general macro for RGB-D cameras #25
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: ros2
Are you sure you want to change the base?
Conversation
|
@TomasMerva not sure if you know about this discussion regarding RGBD sensor frames differences gazebosim/gz-sensors#488 and gazebosim/ros_gz#703 |
…o change the frame name
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.
Pull Request Overview
This PR refactors the UAV sensor framework to improve sensor support and unify naming conventions. The changes focus on better handling of different sensor types (RGB cameras, RGBD cameras, depth cameras, and LiDARs) and establishing consistent frame naming patterns.
Key changes include:
- Refactored SDF to TF publisher to support optical frames for camera sensors
- Added support for RGBD and depth camera sensor types
- Unified sensor data structures using enums for better type safety
- Renamed variables from "link" to "frame" for consistency with TF conventions
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| spawner_enums.py | Defines enums for sensor types and topic categorization |
| sdf_tf_enums.py | Defines enums for sensor link data structure keys |
| sdf_to_tf_publisher.py | Refactored to handle optical frames and multiple sensor types |
| mrs_drone_spawner.py | Updated to use enums and handle RGBD/depth cameras |
| generic_components.sdf.jinja | Added macros for RGBD and depth cameras, split 2D/3D LiDAR macros |
| camera templates | Updated to use new camera macros and add optical frames |
| lidar templates | Renamed links to frames and updated to use split macros |
| uav_ros_gz_bridge_config.yaml.jinja | Simplified topic handling using consolidated lists |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| def _get_transform_from_string_pose(self, pose_rpy_str: str) -> np.ndarray: | ||
| T_frame = np.eye(4) | ||
| if pose_rpy_str is not None and(pose_rpy_str != ""): |
Copilot
AI
Nov 5, 2025
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.
Missing space after 'and' keyword before the opening parenthesis. Should be and (pose_rpy_str != \"\") for consistency with Python style conventions.
| if pose_rpy_str is not None and(pose_rpy_str != ""): | |
| if pose_rpy_str is not None and (pose_rpy_str != ""): |
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.
fixed
| if link_name is None: | ||
| return "" | ||
| for link in model_xml.findall('.//link'): | ||
| if link.attrib["name"] == link_name: |
Copilot
AI
Nov 5, 2025
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.
Inconsistent attribute access method. Line 143 uses .get(\"name\") while this line uses .attrib[\"name\"]. The .get() method is safer as it returns None if the attribute doesn't exist, while .attrib[] will raise a KeyError. Use link.get(\"name\") for consistency and error handling.
| if link.attrib["name"] == link_name: | |
| if link.get("name") == link_name: |
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.
unified
| attached_sensors['cameras'].append(camera) | ||
| basic_topic_name = '/' + topic[0].firstChild.data | ||
| camera[SensorTopics.IMAGE] = basic_topic_name | ||
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name.replace('image', 'camera_info') |
Copilot
AI
Nov 5, 2025
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.
The .replace('image', 'camera_info') call may produce unexpected results if 'image' appears multiple times in the topic name. Consider using a more specific replacement or reconstructing the topic path to ensure only the intended part is replaced.
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name.replace('image', 'camera_info') | |
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name.rsplit('image', 1)[0] + 'camera_info' if 'image' in basic_topic_name else basic_topic_name + '/camera_info' |
| basic_topic_name = '/' + topic[0].firstChild.data | ||
| camera[SensorTopics.DEPTH_IMAGE] = basic_topic_name | ||
| camera[SensorTopics.POINTS] = camera[SensorTopics.DEPTH_IMAGE] + '/points' | ||
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name.replace('depth_image', 'camera_info') |
Copilot
AI
Nov 5, 2025
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.
The .replace('depth_image', 'camera_info') call may produce unexpected results if 'depth_image' appears multiple times in the topic name. Consider using a more specific replacement or reconstructing the topic path to ensure only the intended part is replaced.
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name.replace('depth_image', 'camera_info') | |
| # Replace only the last segment if it is 'depth_image' | |
| path_parts = basic_topic_name.rstrip('/').split('/') | |
| if path_parts[-1] == 'depth_image': | |
| path_parts[-1] = 'camera_info' | |
| camera_info_topic = '/'.join(path_parts) | |
| if not camera_info_topic.startswith('/'): | |
| camera_info_topic = '/' + camera_info_topic | |
| camera[SensorTopics.CAMERA_INFO] = camera_info_topic | |
| else: | |
| camera[SensorTopics.CAMERA_INFO] = basic_topic_name + '/camera_info' |
| roll = math.radians(90), | ||
| pitch = 0, | ||
| yaw = 0) | ||
| }} |
Copilot
AI
Nov 5, 2025
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.
[nitpick] There's an inconsistent blank line pattern. Line 45 has the closing braces followed immediately by the comment on line 46, while in other locations there's typically a blank line. Consider adding a blank line after line 45 for consistency.
| }} | |
| }} |
| gz_type_name: "gz.msgs.CameraInfo" | ||
| direction: GZ_TO_ROS | ||
| {%- endfor -%} | ||
| {% endfor %} |
Copilot
AI
Nov 5, 2025
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.
[nitpick] Inconsistent Jinja2 template whitespace control. Lines 7 and 15 use {% endfor %} without the - for whitespace control, while line 23 uses {% endfor %}. However, all opening tags use {%-. For consistency, consider using {%- endfor -%} on all three lines.
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.
Do not remove -, because doing so will break the generation of the ros_gz_bridge config file.
|
This update includes:
RGB-D camera template (pending bug fix):
|
|
Update:
|
|
@TomasMerva, please resolve the conflicts, and I will then perform the final check with Copilot. |
| {%- set camera_gz_frame_id = spawner_args['name'] + '/' + camera_name + '/color_optical' -%} | ||
| ``` | ||
|
|
||
| The resulting camera-related topics will look like as follows: |
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.
This is relevant to the gazebo topic; perhaps we could also discuss how it is implemented on the ROS side.
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.
I meant write it in the README :)
…o that there is only one broadcaster, even if new spawn requests come later

Addressing #23