Files
yiliao2026/src/my_robot_bringup/launch/master_launch.py

353 lines
14 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ============================================================================
# master_launch.py —— 机器人系统总启动文件
# 启动顺序: origincar_base → LiDAR → TTS服务 → USB相机+二维码 → 障碍物检测 → 路径规划 → 轨迹跟随 → VLM
# 用法:
# ros2 launch my_robot_bringup master_launch.py
# ros2 launch my_robot_bringup master_launch.py use_qr:=false
# ros2 launch my_robot_bringup master_launch.py use_vlm:=false
# ros2 launch my_robot_bringup master_launch.py use_planner:=false
# ============================================================================
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
IncludeLaunchDescription,
TimerAction,
LogInfo,
)
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
# ================================================================
# 路径
# ================================================================
origincar_dir = get_package_share_directory('origincar_base')
lslidar_dir = get_package_share_directory('lslidar_driver')
obstacle_dir = get_package_share_directory('obstacle_scanner')
planner_dir = get_package_share_directory('planner')
vlm_dir = get_package_share_directory('vlm_detect')
# ================================================================
# Launch 参数 —— 可通过命令行灵活切换
# ================================================================
# 模块开关
use_base = LaunchConfiguration('use_base', default='true')
use_lidar = LaunchConfiguration('use_lidar', default='true')
use_qr = LaunchConfiguration('use_qr', default='true')
use_tts = LaunchConfiguration('use_tts', default='true')
use_obstacle = LaunchConfiguration('use_obstacle', default='true')
use_planner = LaunchConfiguration('use_planner', default='true')
use_vlm = LaunchConfiguration('use_vlm', default='true')
# 车辆模式
akmcar = LaunchConfiguration('akmcar', default='true')
carto_slam = LaunchConfiguration('carto_slam', default='false')
# 摄像头设备
camera_device = LaunchConfiguration('camera_device', default='/dev/video0')
# TTS 参数
audio_sink = LaunchConfiguration('audio_sink',
default='alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo')
tts_speed = LaunchConfiguration('tts_speed', default='1.5')
# 地图文件 (AMCL 定位用)
map_file = LaunchConfiguration('map_file', default=os.path.join(
planner_dir, 'maps', 'real_5x5.yaml'))
# Planner / Tracker 参数文件
planner_params_file = LaunchConfiguration('planner_params_file', default=os.path.join(
planner_dir, 'config', 'real_hybrid_astar.yaml'))
tracker_params_file = LaunchConfiguration('tracker_params_file', default=os.path.join(
planner_dir, 'config', 'real_pure_pursuit.yaml'))
amcl_params_file = LaunchConfiguration('amcl_params_file', default=os.path.join(
planner_dir, 'config', 'real_amcl.yaml'))
# VLM 服务器地址
vlm_host = LaunchConfiguration('vlm_host', default='http://192.168.10.189:8000')
# 通用
use_sim_time = LaunchConfiguration('use_sim_time', default='false')
# ================================================================
# 阶段 1: 底盘驱动 + EKF + TF + IMU (t=0s)
# ================================================================
origincar_bringup = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
origincar_dir, '/launch', '/origincar_bringup.launch.py'
]),
condition=IfCondition(use_base),
launch_arguments={
'akmcar': akmcar,
'carto_slam': carto_slam,
}.items(),
)
# ================================================================
# 阶段 2: 激光雷达 (t=2s)
# ================================================================
lidar_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
lslidar_dir, '/launch', '/lsn10_launch.py'
]),
condition=IfCondition(use_lidar),
)
# ================================================================
# 阶段 3: TTS 语音播报服务 + 二维码播报桥接 (t=3s)
# tts_server: Piper 离线 TTS + espeak 降级,提供 /tts/speak 服务
# qr_tts_bridge: 订阅 qr_results调用 /tts/speak
# ================================================================
tts_server = Node(
package='vlm_detect',
executable='tts_server',
name='tts_server',
output='screen',
condition=IfCondition(use_tts),
parameters=[{
'audio_sink': audio_sink,
'tts_speed': tts_speed,
}],
)
qr_tts_bridge = Node(
package='vlm_detect',
executable='qr_tts_bridge',
name='qr_tts_bridge',
output='screen',
condition=IfCondition(use_tts),
)
# ================================================================
# 阶段 4: USB 摄像头 + 二维码识别 (t=4s)
# usb_cam: 驱动 USB 摄像头,发布 /image_raw
# qr_detect: 订阅 /image_raw识别二维码发布 qr_results
# ================================================================
usb_camera = Node(
package='usb_cam',
executable='usb_cam_node_exe',
name='usb_cam',
output='screen',
condition=IfCondition(use_qr),
parameters=[{
'video_device': camera_device,
'image_size': [640, 480],
'pixel_format': 'YUYV',
'framerate': 30.0,
}],
)
qr_detect = Node(
package='qr_detection',
executable='qr_detect',
name='qr_detect',
output='screen',
condition=IfCondition(use_qr),
parameters=[{'image_topic': '/image_raw'}],
)
# ================================================================
# 阶段 5: 障碍物检测 (t=5s)
# ================================================================
obstacle_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
obstacle_dir, '/launch', '/obstacle_scanner.launch.py'
]),
condition=IfCondition(use_obstacle),
)
# ================================================================
# 阶段 6: 地图服务器 + AMCL 定位 (t=7s)
# ================================================================
map_server_node = Node(
package='nav2_map_server',
executable='map_server',
name='map_server',
output='screen',
condition=IfCondition(use_planner),
parameters=[{'yaml_filename': map_file,
'use_sim_time': use_sim_time}],
)
amcl_node = Node(
package='nav2_amcl',
executable='amcl',
name='amcl',
output='screen',
condition=IfCondition(use_planner),
parameters=[amcl_params_file,
{'use_sim_time': use_sim_time}],
)
lifecycle_manager = Node(
package='nav2_lifecycle_manager',
executable='lifecycle_manager',
name='lifecycle_manager_localization',
output='screen',
condition=IfCondition(use_planner),
parameters=[{'use_sim_time': use_sim_time,
'autostart': True,
'node_names': ['map_server', 'amcl']}],
)
# ================================================================
# 阶段 7: Hybrid A* 路径规划 + Pure Pursuit 轨迹跟随 (t=9s)
# ================================================================
planner_node = Node(
package='planner',
executable='grid_astar_theta_node',
name='grid_astar_theta_planner',
output='screen',
condition=IfCondition(use_planner),
parameters=[planner_params_file,
{'use_sim_time': use_sim_time,
'obstacles_topic': '/obstacles'}],
)
tracker_node = Node(
package='planner',
executable='topology_pure_pursuit_node.py',
name='topology_pure_pursuit',
output='screen',
condition=IfCondition(use_planner),
parameters=[tracker_params_file,
{'use_sim_time': use_sim_time}],
)
# ================================================================
# 阶段 8: VLM 图生文 (t=11s)
# vlm_node 内部自带 TTS 服务客户端,识别完自动调用 /tts/speak
# 注意: TTS 服务和桥接已在阶段 3 启动,这里只启动 vlm_node
# ================================================================
vlm_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
vlm_dir, '/launch', '/vlm_detect.launch.py'
]),
condition=IfCondition(use_vlm),
launch_arguments={
'vlm_host': vlm_host,
'use_tts': 'false', # tts_server 已在阶段 3 启动
'use_qr_tts': 'false', # qr_tts_bridge 已在阶段 3 启动
}.items(),
)
# ================================================================
# 组装 —— 通过 TimerAction 保证先后顺序
# ================================================================
return LaunchDescription([
# 模块 开关 参数
DeclareLaunchArgument('use_base', default_value='true',
description='底盘驱动 + EKF + TF'),
DeclareLaunchArgument('use_lidar', default_value='true',
description='激光雷达 (lsn10)'),
DeclareLaunchArgument('use_qr', default_value='true',
description='USB 摄像头 + 二维码识别'),
DeclareLaunchArgument('use_tts', default_value='true',
description='TTS 语音播报服务 + 二维码播报桥接'),
DeclareLaunchArgument('use_obstacle', default_value='true',
description='障碍物检测'),
DeclareLaunchArgument('use_planner', default_value='true',
description='路径规划 + 轨迹跟随'),
DeclareLaunchArgument('use_vlm', default_value='true',
description='VLM 图生文'),
DeclareLaunchArgument('akmcar', default_value='true',
description='车辆模型 (true=阿克曼, false=麦轮)'),
DeclareLaunchArgument('carto_slam', default_value='false',
description='使用 Cartographer 替代 EKF'),
DeclareLaunchArgument('camera_device', default_value='/dev/video0',
description='USB 摄像头设备路径'),
DeclareLaunchArgument('audio_sink',
default_value='alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo',
description='音频输出设备 (PulseAudio sink)'),
DeclareLaunchArgument('tts_speed', default_value='1.5',
description='TTS 语速倍率 (0.5~2.0)'),
DeclareLaunchArgument('map_file', default_value=os.path.join(
planner_dir, 'maps', 'real_5x5.yaml'),
description='预建地图 YAML 文件'),
DeclareLaunchArgument('planner_params_file', default_value=os.path.join(
planner_dir, 'config', 'real_hybrid_astar.yaml'),
description='Hybrid A* 规划器参数文件'),
DeclareLaunchArgument('tracker_params_file', default_value=os.path.join(
planner_dir, 'config', 'real_pure_pursuit.yaml'),
description='Pure Pursuit 跟踪器参数文件'),
DeclareLaunchArgument('amcl_params_file', default_value=os.path.join(
planner_dir, 'config', 'real_amcl.yaml'),
description='AMCL 定位参数文件'),
DeclareLaunchArgument('vlm_host', default_value='http://192.168.10.189:8000',
description='VLM 服务器地址'),
DeclareLaunchArgument('use_sim_time', default_value='false',
description='使用仿真时间'),
LogInfo(msg='========================================'),
LogInfo(msg=' Robot System Bringup'),
LogInfo(msg='========================================'),
# t=0s: 底盘 + EKF
TimerAction(period=0.0, actions=[
LogInfo(msg='[1/8] Starting base driver + EKF + TF + IMU ...'),
origincar_bringup,
]),
# t=2s: 激光雷达
TimerAction(period=2.0, actions=[
LogInfo(msg='[2/8] Starting LiDAR (lsn10) ...'),
lidar_launch,
]),
# t=3s: TTS 服务 + 二维码播报桥接
TimerAction(period=3.0, actions=[
LogInfo(msg='[3/8] Starting TTS Server + QR-TTS Bridge ...'),
tts_server,
qr_tts_bridge,
]),
# t=4s: USB 摄像头 + 二维码识别
TimerAction(period=4.0, actions=[
LogInfo(msg='[4/8] Starting USB Camera + QR Detection ...'),
usb_camera,
qr_detect,
]),
# t=5s: 障碍物检测
TimerAction(period=5.0, actions=[
LogInfo(msg='[5/8] Starting Obstacle Scanner ...'),
obstacle_launch,
]),
# t=7s: 地图 + AMCL 定位
TimerAction(period=7.0, actions=[
LogInfo(msg='[6/8] Starting Map Server + AMCL localization ...'),
map_server_node,
amcl_node,
lifecycle_manager,
]),
# t=9s: 路径规划 + 轨迹跟随
TimerAction(period=9.0, actions=[
LogInfo(msg='[7/8] Starting Hybrid A* Planner + Pure Pursuit Tracker ...'),
planner_node,
tracker_node,
]),
# t=11s: VLM 图生文
TimerAction(period=11.0, actions=[
LogInfo(msg='[8/8] Starting VLM ...'),
vlm_launch,
]),
LogInfo(msg='========================================'),
LogInfo(msg=' All modules started!'),
LogInfo(msg='========================================'),
])