From 65e44b3a66c2cfa22ba1f8740cdff6fd12c39620 Mon Sep 17 00:00:00 2001 From: Franco Cipollone <53065142+francocipollone@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:10:30 -0300 Subject: [PATCH 1/2] Adds templates and CO. (#27) Signed-off-by: Franco Cipollone --- .github/CODEOWNERS | 4 +++ .github/ISSUE_TEMPLATE/bug_report.md | 27 ++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++ .github/pull_request_template.md | 43 +++++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/pull_request_template.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..ae2b0a9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# More info: +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners + +* @agalbachicar @lneumarkt @francocipollone diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..1715ce7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Report a bug +labels: bug +--- + + +## Environment +* OS Version: +* Source or binary build? + + + +## Description +* Expected behavior: +* Actual behavior: + +## Steps to reproduce + + +1. +2. +3. + +## Output + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..f4c3126 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Request a new feature +labels: enhancement +--- + + +## Desired behavior + + +## Alternatives considered + + +## Implementation suggestion + + +## Additional context + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..4b47ac5 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,43 @@ + + +# 🦟 Bug fix + +Fixes # + +## Summary + + +## Checklist +- [ ] Signed all commits for DCO +- [ ] Added tests +- [ ] Updated documentation (as needed) +- [ ] Updated migration guide (as needed) + + +πŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”ΈπŸ”Έ + +# πŸŽ‰ New feature + +Closes # + +## Summary + + +## Test it + + +## Checklist +- [ ] Signed all commits for DCO +- [ ] Added tests +- [ ] Added example and/or tutorial +- [ ] Updated documentation (as needed) +- [ ] Updated migration guide (as needed) + From aec3fb32931b222511d430e59e7728bb84b78e20 Mon Sep 17 00:00:00 2001 From: Agustin Alba Chicar Date: Wed, 31 Jan 2024 22:18:09 +0100 Subject: [PATCH 2/2] Adds a spawn launchfile and modifies the main launchfile to use it (#19) Signed-off-by: Agustin Alba Chicar Signed-off-by: Franco Cipollone Co-authored-by: Franco Cipollone --- README.md | 14 +++ andino_gz/launch/andino_gz.launch.py | 71 ++++--------- andino_gz/launch/spawn_robot.launch.py | 140 +++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 50 deletions(-) create mode 100644 andino_gz/launch/spawn_robot.launch.py diff --git a/README.md b/README.md index 0f36c73..b59e48e 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,20 @@ If you'd like to work from ROS you can launch the ros bridge via: Make sure to review the required topics using `ign topics` and `ros2 topic` CLI tools. Also, consider using looking at the translation entries under `andino_gz/config/bridge_config.yaml`. +### Spawn multiple Andinos + +Launch simulation as before: + ```sh + ros2 launch andino_gz andino_gz.launch.py + ``` + +This will spawn only one Andino in the simulation + +For spawning more Andinos you can use the `spawn_robot` launch file. Make sure a different `entity` name is passed as argument as well as initial positions. + ```sh + ros2 launch andino_gz spawn_robot.launch.py entity:=andino_n initial_pose_x:=1 initial_pose_y:=1 + ``` + ## :raised_hands: Contributing Issues or PRs are always welcome! Please refer to [CONTRIBUTING](CONTRIBUTING.md) doc. diff --git a/andino_gz/launch/andino_gz.launch.py b/andino_gz/launch/andino_gz.launch.py index 78eb0d8..dc2a564 100644 --- a/andino_gz/launch/andino_gz.launch.py +++ b/andino_gz/launch/andino_gz.launch.py @@ -11,53 +11,42 @@ import xacro -pkg_andino_description = get_package_share_directory('andino_description') -pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim') -pkg_andino_gz = get_package_share_directory('andino_gz') - - def generate_launch_description(): + pkg_andino_gz = get_package_share_directory('andino_gz') + rviz_arg = DeclareLaunchArgument('rviz', default_value='false', description='Start RViz.') - rsp_arg = DeclareLaunchArgument('rsp', default_value='false', description='Run robot state publisher node.') jsp_gui_arg = DeclareLaunchArgument('jsp_gui', default_value='false', description='Run joint state publisher gui node.') - # Parse robot description from xacro - robot_description_file = os.path.join(pkg_andino_gz, 'urdf', 'andino_gz.urdf.xacro') - mappings = {'use_fixed_caster': 'false'} - robot_description_config = xacro.process_file(robot_description_file, mappings=mappings) - robot_desc = robot_description_config.toprettyxml(indent=' ') - # Passing absolute path to the robot description due to Gazebo issues finding andino_description pkg path. - robot_desc = robot_desc.replace( - 'package://andino_description/', f'file://{pkg_andino_description}/' - ) - world_name = 'depot.sdf' world_path = os.path.join(pkg_andino_gz, 'worlds', world_name) # Uncomment the following line to use the empty world # world_path = '-r empty.sdf' - # Robot state publisher - robot_state_publisher = Node( - package='robot_state_publisher', - executable='robot_state_publisher', - name='robot_state_publisher', - output='both', - parameters=[ - { - 'robot_description': robot_desc, - } - ], - ) - # Gazebo Sim gazebo = IncludeLaunchDescription( PythonLaunchDescriptionSource( - os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py') + os.path.join(get_package_share_directory('ros_gz_sim'), 'launch', 'gz_sim.launch.py') ), launch_arguments={'gz_args': world_path}.items(), ) + # Spawn the robot and the Robot State Publisher node. + spawn_robot_and_rsp = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(pkg_andino_gz, 'launch', 'spawn_robot.launch.py') + ), + launch_arguments={ + 'entity': 'andino', + 'initial_pose_x': '0', + 'initial_pose_y': '0', + 'initial_pose_z': '0.1', + 'initial_pose_yaw': '0', + 'robot_description_topic': '/robot_description', + 'use_sim_time': 'true', + }.items(), + ) + # RViz rviz = Node( package='rviz2', @@ -75,32 +64,14 @@ def generate_launch_description(): condition=IfCondition(LaunchConfiguration('jsp_gui')) ) - # Spawn - spawn = Node( - package='ros_gz_sim', - executable='create', - arguments=[ - '-name', 'andino', - '-topic', 'robot_description', - '-x', '0', - '-y', '0', - '-z', '0.1', - ], - output='screen', - ) - - ld = LaunchDescription( + return LaunchDescription( [ # Arguments and Nodes jsp_gui_arg, - rsp_arg, rviz_arg, gazebo, + spawn_robot_and_rsp, jsp_gui, - robot_state_publisher, rviz, - spawn, ] ) - - return ld diff --git a/andino_gz/launch/spawn_robot.launch.py b/andino_gz/launch/spawn_robot.launch.py new file mode 100644 index 0000000..fc52081 --- /dev/null +++ b/andino_gz/launch/spawn_robot.launch.py @@ -0,0 +1,140 @@ +"""Spawn an Andino robot in new Gazebo, also launch the robot_state_publisher.""" + +import os + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.conditions import IfCondition +from launch.substitutions import LaunchConfiguration +from launch.substitutions import PythonExpression +from launch_ros.actions import Node +from xacro import process_file + +PKG_ANDINO_DESCRIPTION = get_package_share_directory('andino_description') +PKG_ANDINO_GZ = get_package_share_directory('andino_gz') + +def get_robot_description() -> str: + """ + Obtain the URDF from the xacro file. + + This replace package tag by file tag to works with gazebo + # See https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1284 + + Considerations: the URDF model of the robot will be set with certain + presets: + - use_fixed_caster: false + + Returns + ------- + URDF of the robot with gazebo data + + """ + # Parse robot description from xacro + robot_description_file_path = os.path.join(PKG_ANDINO_GZ, 'urdf', 'andino_gz.urdf.xacro') + mappings = {'use_fixed_caster': 'false'} + robot_description_config = process_file(robot_description_file_path, mappings=mappings) + robot_desc = robot_description_config.toprettyxml(indent=' ') + # Passing absolute path to the robot description due to Gazebo issues finding andino_description pkg path. + robot_desc = robot_desc.replace( + 'package://andino_description/', f'file://{PKG_ANDINO_DESCRIPTION}/' + ) + return robot_desc + + +def generate_launch_description(): + # Arguments + entity = LaunchConfiguration('entity') + initial_pose_x = LaunchConfiguration('initial_pose_x') + initial_pose_y = LaunchConfiguration('initial_pose_y') + initial_pose_z = LaunchConfiguration('initial_pose_z') + initial_pose_yaw = LaunchConfiguration('initial_pose_yaw') + robot_description_topic = LaunchConfiguration('robot_description_topic') + rsp_frequency = LaunchConfiguration('rsp_frequency') + use_sim_time = LaunchConfiguration('use_sim_time') + + entity_argument = DeclareLaunchArgument( + 'entity', default_value='andino', description='Name of the robot.' + ) + x_argument = DeclareLaunchArgument( + 'initial_pose_x', + default_value='0.0', + description='Initial x pose of andino in the simulation.', + ) + y_argument = DeclareLaunchArgument( + 'initial_pose_y', + default_value='0.0', + description='Initial y pose of andino in the simulation', + ) + z_argument = DeclareLaunchArgument( + 'initial_pose_z', + default_value='0.1', + description='Initial z pose of andino in the simulation.', + ) + yaw_argument = DeclareLaunchArgument( + 'initial_pose_yaw', + default_value='0.0', + description='Initial yaw pose of andino in the simulation.', + ) + robot_desc_argument = DeclareLaunchArgument( + 'robot_description_topic', + default_value='/robot_description', + description='Robot description topic.', + ) + rsp_frequency_argument = DeclareLaunchArgument( + 'rsp_frequency', + default_value='30.0', + description='Robot State Publisher frequency.', + ) + use_sim_time_argument = DeclareLaunchArgument( + 'use_sim_time', + default_value='true', + description='Use simulation (Gazebo) clock if true', + ) + + # Robot state publisher. + rsp_node = Node( + package='robot_state_publisher', + executable='robot_state_publisher', + name='robot_state_publisher', + output='both', + parameters=[ + { + 'use_sim_time': use_sim_time, + 'publish_frequency': rsp_frequency, + 'robot_description': get_robot_description(), + } + ], + ) + + # Spawn the robot model. + spawn_node = Node( + package='ros_gz_sim', + executable='create', + arguments=[ + '-name', entity, + '-topic', robot_description_topic, + '-x', initial_pose_x, + '-y', initial_pose_y, + '-z', initial_pose_z, + '-R', '0', + '-P', '0', + '-Y', initial_pose_yaw, + ], + output='screen', + ) + + return LaunchDescription( + [ + entity_argument, + x_argument, + y_argument, + z_argument, + yaw_argument, + robot_desc_argument, + rsp_frequency_argument, + use_sim_time_argument, + rsp_node, + spawn_node, + ] + )