forked from zbw/yiliao2026
154 lines
5.7 KiB
Python
154 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
# =============================================================================
|
|
# gc_bringup — SLAM 建图模式
|
|
# 启动 Gazebo + 机器人 + slam_toolbox 在线异步建图 + RViz
|
|
# =============================================================================
|
|
import os
|
|
from ament_index_python.packages import get_package_share_directory
|
|
from launch import LaunchDescription
|
|
from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction
|
|
from launch.conditions import IfCondition, UnlessCondition
|
|
from launch.substitutions import LaunchConfiguration, Command
|
|
from launch_ros.actions import Node
|
|
from launch_ros.parameter_descriptions import ParameterValue
|
|
|
|
|
|
def generate_launch_description():
|
|
# ============================ 包路径 ============================
|
|
bringup_dir = get_package_share_directory('gc_bringup')
|
|
origincar_dir = get_package_share_directory('origincar_description')
|
|
|
|
# ============================ 启动参数 ============================
|
|
use_sim_time = LaunchConfiguration('use_sim_time', default='true')
|
|
use_gazebo = LaunchConfiguration('use_gazebo', default='true')
|
|
use_rviz = LaunchConfiguration('use_rviz', default='false')
|
|
world = LaunchConfiguration('world', default=os.path.join(
|
|
origincar_dir, 'world', 'gc_world.world'))
|
|
|
|
declare_use_sim_time = DeclareLaunchArgument(
|
|
'use_sim_time', default_value='true',
|
|
description='Use simulation (Gazebo) clock if true')
|
|
declare_use_gazebo = DeclareLaunchArgument(
|
|
'use_gazebo', default_value='true',
|
|
description='Start Gazebo simulation')
|
|
declare_use_rviz = DeclareLaunchArgument(
|
|
'use_rviz', default_value='false',
|
|
description='Start RViz2 (set true if you need local visualization)')
|
|
declare_world = DeclareLaunchArgument(
|
|
'world', default_value=os.path.join(origincar_dir, 'world', 'gc_world.world'),
|
|
description='Full path to Gazebo world file')
|
|
|
|
# ============================ 机器人模型 ============================
|
|
default_model_path = os.path.join(origincar_dir, 'urdf', 'origincar.urdf')
|
|
robot_description = ParameterValue(
|
|
Command(['xacro ', default_model_path]), value_type=str)
|
|
|
|
# ============================ Gazebo ============================
|
|
start_gazebo = ExecuteProcess(
|
|
condition=IfCondition(use_gazebo),
|
|
cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_init.so',
|
|
'-s', 'libgazebo_ros_factory.so', world],
|
|
output='screen'
|
|
)
|
|
|
|
spawn_robot = Node(
|
|
condition=IfCondition(use_gazebo),
|
|
package='gazebo_ros',
|
|
executable='spawn_entity.py',
|
|
arguments=['-entity', 'mycar',
|
|
'-file', default_model_path,
|
|
'-x', '0.0', '-y', '0.0', '-z', '0.1'],
|
|
output='screen'
|
|
)
|
|
|
|
# ============================ TF & 机器人状态 ============================
|
|
robot_state_publisher = Node(
|
|
package='robot_state_publisher',
|
|
executable='robot_state_publisher',
|
|
name='robot_state_publisher',
|
|
parameters=[{
|
|
'robot_description': robot_description,
|
|
'use_sim_time': True,
|
|
'publish_frequency': 30.0
|
|
}],
|
|
output='screen'
|
|
)
|
|
|
|
joint_state_publisher = Node(
|
|
package='joint_state_publisher',
|
|
executable='joint_state_publisher',
|
|
name='joint_state_publisher',
|
|
parameters=[{'use_sim_time': True}],
|
|
output='screen'
|
|
)
|
|
|
|
# ============================ SLAM Toolbox (在线异步建图) ============================
|
|
slam_params_file = os.path.join(
|
|
bringup_dir, 'config', 'mapper_params_online_async.yaml')
|
|
|
|
slam_toolbox_node = Node(
|
|
package='slam_toolbox',
|
|
executable='async_slam_toolbox_node',
|
|
name='slam_toolbox',
|
|
output='screen',
|
|
parameters=[slam_params_file, {'use_sim_time': True}],
|
|
remappings=[('/scan', '/scan')]
|
|
)
|
|
|
|
# ============================ RViz2 ============================
|
|
rviz_config = os.path.join(bringup_dir, 'rviz', 'slam_mapping.rviz')
|
|
rviz_node = Node(
|
|
condition=IfCondition(use_rviz),
|
|
package='rviz2',
|
|
executable='rviz2',
|
|
name='rviz2',
|
|
arguments=['-d', rviz_config],
|
|
parameters=[{'use_sim_time': True}],
|
|
output='screen'
|
|
)
|
|
|
|
# ============================ 键盘遥控 (用于驱动机器人建图) ============================
|
|
use_teleop = LaunchConfiguration('use_teleop', default='true')
|
|
declare_use_teleop = DeclareLaunchArgument(
|
|
'use_teleop', default_value='true',
|
|
description='Start keyboard teleop for driving')
|
|
|
|
teleop_node = Node(
|
|
condition=IfCondition(use_teleop),
|
|
package='teleop_twist_keyboard',
|
|
executable='teleop_twist_keyboard',
|
|
name='teleop_twist_keyboard',
|
|
prefix='xterm -e',
|
|
output='screen',
|
|
remappings=[('/cmd_vel', '/cmd_vel')],
|
|
parameters=[{'use_sim_time': True}]
|
|
)
|
|
|
|
# ============================ 组装启动描述 ============================
|
|
ld = LaunchDescription()
|
|
|
|
ld.add_action(declare_use_sim_time)
|
|
ld.add_action(declare_use_gazebo)
|
|
ld.add_action(declare_use_rviz)
|
|
ld.add_action(declare_world)
|
|
ld.add_action(declare_use_teleop)
|
|
|
|
ld.add_action(start_gazebo)
|
|
|
|
# 等 Gazebo 启动后再生成机器人 (延迟 5 秒)
|
|
ld.add_action(TimerAction(
|
|
period=5.0,
|
|
actions=[spawn_robot]
|
|
))
|
|
|
|
ld.add_action(robot_state_publisher)
|
|
ld.add_action(joint_state_publisher)
|
|
|
|
# 等机器人生成后再启动 SLAM (延迟 3 秒)
|
|
ld.add_action(TimerAction(
|
|
period=8.0,
|
|
actions=[slam_toolbox_node, teleop_node, rviz_node]
|
|
))
|
|
|
|
return ld
|