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

Java SpringBoot+Vue3+MyBatis Web宠物商城网站系统源码|前后端分离+MySQL数据库

Java SpringBoot+Vue3+MyBatis Web宠物商城网站系统源码|前后端分离+MySQL数据库

摘要 随着互联网技术的快速发展,电子商务逐渐渗透到各个行业领域,宠物行业也不例外。宠物市场的规模不断扩大,消费者对于线上购买宠物及相关用品的需求日益增长。传统的宠物商店受限于地理位置和营业时间,难以满足消费者的便捷购物需求。因此,开发一款功能完善、用户体验良好的宠物商城系统具有重要的现实意义。该系统能够为宠物爱好者提供一站式的购物体验,涵盖宠物食品、用品、医疗服务等多种商品和服务。关键词:宠物商城、电子商务、互联网技术、线上购物、用户体验。 本系统采用前后端分离的架构设计,前端使用Vue3框架实现动态交互和响应式布局,后端基于SpringBoot框架搭建RESTful API服务,数据库采用MySQL进行数据存储,并通过MyBatis实现数据持久化操作。系统功能模块包括用户管理、商品分类与展示、购物车管理、订单处理、支付接口集成以及后台管理功能。用户可以通过注册登录浏览商品、添加购物车、下单支付,管理员则可以通过后台管理系统对商品、订单和用户信息进行管理。系统设计注重性能优化和安全性,确保用户数据的安全性和系统的稳定性。关键词:SpringBoot、Vue3、MyBatis、前后端

前端国际化实现方案:让你的应用走向全球

前端国际化实现方案:让你的应用走向全球 毒舌时刻 国际化?听起来就像是前端工程师为了显得自己很专业而特意搞的一套复杂流程。你以为随便加个i18n库就能实现国际化?别做梦了!到时候你会发现,翻译文件比代码还多,维护起来比代码还麻烦。 你以为翻译就是简单的文本替换?别天真了!不同语言的语法结构不同,直接替换会导致语法错误。还有那些所谓的国际化库,看起来高大上,用起来却各种问题。 为什么你需要这个 1. 全球用户:国际化可以让你的应用支持全球用户,扩大用户群体。 2. 用户体验:使用用户的母语可以提高用户体验,增加用户粘性。 3. 市场竞争力:支持多语言的应用在国际市场上更具竞争力。 4. 合规要求:某些国家和地区要求应用提供当地语言支持。 5. 品牌形象:支持多语言可以提升品牌的国际化形象。 反面教材 // 1. 硬编码文本 function Welcome() { return <h1>Welcome to our app!</h1&

零基础入门MC.JS WEBMC1.8:10分钟创建你的第一个方块世界

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 输入框内输入如下内容: 生成一个极简的MC.JS WEBMC1.8入门教程项目。包含一个基础的3D场景,地面由绿色方块组成,玩家可以使用WASD移动,鼠标点击放置红色方块。代码要极度简化,每个关键部分都有详细注释说明。提供一个分步教程文档,解释如何修改代码来改变方块颜色、大小和移动速度等基本参数。界面要友好,有明确的操作指引。 1. 点击'项目生成'按钮,等待项目生成完整后预览效果 最近在学习3D游戏开发,发现用MC.JS WEBMC1.8创建简单的方块世界特别适合新手入门。今天就把我的学习过程记录下来,分享给同样想尝试的小伙伴们。 1. 环境准备 不需要安装任何软件,直接打开浏览器就能开始。MC.JS WEBMC1.8是基于Web的简化版Minecraft开发框架,特别适合快速搭建3D场景原型。

前端国际化实现:别再只支持中文了

前端国际化实现:别再只支持中文了

前端国际化实现:别再只支持中文了 毒舌时刻 这代码写得跟网红滤镜似的——仅供参考。 各位前端同行,咱们今天聊聊前端国际化。别告诉我你的应用只支持中文,那感觉就像只卖一种口味的冰淇淋——单调又无趣。 为什么你需要国际化 最近看到一个项目,所有文本都硬编码在代码里,要支持英文时傻眼了,我差点当场去世。我就想问:你是在开发应用还是在开发中文专用软件? 反面教材 // 反面教材:硬编码文本 function LoginForm() { return ( <form> <h1>登录</h1> <input placeholder="请输入邮箱" /> <input placeholder="请输入密码" type="password"