diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9847eb2f..43dc16b7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,9 @@ # More info: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners +<<<<<<< HEAD * @chapulina +======= +* @adityapande-1995 +* @ahcorde +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/.github/workflows/build-and-test.sh b/.github/workflows/build-and-test.sh index 86b2fd8b..a834a788 100755 --- a/.github/workflows/build-and-test.sh +++ b/.github/workflows/build-and-test.sh @@ -10,6 +10,7 @@ export ROS_PYTHON_VERSION=3 apt update -qq apt install -qq -y lsb-release wget curl build-essential +<<<<<<< HEAD if [ "$GZ_VERSION" == "garden" ]; then echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list wget https://packages.osrfoundation.org/gazebo.key -O - | apt-key add - @@ -27,14 +28,23 @@ elif [ "$GZ_VERSION" == "harmonic" ]; then fi # Fortress comes through rosdep for Focal and Jammy +======= +echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list +wget https://packages.osrfoundation.org/gazebo.key -O - | apt-key add - +>>>>>>> 63b651a (Garden EOL (#662)) # Dependencies. echo "deb http://packages.ros.org/ros2-testing/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros2-testing.list curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - apt-get update -qq +<<<<<<< HEAD apt-get install -y $GZ_DEPS \ python3-colcon-common-extensions \ python3-rosdep +======= +apt-get install -y python3-colcon-common-extensions \ + python3-rosdep +>>>>>>> 63b651a (Garden EOL (#662)) rosdep init rosdep update diff --git a/.github/workflows/ros2-ci.yml b/.github/workflows/ros2-ci.yml index f5040c0b..37fdfc78 100644 --- a/.github/workflows/ros2-ci.yml +++ b/.github/workflows/ros2-ci.yml @@ -10,6 +10,7 @@ jobs: fail-fast: false matrix: include: +<<<<<<< HEAD - docker-image: "ubuntu:22.04" gz-version: "fortress" ros-distro: "humble" @@ -19,6 +20,11 @@ jobs: - docker-image: "ubuntu:22.04" gz-version: "harmonic" ros-distro: "humble" +======= + - docker-image: "ubuntu:24.04" + gz-version: "harmonic" + ros-distro: "rolling" +>>>>>>> 63b651a (Garden EOL (#662)) container: image: ${{ matrix.docker-image }} steps: @@ -30,9 +36,12 @@ jobs: DOCKER_IMAGE: ${{ matrix.docker-image }} GZ_VERSION: ${{ matrix.gz-version }} ROS_DISTRO: ${{ matrix.ros-distro }} +<<<<<<< HEAD - name: Build sdformat_urdf from source uses: actions/checkout@v4 if: ${{ matrix.gz-version }} == "garden" with: repository: ros/sdformat_urdf ref: humble +======= +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 736670e0..999d07b4 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -10,10 +10,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Add ticket to inbox +<<<<<<< HEAD uses: technote-space/create-project-card-action@v1 with: PROJECT: Core development COLUMN: Inbox GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} CHECK_ORG_PROJECT: true +======= + uses: actions/add-to-project@v0.5.0 + with: + project-url: https://github.com/orgs/gazebosim/projects/7 + github-token: ${{ secrets.TRIAGE_TOKEN }} +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/README.md b/README.md index 8e1d74d0..1b95f289 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ROS 2 version | Gazebo version | Branch | Binaries hosted at -- | -- | -- | -- Foxy | Citadel | [foxy](https://github.com/gazebosim/ros_gz/tree/foxy) | https://packages.ros.org +<<<<<<< HEAD Foxy | Edifice | [foxy](https://github.com/gazebosim/ros_gz/tree/foxy) | only from source Galactic | Edifice | [galactic](https://github.com/gazebosim/ros_gz/tree/galactic) | https://packages.ros.org Galactic | Fortress | [galactic](https://github.com/gazebosim/ros_gz/tree/galactic) | only from source @@ -19,6 +20,27 @@ Rolling | Harmonic | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | onl For information on ROS 2 and Gazebo compatibility, refer to the [melodic branch README](https://github.com/gazebosim/ros_gz/tree/melodic) > Please [ticket an issue](https://github.com/gazebosim/ros_gz/issues/) if you'd like support to be added for some combination. +======= +Foxy | Edifice | [foxy](https://github.com/gazebosim/ros_gz/tree/foxy) | only from source [^2] +Galactic | Edifice | [galactic](https://github.com/gazebosim/ros_gz/tree/galactic) | https://packages.ros.org [^2] +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] [^2] +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] +Iron | Fortress | [humble](https://github.com/gazebosim/ros_gz/tree/iron) | https://packages.ros.org +Iron | Garden | [humble](https://github.com/gazebosim/ros_gz/tree/iron) | only from source [^2] +Iron | Harmonic | [humble](https://github.com/gazebosim/ros_gz/tree/iron) | only from source +Jazzy | Garden | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | only from source [^2] +Jazzy | Harmonic | [jazzy](https://github.com/gazebosim/ros_gz/tree/jazzy) | https://packages.ros.org +Rolling | Fortress | [humble](https://github.com/gazebosim/ros_gz/tree/humble) | https://packages.ros.org +Rolling | Garden | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | only from source [^2] +Rolling | Harmonic | [ros2](https://github.com/gazebosim/ros_gz/tree/ros2) | only from source + +[^1]: Binaries for these pairings are provided from the packages.osrfoundation.org repository. Refer to https://gazebosim.org/docs/latest/ros_installation for installation instructions. +[^2]: Note that the Gazebo version on this row has reached end-of-life. + +For information on ROS(1) and Gazebo compatibility, refer to the [noetic branch README](https://github.com/gazebosim/ros_gz/tree/noetic) +>>>>>>> 63b651a (Garden EOL (#662)) [Details about the renaming process](README_RENAME.md) from `ign` to `gz` . @@ -55,11 +77,19 @@ This repository holds packages that provide integration between ## Install +<<<<<<< HEAD This branch supports ROS Humble. See above for other ROS versions. ### Binaries Humble binaries are available for Fortress. +======= +This branch supports ROS Rolling. See above for other ROS versions. + +### Binaries + +Rolling binaries are available for Fortress. +>>>>>>> 63b651a (Garden EOL (#662)) They are hosted at https://packages.ros.org. 1. Add https://packages.ros.org @@ -70,30 +100,50 @@ They are hosted at https://packages.ros.org. 1. Install `ros_gz` +<<<<<<< HEAD sudo apt install ros-humble-ros-gz +======= + sudo apt install ros-rolling-ros-gz +>>>>>>> 63b651a (Garden EOL (#662)) ### From source #### ROS Be sure you've installed +<<<<<<< HEAD [ROS Humble](https://docs.ros.org/en/humble/Installation.html) +======= +[ROS Rolling](https://docs.ros.org/en/rolling/index.html) +>>>>>>> 63b651a (Garden EOL (#662)) (at least ROS-Base). More ROS dependencies will be installed below. #### Gazebo +<<<<<<< HEAD Install either [Edifice, Fortress, or Garden](https://gazebosim.org/docs). +======= +Install either [Fortress, Harmonic or Ionic](https://gazebosim.org/docs). +>>>>>>> 63b651a (Garden EOL (#662)) Set the `GZ_VERSION` environment variable to the Gazebo version you'd like to compile against. For example: +<<<<<<< HEAD export GZ_VERSION=edifice # IMPORTANT: Replace with correct version +======= + export GZ_VERSION=harmonic # IMPORTANT: Replace with correct version +>>>>>>> 63b651a (Garden EOL (#662)) > You only need to set this variable when compiling, not when running. #### Compile ros_gz +<<<<<<< HEAD The following steps are for Linux and OSX. +======= +The following steps are for Linux and macOS. +>>>>>>> 63b651a (Garden EOL (#662)) 1. Create a colcon workspace: @@ -103,14 +153,22 @@ The following steps are for Linux and OSX. cd ~/ws/src # Download needed software +<<<<<<< HEAD git clone https://github.com/gazebosim/ros_gz.git -b humble +======= + git clone https://github.com/gazebosim/ros_gz.git -b ros2 +>>>>>>> 63b651a (Garden EOL (#662)) ``` 1. Install dependencies (this may also install Gazebo): ``` cd ~/ws +<<<<<<< HEAD rosdep install -r --from-paths src -i -y --rosdistro humble +======= + rosdep install -r --from-paths src -i -y --rosdistro rolling +>>>>>>> 63b651a (Garden EOL (#662)) ``` > If `rosdep` fails to install Gazebo libraries and you have not installed them before, please follow [Gazebo installation instructions](https://gazebosim.org/docs/latest/install). @@ -130,6 +188,7 @@ The following steps are for Linux and OSX. > try building with `colcon build --parallel-workers=1 --executor sequential`. You might also have to set `export MAKEFLAGS="-j 1"` before running `colcon build` to limit > the number of processors used to build a single package. +<<<<<<< HEAD If `colcon build` fails with [this issue](https://github.com/gazebosim/ros_gz/issues/401) ``` @@ -146,6 +205,8 @@ The following steps are for Linux and OSX. colcon build ``` +======= +>>>>>>> 63b651a (Garden EOL (#662)) ## ROSCon 2022 [![](img/video_img.png)](https://vimeo.com/showcase/9954564/video/767127300) diff --git a/README_RENAME.md b/README_RENAME.md index 17007f4e..204fc9f6 100644 --- a/README_RENAME.md +++ b/README_RENAME.md @@ -7,7 +7,11 @@ This allows users to do either of these and get equivalent behavior: ```bash ros2 run ros_gz parameter_bridge [...] +<<<<<<< HEAD ros2 run ros_ign parameter_bridge [...] # Will emit deprecation warning +======= +ros2 run ros_gz parameter_bridge [...] # Will emit deprecation warning +>>>>>>> 63b651a (Garden EOL (#662)) ``` Additionally, installed files like launch files, message interfaces etc. are **duplicated** versions of the ones in `ros_gz` (but renamed as appropriate), and point to `ros_gz` dependencies as well (e.g. launch files pointing to `ros_gz` nodes.) diff --git a/img/video_img.png b/img/video_img.png new file mode 100644 index 00000000..626c7353 Binary files /dev/null and b/img/video_img.png differ diff --git a/ros_gz/CHANGELOG.rst b/ros_gz/CHANGELOG.rst index 4ccbf16a..bb667f41 100644 --- a/ros_gz/CHANGELOG.rst +++ b/ros_gz/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros_gz ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- @@ -19,6 +20,63 @@ Changelog for package ros_gz 0.244.11 (2023-05-23) --------------------- +======= +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ + +2.1.0 (2024-09-12) +------------------ + +2.0.1 (2024-08-29) +------------------ + +2.0.0 (2024-07-22) +------------------ + +1.0.1 (2024-07-03) +------------------ +* Prepare for 1.0.0 Release (`#495 `_) +* 0.244.14 +* Changelog +* 0.244.13 +* Changelog +* 0.244.12 +* Changelog +* 0.246.0 +* Update changelogs +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Jose Luis Rivero, Michael Carroll, ahcorde + +1.0.0 (2024-04-24) +------------------ + +0.246.0 (2023-08-31) +-------------------- +* Port: humble to ros2 (`#386 `_) +* Update maintainers (`#376 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Contributors: Aditya Pande, Alejandro Hernández Cordero, Michael Carroll, ahcorde + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Contributors: Alejandro Hernández Cordero, ahcorde +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz/package.xml b/ros_gz/package.xml index da3e888c..d02a02f0 100644 --- a/ros_gz/package.xml +++ b/ros_gz/package.xml @@ -4,11 +4,22 @@ ros_gz +<<<<<<< HEAD 0.244.16 Meta-package containing interfaces for using ROS 2 with Gazebo simulation. Louise Poubel Apache 2.0 +======= + 2.1.2 + Meta-package containing interfaces for using ROS 2 with Gazebo simulation. + Aditya Pande + Alejandro Hernandez + Apache 2.0 + + Louise Poubel + +>>>>>>> 63b651a (Garden EOL (#662)) ament_cmake ros_gz_bridge diff --git a/ros_gz_bridge/CHANGELOG.rst b/ros_gz_bridge/CHANGELOG.rst index e1b6fef2..5ae67ca1 100644 --- a/ros_gz_bridge/CHANGELOG.rst +++ b/ros_gz_bridge/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros_gz_bridge ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- * Add support for gz.msgs.EntityWrench (base branch: ros2) (backport `#573 `_) (`#575 `_) @@ -35,6 +36,101 @@ Changelog for package ros_gz_bridge * Add a virtual destructor to suppress compiler warning (`#502 `_) (`#505 `_) Co-authored-by: Michael Carroll * Add option to change material color from ROS. (`#486 `_) +======= +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ +* Extra parameter to start a container (`#616 `_) +* adds deadline and liveliness QoSPolicyKinds to qos_overriding_options (`#609 `_) + Co-authored-by: nora +* Contributors: Carlos Agüero, norakon + +2.1.0 (2024-09-12) +------------------ +* Remove default_value for required arguments (`#602 `_) + * Remove default_value for config_file +* Fix errors with name of bridge not being given (`#600 `_) + * Add argument bridge_name to fix errors +* Use optional parameters in actions (`#601 `_) +* Contributors: Amronos, Carlos Agüero + +2.0.1 (2024-08-29) +------------------ +* Stamp all outgoing headers with the wall time if parameter override_timestamps_with_wall_time is set to true (`#562 `_) +* Contributors: Rein Appeldoorn + +2.0.0 (2024-07-22) +------------------ +* Making use_composition true by default (`#578 `_) +* Contributors: Addisu Z. Taddese + +1.0.1 (2024-07-03) +------------------ +* Add support for gz.msgs.EntityWrench (base branch: ros2) (`#573 `_) +* Merge pull request `#571 `_ from azeey/jazzy_to_ros2 + Merge jazzy ➡️ ros2 +* Merge branch 'ros2' into jazzy_to_ros2 +* Use memcpy instead of std::copy when bridging images (`#565 `_) + While testing ros <-> gz communication using the bridge I noticed that the bridge was talking quite a bit of time copying images from Gazebo to ROS. I found that the std::copy operation that we're doing is substantially slower than the memcpy alternative. I think that in principle this shouldn't happen but the numbers are quite clear. Perhaps std::copy is doing something that doesn't use cache effectively + --------- + Co-authored-by: Jose Luis Rivero +* Merge jazzy into ros2 +* Merge pull request `#569 `_ from azeey/iron_to_jazzy + Merge iron ➡️ jazzy +* Merge iron into jazzy +* Add option to change material color from ROS. (`#521 `_) + Forward port of `#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. + (cherry picked from commit 78dc4823121f085594e6028a93f1e571eb04f58b) +* Merge pull request `#564 `_ from azeey/humble_to_iron + Humble ➡️ Iron +* Merge humble -> iron +* Use `ignoreLocalMessages` in the bridge (`#559 `_) + * Ignore local messages +* Update launch files with name parameter (`#556 `_) + * Name is required. +* Ensure the same container is used for the bridge and gz_server (`#553 `_) + This also adds a required `name` parameter for the bridge so that + multiple different bridges can be created without name collision +* Launch ros_gz_bridge from xml (`#550 `_) + * Add gzserver with ability to load an SDF file or string +* Launch gzserver and the bridge as composable nodes (`#528 `_) + * Add gzserver with ability to load an SDF file or string +* Add option to change material color from ROS. (`#521 `_) + Forward port of `#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. +* populate imu covariances when converting (`#375 `_) (`#540 `_) + Co-authored-by: El Jawad Alaa +* Prepare for 1.0.0 Release (`#495 `_) +* Use gz_vendor packages (`#531 `_) +* [backport Humble] Create bridge for GPSFix msg (`#316 `_) (`#538 `_) + Co-authored-by: Rousseau Vincent +* [backport Iron] Create bridge for GPSFix msg (`#316 `_) (`#537 `_) + Co-authored-by: Rousseau Vincent +* 0.244.14 +* Changelog +* Added conversion for Detection3D and Detection3DArray (`#523 `_) (`#526 `_) + Co-authored-by: wittenator <9154515+wittenator@users.noreply.github.com> +* Added conversion for Detection3D and Detection3DArray (`#523 `_) (`#525 `_) + Co-authored-by: wittenator <9154515+wittenator@users.noreply.github.com> +* [Backport rolling] Add ROS namespaces to GZ topics (`#517 `_) + Co-authored-by: Krzysztof Wojciechowski <49921081+Kotochleb@users.noreply.github.com> +* ign to gz (`#519 `_) +* 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 +* Correctly export ros_gz_bridge for downstream targets (`#503 `_) +* Add a virtual destructor to suppress compiler warning (`#502 `_) +* Add option to change material color from ROS. (`#486 `_) +>>>>>>> 63b651a (Garden EOL (#662)) * Message and bridge for MaterialColor. This allows bridging MaterialColor from ROS to GZ and is important for allowing simulation users to create status lights. @@ -42,6 +138,7 @@ Changelog for package ros_gz_bridge Co-authored-by: Alejandro Hernández Cordero Co-authored-by: Addisu Z. Taddese Co-authored-by: Addisu Z. Taddese +<<<<<<< HEAD * Contributors: Alejandro Hernández Cordero, Benjamin Perseghetti, Krzysztof Wojciechowski, Michael Carroll 0.244.13 (2024-01-23) @@ -66,6 +163,128 @@ Changelog for package ros_gz_bridge --------------------- * Add actuator_msgs to humble bridge. (`#394 `_) * Contributors: Benjamin Perseghetti +======= +* 0.244.13 +* Changelog +* backport pr 374 (`#489 `_) +* populate imu covariances when converting (`#488 `_) +* 0.244.12 +* Changelog +* Backport: Add conversion for geometry_msgs/msg/TwistStamped <-> gz.msgs.Twist (`#468 `_) (`#470 `_) +* Add conversion for geometry_msgs/msg/TwistStamped <-> gz.msgs.Twist (`#468 `_) +* Added messages for 2D Bounding Boxes to ros_gz_bridge (`#458 `_) (`#466 `_) + Co-authored-by: Alejandro Hernandez Cordero +* populate imu covariances when converting (`#375 `_) +* 0.246.0 +* Update changelogs +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* SensorNoise msg bridging (`#417 `_) +* Added Altimeter msg bridging (`#413 `_) +* Update README.md (`#411 `_) + The ROS type for gz.msgs.NavSat messages should be **sensor_msgs/msg/NavSatFix** instead of **sensor_msgs/msg/NavSatFixed** +* Add missing rosidl_cmake dep to ros_gz_bridge (`#391 `_) + Co-authored-by: Chris Lalancette +* allow converting from/to TwistWithCovarianceStamped (`#374 `_) + * allow converting from/to TwistWithCovarianceStamped + -------- + Co-authored-by: Alejandro Hernández Cordero +* Added doc (`#393 `_) +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* allow converting from/to PoseWithCovarianceStamped (`#381 `_) + * allow converting from/to PoseWithCovarianceStamped +* Add actuator_msgs to bridge. (`#378 `_) +* Update maintainers (`#376 `_) +* Fix warning message (`#371 `_) +* Improve error messages around config loading (`#356 `_) +* Bringing the Joy to gazebo. (`#350 `_) + Enable using the gazebo bridge with Joy. +* Fix double wait in ros_gz_bridge (`#347 `_) +* Create bridge for GPSFix msg (`#316 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Remove Humble+ deprecations (`#312 `_) + * Remove Humble+ deprecations +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Arjun K Haridas, Benjamin Perseghetti, Carlos Agüero, El Jawad Alaa, Jose Luis Rivero, Krzysztof Wojciechowski, Michael Carroll, Rousseau Vincent, Victor T. Noppeney, Yadu, ahcorde, wittenator, ymd-stella + +1.0.0 (2024-04-24) +------------------ +* Use gz_vendor packages (`#531 `_) +* Added conversion for Detection3D and Detection3DArray (`#523 `_) (`#525 `_) + Co-authored-by: wittenator <9154515+wittenator@users.noreply.github.com> +* [Backport rolling] Add ROS namespaces to GZ topics (`#517 `_) + Co-authored-by: Krzysztof Wojciechowski <49921081+Kotochleb@users.noreply.github.com> +* ign to gz (`#519 `_) +* Correctly export ros_gz_bridge for downstream targets (`#503 `_) +* Add a virtual destructor to suppress compiler warning (`#502 `_) +* Add conversion for geometry_msgs/msg/TwistStamped <-> gz.msgs.Twist (`#468 `_) +* Added messages for 2D Bounding Boxes to ros_gz_bridge (`#458 `_) (`#466 `_) + Co-authored-by: Alejandro Hernandez Cordero +* populate imu covariances when converting (`#375 `_) +* Contributors: Addisu Z. Taddese, Alejandro Hernández Cordero, El Jawad Alaa, Michael Carroll + +0.246.0 (2023-08-31) +-------------------- +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* SensorNoise msg bridging (`#417 `_) +* Added Altimeter msg bridging (`#413 `_) +* Update README.md (`#411 `_) + The ROS type for gz.msgs.NavSat messages should be **sensor_msgs/msg/NavSatFix** instead of **sensor_msgs/msg/NavSatFixed** +* Add missing rosidl_cmake dep to ros_gz_bridge (`#391 `_) + Co-authored-by: Chris Lalancette +* allow converting from/to TwistWithCovarianceStamped (`#374 `_) + Co-authored-by: Alejandro Hernández Cordero +* Added doc (`#393 `_) +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* allow converting from/to PoseWithCovarianceStamped (`#381 `_) + * allow converting from/to PoseWithCovarianceStamped +* Add actuator_msgs to bridge. (`#378 `_) +* Update maintainers (`#376 `_) +* Fix warning message (`#371 `_) +* Improve error messages around config loading (`#356 `_) +* Bringing the Joy to gazebo. (`#350 `_) + Enable using the gazebo bridge with Joy. +* Fix double wait in ros_gz_bridge (`#347 `_) +* Create bridge for GPSFix msg (`#316 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Contributors: Aditya Pande, Alejandro Hernández Cordero, Arjun K Haridas, Benjamin Perseghetti, El Jawad Alaa, Michael Carroll, Rousseau Vincent, Yadu, ahcorde, ymd-stella + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Remove Humble+ deprecations (`#312 `_) + * Remove Humble+ deprecations +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Alejandro Hernández Cordero, Michael Carroll, ahcorde +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz_bridge/CMakeLists.txt b/ros_gz_bridge/CMakeLists.txt index 8f4cc27d..9e7e6c7a 100644 --- a/ros_gz_bridge/CMakeLists.txt +++ b/ros_gz_bridge/CMakeLists.txt @@ -14,6 +14,7 @@ find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(rclcpp_components REQUIRED) find_package(yaml_cpp_vendor REQUIRED) +<<<<<<< HEAD # TODO(CH3): Deprecated. Remove on tock. if("$ENV{GZ_VERSION}" STREQUAL "" AND NOT "$ENV{IGNITION_VERSION}" STREQUAL "") @@ -66,6 +67,20 @@ set(GZ_MSGS_VERSION_MAJOR ${${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}_VERSION_MAJOR set(GZ_MSGS_VERSION_MINOR ${${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}_VERSION_MINOR}) set(GZ_MSGS_VERSION_PATCH ${${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}_VERSION_PATCH}) set(GZ_MSGS_VERSION_FULL ${GZ_MSGS_VERSION_MAJOR}.${GZ_MSGS_VERSION_MINOR}.${GZ_MSGS_VERSION_PATCH}) +======= +find_package(yaml-cpp REQUIRED) + +find_package(gz_transport_vendor REQUIRED) +find_package(gz-transport REQUIRED) + +find_package(gz_msgs_vendor REQUIRED) +find_package(gz-msgs REQUIRED) + +# Install the python module for this package +ament_python_install_package(${PROJECT_NAME}) + +set(GZ_MSGS_VERSION_FULL ${gz-msgs_VERSION}) +>>>>>>> 63b651a (Garden EOL (#662)) set(BRIDGE_MESSAGE_TYPES builtin_interfaces @@ -138,6 +153,7 @@ add_library(${bridge_lib} ) target_link_libraries(${bridge_lib} +<<<<<<< HEAD ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core ) @@ -147,6 +163,20 @@ ament_target_dependencies(${bridge_lib} rclcpp_components yaml_cpp_vendor ${BRIDGE_MESSAGE_TYPES} +======= + PUBLIC + gz-msgs::core + gz-transport::core + PRIVATE + yaml-cpp::yaml-cpp +) + +ament_target_dependencies(${bridge_lib} + PUBLIC + rclcpp + rclcpp_components + ${BRIDGE_MESSAGE_TYPES} +>>>>>>> 63b651a (Garden EOL (#662)) ) target_include_directories(${bridge_lib} @@ -158,11 +188,14 @@ target_include_directories(${bridge_lib} "$" ) +<<<<<<< HEAD target_link_libraries(${bridge_lib} ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core ) +======= +>>>>>>> 63b651a (Garden EOL (#662)) rclcpp_components_register_node( ${bridge_lib} PLUGIN ros_gz_bridge::RosGzBridge @@ -178,6 +211,14 @@ install( DESTINATION include/${PROJECT_NAME} ) +<<<<<<< HEAD +======= +install( + DIRECTORY launch/ + DESTINATION share/${PROJECT_NAME}/launch +) + +>>>>>>> 63b651a (Garden EOL (#662)) set(bridge_executables parameter_bridge static_bridge @@ -213,7 +254,11 @@ if(BUILD_TESTING) ${PROJECT_SOURCE_DIR}/src/convert/rcl_interfaces_TEST.cpp ) target_link_libraries(test_rcl_interfaces +<<<<<<< HEAD ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core +======= + gz-msgs::core +>>>>>>> 63b651a (Garden EOL (#662)) ${rcl_interfaces_TARGETS} gtest gtest_main @@ -248,8 +293,13 @@ if(BUILD_TESTING) ) target_link_libraries(test_utils ${GTEST_LIBRARIES} +<<<<<<< HEAD ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core +======= + gz-msgs::core + gz-transport::core +>>>>>>> 63b651a (Garden EOL (#662)) ) ament_target_dependencies(test_utils rclcpp @@ -361,9 +411,16 @@ ament_export_targets(export_${PROJECT_NAME}) # specific order: dependents before dependencies ament_export_dependencies(rclcpp) ament_export_dependencies(rclcpp_components) +<<<<<<< HEAD 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(gz_msgs_vendor) +ament_export_dependencies(gz-msgs) +ament_export_dependencies(gz_transport_vendor) +ament_export_dependencies(gz-transport) +>>>>>>> 63b651a (Garden EOL (#662)) ament_export_dependencies(${BRIDGE_MESSAGE_TYPES}) ament_package() diff --git a/ros_gz_bridge/README.md b/ros_gz_bridge/README.md index c2f7ce3d..fa8707e1 100644 --- a/ros_gz_bridge/README.md +++ b/ros_gz_bridge/README.md @@ -5,6 +5,7 @@ between ROS and Gazebo Transport. The following message types can be bridged for topics: +<<<<<<< HEAD | ROS type | Gazebo type | |---------------------------------------------|:-------------------------------------------:| | builtin_interfaces/msg/Time | ignition::msgs::Time | @@ -67,15 +68,103 @@ The following message types can be bridged for topics: | trajectory_msgs/msg/JointTrajectory | ignition::msgs::JointTrajectory | | vision_msgs/msg/Detection3D | ignition::msgs::AnnotatedOriented3DBox | | vision_msgs/msg/Detection3DArray | ignition::msgs::AnnotatedOriented3DBox_V | +======= +| ROS type | Gazebo Transport Type | +| ---------------------------------------------- | :------------------------------: | +| actuator_msgs/msg/Actuators | gz.msgs.Actuators | +| builtin_interfaces/msg/Time | gz.msgs.Time | +| geometry_msgs/msg/Point | gz.msgs.Vector3d | +| geometry_msgs/msg/Pose | gz.msgs.Pose | +| geometry_msgs/msg/PoseArray | gz.msgs.Pose_V | +| geometry_msgs/msg/PoseStamped | gz.msgs.Pose | +| geometry_msgs/msg/PoseWithCovariance | gz.msgs.PoseWithCovariance | +| geometry_msgs/msg/PoseWithCovarianceStamped | gz.msgs.PoseWithCovariance | +| geometry_msgs/msg/Quaternion | gz.msgs.Quaternion | +| geometry_msgs/msg/Transform | gz.msgs.Pose | +| geometry_msgs/msg/TransformStamped | gz.msgs.Pose | +| geometry_msgs/msg/Twist | gz.msgs.Twist | +| geometry_msgs/msg/TwistStamped | gz.msgs.Twist | +| geometry_msgs/msg/TwistWithCovariance | gz.msgs.TwistWithCovariance | +| geometry_msgs/msg/TwistWithCovarianceStamped | gz.msgs.TwistWithCovariance | +| geometry_msgs/msg/Vector3 | gz.msgs.Vector3d | +| geometry_msgs/msg/Wrench | gz.msgs.Wrench | +| geometry_msgs/msg/WrenchStamped | gz.msgs.Wrench | +| gps_msgs/msg/GPSFix | gz.msgs.NavSat | +| nav_msgs/msg/Odometry | gz.msgs.Odometry | +| nav_msgs/msg/Odometry | gz.msgs.OdometryWithCovariance | +| rcl_interfaces/msg/ParameterValue | gz.msgs.Any | +| ros_gz_interfaces/msg/Altimeter | gz.msgs.Altimeter | +| ros_gz_interfaces/msg/Contact | gz.msgs.Contact | +| ros_gz_interfaces/msg/Contacts | gz.msgs.Contacts | +| ros_gz_interfaces/msg/Dataframe | gz.msgs.Dataframe | +| ros_gz_interfaces/msg/Entity | gz.msgs.Entity | +| ros_gz_interfaces/msg/EntityWrench | gz.msgs.EntityWrench | +| ros_gz_interfaces/msg/Float32Array | gz.msgs.Float_V | +| ros_gz_interfaces/msg/GuiCamera | gz.msgs.GUICamera | +| ros_gz_interfaces/msg/JointWrench | gz.msgs.JointWrench | +| ros_gz_interfaces/msg/Light | gz.msgs.Light | +| ros_gz_interfaces/msg/ParamVec | gz.msgs.Param | +| ros_gz_interfaces/msg/ParamVec | gz.msgs.Param_V | +| ros_gz_interfaces/msg/SensorNoise | gz.msgs.SensorNoise | +| ros_gz_interfaces/msg/StringVec | gz.msgs.StringMsg_V | +| ros_gz_interfaces/msg/TrackVisual | gz.msgs.TrackVisual | +| ros_gz_interfaces/msg/VideoRecord | gz.msgs.VideoRecord | +| rosgraph_msgs/msg/Clock | gz.msgs.Clock | +| sensor_msgs/msg/BatteryState | gz.msgs.BatteryState | +| sensor_msgs/msg/CameraInfo | gz.msgs.CameraInfo | +| sensor_msgs/msg/FluidPressure | gz.msgs.FluidPressure | +| sensor_msgs/msg/Image | gz.msgs.Image | +| sensor_msgs/msg/Imu | gz.msgs.IMU | +| sensor_msgs/msg/JointState | gz.msgs.Model | +| sensor_msgs/msg/Joy | gz.msgs.Joy | +| sensor_msgs/msg/LaserScan | gz.msgs.LaserScan | +| sensor_msgs/msg/MagneticField | gz.msgs.Magnetometer | +| sensor_msgs/msg/NavSatFix | gz.msgs.NavSat | +| sensor_msgs/msg/PointCloud2 | gz.msgs.PointCloudPacked | +| std_msgs/msg/Bool | gz.msgs.Boolean | +| std_msgs/msg/ColorRGBA | gz.msgs.Color | +| std_msgs/msg/Empty | gz.msgs.Empty | +| std_msgs/msg/Float32 | gz.msgs.Float | +| std_msgs/msg/Float64 | gz.msgs.Double | +| std_msgs/msg/Header | gz.msgs.Header | +| std_msgs/msg/Int32 | gz.msgs.Int32 | +| std_msgs/msg/String | gz.msgs.StringMsg | +| std_msgs/msg/UInt32 | gz.msgs.UInt32 | +| tf2_msgs/msg/TFMessage | gz.msgs.Pose_V | +| trajectory_msgs/msg/JointTrajectory | gz.msgs.JointTrajectory | +| vision_msgs/msg/Detection2D | gz.msgs.AnnotatedAxisAligned2DBox | +| vision_msgs/msg/Detection2DArray | gz.msgs.AnnotatedAxisAligned2DBox_V | +| vision_msgs/msg/Detection3D | gz::msgs::AnnotatedOriented3DBox | +| vision_msgs/msg/Detection3DArray | gz::msgs::AnnotatedOriented3DBox_V | +>>>>>>> 63b651a (Garden EOL (#662)) And the following for services: | ROS type | Gazebo request | Gazebo response | |--------------------------------------|:--------------------------:| --------------------- | +<<<<<<< HEAD | ros_gz_interfaces/srv/ControlWorld | ignition.msgs.WorldControl | ignition.msgs.Boolean | Run `ros2 run ros_gz_bridge parameter_bridge -h` for instructions. +======= +| ros_gz_interfaces/srv/ControlWorld | gz.msgs.WorldControl | gz.msgs.Boolean | + +Run `ros2 run ros_gz_bridge parameter_bridge -h` for instructions. + +**NOTE**: If during startup, gazebo detects that there is another publisher on `/clock`, it will only create the fully qualified `/world//clock topic`. +Gazebo would be the only `/clock` publisher, the sole source of clock information. + +You should create an unidirectional `/clock` bridge: + +```bash +ros2 run ros_gz_bridge parameter_bridge /clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock +``` + +An alternative set-up can be using the bridge with the `override_timestamps_with_wall_time` ros parameter set to `true` (default=`false`). In this set-up, +all header timestamps of the outgoing messages will be stamped with the wall time. This can be useful when the simulator has to communicate with an external system that requires wall times. + +>>>>>>> 63b651a (Garden EOL (#662)) ## Example 1a: Gazebo Transport talker and ROS 2 listener Start the parameter bridge which will watch the specified topics. @@ -83,14 +172,22 @@ Start the parameter bridge which will watch the specified topics. ``` # Shell A: . ~/bridge_ws/install/setup.bash +<<<<<<< HEAD ros2 run ros_gz_bridge parameter_bridge /chatter@std_msgs/msg/String@ignition.msgs.StringMsg +======= +ros2 run ros_gz_bridge parameter_bridge /chatter@std_msgs/msg/String@gz.msgs.StringMsg +>>>>>>> 63b651a (Garden EOL (#662)) ``` Now we start the ROS listener. ``` # Shell B: +<<<<<<< HEAD . /opt/ros/humble/setup.bash +======= +. /opt/ros/rolling/setup.bash +>>>>>>> 63b651a (Garden EOL (#662)) ros2 topic echo /chatter ``` @@ -98,7 +195,11 @@ Now we start the Gazebo Transport talker. ``` # Shell C: +<<<<<<< HEAD ign topic -t /chatter -m ignition.msgs.StringMsg -p 'data:"Hello"' +======= +gz topic -t /chatter -m gz.msgs.StringMsg -p 'data:"Hello"' +>>>>>>> 63b651a (Garden EOL (#662)) ``` ## Example 1b: ROS 2 talker and Gazebo Transport listener @@ -108,21 +209,33 @@ Start the parameter bridge which will watch the specified topics. ``` # Shell A: . ~/bridge_ws/install/setup.bash +<<<<<<< HEAD ros2 run ros_gz_bridge parameter_bridge /chatter@std_msgs/msg/String@ignition.msgs.StringMsg +======= +ros2 run ros_gz_bridge parameter_bridge /chatter@std_msgs/msg/String@gz.msgs.StringMsg +>>>>>>> 63b651a (Garden EOL (#662)) ``` Now we start the Gazebo Transport listener. ``` # Shell B: +<<<<<<< HEAD ign topic -e -t /chatter +======= +gz topic -e -t /chatter +>>>>>>> 63b651a (Garden EOL (#662)) ``` Now we start the ROS talker. ``` # Shell C: +<<<<<<< HEAD . /opt/ros/humble/setup.bash +======= +. /opt/ros/rolling/setup.bash +>>>>>>> 63b651a (Garden EOL (#662)) ros2 topic pub /chatter std_msgs/msg/String "data: 'Hi'" --once ``` @@ -136,14 +249,22 @@ First we start Gazebo Sim (don't forget to hit play, or Gazebo Sim won't generat ``` # Shell A: +<<<<<<< HEAD ign gazebo sensors_demo.sdf +======= +gz sim sensors_demo.sdf +>>>>>>> 63b651a (Garden EOL (#662)) ``` Let's see the topic where camera images are published. ``` # Shell B: +<<<<<<< HEAD ign topic -l | grep image +======= +gz topic -l | grep image +>>>>>>> 63b651a (Garden EOL (#662)) /rgbd_camera/depth_image /rgbd_camera/image ``` @@ -153,14 +274,22 @@ Then we start the parameter bridge with the previous topic. ``` # Shell B: . ~/bridge_ws/install/setup.bash +<<<<<<< HEAD ros2 run ros_gz_bridge parameter_bridge /rgbd_camera/image@sensor_msgs/msg/Image@ignition.msgs.Image +======= +ros2 run ros_gz_bridge parameter_bridge /rgbd_camera/image@sensor_msgs/msg/Image@gz.msgs.Image +>>>>>>> 63b651a (Garden EOL (#662)) ``` Now we start the ROS GUI: ``` # Shell C: +<<<<<<< HEAD . /opt/ros/humble/setup.bash +======= +. /opt/ros/rolling/setup.bash +>>>>>>> 63b651a (Garden EOL (#662)) ros2 run rqt_image_view rqt_image_view /rgbd_camera/image ``` @@ -194,15 +323,25 @@ On terminal B, we start a ROS 2 listener: And terminal C, publish an Gazebo message: +<<<<<<< HEAD `ign topic -t /chatter -m ignition.msgs.StringMsg -p 'data:"Hello"'` +======= +`gz topic -t /chatter -m gz.msgs.StringMsg -p 'data:"Hello"'` +>>>>>>> 63b651a (Garden EOL (#662)) At this point, you should see the ROS 2 listener echoing the message. Now let's try the other way around, ROS 2 -> Gazebo. +<<<<<<< HEAD On terminal D, start an Igntion listener: `ign topic -e -t /chatter` +======= +On terminal D, start an Gazebo listener: + +`gz topic -e -t /chatter` +>>>>>>> 63b651a (Garden EOL (#662)) And on terminal E, publish a ROS 2 message: @@ -220,7 +359,11 @@ On terminal A, start the service bridge: On terminal B, start Gazebo, it will be paused by default: +<<<<<<< HEAD `ign gazebo shapes.sdf` +======= +`gz sim shapes.sdf` +>>>>>>> 63b651a (Garden EOL (#662)) On terminal C, make a ROS request to unpause simulation: @@ -242,11 +385,16 @@ bridge may be specified: # Set just topic name, applies to both - topic_name: "chatter" ros_type_name: "std_msgs/msg/String" +<<<<<<< HEAD gz_type_name: "ignition.msgs.StringMsg" +======= + gz_type_name: "gz.msgs.StringMsg" +>>>>>>> 63b651a (Garden EOL (#662)) # Set just ROS topic name, applies to both - ros_topic_name: "chatter_ros" ros_type_name: "std_msgs/msg/String" +<<<<<<< HEAD gz_type_name: "ignition.msgs.StringMsg" # Set just GZ topic name, applies to both @@ -265,12 +413,37 @@ bridge may be specified: gz_topic_name: "ign_chatter" ros_type_name: "std_msgs/msg/String" gz_type_name: "ignition.msgs.StringMsg" +======= + gz_type_name: "gz.msgs.StringMsg" + +# Set just GZ topic name, applies to both +- gz_topic_name: "chatter_gz" + ros_type_name: "std_msgs/msg/String" + gz_type_name: "gz.msgs.StringMsg" + +# Set each topic name explicitly +- ros_topic_name: "chatter_both_ros" + gz_topic_name: "chatter_both_gz" + ros_type_name: "std_msgs/msg/String" + gz_type_name: "gz.msgs.StringMsg" + +# Full set of configurations +- ros_topic_name: "ros_chatter" + gz_topic_name: "gz_chatter" + ros_type_name: "std_msgs/msg/String" + gz_type_name: "gz.msgs.StringMsg" +>>>>>>> 63b651a (Garden EOL (#662)) subscriber_queue: 5 # Default 10 publisher_queue: 6 # Default 10 lazy: true # Default "false" direction: BIDIRECTIONAL # Default "BIDIRECTIONAL" - Bridge both directions +<<<<<<< HEAD # "GZ_TO_ROS" - Bridge Ignition topic to ROS # "ROS_TO_GZ" - Bridge ROS topic to Ignition +======= + # "GZ_TO_ROS" - Bridge Gz topic to ROS + # "ROS_TO_GZ" - Bridge ROS topic to Gz +>>>>>>> 63b651a (Garden EOL (#662)) ``` To run the bridge node with the above configuration: @@ -298,14 +471,22 @@ Now we start the Gazebo Transport listener. ```bash # Shell B: +<<<<<<< HEAD ign topic -e -t /demo/chatter +======= +gz topic -e -t /demo/chatter +>>>>>>> 63b651a (Garden EOL (#662)) ``` Now we start the ROS talker. ```bash # Shell C: +<<<<<<< HEAD . /opt/ros/humble/setup.bash +======= +. /opt/ros/rolling/setup.bash +>>>>>>> 63b651a (Garden EOL (#662)) ros2 topic pub /demo/chatter std_msgs/msg/String "data: 'Hi from inside of a namespace'" --once ``` diff --git a/ros_gz_bridge/bin/ros_gz_bridge_markdown_table b/ros_gz_bridge/bin/ros_gz_bridge_markdown_table index 05c11b72..a96f8e0d 100755 --- a/ros_gz_bridge/bin/ros_gz_bridge_markdown_table +++ b/ros_gz_bridge/bin/ros_gz_bridge_markdown_table @@ -37,11 +37,19 @@ def main(argv=sys.argv[1:]): msgs_ver = tuple(map(int, args.gz_msgs_ver.split('.'))) rows = [] +<<<<<<< HEAD rows.append(f'| {"ROS type":32}| {"Gazebo Transport Type":32}|') rows.append(f'|{"-":-<33}|:{"-":-<31}:|') for mapping in mappings(msgs_ver): rows.append('| {:32}| {:32}|'.format( +======= + rows.append(f'| {"ROS type":35}| {"Gazebo Transport Type":35}|') + rows.append(f'|{"-":-<36}|:{"-":-<34}:|') + + for mapping in mappings(msgs_ver): + rows.append('| {:35}| {:35}|'.format( +>>>>>>> 63b651a (Garden EOL (#662)) mapping.ros2_package_name + '/msg/' + mapping.ros2_message_name, mapping.gz_string())) print('\n'.join(rows)) diff --git a/ros_gz_bridge/include/ros_gz_bridge/convert/geometry_msgs.hpp b/ros_gz_bridge/include/ros_gz_bridge/convert/geometry_msgs.hpp index 70537def..ef3ed12b 100644 --- a/ros_gz_bridge/include/ros_gz_bridge/convert/geometry_msgs.hpp +++ b/ros_gz_bridge/include/ros_gz_bridge/convert/geometry_msgs.hpp @@ -30,6 +30,10 @@ #include #include #include +<<<<<<< HEAD +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -116,6 +120,21 @@ template<> void convert_gz_to_ros( const gz::msgs::PoseWithCovariance & gz_msg, +<<<<<<< HEAD +======= + geometry_msgs::msg::PoseWithCovarianceStamped & ros_msg); + +template<> +void +convert_ros_to_gz( + const geometry_msgs::msg::PoseWithCovarianceStamped & ros_msg, + gz::msgs::PoseWithCovariance & gz_msg); + +template<> +void +convert_gz_to_ros( + const gz::msgs::PoseWithCovariance & gz_msg, +>>>>>>> 63b651a (Garden EOL (#662)) geometry_msgs::msg::PoseWithCovariance & ros_msg); template<> diff --git a/ros_gz_bridge/include/ros_gz_bridge/convert/rcl_interfaces.hpp b/ros_gz_bridge/include/ros_gz_bridge/convert/rcl_interfaces.hpp index 261849c5..97ff2e14 100644 --- a/ros_gz_bridge/include/ros_gz_bridge/convert/rcl_interfaces.hpp +++ b/ros_gz_bridge/include/ros_gz_bridge/convert/rcl_interfaces.hpp @@ -15,7 +15,11 @@ #ifndef ROS_GZ_BRIDGE__CONVERT__RCL_INTERFACES_HPP_ #define ROS_GZ_BRIDGE__CONVERT__RCL_INTERFACES_HPP_ +<<<<<<< HEAD // Ignition messages +======= +// GZ messages +>>>>>>> 63b651a (Garden EOL (#662)) #include // ROS 2 messages 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 756ff2a8..1fc2811d 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 @@ -22,9 +22,17 @@ #include #include #include +<<<<<<< HEAD #include #include #include +======= +#include +#include +#include +#include +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -40,9 +48,17 @@ #include #include #include +<<<<<<< HEAD +#include +#include +#include +======= +#include #include #include #include +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -50,6 +66,7 @@ #include #include +<<<<<<< HEAD // Required for HAVE_DATAFRAME definition #include @@ -63,6 +80,10 @@ #include #endif // HAVE_MATERIALCOLOR +======= +#include + +>>>>>>> 63b651a (Garden EOL (#662)) #include namespace ros_gz_bridge @@ -140,7 +161,10 @@ convert_gz_to_ros( const gz::msgs::Contacts & gz_msg, ros_gz_interfaces::msg::Contacts & ros_msg); +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void convert_ros_to_gz( @@ -152,7 +176,10 @@ void convert_gz_to_ros( const gz::msgs::Dataframe & ign_msg, ros_gz_interfaces::msg::Dataframe & ros_msg); +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void @@ -178,7 +205,10 @@ convert_gz_to_ros( const gz::msgs::Light & gz_msg, ros_gz_interfaces::msg::Light & ros_msg); +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void convert_ros_to_gz( @@ -190,7 +220,10 @@ void convert_gz_to_ros( const gz::msgs::MaterialColor & gz_msg, ros_gz_interfaces::msg::MaterialColor & ros_msg); +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void diff --git a/ros_gz_bridge/include/ros_gz_bridge/convert/rosgraph_msgs.hpp b/ros_gz_bridge/include/ros_gz_bridge/convert/rosgraph_msgs.hpp index 7916aaa7..7c16b145 100644 --- a/ros_gz_bridge/include/ros_gz_bridge/convert/rosgraph_msgs.hpp +++ b/ros_gz_bridge/include/ros_gz_bridge/convert/rosgraph_msgs.hpp @@ -16,7 +16,11 @@ #define ROS_GZ_BRIDGE__CONVERT__ROSGRAPH_MSGS_HPP_ // Gazebo Msgs +<<<<<<< HEAD #include +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) // ROS 2 messages #include 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 71abf1d7..6426541b 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 @@ -24,6 +24,7 @@ #include #include "ros_gz_bridge/bridge_config.hpp" +<<<<<<< HEAD // Dataframe is available from versions 8.4.0 (fortress) forward // This can be removed when the minimum supported version passes 8.4.0 #if (IGNITION_MSGS_MAJOR_VERSION > 8) || \ @@ -43,6 +44,8 @@ #define HAVE_MATERIALCOLOR true #endif +======= +>>>>>>> 63b651a (Garden EOL (#662)) namespace ros_gz_bridge { /// Forward declarations @@ -56,7 +59,11 @@ class RosGzBridge : public rclcpp::Node /// \param[in] options options control creation of the ROS 2 node explicit RosGzBridge(const rclcpp::NodeOptions & options = rclcpp::NodeOptions()); +<<<<<<< HEAD /// \brief Add a new ROS-IGN bridge to the node +======= + /// \brief Add a new ROS-GZ bridge to the node +>>>>>>> 63b651a (Garden EOL (#662)) /// \param[in] config Parameters to control creation of a new bridge void add_bridge(const BridgeConfig & config); diff --git a/ros_gz_bridge/launch/ros_gz_bridge.launch b/ros_gz_bridge/launch/ros_gz_bridge.launch new file mode 100644 index 00000000..96757e4e --- /dev/null +++ b/ros_gz_bridge/launch/ros_gz_bridge.launch @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/ros_gz_bridge/launch/ros_gz_bridge.launch.py b/ros_gz_bridge/launch/ros_gz_bridge.launch.py new file mode 100644 index 00000000..e1690a84 --- /dev/null +++ b/ros_gz_bridge/launch/ros_gz_bridge.launch.py @@ -0,0 +1,97 @@ +# 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. + +"""Launch ros_gz bridge in a component container.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from ros_gz_bridge.actions import RosGzBridge + + +def generate_launch_description(): + + declare_bridge_name_cmd = DeclareLaunchArgument( + 'bridge_name', description='Name of ros_gz_bridge node' + ) + + declare_config_file_cmd = DeclareLaunchArgument( + 'config_file', description='YAML config file' + ) + + declare_container_name_cmd = DeclareLaunchArgument( + 'container_name', + default_value='ros_gz_container', + description='Name of container that nodes will load in if use composition', + ) + + declare_create_own_container_cmd = DeclareLaunchArgument( + 'create_own_container', + default_value='False', + description='Whether the bridge should start its own ROS container when using composition \ + (not recommended). This option should only be set to true if you plan to put your ROS \ + node in the container created by the bridge. This is not needed if you want Gazebo and \ + the bridge to be in the same ROS container.', + ) + + declare_namespace_cmd = DeclareLaunchArgument( + 'namespace', default_value='', description='Top-level namespace' + ) + + declare_use_composition_cmd = DeclareLaunchArgument( + 'use_composition', default_value='False', description='Use composed bringup if True' + ) + + declare_use_respawn_cmd = DeclareLaunchArgument( + 'use_respawn', + default_value='False', + description='Whether to respawn if a node crashes. Applied when composition is disabled.', + ) + + declare_log_level_cmd = DeclareLaunchArgument( + 'log_level', default_value='info', description='log level' + ) + + declare_bridge_params_cmd = DeclareLaunchArgument( + 'bridge_params', default_value='', description='Extra parameters to pass to the bridge.' + ) + + ros_gz_bridge_action = RosGzBridge( + bridge_name=LaunchConfiguration('bridge_name'), + config_file=LaunchConfiguration('config_file'), + container_name=LaunchConfiguration('container_name'), + create_own_container=LaunchConfiguration('create_own_container'), + namespace=LaunchConfiguration('namespace'), + use_composition=LaunchConfiguration('use_composition'), + use_respawn=LaunchConfiguration('use_respawn'), + log_level=LaunchConfiguration('log_level'), + bridge_params=LaunchConfiguration('bridge_params') + ) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_bridge_name_cmd) + ld.add_action(declare_config_file_cmd) + ld.add_action(declare_container_name_cmd) + ld.add_action(declare_create_own_container_cmd) + ld.add_action(declare_namespace_cmd) + ld.add_action(declare_use_composition_cmd) + ld.add_action(declare_use_respawn_cmd) + ld.add_action(declare_log_level_cmd) + ld.add_action(declare_bridge_params_cmd) + # Add the ros_gz_bridge action + ld.add_action(ros_gz_bridge_action) + return ld diff --git a/ros_gz_bridge/package.xml b/ros_gz_bridge/package.xml index d7b85c51..fe665d6d 100644 --- a/ros_gz_bridge/package.xml +++ b/ros_gz_bridge/package.xml @@ -2,20 +2,42 @@ ros_gz_bridge +<<<<<<< HEAD 0.244.16 Bridge communication between ROS and Gazebo Transport Louise Poubel +======= + 2.1.2 + Bridge communication between ROS and Gazebo Transport + Aditya Pande + Alejandro Hernandez +>>>>>>> 63b651a (Garden EOL (#662)) Apache 2.0 Shivesh Khaitan +<<<<<<< HEAD + + ament_cmake + pkg-config +======= + Louise Poubel + Carlos Agüero ament_cmake + ament_cmake_python pkg-config + rosidl_pycommon +>>>>>>> 63b651a (Garden EOL (#662)) actuator_msgs geometry_msgs gps_msgs +<<<<<<< HEAD +======= + launch + launch_ros +>>>>>>> 63b651a (Garden EOL (#662)) nav_msgs rclcpp rclcpp_components @@ -28,6 +50,7 @@ yaml_cpp_vendor vision_msgs +<<<<<<< HEAD gz-msgs10 gz-transport13 @@ -42,6 +65,10 @@ ignition-msgs7 ignition-transport10 +======= + gz_msgs_vendor + gz_transport_vendor +>>>>>>> 63b651a (Garden EOL (#662)) ament_cmake_gtest ament_lint_auto diff --git a/ros_gz_bridge/resource/pkg_factories.cpp.em b/ros_gz_bridge/resource/pkg_factories.cpp.em index ef81673e..8abb098c 100644 --- a/ros_gz_bridge/resource/pkg_factories.cpp.em +++ b/ros_gz_bridge/resource/pkg_factories.cpp.em @@ -39,7 +39,11 @@ get_factory__@(ros2_package_name)( return std::make_shared< Factory< @(m.ros2_type()), +<<<<<<< HEAD @(m.ign_type()) +======= + @(m.gz_type()) +>>>>>>> 63b651a (Garden EOL (#662)) > >("@(m.ros2_string())", "@(m.gz_string())"); } @@ -52,10 +56,17 @@ template<> void Factory< @(m.ros2_type()), +<<<<<<< HEAD @(m.ign_type()) >::convert_ros_to_gz( const @(m.ros2_type()) & ros_msg, @(m.ign_type()) & gz_msg) +======= + @(m.gz_type()) +>::convert_ros_to_gz( + const @(m.ros2_type()) & ros_msg, + @(m.gz_type()) & gz_msg) +>>>>>>> 63b651a (Garden EOL (#662)) { ros_gz_bridge::convert_ros_to_gz(ros_msg, gz_msg); } @@ -64,9 +75,15 @@ template<> void Factory< @(m.ros2_type()), +<<<<<<< HEAD @(m.ign_type()) >::convert_gz_to_ros( const @(m.ign_type()) & gz_msg, +======= + @(m.gz_type()) +>::convert_gz_to_ros( + const @(m.gz_type()) & gz_msg, +>>>>>>> 63b651a (Garden EOL (#662)) @(m.ros2_type()) & ros_msg) { ros_gz_bridge::convert_gz_to_ros(gz_msg, ros_msg); diff --git a/ros_gz_bridge/resource/ros_gz_bridge b/ros_gz_bridge/resource/ros_gz_bridge new file mode 100644 index 00000000..e69de29b diff --git a/ros_gz_bridge/ros_gz_bridge/__init__.py b/ros_gz_bridge/ros_gz_bridge/__init__.py index ef021faf..5624fadd 100644 --- a/ros_gz_bridge/ros_gz_bridge/__init__.py +++ b/ros_gz_bridge/ros_gz_bridge/__init__.py @@ -16,9 +16,21 @@ import os +<<<<<<< HEAD from ros_gz_bridge.mappings import MAPPINGS, MAPPINGS_10_1_0, MAPPINGS_8_4_0 from rosidl_cmake import expand_template +======= +from ros_gz_bridge.mappings import MAPPINGS + +from rosidl_pycommon import expand_template + +from . import actions + +__all__ = [ + 'actions', +] +>>>>>>> 63b651a (Garden EOL (#662)) @dataclass @@ -66,6 +78,7 @@ def mappings(gz_msgs_ver): ros2_message_name=mapping.ros_type, gz_message_name=mapping.gz_type )) +<<<<<<< HEAD if gz_msgs_ver >= (8, 4, 0): for (ros2_package_name, mappings) in MAPPINGS_8_4_0.items(): @@ -83,6 +96,8 @@ def mappings(gz_msgs_ver): ros2_message_name=mapping.ros_type, gz_message_name=mapping.gz_type )) +======= +>>>>>>> 63b651a (Garden EOL (#662)) return sorted(data, key=lambda mm: mm.ros2_string()) diff --git a/ros_gz_bridge/ros_gz_bridge/actions/__init__.py b/ros_gz_bridge/ros_gz_bridge/actions/__init__.py new file mode 100644 index 00000000..0a2c2665 --- /dev/null +++ b/ros_gz_bridge/ros_gz_bridge/actions/__init__.py @@ -0,0 +1,22 @@ +# 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. + +"""Actions module.""" + +from .ros_gz_bridge import RosGzBridge + + +__all__ = [ + 'RosGzBridge', +] diff --git a/ros_gz_bridge/ros_gz_bridge/actions/ros_gz_bridge.py b/ros_gz_bridge/ros_gz_bridge/actions/ros_gz_bridge.py new file mode 100644 index 00000000..bcebee0c --- /dev/null +++ b/ros_gz_bridge/ros_gz_bridge/actions/ros_gz_bridge.py @@ -0,0 +1,245 @@ +# 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. + +"""Module for the ros_gz bridge action.""" + +from typing import List +from typing import Optional + +from launch.action import Action +from launch.actions import GroupAction +from launch.conditions import IfCondition +from launch.frontend import Entity, expose_action, Parser +from launch.launch_context import LaunchContext +from launch.some_substitutions_type import SomeSubstitutionsType +from launch.substitutions import PythonExpression +from launch_ros.actions import ComposableNodeContainer, LoadComposableNodes, Node +from launch_ros.descriptions import ComposableNode + + +@expose_action('ros_gz_bridge') +class RosGzBridge(Action): + """Action that executes a ros_gz bridge ROS [composable] node.""" + + def __init__( + self, + *, + bridge_name: SomeSubstitutionsType, + config_file: SomeSubstitutionsType, + container_name: Optional[SomeSubstitutionsType] = 'ros_gz_container', + create_own_container: Optional[SomeSubstitutionsType] = 'False', + namespace: Optional[SomeSubstitutionsType] = '', + use_composition: Optional[SomeSubstitutionsType] = 'False', + use_respawn: Optional[SomeSubstitutionsType] = 'False', + log_level: Optional[SomeSubstitutionsType] = 'info', + bridge_params: Optional[SomeSubstitutionsType] = '', + **kwargs + ) -> None: + """ + Construct a ros_gz bridge action. + + :param: bridge_name Name of ros_gz_bridge node + :param: config_file YAML config file. + :param: container_name Name of container that nodes will load in if use composition. + :param: create_own_container Whether to start a ROS container when using composition. + :param: namespace Top-level namespace. + :param: use_composition Use composed bringup if True. + :param: use_respawn Whether to respawn if a node crashes (when composition is disabled). + :param: log_level Log level. + :param: bridge_params Extra parameters to pass to the bridge. + """ + super().__init__(**kwargs) + self.__bridge_name = bridge_name + self.__config_file = config_file + self.__container_name = container_name + self.__create_own_container = create_own_container + self.__namespace = namespace + self.__use_composition = use_composition + self.__use_respawn = use_respawn + self.__log_level = log_level + self.__bridge_params = bridge_params + + @classmethod + def parse(cls, entity: Entity, parser: Parser): + """Parse ros_gz_bridge.""" + _, kwargs = super().parse(entity, parser) + + bridge_name = entity.get_attr( + 'bridge_name', data_type=str, + optional=False) + + config_file = entity.get_attr( + 'config_file', data_type=str, + optional=False) + + container_name = entity.get_attr( + 'container_name', data_type=str, + optional=True) + + create_own_container = entity.get_attr( + 'create_own_container', data_type=str, + optional=True) + + namespace = entity.get_attr( + 'namespace', data_type=str, + optional=True) + + use_composition = entity.get_attr( + 'use_composition', data_type=str, + optional=True) + + use_respawn = entity.get_attr( + 'use_respawn', data_type=str, + optional=True) + + log_level = entity.get_attr( + 'log_level', data_type=str, + optional=True) + + bridge_params = entity.get_attr( + 'bridge_params', data_type=str, + optional=True) + + if isinstance(bridge_name, str): + bridge_name = parser.parse_substitution(bridge_name) + kwargs['bridge_name'] = bridge_name + + if isinstance(config_file, str): + config_file = parser.parse_substitution(config_file) + kwargs['config_file'] = config_file + + if isinstance(container_name, str): + container_name = parser.parse_substitution(container_name) + kwargs['container_name'] = container_name + + if isinstance(create_own_container, str): + create_own_container = \ + parser.parse_substitution(create_own_container) + kwargs['create_own_container'] = create_own_container + + if isinstance(namespace, str): + namespace = parser.parse_substitution(namespace) + kwargs['namespace'] = namespace + + if isinstance(use_composition, str): + use_composition = parser.parse_substitution(use_composition) + kwargs['use_composition'] = use_composition + + if isinstance(use_respawn, str): + use_respawn = parser.parse_substitution(use_respawn) + kwargs['use_respawn'] = use_respawn + + if isinstance(log_level, str): + log_level = parser.parse_substitution(log_level) + kwargs['log_level'] = log_level + + if isinstance(bridge_params, str): + bridge_params = parser.parse_substitution(bridge_params) + kwargs['bridge_params'] = bridge_params + + return cls, kwargs + + def execute(self, context: LaunchContext) -> Optional[List[Action]]: + """Execute the action.""" + if hasattr(self.__bridge_params, 'perform'): + string_bridge_params = self.__bridge_params.perform(context) + elif isinstance(self.__bridge_params, list): + if hasattr(self.__bridge_params[0], 'perform'): + string_bridge_params = self.__bridge_params[0].perform(context) + else: + string_bridge_params = str(self.__bridge_params) + # Remove unnecessary symbols + simplified_bridge_params = string_bridge_params.translate( + {ord(i): None for i in '{} "\''} + ) + # Parse to dictionary + parsed_bridge_params = {} + if simplified_bridge_params: + bridge_params_pairs = simplified_bridge_params.split(',') + parsed_bridge_params = dict(pair.split(':') for pair in bridge_params_pairs) + + if isinstance(self.__use_composition, list): + self.__use_composition = self.__use_composition[0] + + if isinstance(self.__create_own_container, list): + self.__create_own_container = self.__create_own_container[0] + + if isinstance(self.__use_respawn, list): + self.__use_respawn = self.__use_respawn[0] + + # Standard node configuration + load_nodes = GroupAction( + condition=IfCondition(PythonExpression(['not ', self.__use_composition])), + actions=[ + Node( + package='ros_gz_bridge', + executable='bridge_node', + name=self.__bridge_name, + namespace=self.__namespace, + output='screen', + respawn=bool(self.__use_respawn), + respawn_delay=2.0, + parameters=[{'config_file': self.__config_file, **parsed_bridge_params}], + arguments=['--ros-args', '--log-level', self.__log_level], + ), + ], + ) + + # Composable node with container configuration + load_composable_nodes_with_container = ComposableNodeContainer( + condition=IfCondition( + PythonExpression([self.__use_composition, ' and ', self.__create_own_container]) + ), + name=self.__container_name, + namespace='', + package='rclcpp_components', + executable='component_container', + composable_node_descriptions=[ + ComposableNode( + package='ros_gz_bridge', + plugin='ros_gz_bridge::RosGzBridge', + name=self.__bridge_name, + namespace=self.__namespace, + parameters=[{'config_file': self.__config_file, **parsed_bridge_params}], + extra_arguments=[{'use_intra_process_comms': True}], + ), + ], + output='screen', + ) + + # Composable node without container configuration + load_composable_nodes_without_container = LoadComposableNodes( + condition=IfCondition( + PythonExpression( + [self.__use_composition, ' and not ', self.__create_own_container] + ) + ), + target_container=self.__container_name, + composable_node_descriptions=[ + ComposableNode( + package='ros_gz_bridge', + plugin='ros_gz_bridge::RosGzBridge', + name=self.__bridge_name, + namespace=self.__namespace, + parameters=[{'config_file': self.__config_file, **parsed_bridge_params}], + extra_arguments=[{'use_intra_process_comms': True}], + ), + ], + ) + + return [ + load_nodes, + load_composable_nodes_with_container, + load_composable_nodes_without_container + ] diff --git a/ros_gz_bridge/ros_gz_bridge/mappings.py b/ros_gz_bridge/ros_gz_bridge/mappings.py index d5923ffa..21e8dd85 100644 --- a/ros_gz_bridge/ros_gz_bridge/mappings.py +++ b/ros_gz_bridge/ros_gz_bridge/mappings.py @@ -36,6 +36,10 @@ Mapping('PoseArray', 'Pose_V'), Mapping('PoseStamped', 'Pose'), Mapping('PoseWithCovariance', 'PoseWithCovariance'), +<<<<<<< HEAD +======= + Mapping('PoseWithCovarianceStamped', 'PoseWithCovariance'), +>>>>>>> 63b651a (Garden EOL (#662)) Mapping('Quaternion', 'Quaternion'), Mapping('Transform', 'Pose'), Mapping('TransformStamped', 'Pose'), @@ -61,12 +65,20 @@ Mapping('Altimeter', 'Altimeter'), Mapping('Contact', 'Contact'), Mapping('Contacts', 'Contacts'), +<<<<<<< HEAD +======= + Mapping('Dataframe', 'Dataframe'), +>>>>>>> 63b651a (Garden EOL (#662)) Mapping('Entity', 'Entity'), Mapping('EntityWrench', 'EntityWrench'), Mapping('Float32Array', 'Float_V'), Mapping('GuiCamera', 'GUICamera'), Mapping('JointWrench', 'JointWrench'), Mapping('Light', 'Light'), +<<<<<<< HEAD +======= + Mapping('MaterialColor', 'MaterialColor'), +>>>>>>> 63b651a (Garden EOL (#662)) Mapping('ParamVec', 'Param'), Mapping('ParamVec', 'Param_V'), Mapping('SensorNoise', 'SensorNoise'), @@ -114,6 +126,7 @@ Mapping('Detection3D', 'AnnotatedOriented3DBox'), ], } +<<<<<<< HEAD MAPPINGS_8_4_0 = { 'ros_gz_interfaces': [ @@ -126,3 +139,5 @@ Mapping('MaterialColor', 'MaterialColor'), ], } +======= +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/ros_gz_bridge/setup.cfg b/ros_gz_bridge/setup.cfg new file mode 100644 index 00000000..1f707813 --- /dev/null +++ b/ros_gz_bridge/setup.cfg @@ -0,0 +1,3 @@ +[options.entry_points] +launch.frontend.launch_extension = + ros_gz_bridge = ros_gz_bridge diff --git a/ros_gz_bridge/src/bridge_config.cpp b/ros_gz_bridge/src/bridge_config.cpp index 52d649f7..f62e5911 100644 --- a/ros_gz_bridge/src/bridge_config.cpp +++ b/ros_gz_bridge/src/bridge_config.cpp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +<<<<<<< HEAD +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include @@ -40,12 +44,15 @@ constexpr const char kBidirectional[] = "BIDIRECTIONAL"; constexpr const char kGzToRos[] = "GZ_TO_ROS"; constexpr const char kRosToGz[] = "ROS_TO_GZ"; +<<<<<<< HEAD /// \TODO(mjcarroll) Remove these in releases past Humble/Garden constexpr const char kIgnTypeName[] = "ign_type_name"; constexpr const char kIgnTopicName[] = "ign_topic_name"; constexpr const char kIgnToRos[] = "IGN_TO_ROS"; constexpr const char kRosToIgn[] = "ROS_TO_IGN"; +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Parse a single sequence entry into a BridgeConfig /// \param[in] yaml_node A node containing a map of bridge config params /// \return BridgeConfig on success, nullopt on failure @@ -60,6 +67,7 @@ std::optional parseEntry(const YAML::Node & yaml_node) return {}; } +<<<<<<< HEAD /// \TODO(mjcarroll) Remove gz_type_name logic in releases past Humble std::string gz_type_name = ""; if (yaml_node[kIgnTypeName] && !yaml_node[kGzTypeName]) { @@ -83,20 +91,47 @@ std::optional parseEntry(const YAML::Node & yaml_node) } if (yaml_node[kTopicName] && yaml_node[kRosTopicName]) { +======= + auto getValue = [yaml_node](const char * key) -> std::string + { + if (yaml_node[key]) { + return yaml_node[key].as(); + } else { + return ""; + } + }; + + const auto topic_name = getValue(kTopicName); + const auto ros_topic_name = getValue(kRosTopicName); + const auto ros_type_name = getValue(kRosTypeName); + const auto gz_topic_name = getValue(kGzTopicName); + const auto gz_type_name = getValue(kGzTypeName); + const auto direction = getValue(kDirection); + + if (!topic_name.empty() && !ros_topic_name.empty()) { +>>>>>>> 63b651a (Garden EOL (#662)) RCLCPP_ERROR( logger, "Could not parse entry: %s and %s are mutually exclusive", kTopicName, kRosTopicName); return {}; } +<<<<<<< HEAD if (yaml_node[kTopicName] && !gz_topic_name.empty()) { +======= + if (!topic_name.empty() && !gz_topic_name.empty()) { +>>>>>>> 63b651a (Garden EOL (#662)) RCLCPP_ERROR( logger, "Could not parse entry: %s and %s are mutually exclusive", kTopicName, kGzTopicName); return {}; } +<<<<<<< HEAD if (!yaml_node[kRosTypeName] || gz_type_name.empty()) { +======= + if (ros_type_name.empty() || gz_type_name.empty()) { +>>>>>>> 63b651a (Garden EOL (#662)) RCLCPP_ERROR( logger, "Could not parse entry: both %s and %s must be set", kRosTypeName, kGzTypeName); @@ -108,6 +143,7 @@ std::optional parseEntry(const YAML::Node & yaml_node) ret.direction = BridgeDirection::BIDIRECTIONAL; if (yaml_node[kDirection]) { +<<<<<<< HEAD auto dirStr = yaml_node[kDirection].as(); if (dirStr == kBidirectional) { @@ -130,10 +166,23 @@ std::optional parseEntry(const YAML::Node & yaml_node) RCLCPP_ERROR( logger, "Could not parse entry: invalid direction [%s]", dirStr.c_str()); +======= + if (direction == kBidirectional) { + ret.direction = BridgeDirection::BIDIRECTIONAL; + } else if (direction == kGzToRos) { + ret.direction = BridgeDirection::GZ_TO_ROS; + } else if (direction == kRosToGz) { + ret.direction = BridgeDirection::ROS_TO_GZ; + } else { + RCLCPP_ERROR( + logger, + "Could not parse entry: invalid direction [%s]", direction.c_str()); +>>>>>>> 63b651a (Garden EOL (#662)) return {}; } } +<<<<<<< HEAD if (yaml_node[kTopicName]) { // Only "topic_name" is set ret.gz_topic_name = yaml_node[kTopicName].as(); @@ -143,17 +192,36 @@ std::optional parseEntry(const YAML::Node & yaml_node) ret.gz_topic_name = yaml_node[kRosTopicName].as(); ret.ros_topic_name = yaml_node[kRosTopicName].as(); } else if (!gz_topic_name.empty() && !yaml_node[kRosTopicName]) { +======= + if (!topic_name.empty()) { + // Only "topic_name" is set + ret.gz_topic_name = topic_name; + ret.ros_topic_name = topic_name; + } else if (!ros_topic_name.empty() && gz_topic_name.empty()) { + // Only "ros_topic_name" is set + ret.gz_topic_name = ros_topic_name; + ret.ros_topic_name = ros_topic_name; + } else if (!gz_topic_name.empty() && ros_topic_name.empty()) { +>>>>>>> 63b651a (Garden EOL (#662)) // Only kGzTopicName is set ret.gz_topic_name = gz_topic_name; ret.ros_topic_name = gz_topic_name; } else { // Both are set ret.gz_topic_name = gz_topic_name; +<<<<<<< HEAD ret.ros_topic_name = yaml_node[kRosTopicName].as(); } ret.gz_type_name = gz_type_name; ret.ros_type_name = yaml_node[kRosTypeName].as(); +======= + ret.ros_topic_name = ros_topic_name; + } + + ret.gz_type_name = gz_type_name; + ret.ros_type_name = ros_type_name; +>>>>>>> 63b651a (Garden EOL (#662)) if (yaml_node[kPublisherQueue]) { ret.publisher_queue_size = yaml_node[kPublisherQueue].as(); @@ -170,16 +238,27 @@ std::optional parseEntry(const YAML::Node & yaml_node) std::vector readFromYaml(std::istream & in) { +<<<<<<< HEAD +======= + auto logger = rclcpp::get_logger("readFromYaml"); +>>>>>>> 63b651a (Garden EOL (#662)) auto ret = std::vector(); YAML::Node yaml_node; yaml_node = YAML::Load(in); +<<<<<<< HEAD auto logger = rclcpp::get_logger("readFromYaml"); if (!yaml_node.IsSequence()) { RCLCPP_ERROR( logger, "Could not parse config, top level must be a YAML sequence"); +======= + if (!yaml_node.IsSequence()) { + RCLCPP_ERROR( + logger, + "Could not parse config: top level must be a YAML sequence"); +>>>>>>> 63b651a (Garden EOL (#662)) return ret; } @@ -197,6 +276,32 @@ std::vector readFromYamlFile(const std::string & filename) { std::vector ret; std::ifstream in(filename); +<<<<<<< HEAD +======= + + auto logger = rclcpp::get_logger("readFromYamlFile"); + if (!in.is_open()) { + RCLCPP_ERROR( + logger, + "Could not parse config: failed to open file [%s]", filename.c_str()); + return ret; + } + + // Compute file size to warn on empty configuration + const auto fbegin = in.tellg(); + in.seekg(0, std::ios::end); + const auto fend = in.tellg(); + const auto fsize = fend - fbegin; + + if (fsize == 0) { + RCLCPP_ERROR( + logger, + "Could not parse config: file empty [%s]", filename.c_str()); + return ret; + } + + in.seekg(0, std::ios::beg); +>>>>>>> 63b651a (Garden EOL (#662)) return readFromYaml(in); } diff --git a/ros_gz_bridge/src/bridge_handle.cpp b/ros_gz_bridge/src/bridge_handle.cpp index c7851503..d17bc977 100644 --- a/ros_gz_bridge/src/bridge_handle.cpp +++ b/ros_gz_bridge/src/bridge_handle.cpp @@ -30,6 +30,11 @@ BridgeHandle::BridgeHandle( config_(config), factory_(get_factory(config.ros_type_name, config.gz_type_name)) { +<<<<<<< HEAD +======= + ros_node_->get_parameter("override_timestamps_with_wall_time", + override_timestamps_with_wall_time_); +>>>>>>> 63b651a (Garden EOL (#662)) } BridgeHandle::~BridgeHandle() = default; diff --git a/ros_gz_bridge/src/bridge_handle.hpp b/ros_gz_bridge/src/bridge_handle.hpp index d1751fb9..8e29c351 100644 --- a/ros_gz_bridge/src/bridge_handle.hpp +++ b/ros_gz_bridge/src/bridge_handle.hpp @@ -101,6 +101,12 @@ class BridgeHandle /// \brief Typed factory used to create publishers/subscribers std::shared_ptr factory_; +<<<<<<< HEAD +======= + + /// \brief Override the header.stamp field of the outgoing messages with the wall time + bool override_timestamps_with_wall_time_ = false; +>>>>>>> 63b651a (Garden EOL (#662)) }; } // namespace ros_gz_bridge diff --git a/ros_gz_bridge/src/bridge_handle_gz_to_ros.cpp b/ros_gz_bridge/src/bridge_handle_gz_to_ros.cpp index ddc292f8..1ec4389b 100644 --- a/ros_gz_bridge/src/bridge_handle_gz_to_ros.cpp +++ b/ros_gz_bridge/src/bridge_handle_gz_to_ros.cpp @@ -70,7 +70,12 @@ void BridgeHandleGzToRos::StartSubscriber() this->gz_node_, this->config_.gz_topic_name, this->config_.subscriber_queue_size, +<<<<<<< HEAD this->ros_publisher_); +======= + this->ros_publisher_, + override_timestamps_with_wall_time_); +>>>>>>> 63b651a (Garden EOL (#662)) this->gz_subscriber_ = this->gz_node_; } diff --git a/ros_gz_bridge/src/convert/actuator_msgs.cpp b/ros_gz_bridge/src/convert/actuator_msgs.cpp index 0c9bcde3..22cb868d 100644 --- a/ros_gz_bridge/src/convert/actuator_msgs.cpp +++ b/ros_gz_bridge/src/convert/actuator_msgs.cpp @@ -17,7 +17,10 @@ namespace ros_gz_bridge { +<<<<<<< HEAD +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void convert_ros_to_gz( diff --git a/ros_gz_bridge/src/convert/geometry_msgs.cpp b/ros_gz_bridge/src/convert/geometry_msgs.cpp index ad83ba6d..870d77b9 100644 --- a/ros_gz_bridge/src/convert/geometry_msgs.cpp +++ b/ros_gz_bridge/src/convert/geometry_msgs.cpp @@ -168,6 +168,30 @@ convert_gz_to_ros( template<> void convert_ros_to_gz( +<<<<<<< HEAD +======= + const geometry_msgs::msg::PoseWithCovarianceStamped & ros_msg, + gz::msgs::PoseWithCovariance & gz_msg) +{ + convert_ros_to_gz(ros_msg.header, (*gz_msg.mutable_pose()->mutable_header())); + convert_ros_to_gz(ros_msg.pose, gz_msg); +} + +template<> +void +convert_gz_to_ros( + const gz::msgs::PoseWithCovariance & gz_msg, + geometry_msgs::msg::PoseWithCovarianceStamped & ros_msg) +{ + convert_gz_to_ros(gz_msg.pose().header(), ros_msg.header); + convert_gz_to_ros(gz_msg, ros_msg.pose); +} + + +template<> +void +convert_ros_to_gz( +>>>>>>> 63b651a (Garden EOL (#662)) const geometry_msgs::msg::PoseStamped & ros_msg, gz::msgs::Pose & gz_msg) { diff --git a/ros_gz_bridge/src/convert/gps_msgs.cpp b/ros_gz_bridge/src/convert/gps_msgs.cpp index de806239..b7cc0e48 100644 --- a/ros_gz_bridge/src/convert/gps_msgs.cpp +++ b/ros_gz_bridge/src/convert/gps_msgs.cpp @@ -55,7 +55,11 @@ convert_gz_to_ros( ros_msg.track = atan2(gz_msg.velocity_north(), gz_msg.velocity_east()); ros_msg.climb = gz_msg.velocity_up(); +<<<<<<< HEAD // position_covariance is not supported in Ignition::Msgs::NavSat. +======= + // position_covariance is not supported in gz::msgs::NavSat. +>>>>>>> 63b651a (Garden EOL (#662)) ros_msg.position_covariance_type = gps_msgs::msg::GPSFix::COVARIANCE_TYPE_UNKNOWN; ros_msg.status.status = gps_msgs::msg::GPSStatus::STATUS_GBAS_FIX; } diff --git a/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp b/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp index 57688b48..16824517 100644 --- a/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp +++ b/ros_gz_bridge/src/convert/ros_gz_interfaces.cpp @@ -245,7 +245,10 @@ convert_gz_to_ros( } } +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void convert_ros_to_gz( @@ -295,7 +298,10 @@ convert_gz_to_ros( gz_msg.data().begin() + gz_msg.data().size(), ros_msg.data.begin()); } +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void @@ -402,7 +408,10 @@ convert_gz_to_ros( ros_msg.intensity = gz_msg.intensity(); } +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void convert_ros_to_gz( @@ -460,7 +469,10 @@ convert_gz_to_ros( ros_msg.shininess = gz_msg.shininess(); } +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) template<> void @@ -497,9 +509,13 @@ convert_gz_to_ros( ros_msg.type = 0; } else if (gz_msg.type() == gz::msgs::SensorNoise_Type::SensorNoise_Type_GAUSSIAN) { ros_msg.type = 2; +<<<<<<< HEAD } else if (gz_msg.type() == // NOLINT gz::msgs::SensorNoise_Type::SensorNoise_Type_GAUSSIAN_QUANTIZED) // NOLINT { // NOLINT +======= + } else if (gz_msg.type() == gz::msgs::SensorNoise_Type::SensorNoise_Type_GAUSSIAN_QUANTIZED) { +>>>>>>> 63b651a (Garden EOL (#662)) ros_msg.type = 3; } diff --git a/ros_gz_bridge/src/convert/sensor_msgs.cpp b/ros_gz_bridge/src/convert/sensor_msgs.cpp index 887f16d0..3c204ee7 100644 --- a/ros_gz_bridge/src/convert/sensor_msgs.cpp +++ b/ros_gz_bridge/src/convert/sensor_msgs.cpp @@ -166,6 +166,7 @@ convert_gz_to_ros( ros_msg.is_bigendian = false; ros_msg.step = ros_msg.width * num_channels * octets_per_channel; +<<<<<<< HEAD auto count = ros_msg.step * ros_msg.height; ros_msg.data.resize(ros_msg.step * ros_msg.height); @@ -173,6 +174,13 @@ convert_gz_to_ros( gz_msg.data().begin(), gz_msg.data().begin() + count, ros_msg.data.begin()); +======= + ros_msg.data.resize(ros_msg.step * ros_msg.height); + + // Prefer memcpy over std::copy for performance reasons, + // see https://github.com/gazebosim/ros_gz/pull/565 + memcpy(ros_msg.data.data(), gz_msg.data().c_str(), gz_msg.data().size()); +>>>>>>> 63b651a (Garden EOL (#662)) } template<> @@ -520,7 +528,11 @@ convert_gz_to_ros( ros_msg.longitude = gz_msg.longitude_deg(); ros_msg.altitude = gz_msg.altitude(); +<<<<<<< HEAD // position_covariance is not supported in Ignition::Msgs::NavSat. +======= + // position_covariance is not supported in gz::msgs::NavSat. +>>>>>>> 63b651a (Garden EOL (#662)) ros_msg.position_covariance_type = sensor_msgs::msg::NavSatFix::COVARIANCE_TYPE_UNKNOWN; ros_msg.status.status = sensor_msgs::msg::NavSatStatus::STATUS_FIX; } diff --git a/ros_gz_bridge/src/factory.hpp b/ros_gz_bridge/src/factory.hpp index 35daf416..b71edbad 100644 --- a/ros_gz_bridge/src/factory.hpp +++ b/ros_gz_bridge/src/factory.hpp @@ -15,11 +15,22 @@ #ifndef FACTORY_HPP_ #define FACTORY_HPP_ +<<<<<<< HEAD #include #include #include #include +======= +#include +#include +#include +#include +#include + +#include +#include +>>>>>>> 63b651a (Garden EOL (#662)) // include ROS 2 #include @@ -27,6 +38,19 @@ #include "factory_interface.hpp" +<<<<<<< HEAD +======= +template +struct has_header : std::false_type +{ +}; + +template +struct has_header>: std::true_type +{ +}; + +>>>>>>> 63b651a (Garden EOL (#662)) namespace ros_gz_bridge { @@ -52,9 +76,17 @@ class Factory : public FactoryInterface auto options = rclcpp::PublisherOptions(); options.qos_overriding_options = rclcpp::QosOverridingOptions { { +<<<<<<< HEAD rclcpp::QosPolicyKind::Depth, rclcpp::QosPolicyKind::Durability, rclcpp::QosPolicyKind::History, +======= + rclcpp::QosPolicyKind::Deadline, + rclcpp::QosPolicyKind::Depth, + rclcpp::QosPolicyKind::Durability, + rclcpp::QosPolicyKind::History, + rclcpp::QosPolicyKind::Liveliness, +>>>>>>> 63b651a (Garden EOL (#662)) rclcpp::QosPolicyKind::Reliability }, }; @@ -103,6 +135,7 @@ class Factory : public FactoryInterface std::shared_ptr node, const std::string & topic_name, size_t /*queue_size*/, +<<<<<<< HEAD rclcpp::PublisherBase::SharedPtr ros_pub) { std::functionSubscribe(topic_name, subCb); +======= + rclcpp::PublisherBase::SharedPtr ros_pub, + bool override_timestamps_with_wall_time) + { + std::function subCb = + [this, ros_pub, override_timestamps_with_wall_time](const GZ_T & _msg) + { + this->gz_callback(_msg, ros_pub, override_timestamps_with_wall_time); + }; + + // Ignore messages that are published from this bridge. + gz::transport::SubscribeOptions opts; + opts.SetIgnoreLocalMessages(true); + node->Subscribe(topic_name, subCb, opts); +>>>>>>> 63b651a (Garden EOL (#662)) } protected: @@ -140,10 +188,27 @@ class Factory : public FactoryInterface static void gz_callback( const GZ_T & gz_msg, +<<<<<<< HEAD rclcpp::PublisherBase::SharedPtr ros_pub) { ROS_T ros_msg; convert_gz_to_ros(gz_msg, ros_msg); +======= + rclcpp::PublisherBase::SharedPtr ros_pub, + bool override_timestamps_with_wall_time) + { + ROS_T ros_msg; + convert_gz_to_ros(gz_msg, ros_msg); + if constexpr (has_header::value) { + if (override_timestamps_with_wall_time) { + auto now = std::chrono::system_clock::now().time_since_epoch(); + auto ns = + std::chrono::duration_cast(now).count(); + ros_msg.header.stamp.sec = ns / 1e9; + ros_msg.header.stamp.nanosec = ns - ros_msg.header.stamp.sec * 1e9; + } + } +>>>>>>> 63b651a (Garden EOL (#662)) std::shared_ptr> pub = std::dynamic_pointer_cast>(ros_pub); if (pub != nullptr) { diff --git a/ros_gz_bridge/src/factory_interface.hpp b/ros_gz_bridge/src/factory_interface.hpp index b760bcd8..7533d8fc 100644 --- a/ros_gz_bridge/src/factory_interface.hpp +++ b/ros_gz_bridge/src/factory_interface.hpp @@ -60,7 +60,12 @@ class FactoryInterface std::shared_ptr node, const std::string & topic_name, size_t queue_size, +<<<<<<< HEAD rclcpp::PublisherBase::SharedPtr ros_pub) = 0; +======= + rclcpp::PublisherBase::SharedPtr ros_pub, + bool override_timestamps_with_wall_time) = 0; +>>>>>>> 63b651a (Garden EOL (#662)) }; } // namespace ros_gz_bridge diff --git a/ros_gz_bridge/src/parameter_bridge.cpp b/ros_gz_bridge/src/parameter_bridge.cpp index 12aac8ab..7ee625bb 100644 --- a/ros_gz_bridge/src/parameter_bridge.cpp +++ b/ros_gz_bridge/src/parameter_bridge.cpp @@ -46,6 +46,7 @@ void usage() "the ROS service will forward request to the Gazebo service and then forward\n" "the response back to the ROS client.\n\n" "A bidirectional bridge example:\n" << +<<<<<<< HEAD " parameter_bridge /chatter@std_msgs/String@ignition.msgs" << ".StringMsg\n\n" << "A bridge from Gazebo to ROS example:\n" << @@ -53,12 +54,25 @@ void usage() ".StringMsg\n\n" << "A bridge from ROS to Gazebo example:\n" << " parameter_bridge /chatter@std_msgs/String]ignition.msgs" << +======= + " parameter_bridge /chatter@std_msgs/String@gz.msgs" << + ".StringMsg\n\n" << + "A bridge from Gazebo to ROS example:\n" << + " parameter_bridge /chatter@std_msgs/String[gz.msgs" << + ".StringMsg\n\n" << + "A bridge from ROS to Gazebo example:\n" << + " parameter_bridge /chatter@std_msgs/String]gz.msgs" << +>>>>>>> 63b651a (Garden EOL (#662)) ".StringMsg\n" << "A service bridge:\n" << " parameter_bridge /world/default/control@ros_gz_interfaces/srv/ControlWorld\n" << "Or equivalently:\n" << " parameter_bridge /world/default/control@ros_gz_interfaces/srv/ControlWorld@" +<<<<<<< HEAD "ignition.msgs.WorldControl@ignition.msgs.Boolean\n" << std::endl; +======= + "gz.msgs.WorldControl@gz.msgs.Boolean\n" << std::endl; +>>>>>>> 63b651a (Garden EOL (#662)) } using RosGzBridge = ros_gz_bridge::RosGzBridge; diff --git a/ros_gz_bridge/src/ros_gz_bridge.cpp b/ros_gz_bridge/src/ros_gz_bridge.cpp index 46a86d98..cfb3aca6 100644 --- a/ros_gz_bridge/src/ros_gz_bridge.cpp +++ b/ros_gz_bridge/src/ros_gz_bridge.cpp @@ -33,6 +33,10 @@ 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); +<<<<<<< HEAD +======= + this->declare_parameter("override_timestamps_with_wall_time", false); +>>>>>>> 63b651a (Garden EOL (#662)) int heartbeat; this->get_parameter("subscription_heartbeat", heartbeat); diff --git a/ros_gz_bridge/src/service_factories/ros_gz_interfaces.cpp b/ros_gz_bridge/src/service_factories/ros_gz_interfaces.cpp index 17fb5289..c52127bc 100644 --- a/ros_gz_bridge/src/service_factories/ros_gz_interfaces.cpp +++ b/ros_gz_bridge/src/service_factories/ros_gz_interfaces.cpp @@ -35,15 +35,24 @@ get_service_factory__ros_gz_interfaces( { if ( ros_type_name == "ros_gz_interfaces/srv/ControlWorld" && +<<<<<<< HEAD (gz_req_type_name.empty() || gz_req_type_name == "ignition.msgs.WorldControl") && (gz_rep_type_name.empty() || gz_rep_type_name == "ignition.msgs.Boolean")) +======= + (gz_req_type_name.empty() || gz_req_type_name == "gz.msgs.WorldControl") && + (gz_rep_type_name.empty() || gz_rep_type_name == "gz.msgs.Boolean")) +>>>>>>> 63b651a (Garden EOL (#662)) { return std::make_shared< ServiceFactory< ros_gz_interfaces::srv::ControlWorld, gz::msgs::WorldControl, gz::msgs::Boolean> +<<<<<<< HEAD >(ros_type_name, "ignition.msgs.WorldControl", "ignition.msgs.Boolean"); +======= + >(ros_type_name, "gz.msgs.WorldControl", "gz.msgs.Boolean"); +>>>>>>> 63b651a (Garden EOL (#662)) } return nullptr; diff --git a/ros_gz_bridge/src/service_factory.hpp b/ros_gz_bridge/src/service_factory.hpp index f771d618..b9f52c15 100644 --- a/ros_gz_bridge/src/service_factory.hpp +++ b/ros_gz_bridge/src/service_factory.hpp @@ -35,7 +35,11 @@ template bool send_response_on_error(RosResT & ros_response); +<<<<<<< HEAD template +======= +template +>>>>>>> 63b651a (Garden EOL (#662)) class ServiceFactory : public ServiceFactoryInterface { public: @@ -60,12 +64,20 @@ class ServiceFactory : public ServiceFactoryInterface std::shared_ptr reqid, std::shared_ptr ros_req) { +<<<<<<< HEAD std::function callback; +======= + std::function callback; +>>>>>>> 63b651a (Garden EOL (#662)) callback = [ srv_handle = std::move(srv_handle), reqid ]( +<<<<<<< HEAD const IgnReplyT & reply, +======= + const GzReplyT & reply, +>>>>>>> 63b651a (Garden EOL (#662)) const bool result) { typename RosServiceT::Response ros_res; @@ -77,7 +89,11 @@ class ServiceFactory : public ServiceFactoryInterface convert_gz_to_ros(reply, ros_res); srv_handle->send_response(*reqid, ros_res); }; +<<<<<<< HEAD IgnRequestT gz_req; +======= + GzRequestT gz_req; +>>>>>>> 63b651a (Garden EOL (#662)) convert_ros_to_gz(*ros_req, gz_req); gz_node->Request( service_name, diff --git a/ros_gz_bridge/src/static_bridge.cpp b/ros_gz_bridge/src/static_bridge.cpp index bf5cd38d..eb3788ab 100644 --- a/ros_gz_bridge/src/static_bridge.cpp +++ b/ros_gz_bridge/src/static_bridge.cpp @@ -37,7 +37,11 @@ int main(int argc, char * argv[]) config.ros_topic_name = "chatter"; config.gz_topic_name = "chatter"; config.ros_type_name = "std_msgs/msg/String"; +<<<<<<< HEAD config.gz_type_name = "ignition.msgs.StringMsg"; +======= + config.gz_type_name = "gz.msgs.StringMsg"; +>>>>>>> 63b651a (Garden EOL (#662)) config.is_lazy = lazy_subscription; bridge_node->add_bridge(config); diff --git a/ros_gz_bridge/test/bridge_config.cpp b/ros_gz_bridge/test/bridge_config.cpp index 45ace8a5..8dd0d524 100644 --- a/ros_gz_bridge/test/bridge_config.cpp +++ b/ros_gz_bridge/test/bridge_config.cpp @@ -16,7 +16,63 @@ #include +<<<<<<< HEAD TEST(BridgeConfig, Minimum) +======= +#include "rcutils/logging.h" + +size_t g_log_calls = 0; + +struct LogEvent +{ + const rcutils_log_location_t * location; + int level; + std::string name; + rcutils_time_point_value_t timestamp; + std::string message; +}; +LogEvent g_last_log_event; + +class BridgeConfig : public ::testing::Test +{ +public: + rcutils_logging_output_handler_t previous_output_handler; + void SetUp() + { + g_log_calls = 0; + ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_initialize()); + rcutils_logging_set_default_logger_level(RCUTILS_LOG_SEVERITY_DEBUG); + + auto rcutils_logging_console_output_handler = []( + const rcutils_log_location_t * location, + int level, const char * name, rcutils_time_point_value_t timestamp, + const char * format, va_list * args) -> void + { + g_log_calls += 1; + g_last_log_event.location = location; + g_last_log_event.level = level; + g_last_log_event.name = name ? name : ""; + g_last_log_event.timestamp = timestamp; + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), format, *args); + g_last_log_event.message = buffer; + }; + + this->previous_output_handler = rcutils_logging_get_output_handler(); + rcutils_logging_set_output_handler(rcutils_logging_console_output_handler); + } + + void TearDown() + { + rcutils_logging_set_output_handler(this->previous_output_handler); + ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_shutdown()); + EXPECT_FALSE(g_rcutils_logging_initialized); + } +}; + + +TEST_F(BridgeConfig, Minimum) +>>>>>>> 63b651a (Garden EOL (#662)) { auto results = ros_gz_bridge::readFromYamlFile("test/config/minimum.yaml"); EXPECT_EQ(4u, results.size()); @@ -63,6 +119,7 @@ TEST(BridgeConfig, Minimum) } } +<<<<<<< HEAD TEST(BridgeConfig, MinimumIgn) { auto results = ros_gz_bridge::readFromYamlFile("test/config/minimum_ign.yaml"); @@ -112,6 +169,9 @@ TEST(BridgeConfig, MinimumIgn) TEST(BridgeConfig, FullGz) +======= +TEST_F(BridgeConfig, FullGz) +>>>>>>> 63b651a (Garden EOL (#662)) { auto results = ros_gz_bridge::readFromYamlFile("test/config/full.yaml"); EXPECT_EQ(2u, results.size()); @@ -141,6 +201,7 @@ TEST(BridgeConfig, FullGz) } } +<<<<<<< HEAD TEST(BridgeConfig, FullIgn) { auto results = ros_gz_bridge::readFromYamlFile("test/config/full.yaml"); @@ -172,6 +233,9 @@ TEST(BridgeConfig, FullIgn) } TEST(BridgeConfig, InvalidSetTwoRos) +======= +TEST_F(BridgeConfig, InvalidSetTwoRos) +>>>>>>> 63b651a (Garden EOL (#662)) { // Cannot set topic_name and ros_topic_name auto yaml = R"( @@ -180,9 +244,18 @@ TEST(BridgeConfig, InvalidSetTwoRos) auto results = ros_gz_bridge::readFromYamlString(yaml); EXPECT_EQ(0u, results.size()); +<<<<<<< HEAD } TEST(BridgeConfig, InvalidSetTwoGz) +======= + EXPECT_EQ( + "Could not parse entry: topic_name and ros_topic_name are mutually exclusive", + g_last_log_event.message); +} + +TEST_F(BridgeConfig, InvalidSetTwoGz) +>>>>>>> 63b651a (Garden EOL (#662)) { // Cannot set topic_name and gz_topic_name auto yaml = R"( @@ -191,9 +264,18 @@ TEST(BridgeConfig, InvalidSetTwoGz) auto results = ros_gz_bridge::readFromYamlString(yaml); EXPECT_EQ(0u, results.size()); +<<<<<<< HEAD } TEST(BridgeConfig, InvalidSetTypes) +======= + EXPECT_EQ( + "Could not parse entry: topic_name and gz_topic_name are mutually exclusive", + g_last_log_event.message); +} + +TEST_F(BridgeConfig, InvalidSetTypes) +>>>>>>> 63b651a (Garden EOL (#662)) { // Both ros_type_name and gz_type_name must be set auto yaml = R"( @@ -202,9 +284,18 @@ TEST(BridgeConfig, InvalidSetTypes) auto results = ros_gz_bridge::readFromYamlString(yaml); EXPECT_EQ(0u, results.size()); +<<<<<<< HEAD } TEST(BridgeConfig, ParseDirection) +======= + EXPECT_EQ( + "Could not parse entry: both ros_type_name and gz_type_name must be set", + g_last_log_event.message); +} + +TEST_F(BridgeConfig, ParseDirection) +>>>>>>> 63b651a (Garden EOL (#662)) { { // Check that default is bidirectional @@ -264,10 +355,47 @@ TEST(BridgeConfig, ParseDirection) - topic_name: foo ros_type_name: std_msgs/msg/String gz_type_name: ignition.msgs.StringMsg +<<<<<<< HEAD direction: asdfasdfasdfasdf +======= + direction: foobar +>>>>>>> 63b651a (Garden EOL (#662)) )"; auto results = ros_gz_bridge::readFromYamlString(yaml); EXPECT_EQ(0u, results.size()); +<<<<<<< HEAD + } +} +======= + EXPECT_EQ("Could not parse entry: invalid direction [foobar]", g_last_log_event.message); } } + +TEST_F(BridgeConfig, InvalidFileDoesntExist) +{ + auto results = ros_gz_bridge::readFromYamlFile("this/should/never/be/a/file.yaml"); + EXPECT_EQ(0u, results.size()); + EXPECT_EQ( + "Could not parse config: failed to open file [this/should/never/be/a/file.yaml]", + g_last_log_event.message); +} + +TEST_F(BridgeConfig, InvalidTopLevel) +{ + auto results = ros_gz_bridge::readFromYamlFile("test/config/invalid.yaml"); + EXPECT_EQ(0u, results.size()); + EXPECT_EQ( + "Could not parse config: top level must be a YAML sequence", + g_last_log_event.message); +} + +TEST_F(BridgeConfig, EmptyYAML) +{ + auto results = ros_gz_bridge::readFromYamlFile("test/config/empty.yaml"); + EXPECT_EQ(0u, results.size()); + EXPECT_EQ( + "Could not parse config: file empty [test/config/empty.yaml]", + g_last_log_event.message); +} +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/ros_gz_bridge/test/config/empty.yaml b/ros_gz_bridge/test/config/empty.yaml new file mode 100644 index 00000000..e69de29b diff --git a/ros_gz_bridge/test/config/invalid.yaml b/ros_gz_bridge/test/config/invalid.yaml new file mode 100644 index 00000000..c14740ad --- /dev/null +++ b/ros_gz_bridge/test/config/invalid.yaml @@ -0,0 +1,8 @@ +ros_topic_name: "ros_chatter" +gz_topic_name: "gz_chatter" +ros_type_name: "std_msgs/msg/String" +gz_type_name: "ignition.msgs.StringMsg" +subscriber_queue: 5 +publisher_queue: 6 +lazy: true +direction: ROS_TO_GZ diff --git a/ros_gz_bridge/test/resource/gz_publisher.cpp.em b/ros_gz_bridge/test/resource/gz_publisher.cpp.em index 9cccbfe0..e4c83667 100644 --- a/ros_gz_bridge/test/resource/gz_publisher.cpp.em +++ b/ros_gz_bridge/test/resource/gz_publisher.cpp.em @@ -55,8 +55,13 @@ int main(int /*argc*/, char **/*argv*/) @[for m in mappings]@ // @(m.gz_string()). auto @(m.unique())_pub = +<<<<<<< HEAD node.Advertise<@(m.ign_type())>("@(m.unique())"); @(m.ign_type()) @(m.unique())_msg; +======= + node.Advertise<@(m.gz_type())>("@(m.unique())"); + @(m.gz_type()) @(m.unique())_msg; +>>>>>>> 63b651a (Garden EOL (#662)) ros_gz_bridge::testing::createTestMsg(@(m.unique())_msg); @[end for]@ diff --git a/ros_gz_bridge/test/resource/gz_subscriber.cpp.em b/ros_gz_bridge/test/resource/gz_subscriber.cpp.em index 6edae074..081d7082 100644 --- a/ros_gz_bridge/test/resource/gz_subscriber.cpp.em +++ b/ros_gz_bridge/test/resource/gz_subscriber.cpp.em @@ -54,7 +54,11 @@ private: gz::transport::Node node; ///////////////////////////////////////////////// TEST(GzSubscriberTest, @(m.unique())) { +<<<<<<< HEAD MyTestClass<@(m.ign_type())> client("@(m.unique())"); +======= + MyTestClass<@(m.gz_type())> client("@(m.unique())"); +>>>>>>> 63b651a (Garden EOL (#662)) using namespace std::chrono_literals; ros_gz_bridge::testing::waitUntilBoolVar( diff --git a/ros_gz_bridge/test/utils/gz_test_msg.cpp b/ros_gz_bridge/test/utils/gz_test_msg.cpp index a966b8f7..022270fb 100644 --- a/ros_gz_bridge/test/utils/gz_test_msg.cpp +++ b/ros_gz_bridge/test/utils/gz_test_msg.cpp @@ -376,6 +376,10 @@ void createTestMsg(gz::msgs::PoseWithCovariance & _msg) { createTestMsg(*_msg.mutable_pose()->mutable_position()); createTestMsg(*_msg.mutable_pose()->mutable_orientation()); +<<<<<<< HEAD +======= + createTestMsg(*_msg.mutable_pose()->mutable_header()); +>>>>>>> 63b651a (Garden EOL (#662)) for (int i = 0; i < 36; i++) { _msg.mutable_covariance()->add_data(i); } @@ -640,7 +644,10 @@ void compareTestMsg(const std::shared_ptr & _msg) } } +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(gz::msgs::Dataframe & _msg) { gz::msgs::Header header_msg; @@ -678,7 +685,10 @@ void compareTestMsg(const std::shared_ptr & _msg) EXPECT_EQ(expected_msg.dst_address(), _msg->dst_address()); EXPECT_EQ(expected_msg.data(), _msg->data()); } +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(gz::msgs::Image & _msg) { @@ -1371,7 +1381,10 @@ void compareTestMsg(const std::shared_ptr & _msg) EXPECT_FLOAT_EQ(expected_msg.intensity(), _msg->intensity()); } +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(gz::msgs::MaterialColor & _msg) { createTestMsg(*_msg.mutable_header()); @@ -1400,7 +1413,10 @@ void compareTestMsg(const std::shared_ptr & _msg) EXPECT_EQ(expected_msg.shininess(), _msg->shininess()); EXPECT_EQ(expected_msg.entity_match(), _msg->entity_match()); } +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(gz::msgs::GUICamera & _msg) { diff --git a/ros_gz_bridge/test/utils/gz_test_msg.hpp b/ros_gz_bridge/test/utils/gz_test_msg.hpp index c815a46d..85707e54 100644 --- a/ros_gz_bridge/test/utils/gz_test_msg.hpp +++ b/ros_gz_bridge/test/utils/gz_test_msg.hpp @@ -30,8 +30,13 @@ #include #include #include +<<<<<<< HEAD #include #include +======= +#include +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -44,6 +49,10 @@ #include #include #include +<<<<<<< HEAD +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -71,6 +80,7 @@ #include #include +<<<<<<< HEAD #if HAVE_DATAFRAME #include #endif // HAVE_DATAFRAME @@ -78,6 +88,8 @@ #if HAVE_MATERIALCOLOR #include #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) namespace ros_gz_bridge { @@ -173,16 +185,26 @@ void compareTestMsg(const std::shared_ptr & _msg); /// \brief Create a message used for testing. /// \param[out] _msg The message populated. +<<<<<<< HEAD void createTestMsg(gz::msgs::StringMsg & _msg); /// \brief Create a message used for testing. /// \param[out] _msg The message populated. +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(gz::msgs::SensorNoise & _msg); /// \brief Compare a message with the populated for testing. /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD +======= +/// \brief Create a message used for testing. +/// \param[out] _msg The message populated. +void createTestMsg(gz::msgs::StringMsg & _msg); + +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Compare a message with the populated for testing. /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); @@ -323,7 +345,10 @@ void createTestMsg(gz::msgs::Contacts & _msg); /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. void createTestMsg(gz::msgs::Dataframe & _msg); @@ -331,7 +356,10 @@ void createTestMsg(gz::msgs::Dataframe & _msg); /// \brief Compare a message with the populated for testing. /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. @@ -469,7 +497,10 @@ void createTestMsg(gz::msgs::Light & _msg); /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. void createTestMsg(gz::msgs::MaterialColor & _msg); @@ -477,7 +508,10 @@ 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); +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. diff --git a/ros_gz_bridge/test/utils/ros_test_msg.cpp b/ros_gz_bridge/test/utils/ros_test_msg.cpp index fcba33f4..54d3da3f 100644 --- a/ros_gz_bridge/test/utils/ros_test_msg.cpp +++ b/ros_gz_bridge/test/utils/ros_test_msg.cpp @@ -58,6 +58,17 @@ void compareTestMsg(const std::shared_ptr & _msg) EXPECT_EQ(expected_msg.data, _msg->data); } +<<<<<<< HEAD +======= +void createTestMsg(std_msgs::msg::ColorRGBA & _msg) +{ + _msg.r = 0.2; + _msg.g = 0.4; + _msg.b = 0.6; + _msg.a = 0.8; +} + +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(actuator_msgs::msg::Actuators & _msg) { std_msgs::msg::Header header_msg; @@ -89,6 +100,7 @@ void compareTestMsg(const std::shared_ptr & _msg) } } +<<<<<<< HEAD void createTestMsg(std_msgs::msg::ColorRGBA & _msg) { _msg.r = 0.2; @@ -97,6 +109,8 @@ void createTestMsg(std_msgs::msg::ColorRGBA & _msg) _msg.a = 0.8; } +======= +>>>>>>> 63b651a (Garden EOL (#662)) void compareTestMsg(const std::shared_ptr & _msg) { std_msgs::msg::ColorRGBA expected_msg; @@ -381,6 +395,21 @@ void compareTestMsg(const std::shared_ptr & _msg) +{ + compareTestMsg(std::make_shared(_msg->pose)); + compareTestMsg(std::make_shared(_msg->header)); +} + +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(geometry_msgs::msg::PoseStamped & _msg) { createTestMsg(_msg.header); @@ -610,7 +639,10 @@ void compareTestMsg(const std::shared_ptr & _msg) EXPECT_FLOAT_EQ(expected_msg.intensity, _msg->intensity); } +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(ros_gz_interfaces::msg::MaterialColor & _msg) { createTestMsg(_msg.header); @@ -638,7 +670,10 @@ void compareTestMsg(const std::shared_ptr EXPECT_EQ(expected_msg.shininess, _msg->shininess); EXPECT_EQ(expected_msg.entity_match, _msg->entity_match); } +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(ros_gz_interfaces::msg::GuiCamera & _msg) { @@ -935,7 +970,10 @@ void compareTestMsg(const std::shared_ptr & _m } } +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(ros_gz_interfaces::msg::Dataframe & _msg) { createTestMsg(_msg.header); @@ -961,7 +999,10 @@ void compareTestMsg(const std::shared_ptr & _ EXPECT_EQ(expected_msg.data[ii], _msg->data[ii]); } } +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) void createTestMsg(nav_msgs::msg::Odometry & _msg) { diff --git a/ros_gz_bridge/test/utils/ros_test_msg.hpp b/ros_gz_bridge/test/utils/ros_test_msg.hpp index 5fea2758..9bb70e2c 100644 --- a/ros_gz_bridge/test/utils/ros_test_msg.hpp +++ b/ros_gz_bridge/test/utils/ros_test_msg.hpp @@ -34,6 +34,10 @@ #include #include #include +<<<<<<< HEAD +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -55,6 +59,7 @@ #include #include #include +<<<<<<< HEAD #if HAVE_DATAFRAME #include #endif // HAVE_DATAFRAME @@ -62,6 +67,11 @@ #if HAVE_MATERIALCOLOR #include #endif // HAVE_MATERIALCOLOR +======= +#include +#include +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include #include @@ -269,6 +279,21 @@ void createTestMsg(geometry_msgs::msg::PoseWithCovariance & _msg); /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD +======= +/// \brief Compare a message with the populated for testing. +/// \param[in] _msg The message to compare. +void compareTestMsg(const geometry_msgs::msg::PoseWithCovarianceStamped & _msg); + +/// \brief Create a message used for testing. +/// \param[out] _msg The message populated. +void createTestMsg(geometry_msgs::msg::PoseWithCovarianceStamped & _msg); + +/// \brief Compare a message with the populated for testing. +/// \param[in] _msg The message to compare. +void compareTestMsg(const std::shared_ptr & _msg); + +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. void createTestMsg(geometry_msgs::msg::PoseStamped & _msg); @@ -401,7 +426,10 @@ void createTestMsg(ros_gz_interfaces::msg::Light & _msg); /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #if HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. void createTestMsg(ros_gz_interfaces::msg::MaterialColor & _msg); @@ -409,7 +437,10 @@ 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); +<<<<<<< HEAD #endif // HAVE_MATERIALCOLOR +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. @@ -443,7 +474,10 @@ void createTestMsg(ros_gz_interfaces::msg::Contacts & _msg); /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #if HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. void createTestMsg(ros_gz_interfaces::msg::Dataframe & _msg); @@ -451,7 +485,10 @@ void createTestMsg(ros_gz_interfaces::msg::Dataframe & _msg); /// \brief Compare a message with the populated for testing. /// \param[in] _msg The message to compare. void compareTestMsg(const std::shared_ptr & _msg); +<<<<<<< HEAD #endif // HAVE_DATAFRAME +======= +>>>>>>> 63b651a (Garden EOL (#662)) /// \brief Create a message used for testing. /// \param[out] _msg The message populated. diff --git a/ros_gz_image/CHANGELOG.rst b/ros_gz_image/CHANGELOG.rst index 810b80e6..c5287297 100644 --- a/ros_gz_image/CHANGELOG.rst +++ b/ros_gz_image/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros1_ign_image ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- @@ -22,6 +23,107 @@ Changelog for package ros1_ign_image 0.244.11 (2023-05-23) --------------------- +======= +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ + +2.1.0 (2024-09-12) +------------------ + +2.0.1 (2024-08-29) +------------------ + +2.0.0 (2024-07-22) +------------------ + +1.0.1 (2024-07-03) +------------------ +* Merge pull request `#571 `_ from azeey/jazzy_to_ros2 + Merge jazzy ➡️ ros2 +* Merge jazzy into ros2 +* Merge pull request `#569 `_ from azeey/iron_to_jazzy + Merge iron ➡️ jazzy +* Merge iron into jazzy +* Prepare for 1.0.0 Release (`#495 `_) +* Use gz_vendor packages (`#531 `_) +* 0.244.14 +* Changelog +* ign to gz (`#519 `_) +* 0.244.13 +* Changelog +* 0.244.12 +* Changelog +* 0.246.0 +* Update changelogs +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Fix linter error by reordering headers (`#373 `_) +* Add QoS profile parameter to image bridge (`#335 `_) +* Fix double wait in ros_gz_bridge (`#347 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Jose Luis Rivero, Michael Carroll, Sebastian Castro, ahcorde, ymd-stella + +1.0.0 (2024-04-24) +------------------ +* Use gz_vendor packages (`#531 `_) +* ign to gz (`#519 `_) +* Contributors: Addisu Z. Taddese, Alejandro Hernández Cordero + +0.246.0 (2023-08-31) +-------------------- +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* Update maintainers (`#376 `_) +* Fix linter error by reordering headers (`#373 `_) +* Add QoS profile parameter to image bridge (`#335 `_) +* Fix double wait in ros_gz_bridge (`#347 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Michael Carroll, Sebastian Castro, ahcorde, ymd-stella + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Alejandro Hernández Cordero, Michael Carroll, ahcorde + +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz_image/CMakeLists.txt b/ros_gz_image/CMakeLists.txt index 545b0b27..6fc6add6 100644 --- a/ros_gz_image/CMakeLists.txt +++ b/ros_gz_image/CMakeLists.txt @@ -16,6 +16,7 @@ find_package(ros_gz_bridge REQUIRED) find_package(rclcpp REQUIRED) find_package(sensor_msgs REQUIRED) +<<<<<<< HEAD # TODO(CH3): Deprecated. Remove on tock. if("$ENV{GZ_VERSION}" STREQUAL "" AND NOT "$ENV{IGNITION_VERSION}" STREQUAL "") message(DEPRECATION "Environment variable [IGNITION_VERSION] is deprecated. Use [GZ_VERSION] instead.") @@ -65,6 +66,13 @@ else() message(STATUS "Compiling against Ignition Fortress") endif() +======= +find_package(gz_transport_vendor REQUIRED) +find_package(gz-transport REQUIRED) + +find_package(gz_msgs_vendor REQUIRED) +find_package(gz-msgs REQUIRED) +>>>>>>> 63b651a (Garden EOL (#662)) include_directories(include) @@ -77,8 +85,13 @@ add_executable(${executable} ) target_link_libraries(${executable} +<<<<<<< HEAD ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core +======= + gz-msgs::core + gz-transport::core +>>>>>>> 63b651a (Garden EOL (#662)) ) ament_target_dependencies(${executable} @@ -112,8 +125,13 @@ if(BUILD_TESTING) # ) # target_link_libraries(${test_publisher}_image # ${catkin_LIBRARIES} +<<<<<<< HEAD # ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core # ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core +======= + # $gz-msgs$::core + # $gz-transport::core +>>>>>>> 63b651a (Garden EOL (#662)) # gtest # gtest_main # ) @@ -125,8 +143,13 @@ if(BUILD_TESTING) # test/subscribers/${test_subscriber}.cpp) # target_link_libraries(test_${test_subscriber}_image # ${catkin_LIBRARIES} +<<<<<<< HEAD # ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core # ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core +======= + # $gz-msgs::core + # $gz-transport::core +>>>>>>> 63b651a (Garden EOL (#662)) # ) # endforeach(test_subscriber) endif() diff --git a/ros_gz_image/README.md b/ros_gz_image/README.md index b7b27e1f..f9006a8c 100644 --- a/ros_gz_image/README.md +++ b/ros_gz_image/README.md @@ -1,7 +1,11 @@ # Image utilities for using ROS and Gazebo Transport This package provides a unidirectional bridge for images from Gazebo to ROS. +<<<<<<< HEAD The bridge subscribes to Gazebo image messages (`ignition::msgs::Image`) +======= +The bridge subscribes to Gazebo image messages (`gz::msgs::Image`) +>>>>>>> 63b651a (Garden EOL (#662)) and republishes them to ROS using [image_transport](http://wiki.ros.org/image_transport). For compressed images, install @@ -9,3 +13,17 @@ For compressed images, install and the bridge will publish `/compressed` images. The same goes for other `image_transport` plugins. +<<<<<<< HEAD +======= +To run the bridge from the command line: + +```shell +ros2 run ros_gz_image image_bridge /topic1 /topic2 +``` + +You can also modify the [Quality of Service (QoS) policy](https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html#qos-policies) used to publish images using an additional `qos` ROS parameter. For example: + +```shell +ros2 run ros_gz_image image_bridge /topic1 /topic2 --ros-args qos:=sensor_data +``` +>>>>>>> 63b651a (Garden EOL (#662)) diff --git a/ros_gz_image/package.xml b/ros_gz_image/package.xml index 2a367440..ccdfdfb8 100644 --- a/ros_gz_image/package.xml +++ b/ros_gz_image/package.xml @@ -1,9 +1,19 @@ ros_gz_image +<<<<<<< HEAD 0.244.16 Image utilities for Gazebo simulation with ROS. Apache 2.0 Louise Poubel +======= + 2.1.2 + Image utilities for Gazebo simulation with ROS. + Apache 2.0 + Aditya Pande + Alejandro Hernandez + + Louise Poubel +>>>>>>> 63b651a (Garden EOL (#662)) ament_cmake pkg-config @@ -13,6 +23,7 @@ rclcpp sensor_msgs +<<<<<<< HEAD gz-msgs10 gz-transport13 @@ -27,6 +38,10 @@ ignition-msgs7 ignition-transport10 +======= + gz_msgs_vendor + gz_transport_vendor +>>>>>>> 63b651a (Garden EOL (#662)) ament_lint_auto ament_lint_common diff --git a/ros_gz_image/src/image_bridge.cpp b/ros_gz_image/src/image_bridge.cpp index c167c67c..e70f47df 100644 --- a/ros_gz_image/src/image_bridge.cpp +++ b/ros_gz_image/src/image_bridge.cpp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +<<<<<<< HEAD +======= +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include @@ -19,17 +23,27 @@ #include #include +<<<<<<< HEAD #include #include #include ////////////////////////////////////////////////// /// \brief Bridges one topic +======= +#include +#include +#include + +////////////////////////////////////////////////// +/// \brief Bridges one image topic +>>>>>>> 63b651a (Garden EOL (#662)) class Handler { public: /// \brief Constructor /// \param[in] _topic Image base topic +<<<<<<< HEAD /// \param[in] _it_node Pointer to image transport node /// \param[in] _gz_node Pointer to Gazebo node Handler( @@ -38,6 +52,33 @@ class Handler std::shared_ptr _gz_node) { this->ros_pub = _it_node->advertise(_topic, 1); +======= + /// \param[in] _node Pointer to ROS node + /// \param[in] _gz_node Pointer to Gazebo node + Handler( + const std::string & _topic, + std::shared_ptr _node, + std::shared_ptr _gz_node) + { + // Get QoS profile from parameter + rmw_qos_profile_t qos_profile = rmw_qos_profile_default; + const auto qos_str = + _node->get_parameter("qos").get_parameter_value().get(); + if (qos_str == "system_default") { + qos_profile = rmw_qos_profile_system_default; + } else if (qos_str == "sensor_data") { + qos_profile = rmw_qos_profile_sensor_data; + } else if (qos_str != "default") { + RCLCPP_ERROR( + _node->get_logger(), + "Invalid QoS profile %s specified. Using default profile.", + qos_str.c_str()); + } + + // Create publishers and subscribers + this->ros_pub = image_transport::create_publisher( + _node.get(), _topic, qos_profile); +>>>>>>> 63b651a (Garden EOL (#662)) _gz_node->Subscribe(_topic, &Handler::OnImage, this); } @@ -77,7 +118,11 @@ int main(int argc, char * argv[]) // ROS node auto node_ = rclcpp::Node::make_shared("ros_gz_image"); +<<<<<<< HEAD auto it_node = std::make_shared(node_); +======= + node_->declare_parameter("qos", "default"); +>>>>>>> 63b651a (Garden EOL (#662)) // Gazebo node auto gz_node = std::make_shared(); @@ -91,7 +136,11 @@ int main(int argc, char * argv[]) // Create publishers and subscribers for (auto topic : args) { +<<<<<<< HEAD handlers.push_back(std::make_shared(topic, it_node, gz_node)); +======= + handlers.push_back(std::make_shared(topic, node_, gz_node)); +>>>>>>> 63b651a (Garden EOL (#662)) } // Spin ROS and Gz until shutdown diff --git a/ros_gz_interfaces/CHANGELOG.rst b/ros_gz_interfaces/CHANGELOG.rst index 6f201eb5..704c8420 100644 --- a/ros_gz_interfaces/CHANGELOG.rst +++ b/ros_gz_interfaces/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros_gz_interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- @@ -25,6 +26,41 @@ Changelog for package ros_gz_interfaces 0.244.14 (2024-04-08) --------------------- * Add option to change material color from ROS. (`#486 `_) +======= +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ + +2.1.0 (2024-09-12) +------------------ + +2.0.1 (2024-08-29) +------------------ + +2.0.0 (2024-07-22) +------------------ + +1.0.1 (2024-07-03) +------------------ +* Add support for gz.msgs.EntityWrench (base branch: ros2) (`#573 `_) +* Add option to change material color from ROS. (`#521 `_) + Forward port of `#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. + (cherry picked from commit 78dc4823121f085594e6028a93f1e571eb04f58b) +* Add option to change material color from ROS. (`#521 `_) + Forward port of `#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. +* Prepare for 1.0.0 Release (`#495 `_) +* 0.244.14 +* Changelog +* Add option to change material color from ROS. (`#486 `_) +>>>>>>> 63b651a (Garden EOL (#662)) * Message and bridge for MaterialColor. This allows bridging MaterialColor from ROS to GZ and is important for allowing simulation users to create status lights. @@ -32,6 +68,7 @@ Changelog for package ros_gz_interfaces Co-authored-by: Alejandro Hernández Cordero Co-authored-by: Addisu Z. Taddese Co-authored-by: Addisu Z. Taddese +<<<<<<< HEAD * Contributors: Benjamin Perseghetti 0.244.13 (2024-01-23) @@ -45,6 +82,51 @@ Changelog for package ros_gz_interfaces 0.244.11 (2023-05-23) --------------------- +======= +* 0.244.13 +* Changelog +* 0.244.12 +* Changelog +* 0.246.0 +* Update changelogs +* SensorNoise msg bridging (`#417 `_) +* Added Altimeter msg bridging (`#413 `_) +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* Export rcl_interfaces exec dependency (`#317 `_) +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Benjamin Perseghetti, Jose Luis Rivero, Michael Carroll, Victor T. Noppeney, ahcorde + +1.0.0 (2024-04-24) +------------------ + +0.246.0 (2023-08-31) +-------------------- +* SensorNoise msg bridging (`#417 `_) +* Added Altimeter msg bridging (`#413 `_) +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Export rcl_interfaces exec dependency (`#317 `_) +* Contributors: Aditya Pande, Alejandro Hernández Cordero, Michael Carroll, ahcorde + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Contributors: Alejandro Hernández Cordero, ahcorde + +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz_interfaces/package.xml b/ros_gz_interfaces/package.xml index 464d3ff5..c6c0f742 100644 --- a/ros_gz_interfaces/package.xml +++ b/ros_gz_interfaces/package.xml @@ -1,10 +1,20 @@ ros_gz_interfaces +<<<<<<< HEAD 0.244.16 Message and service data structures for interacting with Gazebo from ROS2. Apache 2.0 Louise Poubel Zhenpeng Ge +======= + 2.1.2 + Message and service data structures for interacting with Gazebo from ROS2. + Apache 2.0 + Louise Poubel + Zhenpeng Ge + Aditya Pande + Alejandro Hernandez +>>>>>>> 63b651a (Garden EOL (#662)) ament_cmake rosidl_default_generators diff --git a/ros_gz_point_cloud/examples/depth_camera.sdf b/ros_gz_point_cloud/examples/depth_camera.sdf index 574d0ce4..ae8fa6ca 100644 --- a/ros_gz_point_cloud/examples/depth_camera.sdf +++ b/ros_gz_point_cloud/examples/depth_camera.sdf @@ -15,7 +15,11 @@ 3. Load the example world, unpaused: +<<<<<<< HEAD ign gazebo -r examples/depth_camera.sdf +======= + gz sim -r examples/depth_camera.sdf +>>>>>>> 63b651a (Garden EOL (#662)) 4. Launch RViz to visualize the point cloud: diff --git a/ros_gz_point_cloud/examples/gpu_lidar.sdf b/ros_gz_point_cloud/examples/gpu_lidar.sdf index 7bd3a735..6971382c 100644 --- a/ros_gz_point_cloud/examples/gpu_lidar.sdf +++ b/ros_gz_point_cloud/examples/gpu_lidar.sdf @@ -15,7 +15,11 @@ 3. Load this world, unpaused: +<<<<<<< HEAD ign gazebo -r examples/gpu_lidar.sdf +======= + gz sim -r examples/gpu_lidar.sdf +>>>>>>> 63b651a (Garden EOL (#662)) 4. Launch RViz to visualize the point cloud: diff --git a/ros_gz_point_cloud/examples/rgbd_camera.sdf b/ros_gz_point_cloud/examples/rgbd_camera.sdf index 64a77b6a..30f9a888 100644 --- a/ros_gz_point_cloud/examples/rgbd_camera.sdf +++ b/ros_gz_point_cloud/examples/rgbd_camera.sdf @@ -16,7 +16,11 @@ 3. Load the example world, unpaused: +<<<<<<< HEAD ign gazebo -r examples/rgbd_camera.sdf +======= + gz sim -r examples/rgbd_camera.sdf +>>>>>>> 63b651a (Garden EOL (#662)) 4. Launch RViz to visualize the point cloud: diff --git a/ros_gz_point_cloud/package.xml b/ros_gz_point_cloud/package.xml index b3d5717e..60309f59 100644 --- a/ros_gz_point_cloud/package.xml +++ b/ros_gz_point_cloud/package.xml @@ -3,7 +3,14 @@ 0.7.0 Point cloud utilities for Gazebo simulation with ROS. Apache 2.0 +<<<<<<< HEAD Louise Poubel +======= + Aditya Pande + Alejandro Hernandez + + Louise Poubel +>>>>>>> 63b651a (Garden EOL (#662)) catkin diff --git a/ros_gz_sim/CHANGELOG.rst b/ros_gz_sim/CHANGELOG.rst index e6a5d773..ddfad66e 100644 --- a/ros_gz_sim/CHANGELOG.rst +++ b/ros_gz_sim/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros_gz_sim ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- @@ -11,6 +12,93 @@ Changelog for package ros_gz_sim 0.244.14 (2024-04-08) --------------------- * Support `` in `package.xml` exports (`#492 `_) +======= +2.1.2 (2024-10-31) +------------------ +* Create ros_gz_spawn_model.launch (`#604 `_) + Co-authored-by: Alejandro Hernández Cordero +* Add create_own_container argument to ros_gz_spawn_model.launch.py (`#622 `_) +* Fix ros_gz_sim.launch.py when create_own_container is enabled. (`#620 `_) +* Contributors: Aarav Gupta, Amronos, Carlos Agüero + +2.1.1 (2024-10-14) +------------------ +* Extra parameter to start a container (`#616 `_) +* Bugfix: `if "false"` is always `True` (`#617 `_) + There is an issue in this launch file when passing the string 'false' as + an argument. In Python, non-empty strings are always evaluated as True, + regardless of their content. This means that even if you pass 'false', + the system will still evaluate it as True. + This bug results in the launch system incorrectly calling the OnShutdown + method twice. When any ROS launch action invokes a RosAdapter, it + triggers the following exception: "Cannot shutdown a ROS adapter that is + not running." + To temporarily work around this issue, you can launch gz_sim_launch.py + with the on_exit_shutdown argument set to an empty string. This prevents + the erroneous shutdown sequence and avoids the associated exception. +* Name gazebo sim node (`#611 `_) +* Contributors: Carlos Agüero, Ignacio Vizzo, Nabeel Sherazi + +2.1.0 (2024-09-12) +------------------ +* Change world_string to model_string in gz_spawn_model files (`#606 `_) + * Change world_string to model_string + Also changed description from XML string to XML(SDF) string +* Use model string in ros_gz_spawn_model.launch.py (`#605 `_) +* Remove default_value for required arguments (`#602 `_) + * Remove default_value for config_file +* Fix errors with name of bridge not being given (`#600 `_) + * Add argument bridge_name to fix errors +* Restore launch file (`#603 `_) +* Use optional parameters in actions (`#601 `_) +* Contributors: Amronos, Carlos Agüero + +2.0.1 (2024-08-29) +------------------ +* Wait for create service to be available. (`#588 `_) +* Contributors: Sebastian Kasperski + +2.0.0 (2024-07-22) +------------------ +* Making use_composition true by default (`#578 `_) +* Contributors: Addisu Z. Taddese + +1.0.1 (2024-07-03) +------------------ +* Merge pull request `#571 `_ from azeey/jazzy_to_ros2 + Merge jazzy ➡️ ros2 +* Merge jazzy into ros2 +* Merge pull request `#569 `_ from azeey/iron_to_jazzy + Merge iron ➡️ jazzy +* Merge remote-tracking branch 'origin/jazzy' into iron_to_jazzy +* Add a ROS node that runs Gazebo (`#500 `_) (`#567 `_) + * Add gzserver with ability to load an SDF file or string + --------- + (cherry picked from commit 92a2891f4adf35e4a4119aca2447dee93e22a06a) + Co-authored-by: Addisu Z. Taddese +* Merge iron into jazzy +* Merge pull request `#564 `_ from azeey/humble_to_iron + Humble ➡️ Iron +* Merge humble -> iron +* Update launch files with name parameter (`#556 `_) + * Name is required. +* Launch gz_spawn_model from xml (`#551 `_) + Spawn models from XML. + Co-authored-by: Addisu Z. Taddese +* Launch ros_gz_bridge from xml (`#550 `_) + * Add gzserver with ability to load an SDF file or string +* Launch gzserver and the bridge as composable nodes (`#528 `_) + * Add gzserver with ability to load an SDF file or string +* Add a ROS node that runs Gazebo (`#500 `_) + * Add gzserver with ability to load an SDF file or string + --------- +* Prepare for 1.0.0 Release (`#495 `_) +* Use gz_vendor packages (`#531 `_) +* 0.244.14 +* Changelog +* ign to gz (`#519 `_) +* Support `` in `package.xml` exports (`#492 `_) +>>>>>>> 63b651a (Garden EOL (#662)) This copies the implementation from `gazebo_ros_paths.py` to provide a way for packages to set resource paths from `package.xml`. ``` @@ -22,6 +110,7 @@ Changelog for package ros_gz_sim 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` --------- +<<<<<<< HEAD * Contributors: Addisu Z. Taddese 0.244.13 (2024-01-23) @@ -35,6 +124,91 @@ Changelog for package ros_gz_sim 0.244.11 (2023-05-23) --------------------- +======= +* Undeprecate use of commandline flags (`#491 `_) +* 0.244.13 +* Changelog +* Remove deprecations using ros_gz_sim_create (`#476 `_) +* Added support for using ROS 2 parameters to spawn entities in Gazebo using ros_gz_sim::create (`#475 `_) +* Fix bug in `create` where command line arguments were truncated (`#472 `_) +* 0.244.12 +* Changelog +* Filter ROS arguments before gflags parsing (`#453 `_) +* 0.246.0 +* Update changelogs +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* Replace deprecated ign_find_package with gz_find_package (`#432 `_) + Co-authored-by: jmackay2 +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* set on_exit_shutdown argument for gz-sim ExecuteProcess (`#355 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Ayush Singh, Carlos Agüero, Jose Luis Rivero, Michael Carroll, ahcorde, andermi, jmackay2, mergify[bot] + +1.0.0 (2024-04-24) +------------------ +* Use gz_vendor packages (`#531 `_) +* ign to gz (`#519 `_) +* Undeprecate use of commandline flags (`#491 `_) +* Remove deprecations using ros_gz_sim_create (`#476 `_) +* Added support for using ROS 2 parameters to spawn entities in Gazebo using ros_gz_sim::create (`#475 `_) +* Fix bug in `create` where command line arguments were truncated (`#472 `_) +* Filter ROS arguments before gflags parsing (`#453 `_) +* Contributors: Addisu Z. Taddese, Alejandro Hernández Cordero, Ayush Singh, Michael Carroll + +0.246.0 (2023-08-31) +-------------------- +* Add harmonic CI (`#447 `_) + * Add harmonic CI + * Include garden options + * Add harmonic stanza + * Additional message headers + --------- +* Replace deprecated ign_find_package with gz_find_package (`#432 `_) + Co-authored-by: jmackay2 +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* set on_exit_shutdown argument for gz-sim ExecuteProcess (`#355 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Aditya Pande, Alejandro Hernández Cordero, Michael Carroll, ahcorde, andermi, jmackay2 + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Alejandro Hernández Cordero, Michael Carroll, ahcorde + +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz_sim/CMakeLists.txt b/ros_gz_sim/CMakeLists.txt index 29d2ea28..0b06fe3f 100644 --- a/ros_gz_sim/CMakeLists.txt +++ b/ros_gz_sim/CMakeLists.txt @@ -12,6 +12,7 @@ endif() find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) +<<<<<<< HEAD find_package(std_msgs REQUIRED) # TODO(CH3): Deprecated. Remove on tock. @@ -94,12 +95,36 @@ else() ign_find_package(${ARGV}) endmacro() endif() +======= +find_package(rclcpp_components REQUIRED) +find_package(std_msgs REQUIRED) + +find_package(gz_math_vendor REQUIRED) +find_package(gz-math REQUIRED) + +find_package(gz_transport_vendor REQUIRED) +find_package(gz-transport REQUIRED) + +find_package(gz_msgs_vendor REQUIRED) +find_package(gz-msgs REQUIRED) + +find_package(gz_sim_vendor REQUIRED) +find_package(gz-sim REQUIRED) +# Needed in launch/gz_sim.launch.py.in +set(GZ_SIM_VER ${gz-sim_VERSION_MAJOR}) +>>>>>>> 63b651a (Garden EOL (#662)) gz_find_package(gflags REQUIRED PKGCONFIG gflags) find_package(std_msgs REQUIRED) +<<<<<<< HEAD +======= +# Install the python module for this package +ament_python_install_package(${PROJECT_NAME}) + +>>>>>>> 63b651a (Garden EOL (#662)) add_executable(create src/create.cpp) ament_target_dependencies(create rclcpp @@ -107,11 +132,29 @@ ament_target_dependencies(create ) target_link_libraries(create gflags +<<<<<<< HEAD ${GZ_TARGET_PREFIX}-math${GZ_MATH_VER}::core ${GZ_TARGET_PREFIX}-msgs${GZ_MSGS_VER}::core ${GZ_TARGET_PREFIX}-transport${GZ_TRANSPORT_VER}::core ) ament_target_dependencies(create std_msgs) +======= + gz-math::core + gz-msgs::core + gz-transport::core +) + +add_executable(remove src/remove.cpp) +ament_target_dependencies(remove + rclcpp + std_msgs +) + +target_link_libraries(remove + gz-msgs::core + gz-transport::core +) +>>>>>>> 63b651a (Garden EOL (#662)) add_library(${PROJECT_NAME} SHARED src/Stopwatch.cpp) ament_target_dependencies(${PROJECT_NAME} @@ -127,6 +170,26 @@ install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION include/${PROJECT_NAME} ) +<<<<<<< HEAD +======= +add_library(gzserver_component SHARED src/gzserver.cpp) +rclcpp_components_register_nodes(gzserver_component "ros_gz_sim::GzServer") +ament_target_dependencies(gzserver_component + rclcpp + rclcpp_components + std_msgs +) +target_link_libraries(gzserver_component + gz-sim::core +) +ament_target_dependencies(gzserver_component std_msgs) +rclcpp_components_register_node( + gzserver_component + PLUGIN "ros_gz_sim::GzServer" + EXECUTABLE gzserver +) + +>>>>>>> 63b651a (Garden EOL (#662)) configure_file( launch/gz_sim.launch.py.in launch/gz_sim.launch.py.configured @@ -142,11 +205,45 @@ install(FILES DESTINATION share/${PROJECT_NAME}/launch ) +<<<<<<< HEAD install(TARGETS create DESTINATION lib/${PROJECT_NAME} ) +======= +install(FILES + "launch/gz_server.launch" + "launch/gz_server.launch.py" + "launch/gz_spawn_model.launch" + "launch/gz_spawn_model.launch.py" + "launch/ros_gz_sim.launch" + "launch/ros_gz_sim.launch.py" + "launch/ros_gz_spawn_model.launch.py" + "launch/gz_remove_model.launch.py" + DESTINATION share/${PROJECT_NAME}/launch +) + +install(TARGETS + create + remove + DESTINATION lib/${PROJECT_NAME} +) + +install(TARGETS + gzserver + DESTINATION lib/${PROJECT_NAME} +) + +ament_export_targets(export_gzserver_component) +install(TARGETS gzserver_component + EXPORT export_gzserver_component + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +>>>>>>> 63b651a (Garden EOL (#662)) install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} ARCHIVE DESTINATION lib @@ -164,11 +261,25 @@ if(BUILD_TESTING) # GTest find_package(ament_cmake_gtest REQUIRED) +<<<<<<< HEAD +======= + find_package(launch_testing_ament_cmake REQUIRED) +>>>>>>> 63b651a (Garden EOL (#662)) ament_find_gtest() ament_add_gtest_executable(test_stopwatch test/test_stopwatch.cpp ) +<<<<<<< HEAD +======= + ament_add_gtest_executable(test_create + test/test_create.cpp + ) + + ament_add_gtest_executable(test_remove + test/test_remove.cpp + ) +>>>>>>> 63b651a (Garden EOL (#662)) ament_target_dependencies(test_stopwatch rclcpp) @@ -180,12 +291,30 @@ if(BUILD_TESTING) target_link_libraries(test_stopwatch ${PROJECT_NAME} ) +<<<<<<< HEAD install( TARGETS test_stopwatch DESTINATION lib/${PROJECT_NAME} ) ament_add_gtest_test(test_stopwatch) +======= + target_link_libraries(test_create + gz-transport::core + ) + + target_link_libraries(test_remove + gz-transport::core + ) + + install( + TARGETS test_stopwatch test_create test_remove + DESTINATION lib/${PROJECT_NAME} + ) + ament_add_gtest_test(test_stopwatch) + add_launch_test(test/test_create_node.launch.py TIMEOUT 200) + add_launch_test(test/test_remove_node.launch.py TIMEOUT 200) +>>>>>>> 63b651a (Garden EOL (#662)) endif() ament_package() diff --git a/ros_gz_sim/README.md b/ros_gz_sim/README.md index e0b05f62..3b859f12 100644 --- a/ros_gz_sim/README.md +++ b/ros_gz_sim/README.md @@ -29,7 +29,11 @@ ros2 launch ros_gz_sim gz_sim.launch.py then spawn a model: ``` +<<<<<<< HEAD ros2 run ros_gz_sim create -world default -file 'https://fuel.ignitionrobotics.org/1.0/openrobotics/models/Gazebo' +======= +ros2 run ros_gz_sim create -world default -file 'https://fuel.gazebosim.org/1.0/openrobotics/models/Gazebo' +>>>>>>> 63b651a (Garden EOL (#662)) ``` See more options with: diff --git a/ros_gz_sim/launch/gz_remove_model.launch.py b/ros_gz_sim/launch/gz_remove_model.launch.py new file mode 100644 index 00000000..14dd643a --- /dev/null +++ b/ros_gz_sim/launch/gz_remove_model.launch.py @@ -0,0 +1,50 @@ +# 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. + +"""Launch remove models in gz sim.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration, TextSubstitution +from launch_ros.actions import Node + + +def generate_launch_description(): + + world = LaunchConfiguration('world') + entity_name = LaunchConfiguration('entity_name') + + declare_world_cmd = DeclareLaunchArgument( + 'world', default_value=TextSubstitution(text=''), + description='World name') + declare_entity_name_cmd = DeclareLaunchArgument( + 'entity_name', default_value=TextSubstitution(text=''), + description='SDF filename') + + remove = Node( + package='ros_gz_sim', + executable='remove', + output='screen', + parameters=[{'world': world, 'entity_name': entity_name}], + ) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_world_cmd) + ld.add_action(declare_entity_name_cmd) + ld.add_action(remove) + + return ld diff --git a/ros_gz_sim/launch/gz_server.launch b/ros_gz_sim/launch/gz_server.launch new file mode 100644 index 00000000..6f29648c --- /dev/null +++ b/ros_gz_sim/launch/gz_server.launch @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/ros_gz_sim/launch/gz_server.launch.py b/ros_gz_sim/launch/gz_server.launch.py new file mode 100644 index 00000000..3c231a1d --- /dev/null +++ b/ros_gz_sim/launch/gz_server.launch.py @@ -0,0 +1,61 @@ +# 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. + +"""Launch gz_server in a component container.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration, TextSubstitution +from ros_gz_sim.actions import GzServer + + +def generate_launch_description(): + + declare_world_sdf_file_cmd = DeclareLaunchArgument( + 'world_sdf_file', default_value=TextSubstitution(text=''), + description='Path to the SDF world file') + declare_world_sdf_string_cmd = DeclareLaunchArgument( + 'world_sdf_string', default_value=TextSubstitution(text=''), + description='SDF world string') + declare_container_name_cmd = DeclareLaunchArgument( + 'container_name', default_value='ros_gz_container', + description='Name of container that nodes will load in if use composition',) + declare_create_own_container_cmd = DeclareLaunchArgument( + 'create_own_container', default_value='False', + description='Whether we should start our own ROS container when using composition.',) + declare_use_composition_cmd = DeclareLaunchArgument( + 'use_composition', default_value='False', + description='Use composed bringup if True') + + gz_server_action = GzServer( + world_sdf_file=LaunchConfiguration('world_sdf_file'), + world_sdf_string=LaunchConfiguration('world_sdf_string'), + container_name=LaunchConfiguration('container_name'), + create_own_container=LaunchConfiguration('create_own_container'), + use_composition=LaunchConfiguration('use_composition'), + ) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_world_sdf_file_cmd) + ld.add_action(declare_world_sdf_string_cmd) + ld.add_action(declare_container_name_cmd) + ld.add_action(declare_create_own_container_cmd) + ld.add_action(declare_use_composition_cmd) + # Add the gz_server action + ld.add_action(gz_server_action) + + return ld diff --git a/ros_gz_sim/launch/gz_sim.launch.py.in b/ros_gz_sim/launch/gz_sim.launch.py.in index 8f87fb7d..3570c26e 100644 --- a/ros_gz_sim/launch/gz_sim.launch.py.in +++ b/ros_gz_sim/launch/gz_sim.launch.py.in @@ -87,6 +87,7 @@ def launch_gz(context, *args, **kwargs): plugin_paths, ] ), +<<<<<<< HEAD "IGN_GAZEBO_SYSTEM_PLUGIN_PATH": os.pathsep.join( # TODO(azeey): To support pre-garden. Deprecated. [ environ.get("IGN_GAZEBO_SYSTEM_PLUGIN_PATH", default=""), @@ -94,18 +95,23 @@ def launch_gz(context, *args, **kwargs): plugin_paths, ] ), +======= +>>>>>>> 63b651a (Garden EOL (#662)) "GZ_SIM_RESOURCE_PATH": os.pathsep.join( [ environ.get("GZ_SIM_RESOURCE_PATH", default=""), model_paths, ] ), +<<<<<<< HEAD "IGN_GAZEBO_RESOURCE_PATH": os.pathsep.join( # TODO(azeey): To support pre-garden. Deprecated. [ environ.get("IGN_GAZEBO_RESOURCE_PATH", default=""), model_paths, ] ), +======= +>>>>>>> 63b651a (Garden EOL (#662)) } gz_args = LaunchConfiguration('gz_args').perform(context) @@ -134,13 +140,21 @@ def launch_gz(context, *args, **kwargs): else: debug_prefix = None +<<<<<<< HEAD if on_exit_shutdown: +======= + if on_exit_shutdown != 'false': +>>>>>>> 63b651a (Garden EOL (#662)) on_exit = Shutdown() else: on_exit = None return [ExecuteProcess( cmd=[exec, exec_args, '--force-version', gz_version], +<<<<<<< HEAD +======= + name='gazebo', +>>>>>>> 63b651a (Garden EOL (#662)) output='screen', additional_env=env, shell=True, diff --git a/ros_gz_sim/launch/gz_spawn_model.launch b/ros_gz_sim/launch/gz_spawn_model.launch new file mode 100644 index 00000000..9285ceff --- /dev/null +++ b/ros_gz_sim/launch/gz_spawn_model.launch @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/ros_gz_sim/launch/gz_spawn_model.launch.py b/ros_gz_sim/launch/gz_spawn_model.launch.py new file mode 100644 index 00000000..5fe3ae41 --- /dev/null +++ b/ros_gz_sim/launch/gz_spawn_model.launch.py @@ -0,0 +1,94 @@ +# 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. + +"""Launch create to spawn models in gz sim.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration, TextSubstitution +from launch_ros.actions import Node + + +def generate_launch_description(): + + world = LaunchConfiguration('world') + file = LaunchConfiguration('file') + model_string = LaunchConfiguration('model_string') + topic = LaunchConfiguration('topic') + entity_name = LaunchConfiguration('entity_name') + allow_renaming = LaunchConfiguration('allow_renaming') + x = LaunchConfiguration('x', default='0.0') + y = LaunchConfiguration('y', default='0.0') + z = LaunchConfiguration('z', default='0.0') + roll = LaunchConfiguration('R', default='0.0') + pitch = LaunchConfiguration('P', default='0.0') + yaw = LaunchConfiguration('Y', default='0.0') + + declare_world_cmd = DeclareLaunchArgument( + 'world', default_value=TextSubstitution(text=''), + description='World name') + declare_file_cmd = DeclareLaunchArgument( + 'file', default_value=TextSubstitution(text=''), + description='SDF filename') + declare_model_string_cmd = DeclareLaunchArgument( + 'model_string', + default_value='', + description='XML(SDF) string', + ) + declare_topic_cmd = DeclareLaunchArgument( + 'topic', default_value=TextSubstitution(text=''), + description='Get XML from this topic' + ) + declare_entity_name_cmd = DeclareLaunchArgument( + 'entity_name', default_value=TextSubstitution(text=''), + description='Name of the entity' + ) + declare_allow_renaming_cmd = DeclareLaunchArgument( + 'allow_renaming', default_value='False', + description='Whether the entity allows renaming or not' + ) + + load_nodes = Node( + package='ros_gz_sim', + executable='create', + output='screen', + parameters=[{'world': world, + 'file': file, + 'string': model_string, + 'topic': topic, + 'name': entity_name, + 'allow_renaming': allow_renaming, + 'x': x, + 'y': y, + 'z': z, + 'R': roll, + 'P': pitch, + 'Y': yaw, + }], + ) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_world_cmd) + ld.add_action(declare_file_cmd) + ld.add_action(declare_model_string_cmd) + ld.add_action(declare_topic_cmd) + ld.add_action(declare_entity_name_cmd) + ld.add_action(declare_allow_renaming_cmd) + # Add the actions to launch all of the create nodes + ld.add_action(load_nodes) + + return ld diff --git a/ros_gz_sim/launch/ros_gz_sim.launch b/ros_gz_sim/launch/ros_gz_sim.launch new file mode 100644 index 00000000..e39f10b6 --- /dev/null +++ b/ros_gz_sim/launch/ros_gz_sim.launch @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/ros_gz_sim/launch/ros_gz_sim.launch.py b/ros_gz_sim/launch/ros_gz_sim.launch.py new file mode 100644 index 00000000..1465c44e --- /dev/null +++ b/ros_gz_sim/launch/ros_gz_sim.launch.py @@ -0,0 +1,117 @@ +# 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. + +"""Launch gzsim + ros_gz_bridge in a component container.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration, TextSubstitution +from ros_gz_bridge.actions import RosGzBridge +from ros_gz_sim.actions import GzServer + + +def generate_launch_description(): + + declare_bridge_name_cmd = DeclareLaunchArgument( + 'bridge_name', description='Name of the bridge' + ) + + declare_config_file_cmd = DeclareLaunchArgument( + 'config_file', description='YAML config file' + ) + + declare_container_name_cmd = DeclareLaunchArgument( + 'container_name', + default_value='ros_gz_container', + description='Name of container that nodes will load in if use composition', + ) + + declare_create_own_container_cmd = DeclareLaunchArgument( + 'create_own_container', + default_value='False', + description='Whether we should start a ROS container when using composition.', + ) + + declare_namespace_cmd = DeclareLaunchArgument( + 'namespace', default_value='', description='Top-level namespace' + ) + + declare_use_composition_cmd = DeclareLaunchArgument( + 'use_composition', default_value='False', description='Use composed bringup if True' + ) + + declare_use_respawn_cmd = DeclareLaunchArgument( + 'use_respawn', + default_value='False', + description='Whether to respawn if a node crashes. Applied when composition is disabled.', + ) + + declare_bridge_log_level_cmd = DeclareLaunchArgument( + 'bridge_log_level', default_value='info', description='Bridge log level' + ) + + declare_bridge_params_cmd = DeclareLaunchArgument( + 'bridge_params', default_value='', description='Extra parameters to pass to the bridge.' + ) + + declare_world_sdf_file_cmd = DeclareLaunchArgument( + 'world_sdf_file', default_value=TextSubstitution(text=''), + description='Path to the SDF world file' + ) + + declare_world_sdf_string_cmd = DeclareLaunchArgument( + 'world_sdf_string', default_value=TextSubstitution(text=''), + description='SDF world string' + ) + + gz_server_action = GzServer( + world_sdf_file=LaunchConfiguration('world_sdf_file'), + world_sdf_string=LaunchConfiguration('world_sdf_string'), + container_name=LaunchConfiguration('container_name'), + create_own_container=LaunchConfiguration('create_own_container'), + use_composition=LaunchConfiguration('use_composition'), + ) + + ros_gz_bridge_action = RosGzBridge( + bridge_name=LaunchConfiguration('bridge_name'), + config_file=LaunchConfiguration('config_file'), + container_name=LaunchConfiguration('container_name'), + create_own_container=str(False), + namespace=LaunchConfiguration('namespace'), + use_composition=LaunchConfiguration('use_composition'), + use_respawn=LaunchConfiguration('use_respawn'), + log_level=LaunchConfiguration('bridge_log_level'), + bridge_params=LaunchConfiguration('bridge_params'), + ) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_bridge_name_cmd) + ld.add_action(declare_config_file_cmd) + ld.add_action(declare_container_name_cmd) + ld.add_action(declare_create_own_container_cmd) + ld.add_action(declare_namespace_cmd) + ld.add_action(declare_use_composition_cmd) + ld.add_action(declare_use_respawn_cmd) + ld.add_action(declare_bridge_log_level_cmd) + ld.add_action(declare_bridge_params_cmd) + ld.add_action(declare_world_sdf_file_cmd) + ld.add_action(declare_world_sdf_string_cmd) + # Add the actions to launch all of the bridge + gz_server nodes + ld.add_action(gz_server_action) + ld.add_action(ros_gz_bridge_action) + + return ld diff --git a/ros_gz_sim/launch/ros_gz_spawn_model.launch b/ros_gz_sim/launch/ros_gz_spawn_model.launch new file mode 100644 index 00000000..e465e7cc --- /dev/null +++ b/ros_gz_sim/launch/ros_gz_spawn_model.launch @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ros_gz_sim/launch/ros_gz_spawn_model.launch.py b/ros_gz_sim/launch/ros_gz_spawn_model.launch.py new file mode 100644 index 00000000..2ac684fc --- /dev/null +++ b/ros_gz_sim/launch/ros_gz_spawn_model.launch.py @@ -0,0 +1,174 @@ +# 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. + +"""Launch gzsim + ros_gz_bridge in a component container.""" + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration, PathJoinSubstitution, TextSubstitution +from launch_ros.substitutions import FindPackageShare +from ros_gz_bridge.actions import RosGzBridge + + +def generate_launch_description(): + + bridge_name = LaunchConfiguration('bridge_name') + config_file = LaunchConfiguration('config_file') + container_name = LaunchConfiguration('container_name') + create_own_container = LaunchConfiguration('create_own_container') + namespace = LaunchConfiguration('namespace') + use_composition = LaunchConfiguration('use_composition') + use_respawn = LaunchConfiguration('use_respawn') + log_level = LaunchConfiguration('log_level') + bridge_params = LaunchConfiguration('bridge_params') + + world = LaunchConfiguration('world') + file = LaunchConfiguration('file') + model_string = LaunchConfiguration('model_string') + topic = LaunchConfiguration('topic') + entity_name = LaunchConfiguration('entity_name') + allow_renaming = LaunchConfiguration('allow_renaming') + x = LaunchConfiguration('x', default='0.0') + y = LaunchConfiguration('y', default='0.0') + z = LaunchConfiguration('z', default='0.0') + roll = LaunchConfiguration('R', default='0.0') + pitch = LaunchConfiguration('P', default='0.0') + yaw = LaunchConfiguration('Y', default='0.0') + + declare_bridge_name_cmd = DeclareLaunchArgument( + 'bridge_name', description='Name of the bridge' + ) + + declare_config_file_cmd = DeclareLaunchArgument( + 'config_file', description='YAML config file' + ) + + declare_container_name_cmd = DeclareLaunchArgument( + 'container_name', + default_value='ros_gz_container', + description='Name of container that nodes will load in if use composition', + ) + + declare_create_own_container_cmd = DeclareLaunchArgument( + 'create_own_container', + default_value='False', + description='Whether we should start a ROS container when using composition.', + ) + + declare_namespace_cmd = DeclareLaunchArgument( + 'namespace', default_value='', description='Top-level namespace' + ) + + declare_use_composition_cmd = DeclareLaunchArgument( + 'use_composition', default_value='False', description='Use composed bringup if True' + ) + + declare_use_respawn_cmd = DeclareLaunchArgument( + 'use_respawn', + default_value='False', + description='Whether to respawn if a node crashes. Applied when composition is disabled.', + ) + + declare_log_level_cmd = DeclareLaunchArgument( + 'log_level', default_value='info', description='log level' + ) + + declare_bridge_params_cmd = DeclareLaunchArgument( + 'bridge_params', default_value='', description='Extra parameters to pass to the bridge.' + ) + + declare_world_cmd = DeclareLaunchArgument( + 'world', default_value=TextSubstitution(text=''), + description='World name') + + declare_file_cmd = DeclareLaunchArgument( + 'file', default_value=TextSubstitution(text=''), + description='SDF filename') + + declare_model_string_cmd = DeclareLaunchArgument( + 'model_string', + default_value='', + description='XML(SDF) string', + ) + + declare_topic_cmd = DeclareLaunchArgument( + 'topic', default_value=TextSubstitution(text=''), + description='Get XML from this topic' + ) + + declare_entity_name_cmd = DeclareLaunchArgument( + 'entity_name', default_value=TextSubstitution(text=''), + description='Name of the entity' + ) + + declare_allow_renaming_cmd = DeclareLaunchArgument( + 'allow_renaming', default_value='False', + description='Whether the entity allows renaming or not' + ) + + ros_gz_bridge_action = RosGzBridge( + bridge_name=bridge_name, + config_file=config_file, + container_name=container_name, + create_own_container=create_own_container, + namespace=namespace, + use_composition=use_composition, + use_respawn=use_respawn, + log_level=log_level, + bridge_params=bridge_params, + ) + + spawn_model_description = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [PathJoinSubstitution([FindPackageShare('ros_gz_sim'), + 'launch', + 'gz_spawn_model.launch.py'])]), + launch_arguments=[('world', world), + ('file', file), + ('model_string', model_string), + ('topic', topic), + ('entity_name', entity_name), + ('allow_renaming', allow_renaming), + ('x', x), + ('y', y), + ('z', z), + ('R', roll), + ('P', pitch), + ('Y', yaw), ]) + + # Create the launch description and populate + ld = LaunchDescription() + + # Declare the launch options + ld.add_action(declare_bridge_name_cmd) + ld.add_action(declare_config_file_cmd) + ld.add_action(declare_container_name_cmd) + ld.add_action(declare_create_own_container_cmd) + ld.add_action(declare_namespace_cmd) + ld.add_action(declare_use_composition_cmd) + ld.add_action(declare_use_respawn_cmd) + ld.add_action(declare_log_level_cmd) + ld.add_action(declare_bridge_params_cmd) + ld.add_action(declare_world_cmd) + ld.add_action(declare_file_cmd) + ld.add_action(declare_model_string_cmd) + ld.add_action(declare_topic_cmd) + ld.add_action(declare_entity_name_cmd) + ld.add_action(declare_allow_renaming_cmd) + # Add the actions to launch all of the bridge + spawn_model nodes + ld.add_action(ros_gz_bridge_action) + ld.add_action(spawn_model_description) + + return ld diff --git a/ros_gz_sim/package.xml b/ros_gz_sim/package.xml index 9471bfb3..7485e9eb 100644 --- a/ros_gz_sim/package.xml +++ b/ros_gz_sim/package.xml @@ -2,13 +2,21 @@ ros_gz_sim +<<<<<<< HEAD 0.244.16 Tools for using Gazebo Sim simulation with ROS. Alejandro Hernandez +======= + 2.1.2 + Tools for using Gazebo Sim simulation with ROS. + Alejandro Hernandez + Aditya Pande +>>>>>>> 63b651a (Garden EOL (#662)) Apache 2.0 Alejandro Hernandez +<<<<<<< HEAD ament_cmake pkg-config @@ -37,6 +45,33 @@ ament_lint_auto ament_lint_common +======= + Addisu Taddese + Carlos Agüero + + ament_cmake + ament_cmake_python + pkg-config + + ament_index_python + launch + launch_ros + libgflags-dev + rclcpp + rclcpp_components + std_msgs + + gz_math_vendor + gz_msgs_vendor + gz_sim_vendor + gz_transport_vendor + + ament_lint_auto + ament_lint_common + launch_testing_ament_cmake + launch_ros + launch_testing +>>>>>>> 63b651a (Garden EOL (#662)) ament_cmake diff --git a/ros_gz_sim/resource/ros_gz_sim b/ros_gz_sim/resource/ros_gz_sim new file mode 100644 index 00000000..e69de29b diff --git a/ros_gz_sim/ros_gz_sim/__init__.py b/ros_gz_sim/ros_gz_sim/__init__.py new file mode 100644 index 00000000..17b9696c --- /dev/null +++ b/ros_gz_sim/ros_gz_sim/__init__.py @@ -0,0 +1,22 @@ +# 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. + +"""Main entry point for the `ros_gz_sim` package.""" + +from . import actions + + +__all__ = [ + 'actions', +] diff --git a/ros_gz_sim/ros_gz_sim/actions/__init__.py b/ros_gz_sim/ros_gz_sim/actions/__init__.py new file mode 100644 index 00000000..bea18edd --- /dev/null +++ b/ros_gz_sim/ros_gz_sim/actions/__init__.py @@ -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. + +"""Actions module.""" + +from .gz_spawn_model import GzSpawnModel +from .gzserver import GzServer + + +__all__ = [ + 'GzSpawnModel', + 'GzServer', +] diff --git a/ros_gz_sim/ros_gz_sim/actions/gz_spawn_model.py b/ros_gz_sim/ros_gz_sim/actions/gz_spawn_model.py new file mode 100644 index 00000000..a8fced10 --- /dev/null +++ b/ros_gz_sim/ros_gz_sim/actions/gz_spawn_model.py @@ -0,0 +1,207 @@ +# 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. + +"""Module for the gz_spawn_model action.""" + +from typing import List +from typing import Optional + +from launch.action import Action +from launch.actions import IncludeLaunchDescription +from launch.frontend import Entity, expose_action, Parser +from launch.launch_context import LaunchContext +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.some_substitutions_type import SomeSubstitutionsType +from launch.substitutions import PathJoinSubstitution +from launch_ros.substitutions import FindPackageShare + + +@expose_action('gz_spawn_model') +class GzSpawnModel(Action): + """Action that executes a gz_spawn_model ROS node.""" + + def __init__( + self, + *, + world: Optional[SomeSubstitutionsType] = None, + file: Optional[SomeSubstitutionsType] = None, + model_string: Optional[SomeSubstitutionsType] = None, + topic: Optional[SomeSubstitutionsType] = None, + entity_name: Optional[SomeSubstitutionsType] = None, + allow_renaming: Optional[SomeSubstitutionsType] = None, + x: Optional[SomeSubstitutionsType] = None, + y: Optional[SomeSubstitutionsType] = None, + z: Optional[SomeSubstitutionsType] = None, + roll: Optional[SomeSubstitutionsType] = None, + pitch: Optional[SomeSubstitutionsType] = None, + yaw: Optional[SomeSubstitutionsType] = None, + **kwargs + ) -> None: + """ + Construct a gz_spawn_model action. + + All arguments are forwarded to `ros_gz_sim.launch.gz_spawn_model.launch.py`, + so see the documentation of that class for further details. + + :param: world World name. + :param: file SDF filename. + :param: model_string XML(SDF) string. + :param: topic Get XML from this topic. + :param: entity_name Name of the entity. + :param: allow_renaming Whether the entity allows renaming or not. + :param: x X coordinate. + :param: y Y coordinate. + :param: z Z coordinate. + :param: roll Roll orientation. + :param: pitch Pitch orientation. + :param: yaw Yaw orientation. + """ + super().__init__(**kwargs) + self.__world = world + self.__file = file + self.__model_string = model_string + self.__topic = topic + self.__entity_name = entity_name + self.__allow_renaming = allow_renaming + self.__x = x + self.__y = y + self.__z = z + self.__roll = roll + self.__pitch = pitch + self.__yaw = yaw + + @classmethod + def parse(cls, entity: Entity, parser: Parser): + """Parse gz_spawn_model.""" + _, kwargs = super().parse(entity, parser) + + world = entity.get_attr( + 'world', data_type=str, + optional=True) + + file = entity.get_attr( + 'file', data_type=str, + optional=True) + + model_string = entity.get_attr( + 'model_string', data_type=str, + optional=True) + + topic = entity.get_attr( + 'topic', data_type=str, + optional=True) + + entity_name = entity.get_attr( + 'entity_name', data_type=str, + optional=True) + + allow_renaming = entity.get_attr( + 'allow_renaming', data_type=str, + optional=True) + + x = entity.get_attr( + 'x', data_type=str, + optional=True) + + y = entity.get_attr( + 'y', data_type=str, + optional=True) + + z = entity.get_attr( + 'z', data_type=str, + optional=True) + + roll = entity.get_attr( + 'roll', data_type=str, + optional=True) + + pitch = entity.get_attr( + 'pitch', data_type=str, + optional=True) + + yaw = entity.get_attr( + 'yaw', data_type=str, + optional=True) + + if isinstance(world, str): + world = parser.parse_substitution(world) + kwargs['world'] = world + + if isinstance(file, str): + file = parser.parse_substitution(file) + kwargs['file'] = file + + if isinstance(model_string, str): + model_string = parser.parse_substitution(model_string) + kwargs['model_string'] = model_string + + if isinstance(topic, str): + topic = parser.parse_substitution(topic) + kwargs['topic'] = topic + + if isinstance(entity_name, str): + entity_name = parser.parse_substitution(entity_name) + kwargs['entity_name'] = entity_name + + if isinstance(allow_renaming, str): + allow_renaming = parser.parse_substitution(allow_renaming) + kwargs['allow_renaming'] = allow_renaming + + if isinstance(x, str): + x = parser.parse_substitution(x) + kwargs['x'] = x + + if isinstance(y, str): + y = parser.parse_substitution(y) + kwargs['y'] = y + + if isinstance(z, str): + z = parser.parse_substitution(z) + kwargs['z'] = z + + if isinstance(roll, str): + roll = parser.parse_substitution(roll) + kwargs['roll'] = roll + + if isinstance(pitch, str): + pitch = parser.parse_substitution(pitch) + kwargs['pitch'] = pitch + + if isinstance(yaw, str): + yaw = parser.parse_substitution(yaw) + kwargs['yaw'] = yaw + + return cls, kwargs + + def execute(self, context: LaunchContext) -> Optional[List[Action]]: + """Execute the action.""" + gz_spawn_model_description = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [PathJoinSubstitution([FindPackageShare('ros_gz_sim'), + 'launch', + 'gz_spawn_model.launch.py'])]), + launch_arguments=[('world', self.__world), + ('file', self.__file), + ('model_string', self.__model_string), + ('topic', self.__topic), + ('entity_name', self.__entity_name), + ('allow_renaming', self.__allow_renaming), + ('x', self.__x), + ('y', self.__y), + ('z', self.__z), + ('roll', self.__roll), + ('pitch', self.__pitch), + ('yaw', self.__yaw), ]) + + return [gz_spawn_model_description] diff --git a/ros_gz_sim/ros_gz_sim/actions/gzserver.py b/ros_gz_sim/ros_gz_sim/actions/gzserver.py new file mode 100644 index 00000000..c8b33c3a --- /dev/null +++ b/ros_gz_sim/ros_gz_sim/actions/gzserver.py @@ -0,0 +1,253 @@ +# 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. + +"""Module for the GzServer action.""" + +import os +from typing import List +from typing import Optional + +from ament_index_python.packages import get_package_share_directory +from catkin_pkg.package import InvalidPackage, PACKAGE_MANIFEST_FILENAME, parse_package +from launch.action import Action +from launch.actions import GroupAction, SetEnvironmentVariable +from launch.conditions import IfCondition +from launch.frontend import Entity, expose_action, Parser +from launch.launch_context import LaunchContext +from launch.some_substitutions_type import SomeSubstitutionsType +from launch.substitutions import PythonExpression +from launch_ros.actions import ComposableNodeContainer, LoadComposableNodes, Node +from launch_ros.descriptions import ComposableNode +from ros2pkg.api import get_package_names + + +""" +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 + + +@expose_action('gz_server') +class GzServer(Action): + """Action that executes a gz_server ROS [composable] node.""" + + def __init__( + self, + *, + world_sdf_file: Optional[SomeSubstitutionsType] = '', + world_sdf_string: Optional[SomeSubstitutionsType] = '', + container_name: Optional[SomeSubstitutionsType] = 'ros_gz_container', + create_own_container: Optional[SomeSubstitutionsType] = 'False', + use_composition: Optional[SomeSubstitutionsType] = 'False', + **kwargs + ) -> None: + """ + Construct a gz_server action. + + All arguments are forwarded to `ros_gz_sim.launch.gz_server.launch.py`, + so see the documentation of that class for further details. + + :param: world_sdf_file Path to the SDF world file. + :param: world_sdf_string SDF world string. + :param: container_name Name of container that nodes will load in if use composition. + :param: create_own_container Whether to start a ROS container when using composition. + :param: use_composition Use composed bringup if True. + """ + super().__init__(**kwargs) + self.__world_sdf_file = world_sdf_file + self.__world_sdf_string = world_sdf_string + self.__container_name = container_name + self.__create_own_container = create_own_container + self.__use_composition = use_composition + + @classmethod + def parse(cls, entity: Entity, parser: Parser): + """Parse gz_server.""" + _, kwargs = super().parse(entity, parser) + + world_sdf_file = entity.get_attr( + 'world_sdf_file', data_type=str, + optional=True) + + world_sdf_string = entity.get_attr( + 'world_sdf_string', data_type=str, + optional=True) + + container_name = entity.get_attr( + 'container_name', data_type=str, + optional=True) + + create_own_container = entity.get_attr( + 'create_own_container', data_type=str, + optional=True) + + use_composition = entity.get_attr( + 'use_composition', data_type=str, + optional=True) + + if isinstance(world_sdf_file, str): + world_sdf_file = parser.parse_substitution(world_sdf_file) + kwargs['world_sdf_file'] = world_sdf_file + + if isinstance(world_sdf_string, str): + world_sdf_string = parser.parse_substitution(world_sdf_string) + kwargs['world_sdf_string'] = world_sdf_string + + if isinstance(container_name, str): + container_name = parser.parse_substitution(container_name) + kwargs['container_name'] = container_name + + if isinstance(create_own_container, str): + create_own_container = \ + parser.parse_substitution(create_own_container) + kwargs['create_own_container'] = create_own_container + + if isinstance(use_composition, str): + use_composition = parser.parse_substitution(use_composition) + kwargs['use_composition'] = use_composition + + return cls, kwargs + + def execute(self, context: LaunchContext) -> Optional[List[Action]]: + """Execute the action.""" + if isinstance(self.__use_composition, list): + self.__use_composition = self.__use_composition[0] + + if isinstance(self.__create_own_container, list): + self.__create_own_container = self.__create_own_container[0] + + model_paths, plugin_paths = GazeboRosPaths.get_paths() + system_plugin_path_env = SetEnvironmentVariable( + 'GZ_SIM_SYSTEM_PLUGIN_PATH', + os.pathsep.join([ + os.environ.get('GZ_SIM_SYSTEM_PLUGIN_PATH', default=''), + os.environ.get('LD_LIBRARY_PATH', default=''), + plugin_paths, + ])) + resource_path_env = SetEnvironmentVariable( + 'GZ_SIM_RESOURCE_PATH', + os.pathsep.join([ + os.environ.get('GZ_SIM_RESOURCE_PATH', default=''), + model_paths, + ])) + + # Standard node configuration + load_nodes = GroupAction( + condition=IfCondition(PythonExpression(['not ', self.__use_composition])), + actions=[ + Node( + package='ros_gz_sim', + executable='gzserver', + output='screen', + parameters=[{'world_sdf_file': self.__world_sdf_file, + 'world_sdf_string': self.__world_sdf_string}], + ), + ], + ) + + # Composable node with container configuration + load_composable_nodes_with_container = ComposableNodeContainer( + condition=IfCondition( + PythonExpression([self.__use_composition, ' and ', self.__create_own_container]) + ), + name=self.__container_name, + namespace='', + package='rclcpp_components', + executable='component_container', + composable_node_descriptions=[ + ComposableNode( + package='ros_gz_sim', + plugin='ros_gz_sim::GzServer', + name='gz_server', + parameters=[{'world_sdf_file': self.__world_sdf_file, + 'world_sdf_string': self.__world_sdf_string}], + extra_arguments=[{'use_intra_process_comms': True}], + ), + ], + output='screen', + ) + + # Composable node without container configuration + load_composable_nodes_without_container = LoadComposableNodes( + condition=IfCondition( + PythonExpression( + [self.__use_composition, ' and not ', self.__create_own_container] + ) + ), + target_container=self.__container_name, + composable_node_descriptions=[ + ComposableNode( + package='ros_gz_sim', + plugin='ros_gz_sim::GzServer', + name='gz_server', + parameters=[{'world_sdf_file': self.__world_sdf_file, + 'world_sdf_string': self.__world_sdf_string}], + extra_arguments=[{'use_intra_process_comms': True}], + ), + ], + ) + + return [ + system_plugin_path_env, + resource_path_env, + load_nodes, + load_composable_nodes_with_container, + load_composable_nodes_without_container + ] diff --git a/ros_gz_sim/setup.cfg b/ros_gz_sim/setup.cfg new file mode 100644 index 00000000..c044b41d --- /dev/null +++ b/ros_gz_sim/setup.cfg @@ -0,0 +1,3 @@ +[options.entry_points] +launch.frontend.launch_extension = + ros_gz_sim = ros_gz_sim diff --git a/ros_gz_sim/src/create.cpp b/ros_gz_sim/src/create.cpp index 6b12daf8..3095b2f9 100644 --- a/ros_gz_sim/src/create.cpp +++ b/ros_gz_sim/src/create.cpp @@ -21,6 +21,13 @@ #include #include +<<<<<<< HEAD +======= +#include +#include +#include +#include +>>>>>>> 63b651a (Garden EOL (#662)) #include #include @@ -29,7 +36,15 @@ #include #include +<<<<<<< HEAD +======= +// ROS interface for spawning entities into Gazebo. +// Suggested for use with roslaunch and loading entities from ROS param. +// If these are not needed, just use the `gz service` command line instead. + +// \TODO(anyone) Remove GFlags in ROS-J +>>>>>>> 63b651a (Garden EOL (#662)) DEFINE_string(world, "", "World name."); DEFINE_string(file, "", "Load XML from a file."); DEFINE_string(param, "", "Load XML from a ROS param."); @@ -44,6 +59,7 @@ DEFINE_double(R, 0, "Roll component of initial orientation, in radians."); DEFINE_double(P, 0, "Pitch component of initial orientation, in radians."); DEFINE_double(Y, 0, "Yaw component of initial orientation, in radians."); +<<<<<<< HEAD // ROS interface for spawning entities into Gazebo. // Suggested for use with roslaunch and loading entities from ROS param. // If these are not needed, just use the `gz service` command line instead. @@ -52,15 +68,103 @@ int main(int _argc, char ** _argv) rclcpp::init(_argc, _argv); auto ros2_node = rclcpp::Node::make_shared("ros_gz_sim"); +======= +// Utility Function to avoid code duplication + +bool set_XML_from_topic( + const std::string & topic_name, const rclcpp::Node::SharedPtr ros2_node, + gz::msgs::EntityFactory & req) +{ + const auto timeout = std::chrono::seconds(1); + std::promise xml_promise; + std::shared_future xml_future(xml_promise.get_future()); + + std::function fun = + [&xml_promise](const std_msgs::msg::String::SharedPtr msg) { + xml_promise.set_value(msg->data); + }; + + rclcpp::executors::SingleThreadedExecutor executor; + executor.add_node(ros2_node); + rclcpp::Subscription::SharedPtr description_subs; + // Transient local is similar to latching in ROS 1. + description_subs = ros2_node->create_subscription( + topic_name, rclcpp::QoS(1).transient_local(), fun); + + rclcpp::FutureReturnCode future_ret; + do { + RCLCPP_INFO(ros2_node->get_logger(), "Waiting messages on topic [%s].", topic_name.c_str()); + future_ret = executor.spin_until_future_complete(xml_future, timeout); + } while (rclcpp::ok() && future_ret != rclcpp::FutureReturnCode::SUCCESS); + + if (future_ret == rclcpp::FutureReturnCode::SUCCESS) { + req.set_sdf(xml_future.get()); + return true; + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Failed to get XML from topic [%s].", topic_name.c_str()); + return false; + } +} + +int main(int _argc, char ** _argv) +{ + auto filtered_arguments = rclcpp::init_and_remove_ros_arguments(_argc, _argv); + auto ros2_node = rclcpp::Node::make_shared("ros_gz_sim"); + + // Construct a new argc/argv pair from the flags that weren't parsed by ROS + // Gflags wants a mutable pointer to argv, which is why we can't use a + // vector of strings here + int filtered_argc = filtered_arguments.size(); + char ** filtered_argv = new char *[(filtered_argc + 1)]; + for (int ii = 0; ii < filtered_argc; ++ii) { + filtered_argv[ii] = new char[filtered_arguments[ii].size() + 1]; + snprintf( + filtered_argv[ii], + filtered_arguments[ii].size() + 1, "%s", filtered_arguments[ii].c_str()); + } + filtered_argv[filtered_argc] = nullptr; + +>>>>>>> 63b651a (Garden EOL (#662)) gflags::AllowCommandLineReparsing(); gflags::SetUsageMessage( R"(Usage: create -world [arg] [-file FILE] [-param PARAM] [-topic TOPIC] [-string STRING] [-name NAME] [-allow_renaming RENAMING] [-x X] [-y Y] [-z Z] [-R ROLL] [-P PITCH] [-Y YAW])"); +<<<<<<< HEAD gflags::ParseCommandLineFlags(&_argc, &_argv, true); // World std::string world_name = FLAGS_world; +======= + gflags::ParseCommandLineFlags(&filtered_argc, &filtered_argv, false); + + // Free our temporary argc/argv pair + for (size_t ii = 0; filtered_argv[ii] != nullptr; ++ii) { + delete[] filtered_argv[ii]; + } + delete[] filtered_argv; + + // Declare ROS 2 parameters to be passed from launch file + ros2_node->declare_parameter("world", ""); + ros2_node->declare_parameter("file", ""); + ros2_node->declare_parameter("string", ""); + ros2_node->declare_parameter("topic", ""); + ros2_node->declare_parameter("name", ""); + ros2_node->declare_parameter("allow_renaming", false); + ros2_node->declare_parameter("x", static_cast(0)); + ros2_node->declare_parameter("y", static_cast(0)); + ros2_node->declare_parameter("z", static_cast(0)); + ros2_node->declare_parameter("R", static_cast(0)); + ros2_node->declare_parameter("P", static_cast(0)); + ros2_node->declare_parameter("Y", static_cast(0)); + + // World + std::string world_name = ros2_node->get_parameter("world").as_string(); + if (world_name.empty() && !FLAGS_world.empty()) { + world_name = FLAGS_world; + } +>>>>>>> 63b651a (Garden EOL (#662)) if (world_name.empty()) { // If caller doesn't provide a world name, get list of worlds from gz-sim server gz::transport::Node node; @@ -94,6 +198,7 @@ int main(int _argc, char ** _argv) // Request message gz::msgs::EntityFactory req; +<<<<<<< HEAD // File if (!FLAGS_file.empty()) { req.set_sdf_filename(FLAGS_file); @@ -142,14 +247,79 @@ int main(int _argc, char ** _argv) } } else { RCLCPP_ERROR(ros2_node->get_logger(), "Must specify either -file, -param, -stdin or -topic"); +======= + // Get ROS parameters + std::string file_name = ros2_node->get_parameter("file").as_string(); + std::string xml_string = ros2_node->get_parameter("string").as_string(); + std::string topic_name = ros2_node->get_parameter("topic").as_string(); + // Check for the SDF filename or XML string or topic name + if (!file_name.empty()) { + req.set_sdf_filename(file_name); + } else if (!xml_string.empty()) { + req.set_sdf(xml_string); + } else if (!topic_name.empty()) { + // set XML string by fetching it from the given topic + if (!set_XML_from_topic(topic_name, ros2_node, req)) { + return -1; + } + } else if (filtered_arguments.size() > 1) { + // Revert to Gflags, if ROS parameters aren't specified + // File + if (!FLAGS_file.empty()) { + req.set_sdf_filename(FLAGS_file); + } else if (!FLAGS_param.empty()) { // Param + ros2_node->declare_parameter(FLAGS_param); + std::string xmlStr; + if (ros2_node->get_parameter(FLAGS_param, xmlStr)) { + req.set_sdf(xmlStr); + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Failed to get XML from param [%s].", FLAGS_param.c_str()); + return -1; + } + } else if (!FLAGS_string.empty()) { // string + req.set_sdf(FLAGS_string); + } else if (!FLAGS_topic.empty()) { // topic + // set XML string by fetching it from the given topic + if (!set_XML_from_topic(FLAGS_topic, ros2_node, req)) { + return -1; + } + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Must specify either -file, -param, -string or -topic"); + return -1; + } + // TODO(azeey) Deprecate use of command line flags in ROS 2 K-turtle in + // favor of ROS 2 parameters. + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Must specify either file, string or topic as ROS 2 parameters"); +>>>>>>> 63b651a (Garden EOL (#662)) return -1; } // Pose +<<<<<<< HEAD +======= + double x_coords = ros2_node->get_parameter("x").as_double(); + double y_coords = ros2_node->get_parameter("y").as_double(); + double z_coords = ros2_node->get_parameter("z").as_double(); + double roll = ros2_node->get_parameter("R").as_double(); + double pitch = ros2_node->get_parameter("P").as_double(); + double yaw = ros2_node->get_parameter("Y").as_double(); + + FLAGS_x = (x_coords != 0.0) ? x_coords : FLAGS_x; + FLAGS_y = (y_coords != 0.0) ? y_coords : FLAGS_y; + FLAGS_z = (z_coords != 0.0) ? z_coords : FLAGS_z; + FLAGS_R = (roll != 0.0) ? roll : FLAGS_R; + FLAGS_P = (pitch != 0.0) ? pitch : FLAGS_P; + FLAGS_Y = (yaw != 0.0) ? yaw : FLAGS_Y; +>>>>>>> 63b651a (Garden EOL (#662)) gz::math::Pose3d pose{FLAGS_x, FLAGS_y, FLAGS_z, FLAGS_R, FLAGS_P, FLAGS_Y}; gz::msgs::Set(req.mutable_pose(), pose); // Name +<<<<<<< HEAD if (!FLAGS_name.empty()) { req.set_name(FLAGS_name); } @@ -157,12 +327,25 @@ int main(int _argc, char ** _argv) if (FLAGS_allow_renaming) { req.set_allow_renaming(FLAGS_allow_renaming); } +======= + std::string entity_name = ros2_node->get_parameter("name").as_string(); + if (!entity_name.empty()) { + req.set_name(entity_name); + } else { + req.set_name(FLAGS_name); + } + + // Allow Renaming + bool allow_renaming = ros2_node->get_parameter("allow_renaming").as_bool(); + req.set_allow_renaming((allow_renaming || FLAGS_allow_renaming)); +>>>>>>> 63b651a (Garden EOL (#662)) // Request gz::transport::Node node; gz::msgs::Boolean rep; bool result; unsigned int timeout = 5000; +<<<<<<< HEAD bool executed = node.Request(service, req, timeout, rep, result); if (executed) { @@ -180,5 +363,26 @@ int main(int _argc, char ** _argv) } RCLCPP_INFO(ros2_node->get_logger(), "OK creation of entity."); +======= + + while(rclcpp::ok()) { + if (node.Request(service, req, timeout, rep, result)) { + if (result && rep.data()) { + RCLCPP_INFO(ros2_node->get_logger(), "Entity creation successfull."); + return 0; + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Entity creation failed.\n %s", + req.DebugString().c_str()); + return 1; + } + } else { + RCLCPP_WARN( + ros2_node->get_logger(), "Waiting for service [%s] to become available ...", + service.c_str()); + } + } + RCLCPP_INFO(ros2_node->get_logger(), "Entity creation was interrupted."); +>>>>>>> 63b651a (Garden EOL (#662)) return 0; } diff --git a/ros_gz_sim/src/gzserver.cpp b/ros_gz_sim/src/gzserver.cpp new file mode 100644 index 00000000..aa4361f5 --- /dev/null +++ b/ros_gz_sim/src/gzserver.cpp @@ -0,0 +1,80 @@ +// 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 +#include +#include +#include +#include +#include +#include + +// ROS node that executes a gz-sim Server given a world SDF file or string. +namespace ros_gz_sim +{ +class GzServer : public rclcpp::Node +{ +public: + // Class constructor. + explicit GzServer(const rclcpp::NodeOptions & options) + : Node("gzserver", options) + { + thread_ = std::thread(std::bind(&GzServer::OnStart, this)); + } + +public: + // Class destructor. + ~GzServer() + { + // Make sure to join the thread on shutdown. + if (thread_.joinable()) { + thread_.join(); + } + } + +public: + /// \brief Run the gz sim server. + void OnStart() + { + auto world_sdf_file = this->declare_parameter("world_sdf_file", ""); + auto world_sdf_string = this->declare_parameter("world_sdf_string", ""); + + gz::common::Console::SetVerbosity(4); + gz::sim::ServerConfig server_config; + + if (!world_sdf_file.empty()) { + server_config.SetSdfFile(world_sdf_file); + } else if (!world_sdf_string.empty()) { + server_config.SetSdfString(world_sdf_string); + } else { + RCLCPP_ERROR( + this->get_logger(), + "Must specify either 'world_sdf_file' or 'world_sdf_string'"); + rclcpp::shutdown(); + return; + } + + gz::sim::Server server(server_config); + server.Run(true /*blocking*/, 0, false /*paused*/); + rclcpp::shutdown(); + } + +private: + /// \brief We don't want to block the ROS thread. + std::thread thread_; +}; +} // namespace ros_gz_sim + +RCLCPP_COMPONENTS_REGISTER_NODE(ros_gz_sim::GzServer) diff --git a/ros_gz_sim/src/remove.cpp b/ros_gz_sim/src/remove.cpp new file mode 100644 index 00000000..43df1758 --- /dev/null +++ b/ros_gz_sim/src/remove.cpp @@ -0,0 +1,110 @@ +// 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 +#include + +#include +#include +#include + +#include +#include + + +constexpr unsigned int timeout{5000}; +std::optional retrieve_world_name(const rclcpp::Node::SharedPtr & ros2_node) +{ + gz::transport::Node node; + bool executed{}; + bool result{}; + const std::string service{"/gazebo/worlds"}; + gz::msgs::StringMsg_V worlds_msg; + + // This loop is here to allow the server time to download resources. + while (rclcpp::ok() && !executed) { + RCLCPP_INFO(ros2_node->get_logger(), "Requesting list of world names."); + executed = node.Request(service, timeout, worlds_msg, result); + } + + if (!executed) { + RCLCPP_INFO(ros2_node->get_logger(), "Timed out when getting world names."); + return std::nullopt; + } + + if (!result || worlds_msg.data().empty()) { + RCLCPP_INFO(ros2_node->get_logger(), "Failed to get world names."); + return std::nullopt; + } + + return worlds_msg.data(0); +} + +int remove_entity( + const std::string & entity_name, + const std::string & world_name, + const rclcpp::Node::SharedPtr & ros2_node) +{ + const std::string service{"/world/" + world_name + "/remove"}; + gz::msgs::Entity entity_remove_request; + entity_remove_request.set_name(entity_name); + entity_remove_request.set_type(gz::msgs::Entity_Type_MODEL); + gz::transport::Node node; + gz::msgs::Boolean response; + bool result; + + while(rclcpp::ok() && !node.Request(service, entity_remove_request, timeout, response, result)) { + RCLCPP_WARN( + ros2_node->get_logger(), "Waiting for service [%s] to become available ...", + service.c_str()); + } + if (result && response.data()) { + RCLCPP_INFO(ros2_node->get_logger(), "Entity removal successful."); + return 0; + } else { + RCLCPP_ERROR( + ros2_node->get_logger(), "Entity removal failed.\n %s", + entity_remove_request.DebugString().c_str()); + return 1; + } + RCLCPP_INFO(ros2_node->get_logger(), "Entity removal was interrupted."); + return 1; +} + +int main(int _argc, char ** _argv) +{ + rclcpp::init(_argc, _argv); + auto ros2_node = rclcpp::Node::make_shared("ros_gz_sim_remove_entity"); + ros2_node->declare_parameter("world", ""); + ros2_node->declare_parameter("entity_name", ""); + + std::string world_name = ros2_node->get_parameter("world").as_string(); + if (world_name.empty()) { + world_name = retrieve_world_name(ros2_node).value_or(""); + if (world_name.empty()) { + return -1; + } + } + + const std::string entity_name = + ros2_node->get_parameter("entity_name").as_string(); + if (entity_name.empty()) { + RCLCPP_INFO(ros2_node->get_logger(), + "Entity to remove name is not provided, entity will not be removed."); + return -1; + } + + return remove_entity(entity_name, world_name, ros2_node); +} diff --git a/ros_gz_sim/test/test_create.cpp b/ros_gz_sim/test/test_create.cpp new file mode 100644 index 00000000..ee92bf39 --- /dev/null +++ b/ros_gz_sim/test/test_create.cpp @@ -0,0 +1,56 @@ +// Copyright 2023 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 +#include +#include +#include +#include +#include +#include + +// Simple application that provides a `/create` service and prints out the +// sdf_filename of the request. This works in conjection with +// test_create_node.launch.py +int main() +{ + std::mutex m; + std::condition_variable cv; + bool test_complete = false; + + gz::transport::Node node; + auto cb = std::function( + [&]( + const gz::msgs::EntityFactory & _req, + gz::msgs::Boolean & _res) -> bool { + std::cout << _req.sdf_filename() << std::endl; + _res.set_data(true); + + { + std::lock_guard lk(m); + test_complete = true; + } + cv.notify_one(); + return true; + }); + + node.Advertise("/world/default/create", cb); + // wait until we receive a message. + std::unique_lock lk(m); + cv.wait(lk, [&] {return test_complete;}); + // Sleep so that the service response can be sent before exiting. + std::this_thread::sleep_for(std::chrono::seconds(1)); +} diff --git a/ros_gz_sim/test/test_create_node.launch.py b/ros_gz_sim/test/test_create_node.launch.py new file mode 100644 index 00000000..79c31c5c --- /dev/null +++ b/ros_gz_sim/test/test_create_node.launch.py @@ -0,0 +1,47 @@ +# Copyright 2023 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. + +import unittest + +from launch import LaunchDescription + +from launch_ros.actions import Node + +import launch_testing + + +def generate_test_description(): + expected_file_name = 'nonexistent/long/file_name' + create = Node(package='ros_gz_sim', executable='create', + parameters=[{'world': 'default', 'file': expected_file_name}], output='screen') + test_create = Node(package='ros_gz_sim', executable='test_create', output='screen') + return LaunchDescription([ + create, + test_create, + launch_testing.util.KeepAliveProc(), + launch_testing.actions.ReadyToTest(), + ]), locals() + + +class WaitForTests(unittest.TestCase): + + def test_termination(self, test_create, proc_info): + proc_info.assertWaitForShutdown(process=test_create, timeout=200) + + +@launch_testing.post_shutdown_test() +class CreateTest(unittest.TestCase): + + def test_output(self, expected_file_name, test_create, proc_output): + launch_testing.asserts.assertInStdout(proc_output, expected_file_name, test_create) diff --git a/ros_gz_sim/test/test_remove.cpp b/ros_gz_sim/test/test_remove.cpp new file mode 100644 index 00000000..74a8f2ce --- /dev/null +++ b/ros_gz_sim/test/test_remove.cpp @@ -0,0 +1,56 @@ +// 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 + +#include +#include +#include +#include + +#include + +// Simple application that provides a `/remove` service and prints out the +// request's entity name. This works in conjuction with +// test_remove_node.launch.py +int main() +{ + std::mutex m; + std::condition_variable cv; + bool test_complete = false; + + gz::transport::Node node; + auto cb = std::function( + [&]( + const gz::msgs::Entity & _req, + gz::msgs::Boolean & _res) -> bool { + std::cout << _req.name() << std::endl; + _res.set_data(true); + + { + std::lock_guard lk(m); + test_complete = true; + } + cv.notify_one(); + return true; + }); + + node.Advertise("/world/default/remove", cb); + // wait until we receive a message. + std::unique_lock lk(m); + cv.wait(lk, [&] {return test_complete;}); + // Sleep so that the service response can be sent before exiting. + std::this_thread::sleep_for(std::chrono::seconds(1)); +} diff --git a/ros_gz_sim/test/test_remove_node.launch.py b/ros_gz_sim/test/test_remove_node.launch.py new file mode 100644 index 00000000..ebca2429 --- /dev/null +++ b/ros_gz_sim/test/test_remove_node.launch.py @@ -0,0 +1,49 @@ +# 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. + +import unittest + +from launch import LaunchDescription + +from launch_ros.actions import Node + +import launch_testing + + +def generate_test_description(): + entity_name = 'my_robot' + remove = Node(package='ros_gz_sim', + executable='remove', + parameters=[{'world': 'default', 'entity_name': entity_name}], + output='screen') + test_remove = Node(package='ros_gz_sim', executable='test_remove', output='screen') + return LaunchDescription([ + remove, + test_remove, + launch_testing.util.KeepAliveProc(), + launch_testing.actions.ReadyToTest(), + ]), locals() + + +class WaitForTests(unittest.TestCase): + + def test_termination(self, test_remove, proc_info): + proc_info.assertWaitForShutdown(process=test_remove, timeout=200) + + +@launch_testing.post_shutdown_test() +class RemoveTest(unittest.TestCase): + + def test_output(self, entity_name, test_remove, proc_output): + launch_testing.asserts.assertInStdout(proc_output, entity_name, test_remove) diff --git a/ros_gz_sim_demos/CHANGELOG.rst b/ros_gz_sim_demos/CHANGELOG.rst index 36f3b6c8..d7db75b9 100644 --- a/ros_gz_sim_demos/CHANGELOG.rst +++ b/ros_gz_sim_demos/CHANGELOG.rst @@ -2,6 +2,7 @@ Changelog for package ros1_gz_sim_demos ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 0.244.16 (2024-07-22) --------------------- @@ -26,6 +27,117 @@ Changelog for package ros1_gz_sim_demos 0.244.11 (2023-05-23) --------------------- +======= +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ + +2.1.0 (2024-09-12) +------------------ + +2.0.1 (2024-08-29) +------------------ + +2.0.0 (2024-07-22) +------------------ + +1.0.1 (2024-07-03) +------------------ +* Prepare for 1.0.0 Release (`#495 `_) +* Use gz_vendor packages (`#531 `_) +* [backport Humble] Create bridge for GPSFix msg (`#316 `_) (`#538 `_) + Co-authored-by: Rousseau Vincent +* [backport Iron] Create bridge for GPSFix msg (`#316 `_) (`#537 `_) + Co-authored-by: Rousseau Vincent +* 0.244.14 +* Changelog +* 0.244.13 +* Changelog +* Remove deprecations using ros_gz_sim_create (`#476 `_) +* 0.244.12 +* Changelog +* 0.246.0 +* Update changelogs +* Added more topic to the bridge (`#422 `_) +* Fix incorrect subscription on demo (`#405 `_) (`#408 `_) + This PR fixes an incorrect subscription on one of the demos. Running + ``` + ros2 launch ros_gz_sim_demos gpu_lidar_bridge.launch.py + ``` + causes rviz2 to crash and exit with the error: + ``` + rviz2-3] + [rviz2-3] >>> [rcutils|error_handling.c:108] rcutils_set_error_state() + [rviz2-3] This error state is being overwritten: + [rviz2-3] + [rviz2-3] 'create_subscription() called for existing topic name rt/lidar with incompatible type sensor_msgs::msg::dds\_::PointCloud2\_, at ./src/subscription.cpp:146, at ./src/rcl/subscription.c:108' + [rviz2-3] + [rviz2-3] with this new error message: + [rviz2-3] + [rviz2-3] 'invalid allocator, at ./src/rcl/subscription.c:218' + [rviz2-3] + [rviz2-3] rcutils_reset_error() should be called after error handling to avoid this. + ``` + This is due to an incorrect subscription on the part of the demo. This + PR fixes it by getting a subscription to the right topic for the + pointcloud display. (`lidar/points` instead of `lidar`). Was tested on + garden + humble. + Co-authored-by: Arjo Chakravarty +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Rename 'ign gazebo' to 'gz sim' (`#343 `_) +* Create bridge for GPSFix msg (`#316 `_) +* Humble ➡️ ROS2 (`#323 `_) + Humble ➡️ ROS2 +* Merge branch 'humble' into ports/humble_to_ros2 +* Fixed ros_gz_sim_demos launch files (`#319 `_) +* 0.245.0 +* Changelog +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Addisu Z. Taddese, Aditya Pande, Alejandro Hernández Cordero, Clyde McQueen, Jose Luis Rivero, Michael Carroll, Rousseau Vincent, ahcorde + +1.0.0 (2024-04-24) +------------------ +* Use gz_vendor packages (`#531 `_) +* Remove deprecations using ros_gz_sim_create (`#476 `_) +* Contributors: Addisu Z. Taddese, Alejandro Hernández Cordero + +0.246.0 (2023-08-31) +-------------------- +* Added more topic to the bridge (`#422 `_) +* Fix incorrect subscription on demo (`#405 `_) (`#408 `_) + Co-authored-by: Arjo Chakravarty +* Port: humble to ros2 (`#386 `_) +* Merge branch 'humble' into mjcarroll/humble_to_ros2 +* Update maintainers (`#376 `_) +* Rename 'ign gazebo' to 'gz sim' (`#343 `_) +* Create bridge for GPSFix msg (`#316 `_) +* Humble ➡️ ROS2 (`#323 `_) +* Fixed ros_gz_sim_demos launch files (`#319 `_) +* Contributors: Aditya Pande, Alejandro Hernández Cordero, Clyde McQueen, Michael Carroll, Rousseau Vincent, ahcorde + +0.245.0 (2022-10-12) +-------------------- +* humble to ros2 (`#311 `_) + Co-authored-by: Michael Carroll +* Merge remote-tracking branch 'origin/humble' into ahcorde/humble_to_ros2 +* Remove all ignition references on ROS 2 branch (`#302 `_) + * Remove all shims + * Update CMakeLists and package.xml for garden + * Complete garden gz renaming + * Drop fortress CI +* Contributors: Alejandro Hernández Cordero, Michael Carroll, ahcorde +>>>>>>> 63b651a (Garden EOL (#662)) 0.244.10 (2023-05-03) --------------------- diff --git a/ros_gz_sim_demos/launch/joint_states.launch.py b/ros_gz_sim_demos/launch/joint_states.launch.py index 95bf1906..4cab965b 100644 --- a/ros_gz_sim_demos/launch/joint_states.launch.py +++ b/ros_gz_sim_demos/launch/joint_states.launch.py @@ -63,10 +63,15 @@ def generate_launch_description(): spawn = Node( package='ros_gz_sim', executable='create', +<<<<<<< HEAD arguments=[ '-name', 'rrbot', '-topic', 'robot_description', ], +======= + parameters=[{'name': 'rrbot', + 'topic': 'robot_description'}], +>>>>>>> 63b651a (Garden EOL (#662)) output='screen', ) diff --git a/ros_gz_sim_demos/launch/robot_description_publisher.launch.py b/ros_gz_sim_demos/launch/robot_description_publisher.launch.py index 882cdee3..12de3320 100755 --- a/ros_gz_sim_demos/launch/robot_description_publisher.launch.py +++ b/ros_gz_sim_demos/launch/robot_description_publisher.launch.py @@ -77,12 +77,21 @@ def generate_launch_description(): # Spawn spawn = Node(package='ros_gz_sim', executable='create', +<<<<<<< HEAD arguments=[ '-name', 'my_custom_model', '-x', '1.2', '-z', '2.3', '-Y', '3.4', '-topic', '/robot_description'], +======= + parameters=[{ + 'name': 'my_custom_model', + 'x': 1.2, + 'z': 2.3, + 'Y': 3.4, + 'topic': '/robot_description'}], +>>>>>>> 63b651a (Garden EOL (#662)) output='screen') return LaunchDescription([ diff --git a/ros_gz_sim_demos/launch/tf_bridge.launch.py b/ros_gz_sim_demos/launch/tf_bridge.launch.py index e134864e..eef644cf 100644 --- a/ros_gz_sim_demos/launch/tf_bridge.launch.py +++ b/ros_gz_sim_demos/launch/tf_bridge.launch.py @@ -27,7 +27,11 @@ def generate_launch_description(): # Launch gazebo ExecuteProcess( cmd=[ +<<<<<<< HEAD 'ign', 'gazebo', '-r', +======= + 'gz', 'sim', '-r', +>>>>>>> 63b651a (Garden EOL (#662)) os.path.join( pkg_ros_gz_sim_demos, 'models', diff --git a/ros_gz_sim_demos/package.xml b/ros_gz_sim_demos/package.xml index 34f57eff..e75a5fa9 100644 --- a/ros_gz_sim_demos/package.xml +++ b/ros_gz_sim_demos/package.xml @@ -1,5 +1,6 @@ ros_gz_sim_demos +<<<<<<< HEAD 0.244.16 Demos using Gazebo Sim simulation with ROS. Apache 2.0 @@ -12,6 +13,19 @@ ignition-gazebo6 ignition-gazebo5 +======= + 2.1.2 + Demos using Gazebo Sim simulation with ROS. + Apache 2.0 + Aditya Pande + Alejandro Hernandez + + Louise Poubel + + ament_cmake + + gz_sim_vendor +>>>>>>> 63b651a (Garden EOL (#662)) image_transport_plugins robot_state_publisher diff --git a/test_ros_gz_bridge/CHANGELOG.rst b/test_ros_gz_bridge/CHANGELOG.rst new file mode 100644 index 00000000..b4f1e3b6 --- /dev/null +++ b/test_ros_gz_bridge/CHANGELOG.rst @@ -0,0 +1,32 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package test_ros_gz_bridge +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +2.1.2 (2024-10-31) +------------------ + +2.1.1 (2024-10-14) +------------------ + +2.1.0 (2024-09-12) +------------------ + +2.0.1 (2024-08-29) +------------------ + +2.0.0 (2024-07-22) +------------------ + +1.0.1 (2024-07-03) +------------------ +* Prepare for 1.0.0 Release (`#495 `_) +* 0.244.14 +* Changelog +* Correctly export ros_gz_bridge for downstream targets (`#503 `_) (`#506 `_) +* Correctly export ros_gz_bridge for downstream targets (`#503 `_) +* Contributors: Addisu Z. Taddese, Alejandro Hernández Cordero, Michael Carroll + +1.0.0 (2024-04-24) +------------------ +* Correctly export ros_gz_bridge for downstream targets (`#503 `_) +* Contributors: Michael Carroll diff --git a/test_ros_gz_bridge/package.xml b/test_ros_gz_bridge/package.xml index fc1429ed..70caddb4 100644 --- a/test_ros_gz_bridge/package.xml +++ b/test_ros_gz_bridge/package.xml @@ -2,7 +2,11 @@ test_ros_gz_bridge +<<<<<<< HEAD 0.244.16 +======= + 2.1.2 +>>>>>>> 63b651a (Garden EOL (#662)) Bridge communication between ROS and Gazebo Transport Aditya Pande Alejandro Hernandez