diff --git a/.github/workflows/ros2-ci.yml b/.github/workflows/ros2-ci.yml
index fb806edbf..1977346db 100644
--- a/.github/workflows/ros2-ci.yml
+++ b/.github/workflows/ros2-ci.yml
@@ -19,15 +19,6 @@ jobs:
- docker-image: "ubuntu:22.04"
gz-version: "harmonic"
ros-distro: "humble"
- - docker-image: "ubuntu:22.04"
- gz-version: "fortress"
- ros-distro: "rolling"
- - docker-image: "ubuntu:22.04"
- gz-version: "garden"
- ros-distro: "rolling"
- - docker-image: "ubuntu:22.04"
- gz-version: "harmonic"
- ros-distro: "rolling"
container:
image: ${{ matrix.docker-image }}
steps:
diff --git a/README.md b/README.md
index 53755a5d4..8e1d74d0a 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Galactic | Edifice | [galactic](https://github.com/gazebosim/ros_gz/tree/galacti
Galactic | Fortress | [galactic](https://github.com/gazebosim/ros_gz/tree/galactic) | only from source
Humble | Fortress | [humble](https://github.com/gazebosim/ros_gz/tree/humble) | https://packages.ros.org
Humble | Garden | [humble](https://github.com/gazebosim/ros_gz/tree/humble) | [gazebo packages](https://gazebosim.org/docs/latest/ros_installation#gazebo-garden-with-ros-2-humble-iron-or-rolling-use-with-caution-)[^1]
-Humble | Harmonic | [humble](https://github.com/gazebosim/ros_gz/tree/humble) | only from source
+Humble | Harmonic | [humble](https://github.com/gazebosim/ros_gz/tree/humble) | [gazebo packages](https://gazebosim.org/docs/harmonic/ros_installation#-gazebo-harmonic-with-ros-2-humble-iron-or-rolling-use-with-caution-)[^1]
Rolling | Edifice | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | only from source
Rolling | Fortress | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | https://packages.ros.org
Rolling | Garden | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | only from source
diff --git a/ros_gz/CHANGELOG.rst b/ros_gz/CHANGELOG.rst
index b305581d3..fb245cca4 100644
--- a/ros_gz/CHANGELOG.rst
+++ b/ros_gz/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_gz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_gz/package.xml b/ros_gz/package.xml
index 1d2a50afc..91c75be01 100644
--- a/ros_gz/package.xml
+++ b/ros_gz/package.xml
@@ -4,7 +4,7 @@
ros_gz
- 0.244.13
+ 0.244.14
Meta-package containing interfaces for using ROS 2 with Gazebo simulation.
Louise Poubel
Apache 2.0
diff --git a/ros_gz_bridge/CHANGELOG.rst b/ros_gz_bridge/CHANGELOG.rst
index afd5bb04a..412842e43 100644
--- a/ros_gz_bridge/CHANGELOG.rst
+++ b/ros_gz_bridge/CHANGELOG.rst
@@ -2,6 +2,25 @@
Changelog for package ros_gz_bridge
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+* Added conversion for Detection3D and Detection3DArray (`#523 `_) (`#526 `_)
+ Co-authored-by: wittenator <9154515+wittenator@users.noreply.github.com>
+* Add ROS namespaces to GZ topics (`#512 `_)
+ Co-authored-by: Alejandro Hernández Cordero
+* Correctly export ros_gz_bridge for downstream targets (`#503 `_) (`#506 `_)
+* Add a virtual destructor to suppress compiler warning (`#502 `_) (`#505 `_)
+ Co-authored-by: Michael Carroll
+* Add option to change material color from ROS. (`#486 `_)
+ * Message and bridge for MaterialColor.
+ This allows bridging MaterialColor from ROS to GZ and is
+ important for allowing simulation users to create status lights.
+ ---------
+ Co-authored-by: Alejandro Hernández Cordero
+ Co-authored-by: Addisu Z. Taddese
+ Co-authored-by: Addisu Z. Taddese
+* Contributors: Alejandro Hernández Cordero, Benjamin Perseghetti, Krzysztof Wojciechowski, Michael Carroll
+
0.244.13 (2024-01-23)
---------------------
* backport pr 374 (`#489 `_)
diff --git a/ros_gz_bridge/CMakeLists.txt b/ros_gz_bridge/CMakeLists.txt
index 4d0e4057f..7df2399bd 100644
--- a/ros_gz_bridge/CMakeLists.txt
+++ b/ros_gz_bridge/CMakeLists.txt
@@ -119,7 +119,7 @@ add_custom_command(
COMMENT "Generating factories for interface types")
set(bridge_lib
- ros_gz_bridge_lib
+ ros_gz_bridge
)
add_library(${bridge_lib}
@@ -129,6 +129,7 @@ add_library(${bridge_lib}
src/bridge_handle_ros_to_gz.cpp
src/bridge_handle_gz_to_ros.cpp
src/factory_interface.cpp
+ src/service_factory_interface.cpp
src/service_factories/ros_gz_interfaces.cpp
src/ros_gz_bridge.cpp
${convert_files}
@@ -148,8 +149,12 @@ ament_target_dependencies(${bridge_lib}
)
target_include_directories(${bridge_lib}
- PUBLIC include
- PRIVATE src ${generated_path}
+ PUBLIC
+ "$"
+ "$"
+ PRIVATE
+ "$"
+ "$"
)
target_link_libraries(${bridge_lib}
@@ -162,19 +167,16 @@ rclcpp_components_register_node(
PLUGIN ros_gz_bridge::RosGzBridge
EXECUTABLE bridge_node)
-install(TARGETS ${bridge_lib}
+install(TARGETS ${bridge_lib} EXPORT export_${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(
DIRECTORY include/
- DESTINATION include
+ DESTINATION include/${PROJECT_NAME}
)
-ament_export_include_directories(include)
-ament_export_libraries(${bridge_lib})
-
set(bridge_executables
parameter_bridge
static_bridge
@@ -193,7 +195,7 @@ foreach(bridge ${bridge_executables})
${BRIDGE_MESSAGE_TYPES}
)
install(TARGETS ${bridge}
- DESTINATION lib/${PROJECT_NAME}
+ RUNTIME DESTINATION lib/${PROJECT_NAME}
)
endforeach()
@@ -348,9 +350,19 @@ if(BUILD_TESTING)
endif()
-ament_export_dependencies(
- rclcpp
- ${BRIDGE_MESSAGE_TYPES}
-)
+# Export old-style CMake variables
+ament_export_include_directories("include/${PROJECT_NAME}")
+ament_export_libraries(${bridge_lib})
+
+# Export modern CMake targets
+ament_export_targets(export_${PROJECT_NAME})
+
+# specific order: dependents before dependencies
+ament_export_dependencies(rclcpp)
+ament_export_dependencies(rclcpp_components)
+ament_export_dependencies(${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER})
+ament_export_dependencies(${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER})
+ament_export_dependencies(yaml_cpp_vendor)
+ament_export_dependencies(${BRIDGE_MESSAGE_TYPES})
ament_package()
diff --git a/ros_gz_bridge/README.md b/ros_gz_bridge/README.md
index aff3b3797..242d92b2d 100644
--- a/ros_gz_bridge/README.md
+++ b/ros_gz_bridge/README.md
@@ -5,64 +5,66 @@ between ROS and Gazebo Transport.
The following message types can be bridged for topics:
-| ROS type | Gazebo type |
-|---------------------------------------------|:--------------------------------------:|
-| builtin_interfaces/msg/Time | ignition::msgs::Time |
-| std_msgs/msg/Bool | ignition::msgs::Boolean |
-| std_msgs/msg/ColorRGBA | ignition::msgs::Color |
-| std_msgs/msg/Empty | ignition::msgs::Empty |
-| std_msgs/msg/Float32 | ignition::msgs::Float |
-| std_msgs/msg/Float64 | ignition::msgs::Double |
-| std_msgs/msg/Header | ignition::msgs::Header |
-| std_msgs/msg/Int32 | ignition::msgs::Int32 |
-| std_msgs/msg/UInt32 | ignition::msgs::UInt32 |
-| std_msgs/msg/String | ignition::msgs::StringMsg |
-| geometry_msgs/msg/Wrench | ignition::msgs::Wrench |
-| geometry_msgs/msg/WrenchStamped | ignition::msgs::Wrench |
-| geometry_msgs/msg/Quaternion | ignition::msgs::Quaternion |
-| geometry_msgs/msg/Vector3 | ignition::msgs::Vector3d |
-| geometry_msgs/msg/Point | ignition::msgs::Vector3d |
-| geometry_msgs/msg/Pose | ignition::msgs::Pose |
-| geometry_msgs/msg/PoseArray | ignition::msgs::Pose_V |
-| geometry_msgs/msg/PoseWithCovariance | ignition::msgs::PoseWithCovariance |
-| geometry_msgs/msg/PoseStamped | ignition::msgs::Pose |
-| geometry_msgs/msg/Transform | ignition::msgs::Pose |
-| geometry_msgs/msg/TransformStamped | ignition::msgs::Pose |
-| geometry_msgs/msg/Twist | ignition::msgs::Twist |
-| geometry_msgs/msg/TwistStamped | ignition::msgs::Twist |
-| geometry_msgs/msg/TwistWithCovariance | ignition::msgs::TwistWithCovariance |
-| geometry_msgs/msg/TwistWithCovarianceStamped| ignition::msgs::TwistWithCovariance |
-| nav_msgs/msg/Odometry | ignition::msgs::Odometry |
-| nav_msgs/msg/Odometry | ignition::msgs::OdometryWithCovariance |
-| rcl_interfaces/msg/ParameterValue | ignition::msgs::Any |
-| ros_gz_interfaces/msg/Altimeter | ignition::msgs::Altimeter |
-| ros_gz_interfaces/msg/Contact | ignition::msgs::Contact |
-| ros_gz_interfaces/msg/Contacts | ignition::msgs::Contacts |
-| ros_gz_interfaces/msg/Dataframe | ignition::msgs::Dataframe |
-| ros_gz_interfaces/msg/Entity | ignition::msgs::Entity |
-| ros_gz_interfaces/msg/Float32Array | ignition::msgs::Float_V |
-| ros_gz_interfaces/msg/GuiCamera | ignition::msgs::GUICamera |
-| ros_gz_interfaces/msg/JointWrench | ignition::msgs::JointWrench |
-| ros_gz_interfaces/msg/Light | ignition::msgs::Light |
-| ros_gz_interfaces/msg/SensorNoise | ignition::msgs::SensorNoise |
-| ros_gz_interfaces/msg/StringVec | ignition::msgs::StringMsg_V |
-| ros_gz_interfaces/msg/TrackVisual | ignition::msgs::TrackVisual |
-| ros_gz_interfaces/msg/VideoRecord | ignition::msgs::VideoRecord |
-| ros_gz_interfaces/msg/WorldControl | ignition::msgs::WorldControl |
-| rosgraph_msgs/msg/Clock | ignition::msgs::Clock |
-| sensor_msgs/msg/BatteryState | ignition::msgs::BatteryState |
-| sensor_msgs/msg/CameraInfo | ignition::msgs::CameraInfo |
-| sensor_msgs/msg/FluidPressure | ignition::msgs::FluidPressure |
-| sensor_msgs/msg/Imu | ignition::msgs::IMU |
-| sensor_msgs/msg/Image | ignition::msgs::Image |
-| sensor_msgs/msg/JointState | ignition::msgs::Model |
-| sensor_msgs/msg/Joy | ignition::msgs::Joy |
-| sensor_msgs/msg/LaserScan | ignition::msgs::LaserScan |
-| sensor_msgs/msg/MagneticField | ignition::msgs::Magnetometer |
-| sensor_msgs/msg/NavSatFix | ignition::msgs::NavSat |
-| sensor_msgs/msg/PointCloud2 | ignition::msgs::PointCloudPacked |
-| tf2_msgs/msg/TFMessage | ignition::msgs::Pose_V |
-| trajectory_msgs/msg/JointTrajectory | ignition::msgs::JointTrajectory |
+| ROS type | Gazebo type |
+|---------------------------------------------|:-------------------------------------------:|
+| builtin_interfaces/msg/Time | ignition::msgs::Time |
+| std_msgs/msg/Bool | ignition::msgs::Boolean |
+| std_msgs/msg/ColorRGBA | ignition::msgs::Color |
+| std_msgs/msg/Empty | ignition::msgs::Empty |
+| std_msgs/msg/Float32 | ignition::msgs::Float |
+| std_msgs/msg/Float64 | ignition::msgs::Double |
+| std_msgs/msg/Header | ignition::msgs::Header |
+| std_msgs/msg/Int32 | ignition::msgs::Int32 |
+| std_msgs/msg/UInt32 | ignition::msgs::UInt32 |
+| std_msgs/msg/String | ignition::msgs::StringMsg |
+| geometry_msgs/msg/Wrench | ignition::msgs::Wrench |
+| geometry_msgs/msg/WrenchStamped | ignition::msgs::Wrench |
+| geometry_msgs/msg/Quaternion | ignition::msgs::Quaternion |
+| geometry_msgs/msg/Vector3 | ignition::msgs::Vector3d |
+| geometry_msgs/msg/Point | ignition::msgs::Vector3d |
+| geometry_msgs/msg/Pose | ignition::msgs::Pose |
+| geometry_msgs/msg/PoseArray | ignition::msgs::Pose_V |
+| geometry_msgs/msg/PoseWithCovariance | ignition::msgs::PoseWithCovariance |
+| geometry_msgs/msg/PoseStamped | ignition::msgs::Pose |
+| geometry_msgs/msg/Transform | ignition::msgs::Pose |
+| geometry_msgs/msg/TransformStamped | ignition::msgs::Pose |
+| geometry_msgs/msg/Twist | ignition::msgs::Twist |
+| geometry_msgs/msg/TwistStamped | ignition::msgs::Twist |
+| geometry_msgs/msg/TwistWithCovariance | ignition::msgs::TwistWithCovariance |
+| geometry_msgs/msg/TwistWithCovarianceStamped| ignition::msgs::TwistWithCovariance |
+| nav_msgs/msg/Odometry | ignition::msgs::Odometry |
+| nav_msgs/msg/Odometry | ignition::msgs::OdometryWithCovariance |
+| rcl_interfaces/msg/ParameterValue | ignition::msgs::Any |
+| ros_gz_interfaces/msg/Altimeter | ignition::msgs::Altimeter |
+| ros_gz_interfaces/msg/Contact | ignition::msgs::Contact |
+| ros_gz_interfaces/msg/Contacts | ignition::msgs::Contacts |
+| ros_gz_interfaces/msg/Dataframe | ignition::msgs::Dataframe |
+| ros_gz_interfaces/msg/Entity | ignition::msgs::Entity |
+| ros_gz_interfaces/msg/Float32Array | ignition::msgs::Float_V |
+| ros_gz_interfaces/msg/GuiCamera | ignition::msgs::GUICamera |
+| ros_gz_interfaces/msg/JointWrench | ignition::msgs::JointWrench |
+| ros_gz_interfaces/msg/Light | ignition::msgs::Light |
+| ros_gz_interfaces/msg/SensorNoise | ignition::msgs::SensorNoise |
+| ros_gz_interfaces/msg/StringVec | ignition::msgs::StringMsg_V |
+| ros_gz_interfaces/msg/TrackVisual | ignition::msgs::TrackVisual |
+| ros_gz_interfaces/msg/VideoRecord | ignition::msgs::VideoRecord |
+| ros_gz_interfaces/msg/WorldControl | ignition::msgs::WorldControl |
+| rosgraph_msgs/msg/Clock | ignition::msgs::Clock |
+| sensor_msgs/msg/BatteryState | ignition::msgs::BatteryState |
+| sensor_msgs/msg/CameraInfo | ignition::msgs::CameraInfo |
+| sensor_msgs/msg/FluidPressure | ignition::msgs::FluidPressure |
+| sensor_msgs/msg/Imu | ignition::msgs::IMU |
+| sensor_msgs/msg/Image | ignition::msgs::Image |
+| sensor_msgs/msg/JointState | ignition::msgs::Model |
+| sensor_msgs/msg/Joy | ignition::msgs::Joy |
+| sensor_msgs/msg/LaserScan | ignition::msgs::LaserScan |
+| sensor_msgs/msg/MagneticField | ignition::msgs::Magnetometer |
+| sensor_msgs/msg/NavSatFix | ignition::msgs::NavSat |
+| sensor_msgs/msg/PointCloud2 | ignition::msgs::PointCloudPacked |
+| tf2_msgs/msg/TFMessage | ignition::msgs::Pose_V |
+| trajectory_msgs/msg/JointTrajectory | ignition::msgs::JointTrajectory |
+| vision_msgs/msg/Detection3D | ignition::msgs::AnnotatedOriented3DBox |
+| vision_msgs/msg/Detection3DArray | ignition::msgs::AnnotatedOriented3DBox_V |
And the following for services:
@@ -86,7 +88,7 @@ Now we start the ROS listener.
```
# Shell B:
-. /opt/ros/galactic/setup.bash
+. /opt/ros/humble/setup.bash
ros2 topic echo /chatter
```
@@ -118,7 +120,7 @@ Now we start the ROS talker.
```
# Shell C:
-. /opt/ros/galactic/setup.bash
+. /opt/ros/humble/setup.bash
ros2 topic pub /chatter std_msgs/msg/String "data: 'Hi'" --once
```
@@ -156,7 +158,7 @@ Now we start the ROS GUI:
```
# Shell C:
-. /opt/ros/galactic/setup.bash
+. /opt/ros/humble/setup.bash
ros2 run rqt_image_view rqt_image_view /rgbd_camera/image
```
@@ -274,9 +276,43 @@ To run the bridge node with the above configuration:
ros2 run ros_gz_bridge parameter_bridge --ros-args -p config_file:=$WORKSPACE/ros_gz/ros_gz_bridge/test/config/full.yaml
```
+## Example 6: Using ROS namespace with the Bridge
+
+When spawning multiple robots inside the same ROS environment, it is convenient to use namespaces to avoid overlapping topic names.
+There are three main types of namespaces: relative, global (`/`) and private (`~/`). For more information, refer to ROS documentation.
+Namespaces are applied to Gazebo topic both when specified as `topic_name` as well as `gz_topic_name`.
+
+By default, the Bridge will not apply ROS namespace on the Gazebo topics. To enable this feature, use parameter `expand_gz_topic_names`.
+Let's test our topic with namespace:
+
+```bash
+# Shell A:
+. ~/bridge_ws/install/setup.bash
+ros2 run ros_gz_bridge parameter_bridge chatter@std_msgs/msg/String@ignition.msgs.StringMsg \
+ --ros-args -p expand_gz_topic_names:=true -r __ns:=/demo
+```
+
+Now we start the Gazebo Transport listener.
+
+```bash
+# Shell B:
+ign topic -e -t /demo/chatter
+```
+
+Now we start the ROS talker.
+
+```bash
+# Shell C:
+. /opt/ros/humble/setup.bash
+ros2 topic pub /demo/chatter std_msgs/msg/String "data: 'Hi from inside of a namespace'" --once
+```
+
+By changing `chatter` to `/chatter` or `~/chatter` you can obtain different results.
+
## API
ROS 2 Parameters:
* `subscription_heartbeat` - Period at which the node checks for new subscribers for lazy bridges.
* `config_file` - YAML file to be loaded as the bridge configuration
+ * `expand_gz_topic_names` - Enable or disable ROS namespace applied on GZ topics.
diff --git a/ros_gz_bridge/include/ros_gz_bridge/convert/ros_gz_interfaces.hpp b/ros_gz_bridge/include/ros_gz_bridge/convert/ros_gz_interfaces.hpp
index c7e671d48..136c8d9b6 100644
--- a/ros_gz_bridge/include/ros_gz_bridge/convert/ros_gz_interfaces.hpp
+++ b/ros_gz_bridge/include/ros_gz_bridge/convert/ros_gz_interfaces.hpp
@@ -56,6 +56,11 @@
#include
#endif // HAVE_DATAFRAME
+#if HAVE_MATERIALCOLOR
+#include
+#include
+#endif // HAVE_MATERIALCOLOR
+
#include
namespace ros_gz_bridge
@@ -159,6 +164,20 @@ convert_gz_to_ros(
const gz::msgs::Light & gz_msg,
ros_gz_interfaces::msg::Light & ros_msg);
+#if HAVE_MATERIALCOLOR
+template<>
+void
+convert_ros_to_gz(
+ const ros_gz_interfaces::msg::MaterialColor & ros_msg,
+ gz::msgs::MaterialColor & gz_msg);
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::MaterialColor & gz_msg,
+ ros_gz_interfaces::msg::MaterialColor & ros_msg);
+#endif // HAVE_MATERIALCOLOR
+
template<>
void
convert_ros_to_gz(
diff --git a/ros_gz_bridge/include/ros_gz_bridge/convert/vision_msgs.hpp b/ros_gz_bridge/include/ros_gz_bridge/convert/vision_msgs.hpp
index f370144fe..b1556f651 100644
--- a/ros_gz_bridge/include/ros_gz_bridge/convert/vision_msgs.hpp
+++ b/ros_gz_bridge/include/ros_gz_bridge/convert/vision_msgs.hpp
@@ -17,9 +17,11 @@
// Gazebo Msgs
#include
+#include
// ROS 2 messages
#include "vision_msgs/msg/detection2_d_array.hpp"
+#include "vision_msgs/msg/detection3_d_array.hpp"
#include
namespace ros_gz_bridge
@@ -47,6 +49,30 @@ void
convert_gz_to_ros(
const gz::msgs::AnnotatedAxisAligned2DBox_V & gz_msg,
vision_msgs::msg::Detection2DArray & ros_msg);
+
+template<>
+void
+convert_ros_to_gz(
+ const vision_msgs::msg::Detection3D & ros_msg,
+ gz::msgs::AnnotatedOriented3DBox & gz_msg);
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::AnnotatedOriented3DBox & gz_msg,
+ vision_msgs::msg::Detection3D & ros_msg);
+
+template<>
+void
+convert_ros_to_gz(
+ const vision_msgs::msg::Detection3DArray & ros_msg,
+ gz::msgs::AnnotatedOriented3DBox_V & gz_msg);
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::AnnotatedOriented3DBox_V & gz_msg,
+ vision_msgs::msg::Detection3DArray & ros_msg);
} // namespace ros_gz_bridge
#endif // ROS_GZ_BRIDGE__CONVERT__VISION_MSGS_HPP_
diff --git a/ros_gz_bridge/include/ros_gz_bridge/ros_gz_bridge.hpp b/ros_gz_bridge/include/ros_gz_bridge/ros_gz_bridge.hpp
index 8d9ff631c..71abf1d7a 100644
--- a/ros_gz_bridge/include/ros_gz_bridge/ros_gz_bridge.hpp
+++ b/ros_gz_bridge/include/ros_gz_bridge/ros_gz_bridge.hpp
@@ -36,6 +36,13 @@
#define HAVE_DATAFRAME true
#endif
+// MaterialColor is available from versions 10.1.0 (Harmonic) forward
+// This can be removed when the minimum supported version passes 10.1.0
+#if (GZ_MSGS_MAJOR_VERSION > 10) || \
+ ((GZ_MSGS_MAJOR_VERSION == 10) && (GZ_MSGS_MINOR_VERSION >= 1))
+#define HAVE_MATERIALCOLOR true
+#endif
+
namespace ros_gz_bridge
{
/// Forward declarations
diff --git a/ros_gz_bridge/package.xml b/ros_gz_bridge/package.xml
index 704b7fd4d..811955d22 100644
--- a/ros_gz_bridge/package.xml
+++ b/ros_gz_bridge/package.xml
@@ -2,7 +2,7 @@
ros_gz_bridge
- 0.244.13
+ 0.244.14
Bridge communication between ROS and Gazebo Transport
Louise Poubel
diff --git a/ros_gz_bridge/ros_gz_bridge/__init__.py b/ros_gz_bridge/ros_gz_bridge/__init__.py
index b92918405..ef021faf8 100644
--- a/ros_gz_bridge/ros_gz_bridge/__init__.py
+++ b/ros_gz_bridge/ros_gz_bridge/__init__.py
@@ -16,7 +16,7 @@
import os
-from ros_gz_bridge.mappings import MAPPINGS, MAPPINGS_8_4_0
+from ros_gz_bridge.mappings import MAPPINGS, MAPPINGS_10_1_0, MAPPINGS_8_4_0
from rosidl_cmake import expand_template
@@ -75,6 +75,14 @@ def mappings(gz_msgs_ver):
ros2_message_name=mapping.ros_type,
gz_message_name=mapping.gz_type
))
+ if gz_msgs_ver >= (10, 1, 0):
+ for (ros2_package_name, mappings) in MAPPINGS_10_1_0.items():
+ for mapping in sorted(mappings):
+ data.append(MessageMapping(
+ ros2_package_name=ros2_package_name,
+ ros2_message_name=mapping.ros_type,
+ gz_message_name=mapping.gz_type
+ ))
return sorted(data, key=lambda mm: mm.ros2_string())
diff --git a/ros_gz_bridge/ros_gz_bridge/mappings.py b/ros_gz_bridge/ros_gz_bridge/mappings.py
index 649fd6e34..ddec0f686 100644
--- a/ros_gz_bridge/ros_gz_bridge/mappings.py
+++ b/ros_gz_bridge/ros_gz_bridge/mappings.py
@@ -106,6 +106,8 @@
'vision_msgs': [
Mapping('Detection2DArray', 'AnnotatedAxisAligned2DBox_V'),
Mapping('Detection2D', 'AnnotatedAxisAligned2DBox'),
+ Mapping('Detection3DArray', 'AnnotatedOriented3DBox_V'),
+ Mapping('Detection3D', 'AnnotatedOriented3DBox'),
],
}
@@ -114,3 +116,9 @@
Mapping('Dataframe', 'Dataframe'),
],
}
+
+MAPPINGS_10_1_0 = {
+ 'ros_gz_interfaces': [
+ Mapping('MaterialColor', 'MaterialColor'),
+ ],
+}
diff --git a/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp b/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp
index fceb296a8..0d6199551 100644
--- a/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp
+++ b/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp
@@ -380,6 +380,66 @@ convert_gz_to_ros(
ros_msg.intensity = gz_msg.intensity();
}
+#if HAVE_MATERIALCOLOR
+template<>
+void
+convert_ros_to_gz(
+ const ros_gz_interfaces::msg::MaterialColor & ros_msg,
+ gz::msgs::MaterialColor & gz_msg)
+{
+ using EntityMatch = gz::msgs::MaterialColor::EntityMatch;
+
+ switch (ros_msg.entity_match) {
+ case ros_gz_interfaces::msg::MaterialColor::FIRST:
+ gz_msg.set_entity_match(EntityMatch::MaterialColor_EntityMatch_FIRST);
+ break;
+ case ros_gz_interfaces::msg::MaterialColor::ALL:
+ gz_msg.set_entity_match(EntityMatch::MaterialColor_EntityMatch_ALL);
+ break;
+ default:
+ std::cerr << "Unsupported entity match type ["
+ << ros_msg.entity_match << "]\n";
+ }
+
+ convert_ros_to_gz(ros_msg.header, (*gz_msg.mutable_header()));
+ convert_ros_to_gz(ros_msg.entity, *gz_msg.mutable_entity());
+ convert_ros_to_gz(ros_msg.ambient, *gz_msg.mutable_ambient());
+ convert_ros_to_gz(ros_msg.diffuse, *gz_msg.mutable_diffuse());
+ convert_ros_to_gz(ros_msg.specular, *gz_msg.mutable_specular());
+ convert_ros_to_gz(ros_msg.emissive, *gz_msg.mutable_emissive());
+
+ gz_msg.set_shininess(ros_msg.shininess);
+}
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::MaterialColor & gz_msg,
+ ros_gz_interfaces::msg::MaterialColor & ros_msg)
+{
+ using EntityMatch = gz::msgs::MaterialColor::EntityMatch;
+ if (gz_msg.entity_match() == EntityMatch::MaterialColor_EntityMatch_FIRST) {
+ ros_msg.entity_match = ros_gz_interfaces::msg::MaterialColor::FIRST;
+/* *INDENT-OFF* */
+ } else if (gz_msg.entity_match() ==
+ EntityMatch::MaterialColor_EntityMatch_ALL) {
+/* *INDENT-ON* */
+ ros_msg.entity_match = ros_gz_interfaces::msg::MaterialColor::ALL;
+ } else {
+ std::cerr << "Unsupported EntityMatch [" <<
+ gz_msg.entity_match() << "]" << std::endl;
+ }
+ convert_gz_to_ros(gz_msg.header(), ros_msg.header);
+ convert_gz_to_ros(gz_msg.entity(), ros_msg.entity);
+ convert_gz_to_ros(gz_msg.ambient(), ros_msg.ambient);
+ convert_gz_to_ros(gz_msg.diffuse(), ros_msg.diffuse);
+ convert_gz_to_ros(gz_msg.specular(), ros_msg.specular);
+ convert_gz_to_ros(gz_msg.emissive(), ros_msg.emissive);
+
+ ros_msg.shininess = gz_msg.shininess();
+}
+#endif // HAVE_MATERIALCOLOR
+
template<>
void
convert_ros_to_gz(
diff --git a/ros_gz_bridge/src/convert/vision_msgs.cpp b/ros_gz_bridge/src/convert/vision_msgs.cpp
index 057426c77..61924af57 100644
--- a/ros_gz_bridge/src/convert/vision_msgs.cpp
+++ b/ros_gz_bridge/src/convert/vision_msgs.cpp
@@ -94,4 +94,89 @@ convert_gz_to_ros(
}
}
+template<>
+void
+convert_ros_to_gz(
+ const vision_msgs::msg::Detection3D & ros_msg,
+ gz::msgs::AnnotatedOriented3DBox & gz_msg)
+{
+ convert_ros_to_gz(ros_msg.header, (*gz_msg.mutable_header()));
+
+ gz::msgs::Oriented3DBox * box = new gz::msgs::Oriented3DBox();
+ gz::msgs::Vector3d * center = new gz::msgs::Vector3d();
+ gz::msgs::Vector3d * box_size = new gz::msgs::Vector3d();
+ gz::msgs::Quaternion * orientation = new gz::msgs::Quaternion();
+
+ if (ros_msg.results.size() != 0) {
+ auto id = ros_msg.results.at(0).hypothesis.class_id;
+ gz_msg.set_label(std::stoi(id));
+ }
+
+ center->set_x(ros_msg.bbox.center.position.x);
+ center->set_y(ros_msg.bbox.center.position.y);
+ center->set_z(ros_msg.bbox.center.position.z);
+ box_size->set_x(ros_msg.bbox.size.x);
+ box_size->set_y(ros_msg.bbox.size.y);
+ box_size->set_z(ros_msg.bbox.size.z);
+ orientation->set_x(ros_msg.bbox.center.orientation.x);
+ orientation->set_y(ros_msg.bbox.center.orientation.y);
+ orientation->set_z(ros_msg.bbox.center.orientation.z);
+ orientation->set_w(ros_msg.bbox.center.orientation.w);
+ box->set_allocated_center(center);
+ box->set_allocated_boxsize(box_size);
+ box->set_allocated_orientation(orientation);
+ gz_msg.set_allocated_box(box);
+}
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::AnnotatedOriented3DBox & gz_msg,
+ vision_msgs::msg::Detection3D & ros_msg)
+{
+ convert_gz_to_ros(gz_msg.header(), ros_msg.header);
+
+ ros_msg.results.resize(1);
+ ros_msg.results.at(0).hypothesis.class_id = std::to_string(gz_msg.label());
+ ros_msg.results.at(0).hypothesis.score = 1.0;
+
+ ros_msg.bbox.center.position.x = gz_msg.box().center().x();
+ ros_msg.bbox.center.position.y = gz_msg.box().center().y();
+ ros_msg.bbox.center.position.z = gz_msg.box().center().z();
+ ros_msg.bbox.size.x = gz_msg.box().boxsize().x();
+ ros_msg.bbox.size.y = gz_msg.box().boxsize().y();
+ ros_msg.bbox.size.z = gz_msg.box().boxsize().z();
+ ros_msg.bbox.center.orientation.x = gz_msg.box().orientation().x();
+ ros_msg.bbox.center.orientation.y = gz_msg.box().orientation().y();
+ ros_msg.bbox.center.orientation.z = gz_msg.box().orientation().z();
+ ros_msg.bbox.center.orientation.w = gz_msg.box().orientation().w();
+}
+
+template<>
+void
+convert_ros_to_gz(
+ const vision_msgs::msg::Detection3DArray & ros_msg,
+ gz::msgs::AnnotatedOriented3DBox_V & gz_msg)
+{
+ convert_ros_to_gz(ros_msg.header, (*gz_msg.mutable_header()));
+ for (const auto & ros_box : ros_msg.detections) {
+ gz::msgs::AnnotatedOriented3DBox * gz_box = gz_msg.add_annotated_box();
+ convert_ros_to_gz(ros_box, *gz_box);
+ }
+}
+
+template<>
+void
+convert_gz_to_ros(
+ const gz::msgs::AnnotatedOriented3DBox_V & gz_msg,
+ vision_msgs::msg::Detection3DArray & ros_msg)
+{
+ convert_gz_to_ros(gz_msg.header(), ros_msg.header);
+ for (const auto & gz_box : gz_msg.annotated_box()) {
+ vision_msgs::msg::Detection3D ros_box;
+ convert_gz_to_ros(gz_box, ros_box);
+ ros_msg.detections.push_back(ros_box);
+ }
+}
+
} // namespace ros_gz_bridge
diff --git a/ros_gz_bridge/src/ros_gz_bridge.cpp b/ros_gz_bridge/src/ros_gz_bridge.cpp
index f542ee90c..46a86d987 100644
--- a/ros_gz_bridge/src/ros_gz_bridge.cpp
+++ b/ros_gz_bridge/src/ros_gz_bridge.cpp
@@ -20,6 +20,8 @@
#include "bridge_handle_ros_to_gz.hpp"
#include "bridge_handle_gz_to_ros.hpp"
+#include
+
namespace ros_gz_bridge
{
@@ -30,6 +32,7 @@ RosGzBridge::RosGzBridge(const rclcpp::NodeOptions & options)
this->declare_parameter("subscription_heartbeat", 1000);
this->declare_parameter("config_file", "");
+ this->declare_parameter("expand_gz_topic_names", false);
int heartbeat;
this->get_parameter("subscription_heartbeat", heartbeat);
@@ -43,14 +46,21 @@ void RosGzBridge::spin()
if (handles_.empty()) {
std::string config_file;
this->get_parameter("config_file", config_file);
+ bool expand_names;
+ this->get_parameter("expand_gz_topic_names", expand_names);
+ const std::string ros_ns = this->get_namespace();
+ const std::string ros_node_name = this->get_name();
if (!config_file.empty()) {
auto entries = readFromYamlFile(config_file);
- for (const auto & entry : entries) {
+ for (auto & entry : entries) {
+ if (expand_names) {
+ entry.gz_topic_name = rclcpp::expand_topic_or_service_name(
+ entry.gz_topic_name, ros_node_name, ros_ns, false);
+ }
this->add_bridge(entry);
}
}
}
-
for (auto & bridge : handles_) {
bridge->Spin();
}
diff --git a/ros_gz_bridge/src/service_factory_interface.cpp b/ros_gz_bridge/src/service_factory_interface.cpp
new file mode 100644
index 000000000..4789e0667
--- /dev/null
+++ b/ros_gz_bridge/src/service_factory_interface.cpp
@@ -0,0 +1,24 @@
+// Copyright 2024 Open Source Robotics Foundation, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "service_factory_interface.hpp"
+
+namespace ros_gz_bridge
+{
+
+ServiceFactoryInterface::~ServiceFactoryInterface()
+{
+}
+
+} // namespace ros_gz_bridge
diff --git a/ros_gz_bridge/src/service_factory_interface.hpp b/ros_gz_bridge/src/service_factory_interface.hpp
index 9d4f73348..766ce5154 100644
--- a/ros_gz_bridge/src/service_factory_interface.hpp
+++ b/ros_gz_bridge/src/service_factory_interface.hpp
@@ -29,6 +29,8 @@ namespace ros_gz_bridge
class ServiceFactoryInterface
{
public:
+ virtual ~ServiceFactoryInterface() = 0;
+
virtual
rclcpp::ServiceBase::SharedPtr
create_ros_service(
diff --git a/ros_gz_bridge/test/utils/gz_test_msg.cpp b/ros_gz_bridge/test/utils/gz_test_msg.cpp
index 0bfdea1db..71a651b3b 100644
--- a/ros_gz_bridge/test/utils/gz_test_msg.cpp
+++ b/ros_gz_bridge/test/utils/gz_test_msg.cpp
@@ -18,6 +18,7 @@
#include
#include
+#include
#if GZ_MSGS_MAJOR_VERSION >= 10
#define GZ_MSGS_IMU_HAS_COVARIANCE
@@ -1346,6 +1347,37 @@ void compareTestMsg(const std::shared_ptr & _msg)
EXPECT_FLOAT_EQ(expected_msg.intensity(), _msg->intensity());
}
+#if HAVE_MATERIALCOLOR
+void createTestMsg(gz::msgs::MaterialColor & _msg)
+{
+ createTestMsg(*_msg.mutable_header());
+ createTestMsg(*_msg.mutable_entity());
+ createTestMsg(*_msg.mutable_ambient());
+ createTestMsg(*_msg.mutable_diffuse());
+ createTestMsg(*_msg.mutable_specular());
+ createTestMsg(*_msg.mutable_emissive());
+
+ _msg.set_shininess(1.0);
+ _msg.set_entity_match(gz::msgs::MaterialColor::EntityMatch::MaterialColor_EntityMatch_ALL);
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ gz::msgs::MaterialColor expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(std::make_shared(_msg->header()));
+ compareTestMsg(std::make_shared(_msg->entity()));
+ compareTestMsg(std::make_shared(_msg->ambient()));
+ compareTestMsg(std::make_shared(_msg->diffuse()));
+ compareTestMsg(std::make_shared(_msg->specular()));
+ compareTestMsg(std::make_shared(_msg->emissive()));
+
+ EXPECT_EQ(expected_msg.shininess(), _msg->shininess());
+ EXPECT_EQ(expected_msg.entity_match(), _msg->entity_match());
+}
+#endif // HAVE_MATERIALCOLOR
+
void createTestMsg(gz::msgs::GUICamera & _msg)
{
gz::msgs::Header header_msg;
@@ -1560,5 +1592,92 @@ void compareTestMsg(const std::shared_ptr
}
}
+void createTestMsg(gz::msgs::AnnotatedOriented3DBox & _msg)
+{
+ gz::msgs::Header header_msg;
+
+ createTestMsg(header_msg);
+
+ _msg.mutable_header()->CopyFrom(header_msg);
+
+ _msg.set_label(1);
+
+ gz::msgs::Oriented3DBox * box = new gz::msgs::Oriented3DBox();
+ gz::msgs::Vector3d * center = new gz::msgs::Vector3d();
+ gz::msgs::Vector3d * size = new gz::msgs::Vector3d();
+ gz::msgs::Quaternion * orientation = new gz::msgs::Quaternion();
+
+ center->set_x(2.0);
+ center->set_y(4.0);
+ center->set_z(6.0);
+ size->set_x(3.0);
+ size->set_y(5.0);
+ size->set_z(7.0);
+ orientation->set_x(0.733);
+ orientation->set_y(0.462);
+ orientation->set_z(0.191);
+ orientation->set_w(0.462);
+
+ box->set_allocated_center(center);
+ box->set_allocated_boxsize(size);
+ box->set_allocated_orientation(orientation);
+ _msg.set_allocated_box(box);
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ gz::msgs::AnnotatedOriented3DBox expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(std::make_shared(_msg->header()));
+
+ EXPECT_EQ(expected_msg.label(), _msg->label());
+
+ gz::msgs::Oriented3DBox box = _msg->box();
+ gz::msgs::Vector3d center = box.center();
+ gz::msgs::Vector3d size = box.boxsize();
+ gz::msgs::Quaternion orientation = box.orientation();
+
+ EXPECT_EQ(expected_msg.box().center().x(), center.x());
+ EXPECT_EQ(expected_msg.box().center().y(), center.y());
+ EXPECT_EQ(expected_msg.box().center().z(), center.z());
+ EXPECT_EQ(expected_msg.box().boxsize().x(), size.x());
+ EXPECT_EQ(expected_msg.box().boxsize().y(), size.y());
+ EXPECT_EQ(expected_msg.box().boxsize().z(), size.z());
+ EXPECT_EQ(expected_msg.box().orientation().w(), orientation.w());
+ EXPECT_EQ(expected_msg.box().orientation().x(), orientation.x());
+ EXPECT_EQ(expected_msg.box().orientation().y(), orientation.y());
+ EXPECT_EQ(expected_msg.box().orientation().z(), orientation.z());
+}
+
+void createTestMsg(gz::msgs::AnnotatedOriented3DBox_V & _msg)
+{
+ gz::msgs::Header header_msg;
+
+ createTestMsg(header_msg);
+
+ _msg.mutable_header()->CopyFrom(header_msg);
+
+ for (size_t i = 0; i < 4; i++) {
+ gz::msgs::AnnotatedOriented3DBox * box = _msg.add_annotated_box();
+ createTestMsg(*box);
+ }
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ gz::msgs::AnnotatedOriented3DBox_V expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(std::make_shared(_msg->header()));
+
+ for (size_t i = 0; i < 4; i++) {
+ compareTestMsg(
+ std::make_shared(
+ _msg->annotated_box(
+ i)));
+ }
+}
+
} // namespace testing
} // namespace ros_gz_bridge
diff --git a/ros_gz_bridge/test/utils/gz_test_msg.hpp b/ros_gz_bridge/test/utils/gz_test_msg.hpp
index 7ec6984a0..ad063b628 100644
--- a/ros_gz_bridge/test/utils/gz_test_msg.hpp
+++ b/ros_gz_bridge/test/utils/gz_test_msg.hpp
@@ -65,6 +65,7 @@
#include
#include
#include
+#include
#include
@@ -73,6 +74,10 @@
#include
#endif // HAVE_DATAFRAME
+#if HAVE_MATERIALCOLOR
+#include
+#endif // HAVE_MATERIALCOLOR
+
namespace ros_gz_bridge
{
namespace testing
@@ -455,6 +460,16 @@ void createTestMsg(gz::msgs::Light & _msg);
/// \param[in] _msg The message to compare.
void compareTestMsg(const std::shared_ptr & _msg);
+#if HAVE_MATERIALCOLOR
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(gz::msgs::MaterialColor & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+#endif // HAVE_MATERIALCOLOR
+
/// \brief Create a message used for testing.
/// \param[out] _msg The message populated.
void createTestMsg(gz::msgs::GUICamera & _msg);
@@ -511,6 +526,22 @@ void createTestMsg(gz::msgs::AnnotatedAxisAligned2DBox_V & _msg);
/// \param[in] _msg The message to compare.
void compareTestMsg(const std::shared_ptr & _msg);
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(gz::msgs::AnnotatedOriented3DBox & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(gz::msgs::AnnotatedOriented3DBox_V & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+
} // namespace testing
} // namespace ros_gz_bridge
diff --git a/ros_gz_bridge/test/utils/ros_test_msg.cpp b/ros_gz_bridge/test/utils/ros_test_msg.cpp
index efca25eaa..c6f085e20 100644
--- a/ros_gz_bridge/test/utils/ros_test_msg.cpp
+++ b/ros_gz_bridge/test/utils/ros_test_msg.cpp
@@ -18,6 +18,7 @@
#include
#include
+#include
#include "gz/msgs/config.hh"
@@ -577,6 +578,36 @@ void compareTestMsg(const std::shared_ptr & _msg)
EXPECT_FLOAT_EQ(expected_msg.intensity, _msg->intensity);
}
+#if HAVE_MATERIALCOLOR
+void createTestMsg(ros_gz_interfaces::msg::MaterialColor & _msg)
+{
+ createTestMsg(_msg.header);
+ createTestMsg(_msg.entity);
+ createTestMsg(_msg.ambient);
+ createTestMsg(_msg.diffuse);
+ createTestMsg(_msg.specular);
+ createTestMsg(_msg.emissive);
+ _msg.shininess = 1.0;
+ _msg.entity_match = ros_gz_interfaces::msg::MaterialColor::ALL;
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ ros_gz_interfaces::msg::MaterialColor expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(_msg->header);
+ compareTestMsg(std::make_shared(_msg->entity));
+ compareTestMsg(std::make_shared(_msg->ambient));
+ compareTestMsg(std::make_shared(_msg->diffuse));
+ compareTestMsg(std::make_shared(_msg->specular));
+ compareTestMsg(std::make_shared(_msg->emissive));
+
+ EXPECT_EQ(expected_msg.shininess, _msg->shininess);
+ EXPECT_EQ(expected_msg.entity_match, _msg->entity_match);
+}
+#endif // HAVE_MATERIALCOLOR
+
void createTestMsg(ros_gz_interfaces::msg::GuiCamera & _msg)
{
createTestMsg(_msg.header);
@@ -1446,5 +1477,76 @@ void compareTestMsg(const std::shared_ptr &
}
}
+void createTestMsg(vision_msgs::msg::Detection3D & _msg)
+{
+ std_msgs::msg::Header header_msg;
+ createTestMsg(header_msg);
+ _msg.header = header_msg;
+
+ vision_msgs::msg::ObjectHypothesisWithPose class_prob;
+ class_prob.hypothesis.class_id = "1";
+ class_prob.hypothesis.score = 1.0;
+ _msg.results.push_back(class_prob);
+
+ _msg.bbox.size.x = 3.0;
+ _msg.bbox.size.y = 5.0;
+ _msg.bbox.size.z = 7.0;
+ _msg.bbox.center.position.x = 2.0;
+ _msg.bbox.center.position.y = 4.0;
+ _msg.bbox.center.position.z = 6.0;
+ _msg.bbox.center.orientation.x = 0.733;
+ _msg.bbox.center.orientation.y = 0.462;
+ _msg.bbox.center.orientation.z = 0.191;
+ _msg.bbox.center.orientation.w = 0.462;
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ vision_msgs::msg::Detection3D expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(_msg->header);
+ EXPECT_EQ(expected_msg.results.size(), _msg->results.size());
+ for (size_t i = 0; i < _msg->results.size(); i++) {
+ EXPECT_EQ(expected_msg.results[i].hypothesis.class_id, _msg->results[i].hypothesis.class_id);
+ EXPECT_EQ(expected_msg.results[i].hypothesis.score, _msg->results[i].hypothesis.score);
+ }
+ EXPECT_EQ(expected_msg.bbox.size.x, _msg->bbox.size.x);
+ EXPECT_EQ(expected_msg.bbox.size.y, _msg->bbox.size.y);
+ EXPECT_EQ(expected_msg.bbox.size.z, _msg->bbox.size.z);
+ EXPECT_EQ(expected_msg.bbox.center.position.x, _msg->bbox.center.position.x);
+ EXPECT_EQ(expected_msg.bbox.center.position.y, _msg->bbox.center.position.y);
+ EXPECT_EQ(expected_msg.bbox.center.position.z, _msg->bbox.center.position.z);
+ EXPECT_EQ(expected_msg.bbox.center.orientation.x, _msg->bbox.center.orientation.x);
+ EXPECT_EQ(expected_msg.bbox.center.orientation.y, _msg->bbox.center.orientation.y);
+ EXPECT_EQ(expected_msg.bbox.center.orientation.z, _msg->bbox.center.orientation.z);
+ EXPECT_EQ(expected_msg.bbox.center.orientation.w, _msg->bbox.center.orientation.w);
+}
+
+void createTestMsg(vision_msgs::msg::Detection3DArray & _msg)
+{
+ std_msgs::msg::Header header_msg;
+ createTestMsg(header_msg);
+ _msg.header = header_msg;
+
+ for (size_t i = 0; i < 4; i++) {
+ vision_msgs::msg::Detection3D detection;
+ createTestMsg(detection);
+ _msg.detections.push_back(detection);
+ }
+}
+
+void compareTestMsg(const std::shared_ptr & _msg)
+{
+ vision_msgs::msg::Detection3DArray expected_msg;
+ createTestMsg(expected_msg);
+
+ compareTestMsg(_msg->header);
+ EXPECT_EQ(expected_msg.detections.size(), _msg->detections.size());
+ for (size_t i = 0; i < _msg->detections.size(); i++) {
+ compareTestMsg(std::make_shared(_msg->detections[i]));
+ }
+}
+
} // namespace testing
} // namespace ros_gz_bridge
diff --git a/ros_gz_bridge/test/utils/ros_test_msg.hpp b/ros_gz_bridge/test/utils/ros_test_msg.hpp
index 589f4de19..5a39c4ab0 100644
--- a/ros_gz_bridge/test/utils/ros_test_msg.hpp
+++ b/ros_gz_bridge/test/utils/ros_test_msg.hpp
@@ -57,6 +57,9 @@
#include
#endif // HAVE_DATAFRAME
#include
+#if HAVE_MATERIALCOLOR
+#include
+#endif // HAVE_MATERIALCOLOR
#include
#include
#include
@@ -79,6 +82,7 @@
#include
#include
#include "vision_msgs/msg/detection2_d_array.hpp"
+#include "vision_msgs/msg/detection3_d_array.hpp"
namespace ros_gz_bridge
{
@@ -385,6 +389,16 @@ void createTestMsg(ros_gz_interfaces::msg::Light & _msg);
/// \param[in] _msg The message to compare.
void compareTestMsg(const std::shared_ptr & _msg);
+#if HAVE_MATERIALCOLOR
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(ros_gz_interfaces::msg::MaterialColor & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+#endif // HAVE_MATERIALCOLOR
+
/// \brief Create a message used for testing.
/// \param[out] _msg The message populated.
void createTestMsg(ros_gz_interfaces::msg::Entity & _msg);
@@ -607,6 +621,22 @@ void createTestMsg(vision_msgs::msg::Detection2D & _msg);
/// \param[in] _msg The message to compare.
void compareTestMsg(const std::shared_ptr & _msg);
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(vision_msgs::msg::Detection3DArray & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+
+/// \brief Create a message used for testing.
+/// \param[out] _msg The message populated.
+void createTestMsg(vision_msgs::msg::Detection3D & _msg);
+
+/// \brief Compare a message with the populated for testing.
+/// \param[in] _msg The message to compare.
+void compareTestMsg(const std::shared_ptr & _msg);
+
} // namespace testing
} // namespace ros_gz_bridge
diff --git a/ros_gz_image/CHANGELOG.rst b/ros_gz_image/CHANGELOG.rst
index 328917c9e..1e68461e8 100644
--- a/ros_gz_image/CHANGELOG.rst
+++ b/ros_gz_image/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros1_ign_image
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_gz_image/package.xml b/ros_gz_image/package.xml
index e524cafdb..66e761ea8 100644
--- a/ros_gz_image/package.xml
+++ b/ros_gz_image/package.xml
@@ -1,6 +1,6 @@
ros_gz_image
- 0.244.13
+ 0.244.14
Image utilities for Gazebo simulation with ROS.
Apache 2.0
Louise Poubel
diff --git a/ros_gz_interfaces/CHANGELOG.rst b/ros_gz_interfaces/CHANGELOG.rst
index abe9c879d..dd1169aa9 100644
--- a/ros_gz_interfaces/CHANGELOG.rst
+++ b/ros_gz_interfaces/CHANGELOG.rst
@@ -2,6 +2,18 @@
Changelog for package ros_gz_interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+* Add option to change material color from ROS. (`#486 `_)
+ * Message and bridge for MaterialColor.
+ This allows bridging MaterialColor from ROS to GZ and is
+ important for allowing simulation users to create status lights.
+ ---------
+ Co-authored-by: Alejandro Hernández Cordero
+ Co-authored-by: Addisu Z. Taddese
+ Co-authored-by: Addisu Z. Taddese
+* Contributors: Benjamin Perseghetti
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_gz_interfaces/CMakeLists.txt b/ros_gz_interfaces/CMakeLists.txt
index 49c49126f..5f3b312e4 100644
--- a/ros_gz_interfaces/CMakeLists.txt
+++ b/ros_gz_interfaces/CMakeLists.txt
@@ -27,6 +27,7 @@ set(msg_files
"msg/GuiCamera.msg"
"msg/JointWrench.msg"
"msg/Light.msg"
+ "msg/MaterialColor.msg"
"msg/ParamVec.msg"
"msg/SensorNoise.msg"
"msg/StringVec.msg"
diff --git a/ros_gz_interfaces/msg/MaterialColor.msg b/ros_gz_interfaces/msg/MaterialColor.msg
new file mode 100644
index 000000000..cda67d27a
--- /dev/null
+++ b/ros_gz_interfaces/msg/MaterialColor.msg
@@ -0,0 +1,12 @@
+# Entities that match to apply material color: constant definition
+uint8 FIRST = 0
+uint8 ALL = 1
+
+std_msgs/Header header # Optional header data
+ros_gz_interfaces/Entity entity # Entity to change material color
+std_msgs/ColorRGBA ambient # Ambient color
+std_msgs/ColorRGBA diffuse # Diffuse color
+std_msgs/ColorRGBA specular # Specular color
+std_msgs/ColorRGBA emissive # Emissive color
+float64 shininess # Specular exponent
+uint8 entity_match # Entities that match to apply material color
diff --git a/ros_gz_interfaces/package.xml b/ros_gz_interfaces/package.xml
index c6cdb2a5b..1cfe9c27a 100644
--- a/ros_gz_interfaces/package.xml
+++ b/ros_gz_interfaces/package.xml
@@ -1,6 +1,6 @@
ros_gz_interfaces
- 0.244.13
+ 0.244.14
Message and service data structures for interacting with Gazebo from ROS2.
Apache 2.0
Louise Poubel
diff --git a/ros_gz_sim/CHANGELOG.rst b/ros_gz_sim/CHANGELOG.rst
index 4a13427ef..3eb837b3e 100644
--- a/ros_gz_sim/CHANGELOG.rst
+++ b/ros_gz_sim/CHANGELOG.rst
@@ -2,6 +2,22 @@
Changelog for package ros_gz_sim
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+* Support `` in `package.xml` exports (`#492 `_)
+ This copies the implementation from `gazebo_ros_paths.py` to provide a
+ way for packages to set resource paths from `package.xml`.
+ ```
+ e.g.
+
+
+
+ ```
+ The value of `gazebo_model_path` and `gazebo_media_path` is appended to `GZ_SIM_RESOURCE_PATH`
+ The value of `plugin_path` appended to `GZ_SIM_SYSTEM_PLUGIN_PATH`
+ ---------
+* Contributors: Addisu Z. Taddese
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_gz_sim/README.md b/ros_gz_sim/README.md
index c4561a5da..e0b05f624 100644
--- a/ros_gz_sim/README.md
+++ b/ros_gz_sim/README.md
@@ -37,3 +37,77 @@ See more options with:
```
ros2 run ros_gz_sim create --helpshort
```
+
+### Using `` to export model paths in `package.xml`
+
+The `` tag inside the `` tag of a `package.xml` file can be
+used to add paths to `GZ_SIM_RESOURCE_PATH` and `GZ_SIM_SYSTEM_PLUGIN_PATH`,
+which are environment variables used to configure Gazebo search paths for
+resources (e.g. SDFormat files, meshes, etc) and plugins respectively.
+
+The values in the attributes `gazebo_model_path` and `gazebo_media_path` are
+appended to `GZ_SIM_RESOURCE_PATH`. The value of `plugin_path` is appended to
+`GZ_SIM_SYSTEM_PLUGIN_PATH`. See the
+[Finding resources](https://gazebosim.org/api/sim/8/resources.html) tutorial to
+learn more about these environment variables.
+
+The keyword `${prefix}` can be used when setting these values and it will be
+expanded to the package's share path (i.e., the value of
+`ros2 pkg prefix --share `)
+
+```xml
+
+
+
+
+
+
+```
+
+Thus the required directory needs to be installed from `CMakeLists.txt`
+
+```cmake
+install(DIRECTORY models
+ DESTINATION share/${PROJECT_NAME})
+```
+
+In order to reference the models in a ROS package unambiguously, it is
+recommended to set the value of `gazebo_model_path` to be the parent
+of the `prefix`.
+
+```xml
+
+
+
+
+```
+
+Consider an example where we have a ROS package called `my_awesome_pkg`
+and it contains an SDFormat model cool `cool_robot`:
+
+```bash
+my_awesome_pkg
+├── models
+│ └── cool_robot
+│ ├── model.config
+│ └── model.sdf
+└── package.xml
+```
+
+With `gazebo_model_path="${prefix}/../` set up, we can
+reference the `cool_robot` model in a world file using the package name
+in the `uri`:
+
+```xml
+
+
+
+ package://my_awesome_pkg/models/cool_robot
+
+
+
+```
+
+However, if we set `gazebo_model_path=${prefix}/models`, we would
+need to reference `cool_robot` as `package://cool_robot`, which
+might have a name conflict with other models in the system.
diff --git a/ros_gz_sim/launch/gz_sim.launch.py.in b/ros_gz_sim/launch/gz_sim.launch.py.in
index 7bed5243e..8f87fb7d1 100644
--- a/ros_gz_sim/launch/gz_sim.launch.py.in
+++ b/ros_gz_sim/launch/gz_sim.launch.py.in
@@ -14,20 +14,99 @@
"""Launch Gazebo Sim with command line arguments."""
+import os
from os import environ
+from ament_index_python.packages import get_package_share_directory
+from catkin_pkg.package import InvalidPackage, PACKAGE_MANIFEST_FILENAME, parse_package
+from ros2pkg.api import get_package_names
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction
from launch.actions import ExecuteProcess, Shutdown
from launch.substitutions import LaunchConfiguration
+# Copied from https://github.com/ros-simulation/gazebo_ros_pkgs/blob/79fd94c6da76781a91499bc0f54b70560b90a9d2/gazebo_ros/scripts/gazebo_ros_paths.py
+"""
+Search for model, plugin and media paths exported by packages.
+
+e.g.
+
+
+
+${prefix} is replaced by package's share directory in install.
+
+Thus the required directory needs to be installed from CMakeLists.txt
+e.g. install(DIRECTORY models
+ DESTINATION share/${PROJECT_NAME})
+"""
+
+class GazeboRosPaths:
+
+ @staticmethod
+ def get_paths():
+ gazebo_model_path = []
+ gazebo_plugin_path = []
+ gazebo_media_path = []
+
+ for package_name in get_package_names():
+ package_share_path = get_package_share_directory(package_name)
+ package_file_path = os.path.join(package_share_path, PACKAGE_MANIFEST_FILENAME)
+ if os.path.isfile(package_file_path):
+ try:
+ package = parse_package(package_file_path)
+ except InvalidPackage:
+ continue
+ for export in package.exports:
+ if export.tagname == 'gazebo_ros':
+ if 'gazebo_model_path' in export.attributes:
+ xml_path = export.attributes['gazebo_model_path']
+ xml_path = xml_path.replace('${prefix}', package_share_path)
+ gazebo_model_path.append(xml_path)
+ if 'plugin_path' in export.attributes:
+ xml_path = export.attributes['plugin_path']
+ xml_path = xml_path.replace('${prefix}', package_share_path)
+ gazebo_plugin_path.append(xml_path)
+ if 'gazebo_media_path' in export.attributes:
+ xml_path = export.attributes['gazebo_media_path']
+ xml_path = xml_path.replace('${prefix}', package_share_path)
+ gazebo_media_path.append(xml_path)
+
+ gazebo_model_path = os.pathsep.join(gazebo_model_path + gazebo_media_path)
+ gazebo_plugin_path = os.pathsep.join(gazebo_plugin_path)
+
+ return gazebo_model_path, gazebo_plugin_path
+
def launch_gz(context, *args, **kwargs):
- env = {'GZ_SIM_SYSTEM_PLUGIN_PATH':
- ':'.join([environ.get('GZ_SIM_SYSTEM_PLUGIN_PATH', default=''),
- environ.get('LD_LIBRARY_PATH', default='')]),
- 'IGN_GAZEBO_SYSTEM_PLUGIN_PATH': # TODO(CH3): To support pre-garden. Deprecated.
- ':'.join([environ.get('IGN_GAZEBO_SYSTEM_PLUGIN_PATH', default=''),
- environ.get('LD_LIBRARY_PATH', default='')])}
+ model_paths, plugin_paths = GazeboRosPaths.get_paths()
+
+ env = {
+ "GZ_SIM_SYSTEM_PLUGIN_PATH": os.pathsep.join(
+ [
+ environ.get("GZ_SIM_SYSTEM_PLUGIN_PATH", default=""),
+ environ.get("LD_LIBRARY_PATH", default=""),
+ plugin_paths,
+ ]
+ ),
+ "IGN_GAZEBO_SYSTEM_PLUGIN_PATH": os.pathsep.join( # TODO(azeey): To support pre-garden. Deprecated.
+ [
+ environ.get("IGN_GAZEBO_SYSTEM_PLUGIN_PATH", default=""),
+ environ.get("LD_LIBRARY_PATH", default=""),
+ plugin_paths,
+ ]
+ ),
+ "GZ_SIM_RESOURCE_PATH": os.pathsep.join(
+ [
+ environ.get("GZ_SIM_RESOURCE_PATH", default=""),
+ model_paths,
+ ]
+ ),
+ "IGN_GAZEBO_RESOURCE_PATH": os.pathsep.join( # TODO(azeey): To support pre-garden. Deprecated.
+ [
+ environ.get("IGN_GAZEBO_RESOURCE_PATH", default=""),
+ model_paths,
+ ]
+ ),
+ }
gz_args = LaunchConfiguration('gz_args').perform(context)
gz_version = LaunchConfiguration('gz_version').perform(context)
diff --git a/ros_gz_sim/package.xml b/ros_gz_sim/package.xml
index 181c31997..2259a64bf 100644
--- a/ros_gz_sim/package.xml
+++ b/ros_gz_sim/package.xml
@@ -2,7 +2,7 @@
ros_gz_sim
- 0.244.13
+ 0.244.14
Tools for using Gazebo Sim simulation with ROS.
Alejandro Hernandez
diff --git a/ros_gz_sim_demos/CHANGELOG.rst b/ros_gz_sim_demos/CHANGELOG.rst
index 377c19d58..47ef9ea99 100644
--- a/ros_gz_sim_demos/CHANGELOG.rst
+++ b/ros_gz_sim_demos/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros1_gz_sim_demos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_gz_sim_demos/package.xml b/ros_gz_sim_demos/package.xml
index 15bf28dc1..d25ec95b4 100644
--- a/ros_gz_sim_demos/package.xml
+++ b/ros_gz_sim_demos/package.xml
@@ -1,6 +1,6 @@
ros_gz_sim_demos
- 0.244.13
+ 0.244.14
Demos using Gazebo Sim simulation with ROS.
Apache 2.0
Louise Poubel
diff --git a/ros_ign/CHANGELOG.rst b/ros_ign/CHANGELOG.rst
index ce4c46463..d2bbe37c1 100644
--- a/ros_ign/CHANGELOG.rst
+++ b/ros_ign/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign/package.xml b/ros_ign/package.xml
index 2e2933896..48ad0ec13 100644
--- a/ros_ign/package.xml
+++ b/ros_ign/package.xml
@@ -2,7 +2,7 @@
ros_ign
- 0.244.13
+ 0.244.14
Shim meta-package to redirect to ros_gz.
Brandon Ong
Apache 2.0
diff --git a/ros_ign_bridge/CHANGELOG.rst b/ros_ign_bridge/CHANGELOG.rst
index 17b74fd3b..d685f19fd 100644
--- a/ros_ign_bridge/CHANGELOG.rst
+++ b/ros_ign_bridge/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign_bridge
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign_bridge/package.xml b/ros_ign_bridge/package.xml
index ccf61c4d6..49db5fd93 100644
--- a/ros_ign_bridge/package.xml
+++ b/ros_ign_bridge/package.xml
@@ -2,7 +2,7 @@
ros_ign_bridge
- 0.244.13
+ 0.244.14
Shim package to redirect to ros_gz_bridge.
Brandon Ong
diff --git a/ros_ign_gazebo/CHANGELOG.rst b/ros_ign_gazebo/CHANGELOG.rst
index 2f10998c3..b01effba1 100644
--- a/ros_ign_gazebo/CHANGELOG.rst
+++ b/ros_ign_gazebo/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign_gazebo
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign_gazebo/package.xml b/ros_ign_gazebo/package.xml
index 9568dec53..ff61e96a9 100644
--- a/ros_ign_gazebo/package.xml
+++ b/ros_ign_gazebo/package.xml
@@ -2,7 +2,7 @@
ros_ign_gazebo
- 0.244.13
+ 0.244.14
Shim package to redirect to ros_gz_sim.
Brandon Ong
diff --git a/ros_ign_gazebo_demos/CHANGELOG.rst b/ros_ign_gazebo_demos/CHANGELOG.rst
index 7edbe3359..c2e740eb2 100644
--- a/ros_ign_gazebo_demos/CHANGELOG.rst
+++ b/ros_ign_gazebo_demos/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign_gazebo_demos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign_gazebo_demos/package.xml b/ros_ign_gazebo_demos/package.xml
index 77bb5ad71..70951d353 100644
--- a/ros_ign_gazebo_demos/package.xml
+++ b/ros_ign_gazebo_demos/package.xml
@@ -1,6 +1,6 @@
ros_ign_gazebo_demos
- 0.244.13
+ 0.244.14
Shim package to redirect to ros_gz_sim_demos.
Apache 2.0
Brandon Ong
diff --git a/ros_ign_image/CHANGELOG.rst b/ros_ign_image/CHANGELOG.rst
index ebc65c75e..2144f0397 100644
--- a/ros_ign_image/CHANGELOG.rst
+++ b/ros_ign_image/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign_image
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign_image/package.xml b/ros_ign_image/package.xml
index 2b69c8d57..236a2a6a1 100644
--- a/ros_ign_image/package.xml
+++ b/ros_ign_image/package.xml
@@ -2,7 +2,7 @@
ros_ign_image
- 0.244.13
+ 0.244.14
Shim package to redirect to ros_gz_image.
Brandon Ong
diff --git a/ros_ign_interfaces/CHANGELOG.rst b/ros_ign_interfaces/CHANGELOG.rst
index 4a008fd4b..281974d50 100644
--- a/ros_ign_interfaces/CHANGELOG.rst
+++ b/ros_ign_interfaces/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_ign_interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+0.244.14 (2024-04-08)
+---------------------
+
0.244.13 (2024-01-23)
---------------------
diff --git a/ros_ign_interfaces/package.xml b/ros_ign_interfaces/package.xml
index 61d040a1d..dadfc9ba9 100644
--- a/ros_ign_interfaces/package.xml
+++ b/ros_ign_interfaces/package.xml
@@ -1,6 +1,6 @@
ros_ign_interfaces
- 0.244.13
+ 0.244.14
Shim package to redirect to ros_gz_interfaces.
Apache 2.0
Brandon Ong
diff --git a/test_ros_gz_bridge/CMakeLists.txt b/test_ros_gz_bridge/CMakeLists.txt
new file mode 100644
index 000000000..9a3bb8a83
--- /dev/null
+++ b/test_ros_gz_bridge/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(test_ros_gz_bridge)
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 17)
+endif()
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
+endif()
+
+find_package(ament_cmake REQUIRED)
+find_package(ros_gz_bridge REQUIRED)
+
+
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ ament_lint_auto_find_test_dependencies()
+
+ find_package(ament_cmake_gtest REQUIRED)
+ find_package(launch_testing_ament_cmake REQUIRED)
+ ament_find_gtest()
+
+ ament_add_gtest(test_ros_gz_bridge src/test_ros_gz_bridge.cpp)
+ target_link_libraries(test_ros_gz_bridge ros_gz_bridge::ros_gz_bridge)
+endif()
+
+ament_package()
diff --git a/test_ros_gz_bridge/package.xml b/test_ros_gz_bridge/package.xml
new file mode 100644
index 000000000..3fb8361fb
--- /dev/null
+++ b/test_ros_gz_bridge/package.xml
@@ -0,0 +1,28 @@
+
+
+
+ test_ros_gz_bridge
+ 0.244.14
+ Bridge communication between ROS and Gazebo Transport
+ Aditya Pande
+ Alejandro Hernandez
+
+ Apache 2.0
+
+ Michael Carroll
+
+ ament_cmake
+
+ ros_gz_bridge
+
+ ament_cmake_gtest
+ ament_lint_auto
+ ament_lint_common
+ launch_testing_ament_cmake
+ launch_ros
+ launch_testing
+
+
+ ament_cmake
+
+
diff --git a/test_ros_gz_bridge/src/test_ros_gz_bridge.cpp b/test_ros_gz_bridge/src/test_ros_gz_bridge.cpp
new file mode 100644
index 000000000..a32ca8e53
--- /dev/null
+++ b/test_ros_gz_bridge/src/test_ros_gz_bridge.cpp
@@ -0,0 +1,36 @@
+// Copyright 2024 Open Source Robotics Foundation, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+
+#include
+
+class test_ros_gz_bridge : public ::testing::Test
+{
+public:
+ static void SetUpTestCase()
+ {
+ rclcpp::init(0, nullptr);
+ }
+
+ static void TearDownTestCase()
+ {
+ rclcpp::shutdown();
+ }
+};
+
+TEST_F(test_ros_gz_bridge, SpawnNode)
+{
+ ros_gz_bridge::RosGzBridge node;
+}