ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

四足机器人Gazebo仿真搭建:URDF建模与Xacro宏详解

四足机器人Gazebo仿真搭建:URDF建模与Xacro宏详解 1. 四足仿真这件事为什么值得认真搭一次做足式机器人的人应该都有过这种体验算法理论上跑得好好的一上真机就各种翻车电机过流、机身侧翻、关节限位报错一次调试下来不是修代码而是修机器人。Unitree A1这类四足狗虽然已经是市面上性价比很高的开源平台但真机价格仍然摆在那里摔倒、撞击、暴力降落的代价都不小。如果每改一个参数都要上真机验证开发节奏会慢得让人怀疑人生。所以我一直坚持一个流程先在Gazebo里把仿真环境搭到“足够接近真机”再带着可信的仿真结果上真机。这里说的“足够接近”不是指动力学参数完全复刻而是指自由度数、关节配置、质量分布、控制接口这些结构性的东西要和真机一致。A1有12个自由度每条腿3个如果你的仿真模型只有8个自由度或者关节轴方向定义错了那后面跑强化学习、模型预测控制、状态估计全部都是在错误的地基上盖楼。这篇文章做的事情就是把从零搭建Unitree A1的Gazebo仿真环境的完整过程拆开讲清楚。核心内容包括用URDF描述A1的机械结构、用Xacro宏来优雅地管理四足这种高重复度的模型文件、以及打通Gazebo仿真中“加载模型—启动控制器—关节可控”的完整链路。适合刚入门ROS但已经知道基本概念的同学也适合那些被URDF模板吓到、不知道从哪下手的人。先说清楚这篇文章的边界。我会用一份简化但结构完整的A1模型不走官方unitree_ros仓库的“拿来主义”而是从零定义坐标系和关节这样你才能真正理解每个参数的含义。等你自己能写出这个模型再去看官方仓库或者任何一款四足机器人的URDF都会觉得非常轻松。2. 环境选型和安装版本搭配决定你能少踩多少坑2.1 ROS版本与Gazebo版本怎么选接触ROS的人一定听过“版本地狱”这种说法。Ubuntu、ROS、Gazebo三个版本的兼容关系基本决定了你后续要花多少时间在装环境上。绝大多数四足机器人相关的开源代码、运动控制库、LQR/MPC示例都是基于ROS Noetic或更早的ROS Kinetic写的。Unitree官方仓库的ROS 1分支也维护得比较全。这方面我的建议很直接如果你不是有明确理由必须用ROS 2首选Ubuntu 20.04 ROS Noetic Gazebo 11这条组合的教程数量最多遇到问题最容易搜到答案。当然ROS 2 Humble/Iron也在快速普及如果你的项目已经基于ROS 2那Ubuntu 22.04 Humble Gazebo 11也是可以跑的只是需要自己适配一些原来基于ROS 1的接口。另外我看到最近已经有人在Ubuntu 24.04上折腾ROS 2 Jazzy Gazebo Harmonic也就是新版的gz-sim这个方向是未来主流但目前资料偏少新手不建议一上来就挑战这个组合。2.2 鱼香ROS一键安装到底解决了什么问题这里必须提到“鱼香ROS一键安装”这个工具。很多教程一上来就是让你添加ROS apt源、配置公钥、再apt update一套操作下来如果网络状况不好可能卡在下载阶段。鱼香ROS脚本做的就是把这些步骤自动化了它会检测你的Ubuntu版本选择合适的ROS发行版顺便把Gazebo也装上。安装方式很简单不需要逐条执行apt命令wget http://fishros.com/install -O fishros bash fishros运行之后会有一个交互式选项菜单选“一键安装ROS”它会自动判断系统版本。实测下来在干净系统上装Noetic Gazebo 11大概需要十几分钟取决于网络。安装完ROS后再跑一次脚本它会提示你把哪些环境变量写进~/.bashrc基本做到开箱即用。不过我还是要补充一句一键安装脚本帮你完成了95%的工作剩下5%的坑它没法帮你避开。比如安装完成后你至少要做一次下面的验证确认环境真的可用source /opt/ros/noetic/setup.bash roscore看到“started core service”之类信息就说明ROS基础环境正常。再验证Gazebogazebo如果Gazebo能弹出一个空世界窗口且没有报libGL相关的错误那环境基本就绪。2.3 Gazebo界面闪烁问题的真相搜索资料的时候能看到很多人问“为什么Gazebo界面一直在闪”。我在虚拟机和物理机上各踩过一次。如果你用的是VMware或VirtualBox且没有开启3D加速Gazebo的渲染窗口大概率会闪烁、撕裂甚至黑屏。这不是Gazebo本身的问题而是OpenGL渲染没有可用的硬件加速。虚拟机用户先检查虚拟机设置里有没有打开“加速3D图形”。如果不想依赖硬件加速可以试试强制使用软件渲染export LIBGL_ALWAYS_SOFTWARE1 gazebo物理机如果也闪优先怀疑显卡驱动。NVIDIA用户装好官方驱动后基本能解决集成显卡用户遇到问题的概率小很多。对纯仿真用途来说不考虑视觉传感器、不需要高帧率画面的话软件渲染其实也能凑合跑只是CPU占用会高一些。3. URDF建模拆解A1机器狗的关节拓扑到底长什么样3.1 从机械结构到URDF的抽象先把A1的腿结构讲明白。每条腿有3个关节髋关节横滚hip roll、髋关节俯仰hip pitch和膝关节俯仰knee pitch。四条腿乘以3一共12个自由度。很多人容易忽略的是髋关节这里其实叠了两个电机一个管侧向摆动一个管前后摆动而不是像传统的单自由度关节那样只绕一个轴转。在URDF里一个link对应一个刚体joint连接两个link并定义它们之间的相对运动。A1的模型可以拆成这样base_link ├── FL_hip_link ── FL_thigh_link ── FL_calf_link ├── FR_hip_link ── FR_thigh_link ── FR_calf_link ├── RL_hip_link ── RL_thigh_link ── RL_calf_link └── RR_hip_link ── RR_thigh_link ── RR_calf_link每个关节的类型都是revolute也就是有限角度旋转需要给limit限制关节范围否则Gazebo里关节会转飞。3.2 坐标系的约定URDF建模最关键的一步是坐标系的定义。我习惯把base_link的坐标系定为x轴朝前y轴朝左z轴朝上。这个约定符合ROS的标准也更方便后续做运动学。在这个坐标系下右前腿的hip关节原点大概在base_link前方0.18到0.19米、左侧负方向0.045米左右的位置。注意A1的hip roll关节绕x轴旋转hip pitch和knee pitch绕y轴旋转。很多人在这一步搞混导致模型加载后腿部扭曲原因就是轴定义和机械结构对不上。我的建议是先画一张纸上的坐标系图标出每个关节轴的朝向再开始写URDF。这一步花十分钟能省下后面调试的一整天。3.3 一个完整的机身与单腿URDF片段下面是一个可以运行的简化版base_link和单腿描述。为了控制篇幅我先展示核心结构link namebase_link visual geometry box size0.36 0.14 0.12/ /geometry origin rpy0 0 0 xyz0 0 0/ /visual collision geometry box size0.36 0.14 0.12/ /geometry /collision inertial mass value6.0/ inertia ixx0.02 ixy0 ixz0 iyy0.03 iyz0 izz0.03/ /inertial /link joint nameFL_hip_joint typerevolute origin xyz0.18 0.045 0 rpy0 0 0/ parent linkbase_link/ child linkFL_hip_link/ axis xyz1 0 0/ limit effort33 lower-0.5 upper0.5 velocity10/ dynamics damping0.2 friction0.0/ /joint link nameFL_hip_link visual geometry box size0.05 0.05 0.04/ /geometry /visual inertial mass value0.5/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.001/ /inertial /link这里有个细节inertial是Gazebo仿真必不可少的。如果你的URDF只写了visual和collisionRviz里能正常显示模型但一进Gazebo就会出问题要么模型直接散架要么因为惯性张量为零导致Gazebo崩掉或物理行为诡异。接着是大腿和小腿的部分。大腿关节绕y轴旋转位置就在hip_link的原点然后大腿本体向下延伸0.21米膝关节在大腿末端joint nameFL_thigh_joint typerevolute origin xyz0 0 0 rpy0 0 0/ parent linkFL_hip_link/ child linkFL_thigh_link/ axis xyz0 1 0/ limit effort33 lower-2.0 upper2.0 velocity10/ dynamics damping0.2 friction0.0/ /joint link nameFL_thigh_link visual geometry box size0.04 0.04 0.21/ /geometry origin rpy0 0 0 xyz0 0 -0.105/ /visual inertial mass value1.2/ inertia ixx0.004 ixy0 ixz0 iyy0.004 iyz0 izz0.0005/ /inertial /link joint nameFL_calf_joint typerevolute origin xyz0 0 -0.21 rpy0 0 0/ parent linkFL_thigh_link/ child linkFL_calf_link/ axis xyz0 1 0/ limit effort33 lower-2.5 upper0 velocity10/ dynamics damping0.2 friction0.0/ /joint小腿部分的结构跟大腿类似只是长度改成0.2米。写完这一条腿你会发现剩下三条腿的逻辑完全一样只是坐标位置和正负号不同。如果直接复制粘贴四遍以后改一个长度参数就要改四个地方而且极容易漏改。这就是引入Xacro的核心动机。4. Xacro宏复用四足模型最怕的就是重复而宏就是解药4.1 为什么要用Xacro而不是纯URDFURDF本质是XML格式它不支持变量、条件判断、循环。你写一条腿没问题写四条腿就开始痛苦写到按键布局相似的传感器支架、末端执行器几乎是在做重复劳动。XacroXML Macros就是为了解决这个问题出现的。它的核心思路是把URDF中重复的部分抽象成“宏”用属性定义可复用的参数用数学表达式计算坐标一次定义、四处调用。对四足机器人来说Xacro几乎是必需品。A1这样的四足结构四条腿的拓扑完全一致只是安装位置和镜像方向不同。用宏定义好一条腿后四条腿的代码可以缩减到四行调用。4.2 用属性管理关键尺寸先把所有需要之后统一调整的尺寸定义成属性xacro:property namebody_length value0.18 / xacro:property namebody_width value0.045 / xacro:property namethigh_length value0.21 / xacro:property namecalf_length value0.2 / xacro:property namehip_mass value0.5 / xacro:property namethigh_mass value1.2 / xacro:property namecalf_mass value0.4 /这里我把body_length和body_width定义成半长半宽也就是从机体中心到髋关节的距离。这样做的好处是调用时只需要传正负号比如body_length是0.18米那么前腿的x坐标就是0.18后腿就是-0.18。属性用${}包裹的表达式来引用支持四则运算。比如大腿惯量张量里的iyy我可以直接写${thigh_mass * thigh_length * thigh_length / 12}而不是手动算出一个硬编码数字。这样以后再改质量或长度惯量会自动跟着变不会出现“质量改了但惯量还是旧值”的低级错误。4.3 把单腿封装成宏宏的语法是xacro:macro用params指定参数列表。我这里设计了四个参数prefix是腿的前缀FL/FR/RL/RRx_sign和y_sign分别控制前后、左右方向的正负mirror_pitch用来处理左右腿pitch方向的差异。一个完整的腿宏内部结构如下xacro:macro nameunitree_leg paramsprefix x_sign y_sign !-- 髋关节横滚 -- joint name${prefix}_hip_joint typerevolute origin xyz${x_sign * body_length} ${y_sign * body_width} 0 rpy0 0 0/ parent linkbase_link/ child link${prefix}_hip_link/ axis xyz1 0 0/ limit effort33 lower-0.5 upper0.5 velocity10/ dynamics damping0.2 friction0.0/ /joint link name${prefix}_hip_link visual geometry box size0.05 0.05 0.04/ /geometry /visual collision geometry box size0.05 0.05 0.04/ /geometry /collision inertial mass value${hip_mass}/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.001/ /inertial /link !-- 髋关节俯仰 -- joint name${prefix}_thigh_joint typerevolute origin xyz0 0 0 rpy0 0 0/ parent link${prefix}_hip_link/ child link${prefix}_thigh_link/ axis xyz0 1 0/ limit effort33 lower-2.0 upper2.0 velocity10/ dynamics damping0.2 friction0.0/ /joint link name${prefix}_thigh_link visual geometry box size0.04 0.04 ${thigh_length}/ /geometry origin rpy0 0 0 xyz0 0 ${-thigh_length / 2.0}/ /visual collision geometry box size0.04 0.04 ${thigh_length}/ /geometry origin rpy0 0 0 xyz0 0 ${-thigh_length / 2.0}/ /collision inertial mass value${thigh_mass}/ inertia ixx${thigh_mass * thigh_length * thigh_length / 12} ixy0 ixz0 iyy${thigh_mass * thigh_length * thigh_length / 12} iyz0 izz0.0005/ /inertial /link !-- 膝关节俯仰 -- joint name${prefix}_calf_joint typerevolute origin xyz0 0 ${-thigh_length} rpy0 0 0/ parent link${prefix}_thigh_link/ child link${prefix}_calf_link/ axis xyz0 1 0/ limit effort33 lower-2.5 upper0.0 velocity10/ dynamics damping0.2 friction0.0/ /joint link name${prefix}_calf_link visual geometry box size0.035 0.035 ${calf_length}/ /geometry origin rpy0 0 0 xyz0 0 ${-calf_length / 2.0}/ /visual collision geometry box size0.035 0.035 ${calf_length}/ /geometry origin rpy0 0 0 xyz0 0 ${-calf_length / 2.0}/ /collision inertial mass value${calf_mass}/ inertia ixx${calf_mass * calf_length * calf_length / 12} ixy0 ixz0 iyy${calf_mass * calf_length * calf_length / 12} iyz0 izz0.0002/ /inertial /link /xacro:macro写完宏之后在robot标签内部调用四次xacro:unitree_leg prefixFL x_sign1.0 y_sign1.0 / xacro:unitree_leg prefixFR x_sign1.0 y_sign-1.0 / xacro:unitree_leg prefixRL x_sign-1.0 y_sign1.0 / xacro:unitree_leg prefixRR x_sign-1.0 y_sign-1.0 /到这里整个模型的JSON结构已经相当清晰。整个URDF文件只需要几十行调用代码加上全局的link和joint定义可读性和可维护性比复制粘贴好了不止一个量级。4.4 左右腿的俯仰方向差异一个容易忽略的细节这里要特别注意一个问题。左右腿在机械结构上是镜像对称的如果只改变hip roll关节的位置的正负号而hip pitch和knee pitch的旋转轴方向不变那么左腿和右腿的“向前摆腿”方向是相反的。处理方式有两种一是给宏增加一个mirror参数当为1.0时pitch关节的axis的y分量取反二是在定义左右腿时用不同的关节限位和初始位置来补偿。第一种方式更通用也更好理解。在宏内部可以这样判断给宏加一个pitch_sign参数把axis xyz0 1 0/改成axis xyz0 ${pitch_sign} 0/左腿传1.0右腿传-1.0。有读者可能会问那关节限位不也反了吗其实不会。因为你限位表达的还是“关节转角”而不是“世界坐标系下的绝对角度”。限位是相对于关节自身的零位定义的所以即使旋转轴方向取反限位值本身不需要变化只是正方向代表的空间运动方向取反。不过下面的内容里为了让初次搭建能够跑通我会暂时用左右对称的简单方式即左右腿pitch轴方向保持一致只在初始装配时通过y方向正负区分左右。这样模型在Gazebo里可以正常站立和摆动等后面做运动学时会再去精细化处理镜像逻辑。5. 从URDF到Gazebo仿真材质、传动、控制器一个都不能少5.1 Gazebo中的材质与外观URDF的visual标签里可以定义material但在Rviz里显示的材质和Gazebo里显示的并不完全是一回事。很多时候你会遇到“Rviz里是灰色的Gazebo里却是纯白色”或者“颜色泛蓝泛紫”的情况。想让Gazebo里的模型颜色可控最稳妥的方式是给每个link单独添加gazebo标签gazebo referencebase_link materialGazebo/DarkGrey/material /gazebo同理四条腿的link也可以分别指定颜色。注意Gazebo的材质名称用的是它内置材质库的名字比如Gazebo/Red、Gazebo/Blue、Gazebo/White。如果你想要自定义RGB可以用下面的方式gazebo referenceFL_thigh_link material ambient0.1 0.1 0.1 1/ambient diffuse0.2 0.2 0.8 1/diffuse specular0.0 0.0 0.0 0/specular /material /gazebo看起来繁琐但确实是Gazebo里控制颜色和材质反射最直接的办法。5.2 transmission和gazebo_ros_control插件URDF描述的是机器人的运动学结构但要让关节在Gazebo里真正被控制必须做两件事一是定义transmission把joint和actuator对应起来二是加载gazebo_ros_control插件让Gazebo和ROS的控制器框架对接。transmission的写法比较固定每个关节一个transmission nameFL_hip_trans typetransmission_interface/SimpleTransmission/type joint nameFL_hip_joint hardwareInterfacehardware_interface/EffortJointInterface/hardwareInterface /joint actuator nameFL_hip_motor hardwareInterfacehardware_interface/EffortJointInterface/hardwareInterface mechanicalReduction1/mechanicalReduction /actuator /transmissionmechanicalReduction是减速比。A1的电机大多有减速器但我们在仿真里如果不需要精确还原电机侧转速保持1即可这样控制量直接对应到关节输出。如果后面要做更精细的动力学仿真再把这个参数改成真实值。然后在robot标签内加载插件gazebo plugin namegazebo_ros_control filenamelibgazebo_ros_control.so robotNamespace//robotNamespace /plugin /gazebo插件加载后会读取URDF里所有的transmission定义并在ROS端暴露一个control manager的接口。没有这个插件你发多少ROS话题关节都不会动弹。5.3 控制器配置位置控制还是力矩控制A1真机在底层支持位置和力矩两种控制模式仿真里也建议保留同样的接口。我用的方案是在controllers.yaml里同时配置一个joint_state_controller和一组position_controllers/JointGroupPositionController。前者负责发布每个关节的角度、速度、力矩反馈后者接收位置指令并完成闭环。joint_state_controller: type: joint_state_controller/JointStateController publish_rate: 100 a1_position_controller: type: position_controllers/JointGroupPositionController joints: - FL_hip_joint - FL_thigh_joint - FL_calf_joint - FR_hip_joint - FR_thigh_joint - FR_calf_joint - RL_hip_joint - RL_thigh_joint - RL_calf_joint - RR_hip_joint - RR_thigh_joint - RR_calf_joint pid_gains: FL_hip_joint: {p: 100.0, i: 0.0, d: 0.2} FL_thigh_joint: {p: 150.0, i: 0.0, d: 0.5} FL_calf_joint: {p: 150.0, i: 0.0, d: 0.5}这里值得说一下PID参数的选择。底层的单关节PD控制器p值决定“刚度”d值决定“阻尼”。p太小关节软绵绵没法支撑机身重量p太大关节会剧烈振荡模型在Gazebo里看起来像帕金森患者。初始建议大腿和膝盖p给到100到200d给到0.2到0.5然后在仿真里观察模型的稳定情况再微调。注意不同版本的gazebo_ros_control对PID参数读取方式略有差别如果你的控制量没有生效先用rqt_gui查看控制器状态里有没有加载PID参数。5.4 初始位姿与重力下的自平衡把模型spawn进Gazebo时初始高度很关键。如果从零高度开始模型会和地面发生穿透产生非常大的接触力直接把模型弹飞。所以我会设置一个略高于理论站立高度的初始位置让模型自然下落然后稳定下来。A1大腿加小腿总长约0.41米站立时髋关节高度约为0.3米左右所以初始z可以给0.35到0.4米。在launch文件里spawn_model节点用-z参数控制初始高度node namespawn_model pkggazebo_ros typespawn_model args-urdf -param robot_description -model a1 -z 0.4 /如果没有设置合适的初始姿态模型一进入Gazebo就可能侧翻、趴下甚至飞出去。这个时候不要慌先看三条线索是否所有关节的角度都从0开始、是否有惯性参数缺失的警告、初始高度是否足够。大多数情况下把这三件事处理好模型就能稳稳落地。6. 把一切串起来launch文件、验证流程与高频故障排查6.1 完整launch文件怎么写现在把前面所有零件拼装成一个可运行的launch文件。核心步骤有三个一是用xacro把模型解析成robot_description参数二是启动Gazebo空世界三是把模型spawn进去。launch param namerobot_description command$(find xacro)/xacro $(find unitree_a1_description)/urdf/a1.xacro / include file$(find gazebo_ros)/launch/empty_world.launch arg namepaused valuefalse/ arg nameuse_sim_time valuetrue/ arg namegui valuetrue/ /include node namespawn_model pkggazebo_ros typespawn_model outputscreen args-urdf -param robot_description -model a1 -z 0.4 / rosparam file$(find unitree_a1_gazebo)/config/controllers.yaml commandload / node namecontroller_spawner pkgcontroller_manager typespawner outputscreen argsjoint_state_controller a1_position_controller / /launch这里有一个常见报错很多人找不到empty_world.launch。这是因为没有安装gazebo_ros包或者包路径没有配置。在Noetic下可以这样安装sudo apt install ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros-control装完source一下再重新launch。6.2 验证模型是否真的被“控制”了模型加载完成不代表仿真环境就通了。我每次搭建完一个新的仿真模型都会按下面的顺序做一遍验证第一看模型在Gazebo世界里的形态。用鼠标旋转视角检查每条腿是否完整颜色是否正确有没有link之间穿模。穿模通常意味着碰撞体尺寸或坐标写错了。第二在终端里查看关节状态话题是否在发布rostopic echo /joint_states如果这个话题有数据说明joint_state_controller已经工作。用rqt_robot_monitor能更直观地看每个关节的角度、速度、力矩值。第三发布一个位置指令让所有关节回到一个中间姿态。比如让大腿抬起来一点rostopic pub /a1_position_controller/command std_msgs/Float64MultiArray data: [0, 0.5, -1.0, 0, 0.5, -1.0, 0, 0.5, -1.0, 0, 0.5, -1.0]命令格式是12个浮点数按你在controllers.yaml里定义的关节顺序排列。如果模型的大腿和小腿确实动了并且最终停在指定角度说明从URDF到Xacro到控制器的全链路已经打通。6.3 高频故障与排查经验故障一模型加载后直接黑屏或消失。原因非常集中——要么是材质设置问题要么是惯性参数缺了。URDF文件里如果漏了inertialGazebo会忽略该link的碰撞和视觉属性导致模型看起来不完整。解决办法是逐个检查所有link的inertial确保质量大于0且惯性张量所有项非负。故障二模型掉落地面后关节一直抖动。这是最折磨人的问题。首要原因是关节阻尼太小模型落地后关节在重力作用下产生振荡。把dynamics damping从0改到0.2到0.5情况会明显改善。其次检查PID中d值如果d为0关节相当于没有速度阻尼也容易抖。实在搞不定的时候有个偷懒的土办法把关节阻尼调大同时把PID的d也调大模型会变得“黏稠”虽然手感偏钝但至少能稳定后续再逐步降低数值。故障三关节反响或者转向不一致。定义左右腿时axis取反后发现运动方向反了。这不一定是代码错误而是关节坐标轴和限位的关系。检查limit的lower和upper是否匹配你的轴方向。如果轴方向取反lower和upper也应该对应调整否则可能出现“明明指令是正向旋转关节却朝limit的另一头跑”。故障四仿真速度很慢或CPU占用极高。Gazebo默认物理步长是1毫秒但如果你没有精简碰撞体或者机器配置一般就会卡得不行。我的做法是把带复杂mesh的link换成简单几何体box、cylinder、sphere只在视觉上保留mesh。另外gazebo里可以设置max_step_size0.005/max_step_size和real_time_factor0.5/real_time_factor来降低仿真精度和加速比对于纯运动学调试足够了。7. 环境搭完以后还能往哪个方向扩展A1仿真环境搭好之后你可以做的事情远超“让模型站着不动”。最直接的方向是运动控制算法的仿真验证。Unitree官方开源了简易的步态控制器你可以把它接到你刚搭好的模型上跑一套trot步态。如果步态抖、迈步别扭先不要怀疑算法回头检查你的URDF参数——很多“算法问题”其实是模型参数和真机不一致导致的。比如大腿长度差了1厘米在步态控制器里体现为落脚点位置偏了最后你会发现是URDF写错了。再进一步可以接入强化学习训练框架。现在四足RL训练的主流路径是Isaac Gym或MuJoCo但Gazebo的优势在于ROS生态、传感器仿真和控制器接口的完整性。把Gazebo里训练好的控制策略通过ROS话题转发到真机中间只需要改一个话题名称和消息格式这种迁移路径非常平滑。如果你之前用过SolidWorks这类CAD软件导出URDF时也要注意SolidWorks导出的URDF往往会把所有link的坐标系设成CAD中的装配坐标不会为每个关节单独建立子坐标系。这导致的结果是Gazebo里模型能显示但关节轴方向乱七八糟。解决办法很简单在URDF里手动添加gazebo reference标签重新定义每个link的质量、惯性、材质用xacro的数学表达式统一计算坐标偏移而不是依赖CAD导出的原始值。另外现在CoppeliaSimV-REP以及Blender也能导入URDF模型。如果你的项目需要和机械臂、移动底盘共用一个仿真场景URDF作为中间格式的优势就很明显。一个模型文件Gazebo、Rviz、CoppeliaSim、Isaac Sim都能吃进去只是各平台对传感器、控制器插件的要求略有不同。最后再多说一句实操层面的经验。我见过太多人卡在“模型加载了但动不了”这一步反复怀疑是控制器配置问题结果发现是launch文件里spawn_model的-z参数没给够模型在地面以下被碰撞引擎疯狂挤压。遇到奇怪物理现象第一反应永远应该是检查初始位姿、检查碰撞体、检查惯性参数。这三样没问题再往控制层面排查。按这套思路走下来你不仅能拥有一台能在仿真里站住的A1更关键的是建立起一套“机械结构到URDFURDF到仿真控制”的完整认知。这个认知一旦建立以后看任何一款机器人的模型文件你都会觉得像是在看一份带标注的机械图纸。
返回列表