Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Launch gzserver and the bridge as composable nodes #528

Merged
merged 27 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
21d4c23
Add gzserver with ability to load an SDF file or string
azeey Feb 21, 2024
3a5e099
Testing components.
caguero Apr 3, 2024
1b3ba4e
Tweak
caguero Apr 4, 2024
04255e3
Tweak
caguero Apr 4, 2024
d28021a
Tweak
caguero Apr 4, 2024
82633e7
Style
caguero Apr 4, 2024
0a34d24
Merge remote-tracking branch 'origin/ros2' into gz_sim_ros_node
azeey Apr 4, 2024
2506cb9
Merge branch 'gz_sim_ros_node' into gz_sim_ros_node_composition
caguero Apr 4, 2024
2f19e16
Remove comments
caguero Apr 5, 2024
1124d28
Launch file for running gz_bridge (#530)
caguero Apr 11, 2024
78127ca
Launch file for running gzserver (#532)
caguero Apr 18, 2024
2e28e0d
Merge branch 'ros2' into gz_sim_ros_node_composition
caguero May 13, 2024
c2a26ef
Launch file for combined gzserver + bridge (#533)
caguero May 15, 2024
6a73faa
Launch file for combined spawn_model + bridge (#534)
caguero May 15, 2024
1ba6ebf
Launch gzserver from xml (#548)
caguero May 21, 2024
7c380c3
Merge remote-tracking branch 'origin/ros2' into gz_sim_ros_node
azeey May 22, 2024
2b07936
Fix build, remove experimental code
azeey May 22, 2024
35be061
Add comment, fix linter
azeey May 22, 2024
85904db
Merge remote-tracking branch 'origin/gz_sim_ros_node' into gz_sim_ros…
azeey May 22, 2024
8d01ae8
Fix end of file newline
azeey May 22, 2024
08e0389
Merge remote-tracking branch 'origin/ros2' into gz_sim_ros_node_compo…
azeey May 22, 2024
f7eaa49
Update ros_gz_sim/src/gzserver.cpp
caguero May 23, 2024
efb5f92
Update ros_gz_sim/src/gzserver.cpp
caguero May 23, 2024
01345e2
Remove launch_gz and use ros_gz_sim instead
caguero May 23, 2024
122ac28
Merge branch 'gz_sim_ros_node_composition' of github.com:gazebosim/ro…
caguero May 23, 2024
305097b
Tweaks
caguero May 23, 2024
2416aaf
Mostly styule.
caguero May 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions launch_gz/launch_gz/__init__.py
Original file line number Diff line number Diff line change
@@ -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 `launch_gz` package."""

from . import actions


__all__ = [
'actions',
]
22 changes: 22 additions & 0 deletions launch_gz/launch_gz/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -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 .gzserver import GzServer


__all__ = [
'GzServer',
]
115 changes: 115 additions & 0 deletions launch_gz/launch_gz/actions/gzserver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# 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."""

from typing import List
from typing import Optional

from launch.action import Action
from launch.actions import IncludeLaunchDescription
from launch.frontend import expose_action, Entity, 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('gzserver')
azeey marked this conversation as resolved.
Show resolved Hide resolved
class GzServer(Action):
"""Action that executes a gzserver ROS [composable] node."""

def __init__(
self,
*,
world_sdf_file: SomeSubstitutionsType,
world_sdf_string: SomeSubstitutionsType,
container_name: SomeSubstitutionsType,
use_composition: SomeSubstitutionsType,
azeey marked this conversation as resolved.
Show resolved Hide resolved
**kwargs
) -> None:
"""
Construct a gzserver action.

All arguments are forwarded to `ros_gz_sim.launch.gzserver.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: 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.__use_composition = use_composition

@classmethod
def parse(cls, entity: Entity, parser: Parser):
"""Parse gzserver."""
_, 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)

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(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.
"""

gzserver_description = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[PathJoinSubstitution([FindPackageShare('ros_gz_sim'),
'launch',
'gzserver.launch.py'])]),
launch_arguments=[('world_sdf_file', self.__world_sdf_file),
('world_sdf_string', self.__world_sdf_string),
('container_name', self.__container_name),
('use_composition', self.__use_composition),
])

return [gzserver_description]
36 changes: 36 additions & 0 deletions launch_gz/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<?xml-model
href="http://download.ros.org/schema/package_format2.xsd"
schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>launch_gz</name>
azeey marked this conversation as resolved.
Show resolved Hide resolved
<version>0.246.0</version>
azeey marked this conversation as resolved.
Show resolved Hide resolved
<description>gz specific extensions to the launch tool.</description>

<maintainer email="ahcorde@openrobotics.org">Alejandro Hernandez</maintainer>
<maintainer email="caguero@openrobotics.org">Carlos Agüero</maintainer>

<license>Apache License 2.0</license>

<author email="caguero@openrobotics.org">Carlos Agüero</author>

<depend>ament_index_python</depend>
<depend>composition_interfaces</depend>
<depend>launch</depend>
<depend>launch_ros</depend>
<depend>lifecycle_msgs</depend>
<depend>osrf_pycommon</depend>
<depend>ros_gz_sim</depend>
<depend>python3-importlib-metadata</depend>
<depend>python3-yaml</depend>
<depend>rclpy</depend>

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<build_type>ament_python</build_type>
</export>
</package>
Empty file added launch_gz/resource/launch_gz
Empty file.
49 changes: 49 additions & 0 deletions launch_gz/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from setuptools import find_packages
from setuptools import setup

package_name = 'launch_gz'

setup(
name=package_name,
version='0.246.0',
azeey marked this conversation as resolved.
Show resolved Hide resolved
packages=find_packages(exclude=['test']),
data_files=[
('share/' + package_name, ['package.xml']),
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
],
package_data={'launch_gz': ['py.typed']},
install_requires=[
'setuptools',
'ament_index_python',
'launch',
'launch_ros',
'osrf_pycommon',
'pyyaml',
],
zip_safe=True,
author='Carlos Agüero',
author_email='caguero@openrobotics.org',
maintainer='Carlos Agüero, Alejandro Hernandez, Michael Carroll',
maintainer_email='caguero@openrobotics.org, alejandro@openrobotics.org, mjcarroll@intrinsic.ai',
azeey marked this conversation as resolved.
Show resolved Hide resolved
url='https://github.com/gazebosim/ros_gz/launch_gz',
download_url='https://github.com/gazebosim/ros_gz/releases',
keywords=['ROS'],
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Topic :: Software Development',
],
description='gz specific extensions to `launch`.',
long_description=(
'This package provides gz specific extensions to the launch package.'
),
license='Apache License, Version 2.0',
tests_require=['pytest'],
entry_points={
'launch.frontend.launch_extension': [
'launch_gz = launch_gz',
],
}
)
5 changes: 5 additions & 0 deletions ros_gz_bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ install(
DESTINATION include/${PROJECT_NAME}
)

install(
DIRECTORY launch/
DESTINATION share/${PROJECT_NAME}/launch
)

set(bridge_executables
parameter_bridge
static_bridge
Expand Down
109 changes: 109 additions & 0 deletions ros_gz_bridge/launch/ros_gz_bridge.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# 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, GroupAction
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, PythonExpression
from launch_ros.actions import ComposableNodeContainer, Node
from launch_ros.descriptions import ComposableNode


def generate_launch_description():

config_file = LaunchConfiguration('config_file')
container_name = LaunchConfiguration('container_name')
namespace = LaunchConfiguration('namespace')
use_composition = LaunchConfiguration('use_composition')
use_respawn = LaunchConfiguration('use_respawn')
log_level = LaunchConfiguration('log_level')

declare_config_file_cmd = DeclareLaunchArgument(
'config_file', default_value='', 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_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'
)

load_nodes = GroupAction(
condition=IfCondition(PythonExpression(['not ', use_composition])),
actions=[
Node(
package='ros_gz_bridge',
executable='bridge_node',
output='screen',
respawn=use_respawn,
respawn_delay=2.0,
parameters=[{'config_file': config_file}],
arguments=['--ros-args', '--log-level', log_level],
),
],
)

load_composable_nodes = ComposableNodeContainer(
condition=IfCondition(use_composition),
name=container_name,
namespace=namespace,
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='ros_gz_bridge',
plugin='ros_gz_bridge::RosGzBridge',
name='ros_gz_bridge',
parameters=[{'config_file': config_file}],
extra_arguments=[{'use_intra_process_comms': True}],
),
],
output='screen',
)

# Create the launch description and populate
ld = LaunchDescription()

# Declare the launch options
ld.add_action(declare_config_file_cmd)
ld.add_action(declare_container_name_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)
# Add the actions to launch all of the bridge nodes
ld.add_action(load_nodes)
ld.add_action(load_composable_nodes)

return ld
Loading