Add multi robot launch

This commit is contained in:
GyuH13 2025-02-05 09:59:52 +09:00
parent a80417abb5
commit 2d757bbe99
4 changed files with 207 additions and 9 deletions

View File

@ -1,15 +1,15 @@
name: humble-devel name: humble
# Controls when the action will run. Triggers the workflow on push or pull request # Controls when the action will run. Triggers the workflow on push or pull request
on: on:
push: push:
branches: [ humble-devel ] branches: [ main, humble ]
pull_request: pull_request:
branches: [ humble-devel ] branches: [ main, humble ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
humble-devel: humble:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
@ -55,4 +55,4 @@ jobs:
package-name: turtlebot3_simulations package-name: turtlebot3_simulations
target-ros2-distro: ${{ matrix.ros_distribution }} target-ros2-distro: ${{ matrix.ros_distribution }}
vcs-repo-file-url: "https://raw.githubusercontent.com/ROBOTIS-GIT/turtlebot3_simulations/ros2-devel/turtlebot3_simulations_ci.repos" vcs-repo-file-url: "https://raw.githubusercontent.com/ROBOTIS-GIT/turtlebot3_simulations/ros2-devel/turtlebot3_simulations_ci.repos"

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python3
#
# Copyright 2019 ROBOTIS CO., LTD.
#
# 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.
#
# Authors: Joep Tool, HyunGyu Kim
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import GroupAction, IncludeLaunchDescription, RegisterEventHandler
from launch_ros.actions import PushRosNamespace
from launch.event_handlers import OnShutdown
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
import xml.etree.ElementTree as ET
def generate_launch_description():
TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL']
number_of_robots = 4
namespace = 'TB3'
pose = [[-2, -0.5], [0.5, -2], [2, 0.5], [-0.5, 2]]
model_folder = 'turtlebot3_' + TURTLEBOT3_MODEL
urdf_path = os.path.join(
get_package_share_directory('turtlebot3_gazebo'),
'models',
model_folder,
'model.sdf'
)
save_path = os.path.join(
get_package_share_directory('turtlebot3_gazebo'),
'models',
model_folder,
'tmp'
)
launch_file_dir = os.path.join(get_package_share_directory('turtlebot3_gazebo'), 'launch')
pkg_gazebo_ros = get_package_share_directory('gazebo_ros')
use_sim_time = LaunchConfiguration('use_sim_time', default='false')
world = os.path.join(
get_package_share_directory('turtlebot3_gazebo'),
'worlds',
'turtlebot3_world.world'
)
gzserver_cmd = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_gazebo_ros, 'launch', 'gzserver.launch.py')
),
launch_arguments={'world': world}.items()
)
gzclient_cmd = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py')
)
)
robot_state_publisher_cmd_list = []
for count in range(number_of_robots):
robot_state_publisher_cmd_list.append(
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, 'robot_state_publisher.launch.py')
),
launch_arguments={
'use_sim_time': use_sim_time,
'frame_prefix': f'{namespace}_{count+1}'
}.items()
)
)
spawn_turtlebot_cmd_list = []
for count in range(number_of_robots):
tree = ET.parse(urdf_path)
root = tree.getroot()
for odom_frame_tag in root.iter('odometry_frame'):
odom_frame_tag.text = f"{namespace}_{count+1}/odom"
for base_frame_tag in root.iter('robot_base_frame'):
base_frame_tag.text = f"{namespace}_{count+1}/base_footprint"
for scan_frame_tag in root.iter('frame_name'):
scan_frame_tag.text = f"{namespace}_{count+1}/base_scan"
urdf_modified = ET.tostring(tree.getroot(), encoding='unicode')
urdf_modified = '<?xml version="1.0" ?>\n'+urdf_modified
with open(f'{save_path}{count+1}.sdf', 'w') as file:
file.write(urdf_modified)
spawn_turtlebot_cmd_list.append(
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, 'multi_spawn_turtlebot3.launch.py')
),
launch_arguments={
'x_pose': str(pose[count][0]),
'y_pose': str(pose[count][1]),
'robot_name': f'{TURTLEBOT3_MODEL}_{count+1}',
'namespace': f'{namespace}_{count+1}',
'sdf_path': f'{save_path}{count+1}.sdf'
}.items()
)
)
ld = LaunchDescription()
# Add the commands to the launch description
ld.add_action(gzserver_cmd)
ld.add_action(gzclient_cmd)
ld.add_action(RegisterEventHandler(
OnShutdown(
on_shutdown=lambda event,
context: [os.remove(f'{save_path}{count+1}.sdf') for count in range(number_of_robots)]
)
))
for count, spawn_turtlebot_cmd in enumerate(spawn_turtlebot_cmd_list, start=1):
ld.add_action(GroupAction([PushRosNamespace(f'{namespace}_{count}'),
robot_state_publisher_cmd_list[count-1],
spawn_turtlebot_cmd]))
return ld

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# 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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL']
# Launch configuration variables specific to simulation
x_pose = LaunchConfiguration('x_pose', default='0.0')
y_pose = LaunchConfiguration('y_pose', default='0.0')
robot_name = LaunchConfiguration('robot_name', default=TURTLEBOT3_MODEL)
namespace = LaunchConfiguration('namespace', default='')
sdf_path = LaunchConfiguration('sdf_path', default='')
declare_x_position_cmd = DeclareLaunchArgument(
'x_pose', default_value='0.0',
description='Specify namespace of the robot')
declare_y_position_cmd = DeclareLaunchArgument(
'y_pose', default_value='0.0',
description='Specify namespace of the robot')
start_gazebo_ros_spawner_cmd = Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=[
'-entity', robot_name,
'-file', sdf_path,
'-x', x_pose,
'-y', y_pose,
'-z', '0.01',
'-robot_namespace', namespace
],
output='screen',
)
ld = LaunchDescription()
# Declare the launch options
ld.add_action(declare_x_position_cmd)
ld.add_action(declare_y_position_cmd)
# Add any conditioned actions
ld.add_action(start_gazebo_ros_spawner_cmd)
return ld

View File

@ -21,15 +21,16 @@ import os
from ament_index_python.packages import get_package_share_directory from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration from launch.substitutions import LaunchConfiguration, PythonExpression
from launch_ros.actions import Node from launch_ros.actions import Node
def generate_launch_description(): def generate_launch_description():
TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL'] TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL']
use_sim_time = LaunchConfiguration('use_sim_time', default='false') use_sim_time = LaunchConfiguration('use_sim_time', default='true')
urdf_file_name = 'turtlebot3_' + TURTLEBOT3_MODEL + '.urdf' urdf_file_name = 'turtlebot3_' + TURTLEBOT3_MODEL + '.urdf'
frame_prefix = LaunchConfiguration('frame_prefix', default='')
print('urdf_file_name : {}'.format(urdf_file_name)) print('urdf_file_name : {}'.format(urdf_file_name))
@ -46,7 +47,6 @@ def generate_launch_description():
'use_sim_time', 'use_sim_time',
default_value='false', default_value='false',
description='Use simulation (Gazebo) clock if true'), description='Use simulation (Gazebo) clock if true'),
Node( Node(
package='robot_state_publisher', package='robot_state_publisher',
executable='robot_state_publisher', executable='robot_state_publisher',
@ -54,7 +54,8 @@ def generate_launch_description():
output='screen', output='screen',
parameters=[{ parameters=[{
'use_sim_time': use_sim_time, 'use_sim_time': use_sim_time,
'robot_description': robot_desc 'robot_description': robot_desc,
'frame_prefix': PythonExpression(["'", frame_prefix, "/'"])
}], }],
), ),
]) ])