gazebo加载机器人与环境launch文件分析

gazebo加载机器人与环境launch文件分析

文章目录

launch文件源码

import launch import launch_ros from ament_index_python.packages import get_package_share_directory from launch.launch_description_sources import PythonLaunchDescriptionSource defgenerate_launch_description():# 获取默认路径 robot_name_in_model ="fishbot" urdf_tutorial_path = get_package_share_directory('fishbot_description') default_model_path = urdf_tutorial_path +'/urdf/fishbot/fishbot.urdf.xacro' default_world_path = urdf_tutorial_path +'/world/custom_room.world'# 为 Launch 声明参数 action_declare_arg_mode_path = launch.actions.DeclareLaunchArgument( name='model', default_value=str(default_model_path), description='URDF 的绝对路径')# 获取文件内容生成新的参数 robot_description = launch_ros.parameter_descriptions.ParameterValue( launch.substitutions.Command(['xacro ', launch.substitutions.LaunchConfiguration('model')]), value_type=str) robot_state_publisher_node = launch_ros.actions.Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[{'robot_description': robot_description}])# 通过 IncludeLaunchDescription 包含另外一个 launch 文件 launch_gazebo = launch.actions.IncludeLaunchDescription( PythonLaunchDescriptionSource([get_package_share_directory('gazebo_ros'),'/launch','/gazebo.launch.py']),# 传递参数 launch_arguments=[('world', default_world_path),('verbose','true')])# 请求 Gazebo 加载机器人 spawn_entity_node = launch_ros.actions.Node( package='gazebo_ros', executable='spawn_entity.py', arguments=['-topic','/robot_description','-entity', robot_name_in_model,])# 加载并激活 fishbot_joint_state_broadcaster 控制器 load_joint_state_controller = launch.actions.ExecuteProcess( cmd=['ros2','control','load_controller','--set-state','active','fishbot_joint_state_broadcaster'], output='screen')# 加载并激活 fishbot_effort_controller 控制器 load_fishbot_effort_controller = launch.actions.ExecuteProcess( cmd=['ros2','control','load_controller','--set-state','active','fishbot_effort_controller'], output='screen') load_fishbot_diff_drive_controller = launch.actions.ExecuteProcess( cmd=['ros2','control','load_controller','--set-state','active','fishbot_diff_drive_controller'], output='screen')return launch.LaunchDescription([ action_declare_arg_mode_path, robot_state_publisher_node, launch_gazebo, spawn_entity_node,# 事件动作,当加载机器人结束后执行  launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=spawn_entity_node, on_exit=[load_joint_state_controller],)),# 事件动作,load_fishbot_diff_drive_controller launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=load_joint_state_controller, on_exit=[load_fishbot_diff_drive_controller],)),])

代码分析

第一段:定义路径常量(机器人模型&仿真世界)
 # 获取默认路径 robot_name_in_model = "fishbot" urdf_tutorial_path = get_package_share_directory('fishbot_description') default_model_path = urdf_tutorial_path + '/urdf/fishbot/fishbot.urdf.xacro' default_world_path = urdf_tutorial_path + '/world/custom_room.world' 
  1. robot_name_in_model = "fishbot":定义机器人在Gazebo中的实体名称,后续在Gazebo中生成机器人时,会用这个名称标识该机器人实体。
  2. get_package_share_directory('fishbot_description'):ROS 2的工具函数,作用是获取fishbot_description包的share目录的绝对路径share目录是ROS 2包中存放配置文件、模型、世界文件等资源的标准目录),避免硬编码路径(不同环境下包的安装路径不同,硬编码会导致路径错误)。
  3. default_model_path:拼接得到机器人模型文件(fishbot.urdf.xacro)的绝对路径,注意文件格式是.urdf.xacro(不是纯.urdf),说明这是一个支持宏定义、参数化的URDF文件,需要先通过xacro工具解析为纯URDF格式才能被ROS 2识别。
  4. default_world_path:拼接得到Gazebo仿真世界文件(custom_room.world)的绝对路径,这个文件定义了Gazebo中的仿真环境(如墙壁、地面、灯光等)。

第二段:声明Launch参数(模型路径)
 # 为 Launch 声明参数 action_declare_arg_mode_path = launch.actions.DeclareLaunchArgument( name='model', default_value=str(default_model_path), description='URDF 的绝对路径') 
  1. 这是ROS 2 Launch的参数声明动作(DeclareLaunchArgument),作用是为当前Launch文件定义一个可外部传入的参数model
  2. 关键属性说明:
    • name='model':参数名,外部启动该Launch文件时,可以通过ros2 launch 包名 该launch文件名 model:=自定义模型路径来覆盖默认值。
    • default_value=str(default_model_path):参数默认值,即第一段中拼接的fishbot.urdf.xacro路径,不传入自定义参数时,使用该默认模型。
    • description:参数描述,用于说明该参数的作用,提高脚本可读性。
  3. 核心目的:提高Launch文件的灵活性,无需修改Launch文件代码,即可切换不同的机器人模型。

第三段:生成机器人描述(解析Xacro为URDF)
 # 获取文件内容生成新的参数 robot_description = launch_ros.parameter_descriptions.ParameterValue( launch.substitutions.Command( ['xacro ', launch.substitutions.LaunchConfiguration('model')]), value_type=str) 

这是整个Launch文件的核心步骤之一,作用是解析Xacro文件,生成可供ROS 2使用的机器人描述(robot_description),拆解如下:

  1. launch.substitutions.LaunchConfiguration('model'):获取第二段声明的model参数的值(默认值或外部传入值),即Xacro文件的路径。
  2. launch.substitutions.Command([...]):ROS 2的替换器,作用是在Launch文件执行时,运行一个系统命令,并获取命令的输出结果。这里的命令是xacro 【Xacro文件路径】,对应终端中的xacro fishbot.urdf.xacro命令,用于将Xacro文件解析为纯URDF格式的字符串。
  3. launch_ros.parameter_descriptions.ParameterValue(...):将命令执行的输出(URDF字符串)封装为ROS 2的参数值,指定value_type=str(确保输出是字符串格式,符合robot_description的要求)。
  4. 最终结果:robot_description变量中存储了完整的、解析后的URDF机器人描述字符串,后续会传递给robot_state_publisher节点。

第四段:启动机器人状态发布节点(robot_state_publisher)
 robot_state_publisher_node = launch_ros.actions.Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[{'robot_description': robot_description}] ) 
  1. launch_ros.actions.Node:ROS 2 Launch中用于启动一个ROS 2节点的动作。
  2. 节点配置说明:
    • package='robot_state_publisher':节点所属的ROS 2包(核心功能包,无需自定义)。
    • executable='robot_state_publisher':要运行的节点可执行文件名称。
    • parameters=[{'robot_description': robot_description}]:向节点传递参数,这里将第三段生成的robot_description(URDF字符串)作为参数传递给该节点。
  3. robot_state_publisher节点的核心作用:
    • 解析robot_description中的URDF模型,获取机器人的关节树结构。
    • 发布机器人的TF/TF2变换(坐标变换)(如从基坐标系base_link到各个关节、传感器坐标系的变换),这是ROS 2中导航、感知、控制的基础(其他节点需要通过TF变换获取各部件的空间位置关系)。

第五段:包含并启动Gazebo仿真环境
 # 通过 IncludeLaunchDescription 包含另外一个 launch 文件 launch_gazebo = launch.actions.IncludeLaunchDescription( PythonLaunchDescriptionSource([get_package_share_directory( 'gazebo_ros'), '/launch', '/gazebo.launch.py']), # 传递参数 launch_arguments=[('world', default_world_path),('verbose','true')] ) 
  1. launch.actions.IncludeLaunchDescription:ROS 2 Launch的文件包含动作,作用是在当前Launch文件中嵌套执行另一个Launch文件,避免重复编写启动Gazebo的代码(gazebo_ros包已经提供了成熟的gazebo.launch.py)。
  2. PythonLaunchDescriptionSource([...]):指定要包含的Launch文件的路径,这里通过get_package_share_directory('gazebo_ros')获取gazebo_ros包的路径,拼接得到gazebo.launch.py(Gazebo的核心启动文件)。
  3. launch_arguments=[('world', default_world_path),('verbose','true')]:向被包含的gazebo.launch.py传递参数:
    • world:指定Gazebo加载的仿真世界文件,即第一段中的custom_room.world
    • verbose='true':开启Gazebo的详细输出模式,便于调试(在终端中打印更多Gazebo的运行日志)。
  4. 执行结果:启动Gazebo仿真器,并加载custom_room.world定义的自定义环境,等待生成机器人实体。

第六段:在Gazebo中生成机器人实体(spawn_entity.py
 # 请求 Gazebo 加载机器人 spawn_entity_node = launch_ros.actions.Node( package='gazebo_ros', executable='spawn_entity.py', arguments=['-topic', '/robot_description', '-entity', robot_name_in_model, ]) 
  1. 启动gazebo_ros包中的spawn_entity.py脚本节点,作用是将机器人模型发布到Gazebo仿真环境中,生成可交互的机器人实体
  2. arguments:向该节点传递命令行参数(对应终端运行ros2 run gazebo_ros spawn_entity.py -h看到的参数):
    • -topic /robot_description:指定从/robot_description话题中获取机器人的URDF描述(robot_state_publisher节点会发布该话题)。
    • -entity robot_name_in_model:指定机器人在Gazebo中的实体名称(即第一段定义的fishbot)。
  3. 执行结果:Gazebo中会出现fishbot机器人模型,机器人被成功加载到仿真环境中,但此时还无法进行控制(需要激活控制器)。

第七段:定义控制器加载进程(3个控制器)
 # 加载并激活 fishbot_joint_state_broadcaster 控制器 load_joint_state_controller = launch.actions.ExecuteProcess( cmd=['ros2', 'control', 'load_controller', '--set-state', 'active', 'fishbot_joint_state_broadcaster'], output='screen' ) # 加载并激活 fishbot_effort_controller 控制器 load_fishbot_effort_controller = launch.actions.ExecuteProcess( cmd=['ros2', 'control', 'load_controller', '--set-state', 'active','fishbot_effort_controller'], output='screen') # 加载并激活 fishbot_diff_drive_controller 控制器 load_fishbot_diff_drive_controller = launch.actions.ExecuteProcess( cmd=['ros2', 'control', 'load_controller', '--set-state', 'active','fishbot_diff_drive_controller'], output='screen') 
  1. launch.actions.ExecuteProcess:ROS 2 Launch中用于**运行一个系统终端命令(非ROS 2节点)**的动作,这里用于执行ros2 control相关命令,加载并激活机器人控制器。
  2. 核心命令:ros2 control load_controller --set-state active 【控制器名称】,这是ROS 2控制框架(ros2_control)的终端命令,作用是从机器人的控制器配置中加载指定名称的控制器,并直接将其设置为激活状态(active)(控制器默认加载后是未激活状态,需要手动或自动激活才能工作)。
  3. 三个控制器的作用说明:
    • fishbot_joint_state_broadcaster关节状态广播器(核心必备),用于采集机器人所有关节的状态(位置、速度、力矩),并发布到/joint_states话题中,供robot_state_publisher、RViz等节点使用。
    • fishbot_effort_controller力矩控制器,用于向机器人关节发送力矩指令,控制关节运动(该Launch文件中未实际执行激活,仅定义了进程)。
    • fishbot_diff_drive_controller差速驱动控制器(核心运动控制器),用于实现机器人的差速驱动(左右轮转速控制,完成前进、转弯等动作),是移动机器人运动控制的核心。
  4. output='screen':将命令执行的输出日志打印到终端,便于调试(查看控制器是否加载成功、有无报错)。

第八段:返回Launch描述(组装所有动作,定义执行逻辑)
 return launch.LaunchDescription([ action_declare_arg_mode_path, robot_state_publisher_node, launch_gazebo, spawn_entity_node, # 事件动作,当加载机器人结束后执行 launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=spawn_entity_node, on_exit=[load_joint_state_controller],) ), # 事件动作,load_fishbot_diff_drive_controller launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=load_joint_state_controller, on_exit=[load_fishbot_diff_drive_controller],) ), ]) 

这是Launch文件的最终返回结果launch.LaunchDescription()接收一个动作列表,定义了所有要执行的动作和执行逻辑,核心分为两部分:顺序执行的基础动作事件驱动的有序控制器激活

  1. 基础动作(按列表顺序执行,无依赖):
    • action_declare_arg_mode_path:先声明model参数。
    • robot_state_publisher_node:启动机器人状态发布节点。
    • launch_gazebo:启动Gazebo仿真环境。
    • spawn_entity_node:在Gazebo中生成机器人实体。
  2. 事件驱动动作(RegisterEventHandler + OnProcessExit):这是该Launch文件的亮点逻辑,解决了「控制器必须在机器人加载完成后才能激活」的依赖问题(如果直接顺序执行,可能出现机器人还没加载好,控制器就开始加载,导致加载失败)。
    • OnProcessExit:事件处理器,作用是监听指定目标动作(target_action)的进程退出事件(即目标动作执行完成、进程正常退出)。
    • 第一个事件监听:
      • target_action=spawn_entity_node:监听spawn_entity_node(机器人生成)的进程退出。
      • on_exit=[load_joint_state_controller]:当机器人生成完成后,自动执行load_joint_state_controller(激活关节状态广播器)。
    • 第二个事件监听:
      • target_action=load_joint_state_controller:监听关节状态广播器的加载完成事件。
      • on_exit=[load_fishbot_diff_drive_controller]:当关节状态广播器激活完成后,自动执行load_fishbot_diff_drive_controller(激活差速驱动控制器)。
    • 最终控制器激活顺序(严格依赖,不会出错):机器人生成完成激活关节状态广播器激活差速驱动控制器
  3. 注意:load_fishbot_effort_controller(力矩控制器)仅定义了进程,但未在LaunchDescription中添加执行逻辑,因此该控制器不会被自动激活(如需激活,可在第二个事件的on_exit中添加该进程,或新增一个事件监听)。

三、补充说明(新手必看)

  1. 依赖条件:运行该Launch文件前,必须确保fishbot_description包已编译(colcon build --packages-select fishbot_description),且已执行source install/setup.bash
  2. 常见报错:
    • 路径错误:get_package_share_directory找不到fishbot_description,大概率是包名拼写错误或未编译。
    • Xacro解析错误:终端提示xacro命令错误,大概率是fishbot.urdf.xacro文件语法错误,或缺少依赖的宏定义。
    • 控制器加载失败:大概率是fishbot的URDF文件中未配置对应的ros2_control控制器(缺少<ros2_control>标签),或控制器名称拼写错误。
  3. 扩展方向:如需添加RViz可视化,可在LaunchDescription中新增rviz2节点,指定配置文件路径。

四、总结

  1. 该Launch文件的核心是一站式启动fishbot机器人的Gazebo仿真环境,并通过事件驱动实现控制器的有序自动激活,避免了手动执行多个终端命令的繁琐。
  2. 关键技术点包括:Xacro文件解析、Launch参数声明、嵌套Launch文件、事件驱动(OnProcessExit)、ros2_control控制器加载。
  3. 核心执行流程:声明参数→启动状态发布节点→启动Gazebo→生成机器人→按依赖激活控制器(关节状态广播器→差速驱动控制器)。

Read more

llama.cpp Docker部署:容器化推理服务搭建

llama.cpp Docker部署:容器化推理服务搭建 【免费下载链接】llama.cppPort of Facebook's LLaMA model in C/C++ 项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp 概述 llama.cpp是Facebook LLaMA模型的C/C++移植版本,提供了高效的本地推理能力。通过Docker容器化部署,可以快速搭建稳定、可移植的AI推理服务环境。本文将详细介绍如何使用Docker部署llama.cpp推理服务,涵盖基础部署、GPU加速、生产环境配置等场景。 环境准备 系统要求 * Docker Engine 20.10+ * NVIDIA Container Toolkit(如需GPU支持)

Claude, Cursor, Aider, Copilot,AI编程助手该选哪个?

2026年,AI编程工具已经非常成熟了。市面上这么多AI编程工具,哪个最好用? 本文选取了当前最具代表性的六款工具:Claude Code、Aider、Cursor、GitHub Copilot、MetaGPT 以及 OpenHands,从技术特性、优缺点及部署门槛进行客观对比。 Claude Code Anthropic 于2025年推出了 Claude Code,这是一款基于命令行的编程智能体工具。它不同于网页版的对话框,而是直接运行在终端中,能够深度理解本地项目结构。最出名的 AI 编程助手,很贵,但一分钱一分货,不得不说它很好用。 通过终端直接通过自然语言操作。它不仅能写代码,还能自主运行测试、解释复杂的架构、甚至执行终端命令来修复错误。其背后依托的是推理能力极强的 Claude 3.5/3.7 Sonnet 模型。 优势: * 推理能力极强:在处理复杂的逻辑重构和长代码理解上,目前处于行业顶尖水平。 * 自主性:

Llama-3.2-3B步骤详解:Ollama部署后启用GPU加速(CUDA/cuDNN)全流程

Llama-3.2-3B步骤详解:Ollama部署后启用GPU加速(CUDA/cuDNN)全流程 1. 为什么需要GPU加速?——从“能跑”到“跑得快”的关键跃迁 你可能已经用Ollama成功拉起了Llama-3.2-3B,输入几句话就能看到回复,一切看似顺利。但当你连续提问、生成稍长文本,或者尝试多轮对话时,会明显感觉到响应变慢——几秒甚至十几秒的等待,让原本流畅的交互体验打了折扣。 这不是模型能力的问题,而是默认情况下Ollama在CPU上运行。Llama-3.2-3B虽是3B参数量的轻量级模型,但其Transformer结构天然适合并行计算。一块中端消费级显卡(比如RTX 3060或更高),在GPU模式下推理速度可比CPU快3~5倍,显存占用更合理,还能释放出CPU资源去做其他事。 更重要的是,Ollama官方明确支持CUDA加速,且无需手动编译模型或修改源码。整个过程不涉及复杂配置文件编辑,也不要求你成为CUDA专家——只要你的机器有NVIDIA显卡、驱动正常、CUDA环境基础就绪,就能完成切换。本文将带你从零开始,一步步验证环境、启用加速、实测对比,并解决你最可能卡

服务器上 VsCode 的 Github Copilot:加载超时?优化与修复方案

服务器上 VS Code 的 GitHub Copilot 加载超时问题:优化与修复方案 当在服务器环境使用 VS Code 的 GitHub Copilot 时,加载超时通常由网络配置或资源限制引起。以下是结构化解决方案: 1. 网络层优化 配置代理(若需跨墙) 在 VS Code 的 settings.json 添加: "http.proxy": "http://your-proxy-ip:port", "https.proxy": "http://your-proxy-ip:port", "http.proxyStrictSSL"