forked from zbw/yiliao2026
迁移了原来的nav2包;新增基于obstacle_scanner构建costmap的nav2,暂未实际测试
This commit is contained in:
352
src/my_robot_bringup/launch/master_launch.py
Executable file
352
src/my_robot_bringup/launch/master_launch.py
Executable file
@@ -0,0 +1,352 @@
|
|||||||
|
#!/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='========================================'),
|
||||||
|
])
|
||||||
218
src/my_robot_bringup/launch/master_launch.py.bak
Executable file
218
src/my_robot_bringup/launch/master_launch.py.bak
Executable file
@@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ============================================================================
|
||||||
|
# master_launch.py — 机器人系统总启动文件
|
||||||
|
# 启动顺序: origincar_base → LiDAR → EKF → SLAM → Nav2 → VLM_Detect
|
||||||
|
# 用法:
|
||||||
|
# ros2 launch my_robot_bringup master_launch.py
|
||||||
|
# ros2 launch my_robot_bringup master_launch.py use_vlm:=false
|
||||||
|
# ros2 launch my_robot_bringup master_launch.py vlm_host:=http://X.X.X.X:8000
|
||||||
|
# ============================================================================
|
||||||
|
## 障碍物检测 路径规划 轨迹跟随 重定位
|
||||||
|
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')
|
||||||
|
cyy_slam_dir = get_package_share_directory('cyy_slamtoolbox')
|
||||||
|
gc_nav_dir = get_package_share_directory('gc_navigation2_slamtoolbox')
|
||||||
|
vlm_dir = get_package_share_directory('vlm_detect')
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# Launch 参数 — 可通过命令行覆盖
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
# 模块开关
|
||||||
|
use_base = LaunchConfiguration('use_base', default='true')
|
||||||
|
use_lidar = LaunchConfiguration('use_lidar', default='true')
|
||||||
|
use_slam = LaunchConfiguration('use_slam', default='true')
|
||||||
|
use_nav2 = LaunchConfiguration('use_nav2', default='true')
|
||||||
|
use_vlm = LaunchConfiguration('use_vlm', default='true')
|
||||||
|
use_tts = LaunchConfiguration('use_tts', default='true')
|
||||||
|
|
||||||
|
# 底盘模式
|
||||||
|
akmcar = LaunchConfiguration('akmcar', default='true')
|
||||||
|
carto_slam = LaunchConfiguration('carto_slam', default='false')
|
||||||
|
|
||||||
|
# SLAM / Nav2 配置文件
|
||||||
|
slam_params_file = LaunchConfiguration('slam_params_file', default=os.path.join(
|
||||||
|
cyy_slam_dir, 'config', 'mapper_params_online_async.yaml'))
|
||||||
|
nav2_params_file = LaunchConfiguration('nav2_params_file', default=os.path.join(
|
||||||
|
gc_nav_dir, 'params', 'gc_navigation_slam.yaml'))
|
||||||
|
|
||||||
|
# VLM 推理服务地址 (Windows WSL)
|
||||||
|
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 内部已包含:
|
||||||
|
# - base_serial.launch.py 底盘驱动 (origincar_base_node)
|
||||||
|
# - robot_mode_description robot_state_publisher (TF from URDF)
|
||||||
|
# - imu_filter_madgwick IMU 姿态滤波
|
||||||
|
# - robot_localization ekf_node EKF 融合 (odom + IMU → odom_combined)
|
||||||
|
# - joint_state_publisher 关节状态发布
|
||||||
|
# - static TF: base_footprint→gyro_link, base_link→laser
|
||||||
|
# ================================================================
|
||||||
|
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)
|
||||||
|
# lsn10_launch.py 启动 LS-N10 型号激光雷达驱动
|
||||||
|
# 如有其他型号,改包名和 launch 文件名即可
|
||||||
|
# ================================================================
|
||||||
|
lidar_launch = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource([
|
||||||
|
lslidar_dir, '/launch', '/lsn10_launch.py'
|
||||||
|
]),
|
||||||
|
condition=IfCondition(use_lidar),
|
||||||
|
)
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 阶段 3: SLAM Toolbox — 实时建图 (t=5s)
|
||||||
|
# 需要: /scan (LiDAR) + odom→base_link TF (EKF)
|
||||||
|
# 输出: map→odom TF + /map topic
|
||||||
|
# ================================================================
|
||||||
|
slam_toolbox_node = Node(
|
||||||
|
package='slam_toolbox',
|
||||||
|
executable='async_slam_toolbox_node',
|
||||||
|
name='slam_toolbox',
|
||||||
|
output='screen',
|
||||||
|
condition=IfCondition(use_slam),
|
||||||
|
parameters=[slam_params_file,
|
||||||
|
{'use_sim_time': use_sim_time}],
|
||||||
|
)
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 阶段 4: Nav2 导航栈 (t=8s)
|
||||||
|
# 需要: /map (SLAM) + /scan + 完整 TF 树 (map→odom→base_link→laser)
|
||||||
|
# 输出: /cmd_vel → origincar_base → 底盘运动
|
||||||
|
# ================================================================
|
||||||
|
nav2_launch = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource([
|
||||||
|
FindPackageShare('nav2_bringup'), '/launch', '/navigation_launch.py'
|
||||||
|
]),
|
||||||
|
condition=IfCondition(use_nav2),
|
||||||
|
launch_arguments={
|
||||||
|
'use_sim_time': use_sim_time,
|
||||||
|
'params_file': nav2_params_file,
|
||||||
|
}.items(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 阶段 5: VLM 图生文 + TTS 语音播报 (t=10s)
|
||||||
|
# 完全独立于导航栈,只依赖 WSL 上 vlm_server.py 已启动
|
||||||
|
# ================================================================
|
||||||
|
vlm_launch = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource([
|
||||||
|
vlm_dir, '/launch', '/vlm_detect.launch.py'
|
||||||
|
]),
|
||||||
|
condition=IfCondition(use_vlm),
|
||||||
|
launch_arguments={
|
||||||
|
'vlm_host': vlm_host,
|
||||||
|
'use_tts': use_tts,
|
||||||
|
}.items(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 组装 — 按时间线顺序,TimerAction 保证先后
|
||||||
|
# ================================================================
|
||||||
|
return LaunchDescription([
|
||||||
|
|
||||||
|
# —— 参数声明 ——
|
||||||
|
DeclareLaunchArgument('use_base', default_value='true',
|
||||||
|
description='底盘驱动 + EKF + TF'),
|
||||||
|
DeclareLaunchArgument('use_lidar', default_value='true',
|
||||||
|
description='激光雷达 (lsn10)'),
|
||||||
|
DeclareLaunchArgument('use_slam', default_value='true',
|
||||||
|
description='slam_toolbox 建图'),
|
||||||
|
DeclareLaunchArgument('use_nav2', default_value='true',
|
||||||
|
description='Nav2 导航栈'),
|
||||||
|
DeclareLaunchArgument('use_vlm', default_value='true',
|
||||||
|
description='VLM 图生文 + TTS'),
|
||||||
|
DeclareLaunchArgument('use_tts', default_value='true',
|
||||||
|
description='TTS 语音播报开关'),
|
||||||
|
DeclareLaunchArgument('akmcar', default_value='true',
|
||||||
|
description='阿克曼底盘 (true=阿克曼, false=差速)'),
|
||||||
|
DeclareLaunchArgument('carto_slam', default_value='false',
|
||||||
|
description='使用 Cartographer 替代 EKF'),
|
||||||
|
DeclareLaunchArgument('slam_params_file', default_value=os.path.join(
|
||||||
|
cyy_slam_dir, 'config', 'mapper_params_online_async.yaml'),
|
||||||
|
description='SLAM 参数文件'),
|
||||||
|
DeclareLaunchArgument('nav2_params_file', default_value=os.path.join(
|
||||||
|
gc_nav_dir, 'params', 'gc_navigation_slam.yaml'),
|
||||||
|
description='Nav2 参数文件'),
|
||||||
|
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/5] Starting base driver + EKF + TF + IMU ...'),
|
||||||
|
origincar_bringup,
|
||||||
|
]),
|
||||||
|
|
||||||
|
# t=2s: 激光雷达
|
||||||
|
TimerAction(period=2.0, actions=[
|
||||||
|
LogInfo(msg='[2/5] Starting LiDAR (lsn10) ...'),
|
||||||
|
lidar_launch,
|
||||||
|
]),
|
||||||
|
|
||||||
|
# t=5s: SLAM
|
||||||
|
TimerAction(period=5.0, actions=[
|
||||||
|
LogInfo(msg='[3/5] Starting slam_toolbox ...'),
|
||||||
|
slam_toolbox_node,
|
||||||
|
]),
|
||||||
|
|
||||||
|
# t=8s: Nav2
|
||||||
|
TimerAction(period=8.0, actions=[
|
||||||
|
LogInfo(msg='[4/5] Starting Nav2 navigation ...'),
|
||||||
|
nav2_launch,
|
||||||
|
]),
|
||||||
|
|
||||||
|
# t=10s: VLM
|
||||||
|
TimerAction(period=10.0, actions=[
|
||||||
|
LogInfo(msg='[5/5] Starting VLM + TTS ...'),
|
||||||
|
vlm_launch,
|
||||||
|
]),
|
||||||
|
|
||||||
|
LogInfo(msg='========================================'),
|
||||||
|
LogInfo(msg=' All modules started!'),
|
||||||
|
LogInfo(msg='========================================'),
|
||||||
|
])
|
||||||
23
src/my_robot_bringup/package.xml
Normal file
23
src/my_robot_bringup/package.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||||
|
<package format="3">
|
||||||
|
<name>my_robot_bringup</name>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<description>Master launch file for the entire robot system</description>
|
||||||
|
<maintainer email="sunrise@todo.todo">sunrise</maintainer>
|
||||||
|
<license>Apache-2.0</license>
|
||||||
|
|
||||||
|
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||||
|
<buildtool_depend>ament_cmake_python</buildtool_depend>
|
||||||
|
|
||||||
|
<exec_depend>origincar_base</exec_depend>
|
||||||
|
<exec_depend>lslidar_driver</exec_depend>
|
||||||
|
<exec_depend>slam_toolbox</exec_depend>
|
||||||
|
<exec_depend>nav2_bringup</exec_depend>
|
||||||
|
<exec_depend>vlm_detect</exec_depend>
|
||||||
|
<exec_depend>robot_localization</exec_depend>
|
||||||
|
|
||||||
|
<export>
|
||||||
|
<build_type>ament_python</build_type>
|
||||||
|
</export>
|
||||||
|
</package>
|
||||||
21
src/my_robot_bringup/setup.py
Normal file
21
src/my_robot_bringup/setup.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
from glob import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
package_name = 'my_robot_bringup'
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name=package_name,
|
||||||
|
version='1.0.0',
|
||||||
|
packages=[],
|
||||||
|
data_files=[
|
||||||
|
('share/' + package_name, ['package.xml']),
|
||||||
|
('share/' + package_name + '/launch', glob('launch/*.py')),
|
||||||
|
],
|
||||||
|
install_requires=['setuptools'],
|
||||||
|
zip_safe=True,
|
||||||
|
maintainer='sunrise',
|
||||||
|
maintainer_email='sunrise@todo.todo',
|
||||||
|
description='Master bringup for robot system',
|
||||||
|
license='Apache-2.0',
|
||||||
|
)
|
||||||
103
src/navigation/gc_navigation2_real/launch/real_mapping.launch.py
Normal file
103
src/navigation/gc_navigation2_real/launch/real_mapping.launch.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# ============================================================================
|
||||||
|
# real_slam_mapping.launch.py
|
||||||
|
# 功能:实车 SLAM 建图启动文件(无 Gazebo 仿真)
|
||||||
|
#
|
||||||
|
# 适用场景:
|
||||||
|
# - 在实际场地遥控机器人建立环境地图
|
||||||
|
# - 在已有地图基础上增量更新
|
||||||
|
# - 单独调试 slam_toolbox 建图参数
|
||||||
|
#
|
||||||
|
# 架构:
|
||||||
|
# origincar_base (bringup) — 底盘串口驱动 + EKF 里程计 + IMU 滤波 + TF
|
||||||
|
# lslidar_driver — 镭神激光雷达驱动 → /scan
|
||||||
|
# async_slam_toolbox_node — 激光 SLAM 建图(mapping 模式)
|
||||||
|
# 发布 map→odom_combined TF
|
||||||
|
# 发布 /map 话题(实时地图)
|
||||||
|
#
|
||||||
|
# 使用方式:
|
||||||
|
# ros2 launch gc_navigation2_real real_slam_mapping.launch.py
|
||||||
|
#
|
||||||
|
# 保存地图:
|
||||||
|
# ros2 service call /slam_toolbox/serialize_map slam_toolbox/srv/SerializePoseGraph \
|
||||||
|
# "{filename: '/home/guoch/test_ws/src/gc_navigation2_real/maps/my_map'}"
|
||||||
|
# ros2 run nav2_map_server map_saver_cli -f <map_name>
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
import os
|
||||||
|
from ament_index_python.packages import get_package_share_directory
|
||||||
|
from launch import LaunchDescription
|
||||||
|
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
|
||||||
|
from launch.substitutions import LaunchConfiguration
|
||||||
|
from launch_ros.actions import Node
|
||||||
|
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||||
|
|
||||||
|
|
||||||
|
def generate_launch_description():
|
||||||
|
"""生成 LaunchDescription,启动实车底盘 + 雷达 + slam_toolbox 建图"""
|
||||||
|
|
||||||
|
# ============================ 1. 包路径 =========================================
|
||||||
|
pkg_dir = get_package_share_directory('gc_navigation2_real')
|
||||||
|
origincar_base_dir = get_package_share_directory('origincar_base')
|
||||||
|
|
||||||
|
# ============================ 2. 声明启动参数 ====================================
|
||||||
|
use_sim_time = LaunchConfiguration('use_sim_time', default='false')
|
||||||
|
|
||||||
|
# slam_params_file: slam_toolbox 配置文件
|
||||||
|
# slam_params_file = LaunchConfiguration(
|
||||||
|
# 'slam_params_file',
|
||||||
|
# default=os.path.join(pkg_dir, 'config', 'slam_toolbox_async_real.yaml'))
|
||||||
|
|
||||||
|
# map_file_name: 可选,加载已有序列化地图继续建图
|
||||||
|
map_file_name = LaunchConfiguration('map_file_name', default='')
|
||||||
|
|
||||||
|
# ============================ 3. 实车底盘 bringup ===============================
|
||||||
|
# 启动 origincar_base:串口驱动 + EKF + IMU 滤波 + TF 发布
|
||||||
|
# 注:origincar_bringup 已包含 robot_state_publisher + joint_state_publisher + 静态 TF
|
||||||
|
origincar_bringup = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource(
|
||||||
|
[origincar_base_dir, '/launch', '/origincar_bringup.launch.py']),
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================ 4. 镭神激光雷达驱动 ===============================
|
||||||
|
# 启动 lslidar_driver → /scan 话题
|
||||||
|
lslidar_launch = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource(
|
||||||
|
[get_package_share_directory('lslidar_driver'),
|
||||||
|
'/launch', '/lsn10_launch.py']),
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================ 5. slam_toolbox 建图节点 ============================
|
||||||
|
slam_toolbox_node = Node(
|
||||||
|
package='slam_toolbox',
|
||||||
|
executable='async_slam_toolbox_node',
|
||||||
|
name='slam_toolbox',
|
||||||
|
output='screen',
|
||||||
|
parameters=[
|
||||||
|
slam_params_file,
|
||||||
|
{
|
||||||
|
'use_sim_time': False,
|
||||||
|
'map_file_name': map_file_name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================ 6. 组装 LaunchDescription =========================
|
||||||
|
return LaunchDescription([
|
||||||
|
DeclareLaunchArgument(
|
||||||
|
'use_sim_time',
|
||||||
|
default_value='false',
|
||||||
|
description='使用仿真时间(实车必须为 false)'),
|
||||||
|
DeclareLaunchArgument(
|
||||||
|
'slam_params_file',
|
||||||
|
default_value=os.path.join(pkg_dir, 'config', 'slam_toolbox_async_real.yaml'),
|
||||||
|
description='slam_toolbox 参数配置文件路径'),
|
||||||
|
DeclareLaunchArgument(
|
||||||
|
'map_file_name',
|
||||||
|
default_value='',
|
||||||
|
description='已有序列化地图路径(.posegraph),留空则从零开始建图'),
|
||||||
|
|
||||||
|
origincar_bringup,
|
||||||
|
lslidar_launch,
|
||||||
|
slam_toolbox_node,
|
||||||
|
])
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user