diff --git a/README.md b/README.md
index a2cf24e2..44712ff9 100644
--- a/README.md
+++ b/README.md
@@ -3,27 +3,26 @@
ROS 2 version | Gazebo version | Branch | Binaries hosted at
-- | -- | -- | --
Foxy | Citadel | [foxy](https://github.com/gazebosim/ros_gz/tree/foxy) | https://packages.ros.org
-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
+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]
+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
+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
+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
+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 a the packages.osrfoundation.org repository. Refer to https://gazebosim.org/docs/latest/ros_installation for installation instructions.
+[^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)
-> Please [ticket an issue](https://github.com/gazebosim/ros_gz/issues/) if you'd like support to be added for some combination.
-
[Details about the renaming process](README_RENAME.md) from `ign` to `gz` .
**Note**: The `ros_ign` prefixed packages are shim packages that redirect to their `ros_gz` counterpart.
@@ -86,7 +85,7 @@ Be sure you've installed
#### Gazebo
-Install either [Fortress, Garden, or Harmonic](https://gazebosim.org/docs).
+Install either [Fortress, Harmonic or Ionic](https://gazebosim.org/docs).
Set the `GZ_VERSION` environment variable to the Gazebo version you'd
like to compile against. For example:
@@ -97,7 +96,7 @@ like to compile against. For example:
#### Compile ros_gz
-The following steps are for Linux and OSX.
+The following steps are for Linux and macOS.
1. Create a colcon workspace:
diff --git a/ros_gz/CHANGELOG.rst b/ros_gz/CHANGELOG.rst
index d2bd485c..9effb7fc 100644
--- a/ros_gz/CHANGELOG.rst
+++ b/ros_gz/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_gz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
diff --git a/ros_gz/package.xml b/ros_gz/package.xml
index d96e8895..585a4754 100644
--- a/ros_gz/package.xml
+++ b/ros_gz/package.xml
@@ -4,7 +4,7 @@
ros_gz
- 2.1.1
+ 2.1.2
Meta-package containing interfaces for using ROS 2 with Gazebo simulation.
Aditya Pande
Alejandro Hernandez
diff --git a/ros_gz_bridge/CHANGELOG.rst b/ros_gz_bridge/CHANGELOG.rst
index ab9c1627..81ce3d08 100644
--- a/ros_gz_bridge/CHANGELOG.rst
+++ b/ros_gz_bridge/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_gz_bridge
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
* Extra parameter to start a container (`#616 `_)
diff --git a/ros_gz_bridge/launch/ros_gz_bridge.launch b/ros_gz_bridge/launch/ros_gz_bridge.launch
index fa76221e..96757e4e 100644
--- a/ros_gz_bridge/launch/ros_gz_bridge.launch
+++ b/ros_gz_bridge/launch/ros_gz_bridge.launch
@@ -7,6 +7,7 @@
+
+ log_level="$(var log_level)"
+ bridge_params="$(var bridge_params)">
diff --git a/ros_gz_bridge/launch/ros_gz_bridge.launch.py b/ros_gz_bridge/launch/ros_gz_bridge.launch.py
index 3e52dee6..e1690a84 100644
--- a/ros_gz_bridge/launch/ros_gz_bridge.launch.py
+++ b/ros_gz_bridge/launch/ros_gz_bridge.launch.py
@@ -15,24 +15,13 @@
"""Launch ros_gz bridge in a component container."""
from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument, GroupAction
-from launch.conditions import IfCondition
-from launch.substitutions import LaunchConfiguration, PythonExpression
-from launch_ros.actions import ComposableNodeContainer, LoadComposableNodes, Node
-from launch_ros.descriptions import ComposableNode
+from launch.actions import DeclareLaunchArgument
+from launch.substitutions import LaunchConfiguration
+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')
-
declare_bridge_name_cmd = DeclareLaunchArgument(
'bridge_name', description='Name of ros_gz_bridge node'
)
@@ -74,57 +63,20 @@ def generate_launch_description():
'log_level', default_value='info', description='log level'
)
- load_nodes = GroupAction(
- condition=IfCondition(PythonExpression(['not ', use_composition])),
- actions=[
- Node(
- package='ros_gz_bridge',
- executable='bridge_node',
- name=bridge_name,
- namespace=namespace,
- output='screen',
- respawn=use_respawn,
- respawn_delay=2.0,
- parameters=[{'config_file': config_file}],
- arguments=['--ros-args', '--log-level', log_level],
- ),
- ],
- )
-
- load_composable_nodes_with_container = ComposableNodeContainer(
- condition=IfCondition(
- PythonExpression([use_composition, ' and ', create_own_container])),
- name=LaunchConfiguration('container_name'),
- namespace='',
- package='rclcpp_components',
- executable='component_container',
- composable_node_descriptions=[
- ComposableNode(
- package='ros_gz_bridge',
- plugin='ros_gz_bridge::RosGzBridge',
- name=bridge_name,
- namespace=namespace,
- parameters=[{'config_file': config_file}],
- extra_arguments=[{'use_intra_process_comms': True}],
- ),
- ],
- output='screen',
+ declare_bridge_params_cmd = DeclareLaunchArgument(
+ 'bridge_params', default_value='', description='Extra parameters to pass to the bridge.'
)
- load_composable_nodes_without_container = LoadComposableNodes(
- condition=IfCondition(
- PythonExpression([use_composition, ' and not ', create_own_container])),
- target_container=container_name,
- composable_node_descriptions=[
- ComposableNode(
- package='ros_gz_bridge',
- plugin='ros_gz_bridge::RosGzBridge',
- name=bridge_name,
- namespace=namespace,
- parameters=[{'config_file': config_file}],
- extra_arguments=[{'use_intra_process_comms': True}],
- ),
- ],
+ 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
@@ -139,9 +91,7 @@ def generate_launch_description():
ld.add_action(declare_use_composition_cmd)
ld.add_action(declare_use_respawn_cmd)
ld.add_action(declare_log_level_cmd)
- # Add the actions to launch all of the bridge nodes
- ld.add_action(load_nodes)
- ld.add_action(load_composable_nodes_with_container)
- ld.add_action(load_composable_nodes_without_container)
-
+ 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 f95cfa22..b43b0cd7 100644
--- a/ros_gz_bridge/package.xml
+++ b/ros_gz_bridge/package.xml
@@ -2,7 +2,7 @@
ros_gz_bridge
- 2.1.1
+ 2.1.2
Bridge communication between ROS and Gazebo Transport
Aditya Pande
Alejandro Hernandez
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
index 8459de4f..ee28a2f4 100644
--- a/ros_gz_bridge/ros_gz_bridge/actions/ros_gz_bridge.py
+++ b/ros_gz_bridge/ros_gz_bridge/actions/ros_gz_bridge.py
@@ -14,17 +14,18 @@
"""Module for the ros_gz bridge action."""
-from typing import List
-from typing import Optional
+from typing import cast, Dict, List, Optional, Union
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
+from launch.substitutions import TextSubstitution
+from launch.utilities import ensure_argument_type
+from launch.utilities.type_utils import normalize_typed_substitution, perform_typed_substitution
+from launch_ros.actions import ComposableNodeContainer, LoadComposableNodes, Node
+from launch_ros.descriptions import ComposableNode
+from launch_ros.parameters_type import SomeParameters
@expose_action('ros_gz_bridge')
@@ -36,20 +37,18 @@ def __init__(
*,
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',
+ container_name: SomeSubstitutionsType = 'ros_gz_container',
+ create_own_container: Union[bool, SomeSubstitutionsType] = False,
+ namespace: SomeSubstitutionsType = '',
+ use_composition: Union[bool, SomeSubstitutionsType] = False,
+ use_respawn: Union[bool, SomeSubstitutionsType] = False,
+ log_level: SomeSubstitutionsType = 'info',
+ bridge_params: Optional[SomeParameters] = None,
**kwargs
) -> None:
"""
Construct a ros_gz bridge action.
- All arguments are forwarded to `ros_gz_bridge.launch.ros_gz_bridge.launch.py`,
- so see the documentation of that class for further details.
-
: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.
@@ -58,21 +57,52 @@ def __init__(
: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
+
+ # This is here to allow using strings or booleans as values for boolean variables when
+ # the Action is used from Python i.e., this allows users to do:
+ # RosGzBridge(bridge_name='bridge1', use_composition='true', create_own_container=True)
+ # Note that use_composition is set to a string while create_own_container is set to a
+ # boolean. The reverse would also work.
+ # At some point, we might want to deprecate this and only allow setting booleans since
+ # that's what users would expect when calling this from Python
+ if isinstance(create_own_container, str):
+ self.__create_own_container = normalize_typed_substitution(
+ TextSubstitution(text=create_own_container), bool
+ )
+ else:
+ self.__create_own_container = normalize_typed_substitution(
+ create_own_container, bool
+ )
+
+ if isinstance(use_composition, str):
+ self.__use_composition = normalize_typed_substitution(
+ TextSubstitution(text=use_composition), bool
+ )
+ else:
+ self.__use_composition = normalize_typed_substitution(use_composition, bool)
+
+ self.__use_respawn = normalize_typed_substitution(use_respawn, bool)
self.__log_level = log_level
+ self.__bridge_params = [{'config_file': self.__config_file}]
+ if bridge_params is not None:
+ # This handling of bridge_params was copied from launch_ros/actions/node.py
+ ensure_argument_type(bridge_params, (list), 'bridge_params', 'RosGzBridge')
+ # All elements in the list are paths to files with parameters (or substitutions that
+ # evaluate to paths), or dictionaries of parameters (fields can be substitutions).
+ self.__bridge_params.extend(cast(list, bridge_params))
@classmethod
def parse(cls, entity: Entity, parser: Parser):
"""Parse ros_gz_bridge."""
- _, kwargs = super().parse(entity, parser)
+ kwargs: Dict = super().parse(entity, parser)[1]
bridge_name = entity.get_attr(
'bridge_name', data_type=str,
@@ -106,6 +136,8 @@ def parse(cls, entity: Entity, parser: Parser):
'log_level', data_type=str,
optional=True)
+ parameters = entity.get_attr('param', data_type=List[Entity], optional=True)
+
if isinstance(bridge_name, str):
bridge_name = parser.parse_substitution(bridge_name)
kwargs['bridge_name'] = bridge_name
@@ -139,22 +171,70 @@ def parse(cls, entity: Entity, parser: Parser):
log_level = parser.parse_substitution(log_level)
kwargs['log_level'] = log_level
+ if parameters is not None:
+ kwargs['bridge_params'] = Node.parse_nested_parameters(parameters, parser)
+
return cls, kwargs
def execute(self, context: LaunchContext) -> Optional[List[Action]]:
"""Execute the action."""
- ros_gz_bridge_description = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- [PathJoinSubstitution([FindPackageShare('ros_gz_bridge'),
- 'launch',
- 'ros_gz_bridge.launch.py'])]),
- launch_arguments=[('bridge_name', self.__bridge_name),
- ('config_file', self.__config_file),
- ('container_name', self.__container_name),
- ('create_own_container', self.__create_own_container),
- ('namespace', self.__namespace),
- ('use_composition', self.__use_composition),
- ('use_respawn', self.__use_respawn),
- ('log_level', self.__log_level), ])
-
- return [ros_gz_bridge_description]
+ use_composition_eval = perform_typed_substitution(
+ context, self.__use_composition, bool
+ )
+ create_own_container_eval = perform_typed_substitution(
+ context, self.__create_own_container, bool
+ )
+
+ launch_descriptions: List[Action] = []
+
+ if not use_composition_eval:
+ # Standard node configuration
+ launch_descriptions.append(Node(
+ package='ros_gz_bridge',
+ executable='bridge_node',
+ name=self.__bridge_name,
+ namespace=self.__namespace,
+ output='screen',
+ respawn=perform_typed_substitution(context, self.__use_respawn, bool),
+ respawn_delay=2.0,
+ parameters=self.__bridge_params,
+ arguments=['--ros-args', '--log-level', self.__log_level],
+ ))
+
+ # Composable node with container configuration
+ if use_composition_eval and create_own_container_eval:
+ launch_descriptions.append(ComposableNodeContainer(
+ 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=self.__bridge_params,
+ extra_arguments=[{'use_intra_process_comms': True}],
+ ),
+ ],
+ output='screen',
+ ))
+
+ # Composable node without container configuration
+ if use_composition_eval and not create_own_container_eval:
+ launch_descriptions.append(LoadComposableNodes(
+ 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=self.__bridge_params,
+ extra_arguments=[{'use_intra_process_comms': True}],
+ ),
+ ],
+ ))
+
+ return launch_descriptions
diff --git a/ros_gz_image/CHANGELOG.rst b/ros_gz_image/CHANGELOG.rst
index fdefc560..1504e16c 100644
--- a/ros_gz_image/CHANGELOG.rst
+++ b/ros_gz_image/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros1_ign_image
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
diff --git a/ros_gz_image/package.xml b/ros_gz_image/package.xml
index 36d33fae..e6961941 100644
--- a/ros_gz_image/package.xml
+++ b/ros_gz_image/package.xml
@@ -1,6 +1,6 @@
ros_gz_image
- 2.1.1
+ 2.1.2
Image utilities for Gazebo simulation with ROS.
Apache 2.0
Aditya Pande
diff --git a/ros_gz_interfaces/CHANGELOG.rst b/ros_gz_interfaces/CHANGELOG.rst
index 7d192134..db0253ff 100644
--- a/ros_gz_interfaces/CHANGELOG.rst
+++ b/ros_gz_interfaces/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros_gz_interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
diff --git a/ros_gz_interfaces/package.xml b/ros_gz_interfaces/package.xml
index d9ab3282..c6aeb753 100644
--- a/ros_gz_interfaces/package.xml
+++ b/ros_gz_interfaces/package.xml
@@ -1,6 +1,6 @@
ros_gz_interfaces
- 2.1.1
+ 2.1.2
Message and service data structures for interacting with Gazebo from ROS2.
Apache 2.0
Louise Poubel
diff --git a/ros_gz_sim/CHANGELOG.rst b/ros_gz_sim/CHANGELOG.rst
index 05a7e81b..4ad7fd41 100644
--- a/ros_gz_sim/CHANGELOG.rst
+++ b/ros_gz_sim/CHANGELOG.rst
@@ -2,6 +2,14 @@
Changelog for package ros_gz_sim
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+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 `_)
diff --git a/ros_gz_sim/CMakeLists.txt b/ros_gz_sim/CMakeLists.txt
index dc21f8a9..e61622f9 100644
--- a/ros_gz_sim/CMakeLists.txt
+++ b/ros_gz_sim/CMakeLists.txt
@@ -48,7 +48,17 @@ target_link_libraries(create
gz-msgs::core
gz-transport::core
)
-ament_target_dependencies(create std_msgs)
+
+add_executable(remove src/remove.cpp)
+ament_target_dependencies(remove
+ rclcpp
+ std_msgs
+)
+
+target_link_libraries(remove
+ gz-msgs::core
+ gz-transport::core
+)
add_library(${PROJECT_NAME} SHARED src/Stopwatch.cpp)
ament_target_dependencies(${PROJECT_NAME}
@@ -104,13 +114,16 @@ install(FILES
"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}
@@ -151,6 +164,10 @@ if(BUILD_TESTING)
test/test_create.cpp
)
+ ament_add_gtest_executable(test_remove
+ test/test_remove.cpp
+ )
+
ament_target_dependencies(test_stopwatch rclcpp)
target_include_directories(test_stopwatch PUBLIC
@@ -165,12 +182,17 @@ if(BUILD_TESTING)
gz-transport::core
)
+ target_link_libraries(test_remove
+ gz-transport::core
+ )
+
install(
- TARGETS test_stopwatch test_create
+ 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)
endif()
ament_package()
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.py b/ros_gz_sim/launch/gz_server.launch.py
index 70de5d24..3c231a1d 100644
--- a/ros_gz_sim/launch/gz_server.launch.py
+++ b/ros_gz_sim/launch/gz_server.launch.py
@@ -16,10 +16,8 @@
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
-from launch.conditions import IfCondition
-from launch.substitutions import LaunchConfiguration, PythonExpression, TextSubstitution
-from launch_ros.actions import ComposableNodeContainer, LoadComposableNodes, Node
-from launch_ros.descriptions import ComposableNode
+from launch.substitutions import LaunchConfiguration, TextSubstitution
+from ros_gz_sim.actions import GzServer
def generate_launch_description():
@@ -40,51 +38,12 @@ def generate_launch_description():
'use_composition', default_value='False',
description='Use composed bringup if True')
- load_nodes = Node(
- condition=IfCondition(PythonExpression(['not ', LaunchConfiguration('use_composition')])),
- package='ros_gz_sim',
- executable='gzserver',
- output='screen',
- parameters=[{'world_sdf_file': LaunchConfiguration('world_sdf_file'),
- 'world_sdf_string': LaunchConfiguration('world_sdf_string')}],
- )
-
- load_composable_nodes_with_container = ComposableNodeContainer(
- condition=IfCondition(
- PythonExpression([LaunchConfiguration('use_composition'), ' and ',
- LaunchConfiguration('create_own_container')])),
- name=LaunchConfiguration('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': LaunchConfiguration('world_sdf_file'),
- 'world_sdf_string': LaunchConfiguration('world_sdf_string')}],
- extra_arguments=[{'use_intra_process_comms': True}],
- ),
- ],
- output='screen',
- )
-
- load_composable_nodes_without_container = LoadComposableNodes(
- condition=IfCondition(
- PythonExpression([LaunchConfiguration('use_composition'), ' and not ',
- LaunchConfiguration('create_own_container')])),
- target_container=LaunchConfiguration('container_name'),
- composable_node_descriptions=[
- ComposableNode(
- package='ros_gz_sim',
- plugin='ros_gz_sim::GzServer',
- name='gz_server',
- parameters=[{'world_sdf_file': LaunchConfiguration('world_sdf_file'),
- 'world_sdf_string': LaunchConfiguration('world_sdf_string')}],
- extra_arguments=[{'use_intra_process_comms': 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
@@ -96,9 +55,7 @@ def generate_launch_description():
ld.add_action(declare_container_name_cmd)
ld.add_action(declare_create_own_container_cmd)
ld.add_action(declare_use_composition_cmd)
- # Add the actions to launch all of the gz_server nodes
- ld.add_action(load_nodes)
- ld.add_action(load_composable_nodes_with_container)
- ld.add_action(load_composable_nodes_without_container)
+ # Add the gz_server action
+ ld.add_action(gz_server_action)
return ld
diff --git a/ros_gz_sim/launch/ros_gz_sim.launch b/ros_gz_sim/launch/ros_gz_sim.launch
index 6130ce0d..e39f10b6 100644
--- a/ros_gz_sim/launch/ros_gz_sim.launch
+++ b/ros_gz_sim/launch/ros_gz_sim.launch
@@ -7,6 +7,7 @@
+
+ log_level="$(var log_level)"
+ bridge_params="$(var bridge_params)">
diff --git a/ros_gz_sim/launch/ros_gz_sim.launch.py b/ros_gz_sim/launch/ros_gz_sim.launch.py
index aba047ee..1465c44e 100644
--- a/ros_gz_sim/launch/ros_gz_sim.launch.py
+++ b/ros_gz_sim/launch/ros_gz_sim.launch.py
@@ -15,26 +15,14 @@
"""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 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():
- 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')
- bridge_log_level = LaunchConfiguration('bridge_log_level')
-
- world_sdf_file = LaunchConfiguration('world_sdf_file')
- world_sdf_string = LaunchConfiguration('world_sdf_string')
-
declare_bridge_name_cmd = DeclareLaunchArgument(
'bridge_name', description='Name of the bridge'
)
@@ -73,6 +61,10 @@ def generate_launch_description():
'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'
@@ -83,30 +75,25 @@ def generate_launch_description():
description='SDF world string'
)
- gz_server_description = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- [PathJoinSubstitution([FindPackageShare('ros_gz_sim'),
- 'launch',
- 'gz_server.launch.py'])]),
- launch_arguments=[('world_sdf_file', world_sdf_file),
- ('world_sdf_string', world_sdf_string),
- ('container_name', container_name),
- ('create_own_container', create_own_container),
- ('use_composition', use_composition), ])
-
- bridge_description = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- [PathJoinSubstitution([FindPackageShare('ros_gz_bridge'),
- 'launch',
- 'ros_gz_bridge.launch.py'])]),
- launch_arguments=[('bridge_name', bridge_name),
- ('config_file', config_file),
- ('container_name', container_name),
- ('namespace', namespace),
- ('create_own_container', str(False)),
- ('use_composition', use_composition),
- ('use_respawn', use_respawn),
- ('bridge_log_level', bridge_log_level), ])
+ 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()
@@ -120,10 +107,11 @@ def generate_launch_description():
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_description)
- ld.add_action(bridge_description)
+ 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
index e5e20ebd..2ac684fc 100644
--- a/ros_gz_sim/launch/ros_gz_spawn_model.launch.py
+++ b/ros_gz_sim/launch/ros_gz_spawn_model.launch.py
@@ -19,6 +19,7 @@
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():
@@ -26,10 +27,12 @@ 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')
@@ -58,12 +61,18 @@ def generate_launch_description():
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='True', description='Use composed bringup if True'
+ 'use_composition', default_value='False', description='Use composed bringup if True'
)
declare_use_respawn_cmd = DeclareLaunchArgument(
@@ -76,6 +85,10 @@ def generate_launch_description():
'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')
@@ -105,18 +118,17 @@ def generate_launch_description():
description='Whether the entity allows renaming or not'
)
- bridge_description = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- [PathJoinSubstitution([FindPackageShare('ros_gz_bridge'),
- 'launch',
- 'ros_gz_bridge.launch.py'])]),
- launch_arguments=[('bridge_name', bridge_name),
- ('config_file', config_file),
- ('container_name', container_name),
- ('namespace', namespace),
- ('use_composition', use_composition),
- ('use_respawn', use_respawn),
- ('log_level', log_level), ])
+ 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(
@@ -143,10 +155,12 @@ def generate_launch_description():
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)
@@ -154,7 +168,7 @@ def generate_launch_description():
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(bridge_description)
+ 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 ac3660ef..d4247f7a 100644
--- a/ros_gz_sim/package.xml
+++ b/ros_gz_sim/package.xml
@@ -2,7 +2,7 @@
ros_gz_sim
- 2.1.1
+ 2.1.2
Tools for using Gazebo Sim simulation with ROS.
Alejandro Hernandez
Aditya Pande
diff --git a/ros_gz_sim/ros_gz_sim/actions/gzserver.py b/ros_gz_sim/ros_gz_sim/actions/gzserver.py
index 64461baf..7e3ee3d3 100644
--- a/ros_gz_sim/ros_gz_sim/actions/gzserver.py
+++ b/ros_gz_sim/ros_gz_sim/actions/gzserver.py
@@ -14,17 +14,73 @@
"""Module for the GzServer action."""
-from typing import List
-from typing import Optional
+import os
+from typing import Dict, List, Optional, Union
+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 IncludeLaunchDescription
+from launch.actions import SetEnvironmentVariable
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
+from launch.substitutions import TextSubstitution
+from launch.utilities.type_utils import normalize_typed_substitution, perform_typed_substitution
+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')
@@ -34,11 +90,11 @@ class GzServer(Action):
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',
+ world_sdf_file: SomeSubstitutionsType = '',
+ world_sdf_string: SomeSubstitutionsType = '',
+ container_name: SomeSubstitutionsType = 'ros_gz_container',
+ create_own_container: Union[bool, SomeSubstitutionsType] = False,
+ use_composition: Union[bool, SomeSubstitutionsType] = False,
**kwargs
) -> None:
"""
@@ -57,13 +113,29 @@ def __init__(
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
+
+ # This is here to allow using strings or booleans as values for boolean variables when
+ # the Action is used from Python See the RosGzBridge.__init__ function for more details.
+ if isinstance(create_own_container, str):
+ self.__create_own_container = normalize_typed_substitution(
+ TextSubstitution(text=create_own_container), bool
+ )
+ else:
+ self.__create_own_container = normalize_typed_substitution(
+ create_own_container, bool
+ )
+
+ if isinstance(use_composition, str):
+ self.__use_composition = normalize_typed_substitution(
+ TextSubstitution(text=use_composition), bool
+ )
+ else:
+ self.__use_composition = normalize_typed_substitution(use_composition, bool)
@classmethod
def parse(cls, entity: Entity, parser: Parser):
"""Parse gz_server."""
- _, kwargs = super().parse(entity, parser)
+ kwargs: Dict = super().parse(entity, parser)[1]
world_sdf_file = entity.get_attr(
'world_sdf_file', data_type=str,
@@ -110,15 +182,73 @@ def parse(cls, entity: Entity, parser: Parser):
def execute(self, context: LaunchContext) -> Optional[List[Action]]:
"""Execute the action."""
- gz_server_description = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- [PathJoinSubstitution([FindPackageShare('ros_gz_sim'),
- 'launch',
- 'gz_server.launch.py'])]),
- launch_arguments=[('world_sdf_file', self.__world_sdf_file),
- ('world_sdf_string', self.__world_sdf_string),
- ('container_name', self.__container_name),
- ('create_own_container', self.__create_own_container),
- ('use_composition', self.__use_composition), ])
-
- return [gz_server_description]
+ launch_descriptions: List[Action] = []
+
+ model_paths, plugin_paths = GazeboRosPaths.get_paths()
+ launch_descriptions.append(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,
+ ])))
+ launch_descriptions.append(SetEnvironmentVariable(
+ 'GZ_SIM_RESOURCE_PATH',
+ os.pathsep.join([
+ os.environ.get('GZ_SIM_RESOURCE_PATH', default=''),
+ model_paths,
+ ])))
+
+ use_composition_eval = perform_typed_substitution(
+ context, self.__use_composition, bool
+ )
+ create_own_container_eval = perform_typed_substitution(
+ context, self.__create_own_container, bool
+ )
+ if not use_composition_eval:
+ # Standard node configuration
+ launch_descriptions.append(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
+ if use_composition_eval and create_own_container_eval:
+ launch_descriptions.append(ComposableNodeContainer(
+ 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
+ if use_composition_eval and not create_own_container_eval:
+ launch_descriptions.append(LoadComposableNodes(
+ 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 launch_descriptions
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_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 7ee59f61..89dc117c 100644
--- a/ros_gz_sim_demos/CHANGELOG.rst
+++ b/ros_gz_sim_demos/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package ros1_gz_sim_demos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
diff --git a/ros_gz_sim_demos/CMakeLists.txt b/ros_gz_sim_demos/CMakeLists.txt
index 8e0f580a..9b69104b 100644
--- a/ros_gz_sim_demos/CMakeLists.txt
+++ b/ros_gz_sim_demos/CMakeLists.txt
@@ -9,6 +9,12 @@ if(BUILD_TESTING)
ament_lint_auto_find_test_dependencies()
endif()
+install(
+ DIRECTORY
+ config/
+ DESTINATION share/${PROJECT_NAME}/config
+)
+
install(
DIRECTORY
launch/
diff --git a/ros_gz_sim_demos/README.md b/ros_gz_sim_demos/README.md
index c404a4dc..e3b64601 100644
--- a/ros_gz_sim_demos/README.md
+++ b/ros_gz_sim_demos/README.md
@@ -14,7 +14,7 @@ There's a convenient launch file, try for example:
Publishes fluid pressure readings.
- ros2 launch ros_gz_sim_demos air_pressure.launch.py
+ ros2 launch ros_gz_sim_demos air_pressure.launch.xml
This demo also shows the use of custom QoS parameters. The sensor data is
published as as "best-effort", so trying to subscribe to "reliable" data won't
@@ -28,6 +28,18 @@ And
![](images/air_pressure_demo.png)
+## Battery
+
+Get the current state of a battery.
+
+ ros2 launch ros_gz_sim_demos battery.launch.py
+
+Then send a command so the vehicle moves and drains the battery.
+
+ ros2 topic pub /model/vehicle_blue/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 5.0}, angular: {z: 0.5}}"
+
+![](images/battery_demo.png)
+
## Camera
Publishes RGB camera image and info.
@@ -116,7 +128,7 @@ Using Gazebo Sim plugin:
Publishes IMU readings.
- ros2 launch ros_gz_sim_demos imu.launch.py
+ ros2 launch ros_gz_sim_demos imu.launch.xml
![](images/imu_demo.png)
@@ -126,7 +138,7 @@ Publishes IMU readings.
Publishes magnetic field readings.
- ros2 launch ros_gz_sim_demos magnetometer.launch.py
+ ros2 launch ros_gz_sim_demos magnetometer.launch.xml
![](images/magnetometer_demo.png)
@@ -134,7 +146,12 @@ Publishes magnetic field readings.
Publishes satellite navigation readings, only available in Fortress on.
- ros2 launch ros_gz_sim_demos navsat.launch.py
+GNSS information can be obtained as:
+
+ # sensor_msgs/msg/NavSatFix
+ ros2 launch ros_gz_sim_demos navsat.launch.xml
+ # gps_msgs/msg/GPSFix
+ ros2 launch ros_gz_sim_demos navsat_gpsfix.launch.xml
![](images/navsat_demo.png)
@@ -164,18 +181,6 @@ Using Gazebo Sim plugin:
![](images/rgbd_camera_demo.png)
-## Battery
-
-Get the current state of a battery.
-
- ros2 launch ros_gz_sim_demos battery.launch.py
-
-Then send a command so the vehicle moves and drains the battery
-
- ros2 topic pub /model/vehicle_blue/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 5.0}, angular: {z: 0.5}}"
-
-![](images/battery_demo.png)
-
## Robot description publisher
Leverage the robot description publisher to spawn a new urdf model in gazebo and
@@ -203,6 +208,6 @@ and transforms of a robot in rviz.
To try the demo launch:
- ros2 launch ros_gz_sim_demos tf_bridge.launch.py
+ ros2 launch ros_gz_sim_demos tf_bridge.launch.xml
![](images/tf_bridge.gif)
diff --git a/ros_gz_sim_demos/config/air_pressure.yaml b/ros_gz_sim_demos/config/air_pressure.yaml
new file mode 100644
index 00000000..36ad5f67
--- /dev/null
+++ b/ros_gz_sim_demos/config/air_pressure.yaml
@@ -0,0 +1,6 @@
+# Air pressure bridge configuration.
+- topic_name: "air_pressure"
+ ros_type_name: "sensor_msgs/msg/FluidPressure"
+ gz_type_name: "gz.msgs.FluidPressure"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/battery.yaml b/ros_gz_sim_demos/config/battery.yaml
new file mode 100644
index 00000000..9f6494bb
--- /dev/null
+++ b/ros_gz_sim_demos/config/battery.yaml
@@ -0,0 +1,12 @@
+# Battery configuration.
+- topic_name: "/model/vehicle_blue/cmd_vel"
+ ros_type_name: "geometry_msgs/msg/Twist"
+ gz_type_name: "gz.msgs.Twist"
+ lazy: true
+ direction: ROS_TO_GZ
+
+- topic_name: "/model/vehicle_blue/battery/linear_battery/state"
+ ros_type_name: "sensor_msgs/msg/BatteryState"
+ gz_type_name: "gz.msgs.BatteryState"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/imu.yaml b/ros_gz_sim_demos/config/imu.yaml
new file mode 100644
index 00000000..9a3ddbcd
--- /dev/null
+++ b/ros_gz_sim_demos/config/imu.yaml
@@ -0,0 +1,6 @@
+# IMU configuration.
+- topic_name: "/imu"
+ ros_type_name: "sensor_msgs/msg/Imu"
+ gz_type_name: "gz.msgs.IMU"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/magnetometer.yaml b/ros_gz_sim_demos/config/magnetometer.yaml
new file mode 100644
index 00000000..e5d38d2e
--- /dev/null
+++ b/ros_gz_sim_demos/config/magnetometer.yaml
@@ -0,0 +1,6 @@
+# Magnetometer configuration.
+- topic_name: "/magnetometer"
+ ros_type_name: "sensor_msgs/msg/MagneticField"
+ gz_type_name: "gz.msgs.Magnetometer"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/navsat.yaml b/ros_gz_sim_demos/config/navsat.yaml
new file mode 100644
index 00000000..0a68ab80
--- /dev/null
+++ b/ros_gz_sim_demos/config/navsat.yaml
@@ -0,0 +1,6 @@
+# Navsat configuration.
+- topic_name: "/navsat"
+ ros_type_name: "sensor_msgs/msg/NavSatFix"
+ gz_type_name: "gz.msgs.NavSat"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/navsat_gpsfix.yaml b/ros_gz_sim_demos/config/navsat_gpsfix.yaml
new file mode 100644
index 00000000..07784eee
--- /dev/null
+++ b/ros_gz_sim_demos/config/navsat_gpsfix.yaml
@@ -0,0 +1,6 @@
+# Navsat_gpsfix configuration.
+- topic_name: "/navsat"
+ ros_type_name: "gps_msgs/msg/GPSFix"
+ gz_type_name: "gz.msgs.NavSat"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/config/tf_bridge.yaml b/ros_gz_sim_demos/config/tf_bridge.yaml
new file mode 100644
index 00000000..9debbf11
--- /dev/null
+++ b/ros_gz_sim_demos/config/tf_bridge.yaml
@@ -0,0 +1,14 @@
+# tf_bridge configuration.
+- ros_topic_name: "/joint_states"
+ gz_topic_name: "/world/default/model/double_pendulum_with_base0/joint_state"
+ ros_type_name: "sensor_msgs/msg/JointState"
+ gz_type_name: "gz.msgs.Model"
+ lazy: true
+ direction: GZ_TO_ROS
+
+- ros_topic_name: "/tf"
+ gz_topic_name: "/model/double_pendulum_with_base0/pose"
+ ros_type_name: "tf2_msgs/msg/TFMessage"
+ gz_type_name: "gz.msgs.Pose_V"
+ lazy: true
+ direction: GZ_TO_ROS
diff --git a/ros_gz_sim_demos/launch/air_pressure.launch.py b/ros_gz_sim_demos/launch/air_pressure.launch.py
deleted file mode 100644
index 2a422b34..00000000
--- a/ros_gz_sim_demos/launch/air_pressure.launch.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2019 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 Gazebo Sim with command line arguments."""
-
-import os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument
-from launch.actions import IncludeLaunchDescription
-from launch.conditions import IfCondition
-from launch.launch_description_sources import PythonLaunchDescriptionSource
-from launch.substitutions import LaunchConfiguration
-
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
-
- pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
-
- # Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=['/air_pressure@sensor_msgs/msg/FluidPressure@gz.msgs.FluidPressure'],
- parameters=[{'qos_overrides./air_pressure.publisher.reliability': 'best_effort'}],
- output='screen'
- )
-
- gz_sim = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
- launch_arguments={'gz_args': '-r sensors.sdf'}.items(),
- )
-
- # RQt
- rqt = Node(
- package='rqt_topic',
- executable='rqt_topic',
- arguments=['-t'],
- condition=IfCondition(LaunchConfiguration('rqt'))
- )
- return LaunchDescription([
- gz_sim,
- DeclareLaunchArgument('rqt', default_value='true',
- description='Open RQt.'),
- bridge,
- rqt
- ])
diff --git a/ros_gz_sim_demos/launch/air_pressure.launch.xml b/ros_gz_sim_demos/launch/air_pressure.launch.xml
new file mode 100644
index 00000000..9fd33397
--- /dev/null
+++ b/ros_gz_sim_demos/launch/air_pressure.launch.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/launch/battery.launch.py b/ros_gz_sim_demos/launch/battery.launch.py
index 8abe8eff..a0da9fdf 100644
--- a/ros_gz_sim_demos/launch/battery.launch.py
+++ b/ros_gz_sim_demos/launch/battery.launch.py
@@ -15,20 +15,20 @@
import os
from ament_index_python.packages import get_package_share_directory
-
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
-
from launch_ros.actions import Node
+from ros_gz_bridge.actions import RosGzBridge
def generate_launch_description():
pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
+ pkg_ros_gz_sim_demos = get_package_share_directory('ros_gz_sim_demos')
# RQt
rqt = Node(
@@ -40,6 +40,7 @@ def generate_launch_description():
condition=IfCondition(LaunchConfiguration('rqt'))
)
+ # Gazebo
gz_sim = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
@@ -49,21 +50,15 @@ def generate_launch_description():
)
# Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=[
- '/model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist@gz.msgs.Twist',
- '/model/vehicle_blue/battery/linear_battery/state@sensor_msgs/msg/BatteryState@'
- 'gz.msgs.BatteryState'
- ],
- output='screen'
+ ros_gz_bridge = RosGzBridge(
+ bridge_name='ros_gz_bridge',
+ config_file=os.path.join(pkg_ros_gz_sim_demos, 'config', 'battery.yaml'),
)
return LaunchDescription([
gz_sim,
DeclareLaunchArgument('rqt', default_value='true',
description='Open RQt.'),
- bridge,
+ ros_gz_bridge,
rqt
])
diff --git a/ros_gz_sim_demos/launch/imu.launch.py b/ros_gz_sim_demos/launch/imu.launch.py
deleted file mode 100644
index cc1bf9e9..00000000
--- a/ros_gz_sim_demos/launch/imu.launch.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2019 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 os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument
-from launch.actions import IncludeLaunchDescription
-from launch.conditions import IfCondition
-from launch.launch_description_sources import PythonLaunchDescriptionSource
-from launch.substitutions import LaunchConfiguration
-
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
-
- pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
-
- gz_sim = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
- launch_arguments={
- 'gz_args': '-r sensors.sdf'
- }.items(),
- )
-
- # RQt
- rqt = Node(
- package='rqt_topic',
- executable='rqt_topic',
- arguments=['-t'],
- condition=IfCondition(LaunchConfiguration('rqt'))
- )
-
- # RViz
- # FIXME: Add once there's an IMU display for RViz2
- # pkg_ros_gz_sim_demos = get_package_share_directory('ros_gz_sim_demos')
- # rviz = Node(
- # package='rviz2',
- # executable='rviz2',
- # # arguments=['-d', os.path.join(pkg_ros_gz_sim_demos, 'rviz', 'imu.rviz')],
- # condition=IfCondition(LaunchConfiguration('rviz'))
- # )
-
- # Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=['/imu@sensor_msgs/msg/Imu@gz.msgs.IMU'],
- output='screen'
- )
-
- return LaunchDescription([
- gz_sim,
- DeclareLaunchArgument(
- 'rqt', default_value='true', description='Open RQt.'
- ),
- DeclareLaunchArgument(
- 'rviz', default_value='true', description='Open RViz.'
- ),
- bridge,
- rqt
- # rviz
- ])
diff --git a/ros_gz_sim_demos/launch/imu.launch.xml b/ros_gz_sim_demos/launch/imu.launch.xml
new file mode 100644
index 00000000..d7ef727c
--- /dev/null
+++ b/ros_gz_sim_demos/launch/imu.launch.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/launch/magnetometer.launch.py b/ros_gz_sim_demos/launch/magnetometer.launch.py
deleted file mode 100644
index e35b8487..00000000
--- a/ros_gz_sim_demos/launch/magnetometer.launch.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2019 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 os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument
-from launch.actions import IncludeLaunchDescription
-from launch.conditions import IfCondition
-from launch.launch_description_sources import PythonLaunchDescriptionSource
-from launch.substitutions import LaunchConfiguration
-
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
-
- pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
-
- gz_sim = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
- launch_arguments={
- 'gz_args': '-r sensors.sdf'
- }.items(),
- )
-
- # RQt
- rqt = Node(
- package='rqt_topic',
- executable='rqt_topic',
- arguments=['-t'],
- condition=IfCondition(LaunchConfiguration('rqt'))
- )
-
- # Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=['/magnetometer@sensor_msgs/msg/MagneticField@gz.msgs.Magnetometer'],
- output='screen'
- )
-
- return LaunchDescription([
- gz_sim,
- DeclareLaunchArgument('rqt', default_value='true',
- description='Open RQt.'),
- bridge,
- rqt
- ])
diff --git a/ros_gz_sim_demos/launch/magnetometer.launch.xml b/ros_gz_sim_demos/launch/magnetometer.launch.xml
new file mode 100644
index 00000000..10639b43
--- /dev/null
+++ b/ros_gz_sim_demos/launch/magnetometer.launch.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/launch/navsat.launch.py b/ros_gz_sim_demos/launch/navsat.launch.py
deleted file mode 100644
index f2172f93..00000000
--- a/ros_gz_sim_demos/launch/navsat.launch.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2019 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 os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument
-from launch.actions import IncludeLaunchDescription
-from launch.conditions import IfCondition
-from launch.launch_description_sources import PythonLaunchDescriptionSource
-from launch.substitutions import LaunchConfiguration
-
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
-
- pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
-
- gz_sim = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
- launch_arguments={
- 'gz_args': '-v 4 -r spherical_coordinates.sdf'
- }.items(),
- )
-
- # RQt
- rqt = Node(
- package='rqt_topic',
- executable='rqt_topic',
- arguments=['-t'],
- condition=IfCondition(LaunchConfiguration('rqt'))
- )
-
- # Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=['/navsat@sensor_msgs/msg/NavSatFix@gz.msgs.NavSat'],
- output='screen'
- )
-
- return LaunchDescription([
- gz_sim,
- DeclareLaunchArgument('rqt', default_value='true',
- description='Open RQt.'),
- bridge,
- rqt
- ])
diff --git a/ros_gz_sim_demos/launch/navsat.launch.xml b/ros_gz_sim_demos/launch/navsat.launch.xml
new file mode 100644
index 00000000..97ad0adc
--- /dev/null
+++ b/ros_gz_sim_demos/launch/navsat.launch.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/launch/navsat_gpsfix.launch.py b/ros_gz_sim_demos/launch/navsat_gpsfix.launch.py
deleted file mode 100644
index 83adcdcc..00000000
--- a/ros_gz_sim_demos/launch/navsat_gpsfix.launch.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2022 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 os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument
-from launch.actions import IncludeLaunchDescription
-from launch.conditions import IfCondition
-from launch.launch_description_sources import PythonLaunchDescriptionSource
-from launch.substitutions import LaunchConfiguration
-
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
-
- pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
-
- gz_sim = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py')),
- launch_arguments={
- 'gz_args': '-v 4 -r spherical_coordinates.sdf'
- }.items(),
- )
-
- # RQt
- rqt = Node(
- package='rqt_topic',
- executable='rqt_topic',
- arguments=['-t'],
- condition=IfCondition(LaunchConfiguration('rqt'))
- )
-
- # Bridge
- bridge = Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=['/navsat@gps_msgs/msg/GPSFix@gz.msgs.NavSat'],
- output='screen'
- )
-
- return LaunchDescription([
- gz_sim,
- DeclareLaunchArgument('rqt', default_value='true',
- description='Open RQt.'),
- bridge,
- rqt
- ])
diff --git a/ros_gz_sim_demos/launch/navsat_gpsfix.launch.xml b/ros_gz_sim_demos/launch/navsat_gpsfix.launch.xml
new file mode 100644
index 00000000..10c8c8a4
--- /dev/null
+++ b/ros_gz_sim_demos/launch/navsat_gpsfix.launch.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/launch/tf_bridge.launch.py b/ros_gz_sim_demos/launch/tf_bridge.launch.py
deleted file mode 100644
index 42f76cdc..00000000
--- a/ros_gz_sim_demos/launch/tf_bridge.launch.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2022 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 os
-
-from ament_index_python.packages import get_package_share_directory
-
-from launch import LaunchDescription
-from launch.actions import ExecuteProcess
-from launch_ros.actions import Node
-
-
-def generate_launch_description():
- pkg_ros_gz_sim_demos = get_package_share_directory('ros_gz_sim_demos')
- return LaunchDescription([
- # Launch gazebo
- ExecuteProcess(
- cmd=[
- 'gz', 'sim', '-r',
- os.path.join(
- pkg_ros_gz_sim_demos,
- 'models',
- 'double_pendulum_model.sdf'
- )
- ]
- ),
- # Launch a bridge to forward tf and joint states to ros2
- Node(
- package='ros_gz_bridge',
- executable='parameter_bridge',
- arguments=[
- '/world/default/model/double_pendulum_with_base0/joint_state@'
- 'sensor_msgs/msg/JointState[gz.msgs.Model',
- '/model/double_pendulum_with_base0/pose@'
- 'tf2_msgs/msg/TFMessage[gz.msgs.Pose_V'
- ],
- remappings=[
- ('/model/double_pendulum_with_base0/pose', '/tf'),
- ('/world/default/model/double_pendulum_with_base0/joint_state', '/joint_states')
- ]
- ),
- # Launch rviz
- Node(
- package='rviz2',
- executable='rviz2',
- arguments=['-d', os.path.join(pkg_ros_gz_sim_demos, 'rviz', 'tf_bridge.rviz')]
- )
- ])
diff --git a/ros_gz_sim_demos/launch/tf_bridge.launch.xml b/ros_gz_sim_demos/launch/tf_bridge.launch.xml
new file mode 100644
index 00000000..321a3d8c
--- /dev/null
+++ b/ros_gz_sim_demos/launch/tf_bridge.launch.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/ros_gz_sim_demos/package.xml b/ros_gz_sim_demos/package.xml
index 13242084..414af4fe 100644
--- a/ros_gz_sim_demos/package.xml
+++ b/ros_gz_sim_demos/package.xml
@@ -1,6 +1,6 @@
ros_gz_sim_demos
- 2.1.1
+ 2.1.2
Demos using Gazebo Sim simulation with ROS.
Apache 2.0
Aditya Pande
@@ -22,6 +22,7 @@
rqt_image_view
rqt_plot
rqt_topic
+ rviz_imu_plugin
rviz2
sdformat_urdf
xacro
diff --git a/ros_gz_sim_demos/rviz/imu.rviz b/ros_gz_sim_demos/rviz/imu.rviz
index 0169390a..2d825af4 100644
--- a/ros_gz_sim_demos/rviz/imu.rviz
+++ b/ros_gz_sim_demos/rviz/imu.rviz
@@ -1,43 +1,41 @@
Panels:
- - Class: rviz/Displays
+ - Class: rviz_common/Displays
Help Height: 78
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
+ - /Status1
+ - /Grid1
- /Imu1
- - /Imu1/Status1
+ - /Imu1/Axes properties1
+ - /Imu1/Acceleration properties1
Splitter Ratio: 0.5
- Tree Height: 352
- - Class: rviz/Selection
+ Tree Height: 555
+ - Class: rviz_common/Selection
Name: Selection
- - Class: rviz/Tool Properties
+ - Class: rviz_common/Tool Properties
Expanded:
- - /2D Pose Estimate1
- - /2D Nav Goal1
+ - /2D Goal Pose1
- /Publish Point1
Name: Tool Properties
Splitter Ratio: 0.5886790156364441
- - Class: rviz/Views
+ - Class: rviz_common/Views
Expanded:
- /Current View1
Name: Views
Splitter Ratio: 0.5
- - Class: rviz/Time
+ - Class: rviz_common/Time
Experimental: false
Name: Time
SyncMode: 0
SyncSource: ""
-Preferences:
- PromptSaveOnExit: true
-Toolbars:
- toolButtonStyle: 2
Visualization Manager:
Class: ""
Displays:
- Alpha: 0.5
Cell Size: 1
- Class: rviz/Grid
+ Class: rviz_default_plugins/Grid
Color: 160; 160; 164
Enabled: true
Line Style:
@@ -53,53 +51,90 @@ Visualization Manager:
Plane Cell Count: 10
Reference Frame:
Value: true
- - Alpha: 1
- Class: rviz_plugin_tutorials/Imu
- Color: 204; 51; 204
+ - Acceleration properties:
+ Acc. vector alpha: 1
+ Acc. vector color: 255; 0; 0
+ Acc. vector scale: 1
+ Derotate acceleration: true
+ Enable acceleration: true
+ Axes properties:
+ Axes scale: 1
+ Enable axes: true
+ Box properties:
+ Box alpha: 1
+ Box color: 255; 0; 0
+ Enable box: false
+ x_scale: 1
+ y_scale: 1
+ z_scale: 1
+ Class: rviz_imu_plugin/Imu
Enabled: true
- History Length: 1
Name: Imu
- Topic: /imu
- Unreliable: false
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ Filter size: 10
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /imu
Value: true
+ fixed_frame_orientation: true
Enabled: true
Global Options:
Background Color: 48; 48; 48
- Default Light: true
- Fixed Frame: sensors/sensors_box/link/imu
+ Fixed Frame: sensors_box/link/imu
Frame Rate: 30
Name: root
Tools:
- - Class: rviz/Interact
+ - Class: rviz_default_plugins/Interact
Hide Inactive Objects: true
- - Class: rviz/MoveCamera
- - Class: rviz/Select
- - Class: rviz/FocusCamera
- - Class: rviz/Measure
- - Class: rviz/SetInitialPose
- Theta std deviation: 0.2617993950843811
- Topic: /initialpose
- X std deviation: 0.5
- Y std deviation: 0.5
- - Class: rviz/SetGoal
- Topic: /move_base_simple/goal
- - Class: rviz/PublishPoint
+ - Class: rviz_default_plugins/MoveCamera
+ - Class: rviz_default_plugins/Select
+ - Class: rviz_default_plugins/FocusCamera
+ - Class: rviz_default_plugins/Measure
+ Line color: 128; 128; 0
+ - Class: rviz_default_plugins/SetInitialPose
+ Covariance x: 0.25
+ Covariance y: 0.25
+ Covariance yaw: 0.06853891909122467
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /initialpose
+ - Class: rviz_default_plugins/SetGoal
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /goal_pose
+ - Class: rviz_default_plugins/PublishPoint
Single click: true
- Topic: /clicked_point
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /clicked_point
+ Transformation:
+ Current:
+ Class: rviz_default_plugins/TF
Value: true
Views:
Current:
- Class: rviz/Orbit
- Distance: 33.22251510620117
+ Class: rviz_default_plugins/Orbit
+ Distance: 29.85377311706543
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Focal Point:
- X: -1.7206333875656128
- Y: -0.9246708154678345
- Z: 1.870512843132019
+ X: 0
+ Y: 0
+ Z: 0
Focal Shape Fixed Size: true
Focal Shape Size: 0.05000000074505806
Invert Z Axis: false
@@ -113,10 +148,10 @@ Visualization Manager:
Window Geometry:
Displays:
collapsed: false
- Height: 575
+ Height: 846
Hide Left Dock: false
Hide Right Dock: false
- QMainWindow State: 000000ff00000000fd000000040000000000000191000001e9fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000001e9000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b000002b4000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000003d70000003efc0100000002fb0000000800540069006d00650000000000000003d70000024400fffffffb0000000800540069006d00650100000000000004500000000000000000000001a2000001e900000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
+ QMainWindow State: 000000ff00000000fd000000040000000000000156000002b4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000002b4000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b000002b4000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b00000025300fffffffb0000000800540069006d006501000000000000045000000000000000000000023f000002b400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Time:
@@ -125,6 +160,6 @@ Window Geometry:
collapsed: false
Views:
collapsed: false
- Width: 825
- X: 751
- Y: 92
+ Width: 1200
+ X: 2219
+ Y: 69
diff --git a/test_ros_gz_bridge/CHANGELOG.rst b/test_ros_gz_bridge/CHANGELOG.rst
index bebf4abc..b4f1e3b6 100644
--- a/test_ros_gz_bridge/CHANGELOG.rst
+++ b/test_ros_gz_bridge/CHANGELOG.rst
@@ -2,6 +2,9 @@
Changelog for package test_ros_gz_bridge
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2.1.2 (2024-10-31)
+------------------
+
2.1.1 (2024-10-14)
------------------
diff --git a/test_ros_gz_bridge/package.xml b/test_ros_gz_bridge/package.xml
index 4f200091..95da57f1 100644
--- a/test_ros_gz_bridge/package.xml
+++ b/test_ros_gz_bridge/package.xml
@@ -2,7 +2,7 @@
test_ros_gz_bridge
- 2.1.1
+ 2.1.2
Bridge communication between ROS and Gazebo Transport
Aditya Pande
Alejandro Hernandez