☰
SolidWorks履带机器人转URDF全流程:坐标系、单位与Gazebo差速仿真排坑指南
2026/10/5 1:02:50 网站建设 项目流程

我最早把履带机器人从SolidWorks转成URDF的时候,在Rviz里看到模型的一瞬间差点怀疑人生:两条履带完全错位,轮子转起来像在跳机械舞,底盘直接超过半个地球大小。后来我把装配体、坐标系、导出插件来回折腾了两天,才搞清楚问题基本都出在三个地方——单位、轴方向、履带建模思路。这篇把完整流程和踩过的坑写出来,给还在和sw_urdf_exporter搏斗的朋友一些参考。

内容适合准备做差速底盘仿真、想给履带机器人配Gazebo环境,或者正在从机械臂转向移动机器人开发的人。尤其是那些SolidWorks建模很熟、但对URDF规范不熟的人,能够少走一大截弯路。

1. 为什么履带机器人转URDF比机械臂更折腾

1.1 机械臂经验不能照搬:履带底盘的本质差异

网上讲SolidWorks转URDF的教程,十个里有八个拿机械臂当例子——六个关节、一根轴连一根轴,每个link只有一个明确的旋转方向,导出后稍微检查下坐标就能跑起来。这套经验放在履带机器人上基本失效。

履带机器人和机械臂在URDF层面上是完全不同的建模对象。机械臂是一个开链运动结构,关节数少、运动学关系清晰,URDF本来就是为这类结构设计的;而履带底盘是闭链加地面交互系统,两条履带和地面构成一组复杂的摩擦驱动问题,它的“行走”不靠某个关节做圆周摆动,而靠左右履带的差速配合。你想在URDF里完整还原履带链节啮合、张紧、地面形变,那是不现实的,也不该这样做。正确思路是:模型层面用多个驱动轮和负重轮去近似履带的物理行为,视觉层面保留履带外观的mesh,其余交给摩擦系数和控制器去补。

1.2 转URDF前要先回答的三个问题

构建之前,先想清楚这三个问题,它们直接决定后面的步骤怎么走。

第一个问题:你的履带需不需要“动”?如果是纯视觉展示,把整条履带建模成一个固定link或直接隐藏掉都可以;如果要在Gazebo里靠摩擦跑起来,就需要用轮组近似,并在两侧轮子上配置不同转速。这里没有中间状态,越早决定越好。

第二个问题:哪些轮子是驱动轮,哪些是负重轮?履带机器人常见布置是前端诱导轮、后端主动轮(驱动轮)、底部负重轮,简化模型里往往只保留左右各两个驱动轮加中间几个负重轮。驱动轮用continuous关节,负重轮可以直接设为fixed,后续会好控制得多。

第三个问题:要不要保留履带的触地外形?履带接地段是平面,轮组近似后接地是两排圆轮,Gazebo里跑起来会有轻微颠簸感,这是简化模型的正常现象。如果你实在介意,可以在底盘两侧加一段薄长方体碰撞体来模拟接地带,效果会好一些。

1.3 适配的读者与路线

我按“SolidWorks装好但完全没转过URDF”的新手来写,也会穿插一些经验判断便于老手参考。整体路线是:准备装配体 → 装插件 → 导出URDF → RViz验证 → Gazebo调试 → 模型瘦身与复用。履带机器人特有的部分(链节处理、摩擦、差速转向)会单独拿出来说清楚,因为这些点才是和机械臂流程分道扬镳的关键。

2. 环境准备:从SolidWorks模型到可导出装配体的前置动作

2.1 sw_urdf_exporter插件选型和安装

现在SolidWorks转URDF主流插件还是ros/solidworks_urdf_exporter,有2.0和3.0两个大版本。3.0支持较新的SolidWorks版本,界面也更友好,但我在实际使用中碰到过只支持特定SW版本的情况;2.0的兼容性反而更好,SW 2018到2022基本都能装。如果你拿不准,直接用2.0。

安装流程很简单:从GitHub下载sw2urdfSetup.exe,安装前先把SolidWorks完全关闭,装完重启SW,菜单栏会出现“Export as URDF”相关按钮,部分版本在“工具”菜单下,部分在“文件”菜单里,找不到就在命令管理器里搜索“URDF”。装完建议先用一个之前能正常打开的小装配体验证插件是否真的加载成功,不要直接拿履带整车试,因为一旦插件没激活,排查时容易和模型问题混淆。

2.2 ROS与Gazebo环境选择

URDF本身无关ROS版本,但后面的可视化验证和仿真调试完全依赖ROS生态。我使用的是ROS Noetic + Ubuntu 20.04,配套Gazebo 11,这个组合教程多、diff_drive资料全,适合新手。如果你用ROS 2 Humble,URDF流程基本一样,只是Gazebo插件要从gazebo_ros_diff_drive换到gazebo_ros2_control,配置方式有差别。

安装ROS的方式,用apt官方源也好,用一键安装脚本也好,都行。我自己的体验是一键安装省心不少,装完记得检查一下rosdep、环境变量source是否写入了~/.bashrc,很多后面URDF包跑不起来的问题都出在环境没生效,而不是模型本身。

2.3 装配体整备三件事:单位、坐标系、履带链节合并

导出前在SolidWorks里把这三件事做完,后面至少少踩一半坑。

第一,单位。SolidWorks默认模板多数是MMGS(毫米-克-秒),URDF要求MKS(米-千克-秒)。在“工具→选项→文档属性→单位”里把装配体单位改成米制,同时记住这是模型显示单位,真正导出时还涉及数值缩放。后面第4章会详细说这个坑有多隐蔽。

第二,坐标系。URDF的规范是x轴向前、y轴向左、z轴向上。SolidWorks默认的前视基准面、右视基准面方向跟这不一样,不能直接拿来当base_link坐标系。我建议在装配体里新建一个三根轴零件,摆到车体几何中心,x正方向朝向车头,z正方向朝上,后面导出时所有关键坐标都参照它来对。

第三,履带链节合并。这是履带机器人的专属问题。如果你按真实履带一节一节画了几十个链节,导出URDF时每个链节都会变成一个link,拖出来的关节树能有一百多行,RViz直接卡成幻灯片,Gazebo物理引擎更是跑不动。正确做法是导出前把链节子装配另存为副本,然后把链节合并成一个整体零件,或者干脆只保留主动轮、诱导轮、负重轮,履带外圈用视觉mesh带过。具体怎么处理,第5章展开。

2.4 我把坐标系箭头做进模型里

这个小技巧帮了我大忙:在SolidWorks装配体里新建一个零件,画三根不同颜色的细圆柱代表x/y/z轴,固定在base_link中心,导出时把它一起导出,但给它一个隐藏的配置。之后在任何环节只要看到坐标箭头,就知道当前朝向对不对。RViz里如果模型方向歪了,看箭头一对比就能定位是哪个link的origin出了问题,不用凭感觉猜。

3. 导出主流程:配置好每个关节参数,URDF才像样

3.1 打开Export as URDF:建立link-joint树

装配体整备完毕,开始导出。先打开整车装配体,确认所有零件都已经“保存”且没有未重建的错误,然后点击Export as URDF。界面左侧是link树,右侧是关节配置区。

初始状态插件会自动读取装配体里的配合关系,生成一套link层级,但往往不是你要的。比如它可能把每个紧固件、每个垫片都当成一个link,还把左右轮子放到了奇怪的位置。这里需要手动整理:先把非必要的固定件、装饰件从树里删除或标记为固定,再把底盘设置成base_link,然后把每个轮子按“轮子link→底盘link”的关系挂到树下面。

我建议在SolidWorks装配体里就把轮子用正确的配合约束到车架上,不要依赖插件自动推断,否则它会把配合关系读错。尤其不要有冗余配合、浮动零件,导出时会产生错误origin。

3.2 关节类型、轴向量和Origin的配置细节

在关节配置区,每个关节都有几个关键项:parent link、child link、type、axis、origin。

关节类型用的最多的是continuous和revolute。驱动轮选用continuous,表示可以无限旋转;如果轮子转向有限位(比如某些转向机构),才用revolute并配置limit。负重轮如果选fixed,就变成一个不动的视觉件;如果选continuous但不给控制输入,在Gazebo里可能会因为重力产生微小转动积累误差,我实际测试下来fixed更稳。

轴向量是这个环节最难的。URDF里axis就是你旋转轴在哪个方向,比如轮子绕y轴转就是<axis xyz="0 1 0"/>。SW插件会让你为每个关节指定轴向量,但很多人的轮子装配是异型孔、“临时轴”或者参考面方向不规矩,导致插件读出来的方向是错的。最稳妥的做法:在SolidWorks里给每个轮子加一根参考轴线,导出时手动把axis指向这根参考轴的正方向。

Origin的含义是“子link坐标系相对父link坐标系的平移和旋转”。SW插件会自动算,但前提是所有配合关系都正常。如果你发现导出后两个link的相对位置错乱,多半是原装配体里有配合冲突、或子装配处于浮动状态。检查方式很简单:在SW里拖动轮子,看它是否只能按预期方向转动,如果还能自由晃动,说明配合没完全约束,先修装配再导出。

3.3 导出后的目录结构

点击“Preview and Export”后,插件会生成一个文件夹,典型结构是:

my_robot/ ├── my_robot.urdf ├── meshes/ │ ├── base_link.STL │ ├── left_wheel.STL │ └── ... └── config/ ├── joint_names.yaml ├── joint_limits.yaml └── ...

meshes目录存的是STL文件,用于视觉显示;config目录里是关节名和限位配置,主要用于后续MoveIt或控制器的读取。URDF只存模型结构和坐标信息,真正的几何形状全靠mesh引用。

稍微说明一下,URDF从SolidWorks导出后,惯性参数(inertial)有时会缺失或数值异常,后面Gazebo仿真时会出问题,第6章专门讲。

3.4 check_urdf验证和RViz首屏检查

导出完成后别急着跑Gazebo,先用验证工具看一眼结构。在ROS环境里执行:

check_urdf my_robot.urdf urdf_to_graphiz my_robot.urdf

check_urdf会输出link和joint的数量、层级关系,出现Error直接按提示改;urdf_to_graphiz会生成一个可视化树形图,可以用图片查看器打开,确认关节父子关系是否正确。

然后启动RViz,通过joint_state_publisher_gui和robot_state_publisher做首屏检查:

roslaunch urdf_tutorial display.launch model:=/path/to/my_robot.urdf

在RViz的Global Options里把Fixed Frame设为base_link,使用左侧的JointStatePublisher面板滑杆,手动转动每个驱动的关节。这里主要看三件事:模型是否居中、轮子旋转方向是否正常、移动关节时连杆有没有“甩”出去的现象。任何异常都先回SolidWorks排查,不要急着在URDF文本里手动改坐标。

4. 坐标系、单位与关节轴:三个最容易翻车的地方

4.1 单位制:毫米和米之间差着一次“放大1000倍”

SW默认毫米,URDF默认米。这个问题听起来很简单,但它坑人的地方在于:sw_urdf_exporter导出时,URDF里的平移量会换算成米,但STL文件内部顶点坐标往往仍保留毫米。结果是RViz里模型link位置对了,但mesh几何体膨胀了1000倍,看起来像是底盘上长出一个巨大零件。

我当时第一次看到这个现象时,根本没往单位上想,还以为是导出插件坏了。后来把STL用文本编辑器打开,看顶点坐标数值都是几百上千,才确定是单位问题。

解决办法是在SolidWorks里统一单位。建议在装配体层面把单位从MMGS改成MKS,并勾选“转换尺寸”,让所有零件尺寸按比例缩小到米级。如果模型已经画得很复杂,不想改单位,那就在导出前选中所有零件执行缩放0.001倍(“插入→特征→缩放”),再另存一份。注意操作前备份原始装配体,避免把设计模型改乱。

一个简单的自查方法:导出URDF后,用readlink检查link的origin数值,如果接近0.5(半米级),说明单位换算成功;如果出现500这种数字,说明还是毫米的底子。

4.2 x/z轴:URDF规定左前上,SW默认是“上+右”

SolidWorks习惯是z轴朝上、x轴朝右,URDF是x轴朝前、z轴朝上、y轴朝左。很多人觉得“z轴朝上一样啊”,但x轴方向一变,整个base_link的朝向就斜了90度。

我踩过最离谱的一次:所有轮子装得好好的,但把base_link的坐标系按SW默认摆放导出来后,整车在RViz里是横着躺的——车头朝左,履带贴地的那面朝后。检查了好久才发现是base_link坐标系没转正。

一个有效的做法:在SolidWorks装配体里先放一个坐标参考体,把x方向对准车头,y方向对准车身左侧,z方向朝上。然后在这个零件上创建坐标系“URDF_Base”,导出时把base_link的origin和它对齐。每次做新模型都复用同一个参考体,测下来出错率最低。

4.3 关节轴方向错了的典型症状:轮子不是转,是晃

关节轴方向错误不是“转反了”,而是会更隐蔽——轮子边转边晃,或者连杆跟着做圆锥运动。

原因是URDF旋转轴向量如果和实际圆柱轴的轴线偏移一个角度,哪怕只有1度,每转一圈就会累积一次位置偏差,RViz里看就像是轮子在做小幅度摆动,而不是纯旋转。轮径越大、转速越快,摆动越明显。

排查方法是:把该关节的type先设成continuous,给一个固定速度,然后看轮子外缘某一点的轨迹。如果轨迹接近正圆,说明轴方向正确;如果轨迹是一个椭圆或花瓣状,说明轴向量不沿旋转轴。这时候回到SolidWorks,调出该轮子零件的参考轴,把导出时的axis直接指定到这条参考轴的正方向。注意方向翻转(正负号)也会导致转动方向相反,但那是比较容易看出来的一种情况。

5. 履带底盘的差异化配置:摩擦、负重轮与差速转向建模

5.1 履带链节不逐个导出,模型要简化为轮组

这是履带机器人转URDF时和机械臂最大的区别。真实履带是一节一节链板铰接起来的,几十个链节和销轴在SolidWorks里看着很真实,但一进URDF就是灾难。

导出前把履带模型做简化:保留主动轮、诱导轮、负重轮的圆柱外形,删除链节或把整条履带外圈合并成一个圆柱环状mesh,只做视觉显示。碰撞体不要用这个环状mesh,用一块简单长方体包住履带外侧就可以。主动轮关节设为continuous,其余负重轮按需设为fixed或者也转,但必须明确它不受驱动。

简化后不仅URDF文件体积小很多,Gazebo物理仿真速度也能快一个量级。说实话,用真实链节去做ROS仿真意义不大,差速运动的宏观行为靠的是两侧履带的速度差,和单个链节的啮合细节没有直接关系。

5.2 摩擦系数与轮距:差速转向的物理基础

履带机器人转弯不靠前轮转向,靠左右履带速度差。因此给轮子设置的摩擦系数要足够大,否则在Gazebo里会边跑边滑,转向时直接原地打滑甚至横着飘。

我做一个对比表格,展示URDF里履带机器人和普通轮式小车在Gazebo配置上的差异:

配置项普通轮式小车履带机器人(轮组近似)
驱动轮左右各1个左右至少各1个,常见各2个
转向方式前轮转角 / 差速只能差速
mu1 / mu2 摩擦0.5~1.0左右建议1.0~5.0
车辆横向侧滑较小,允许忽略剧烈,必须调高摩擦系数
接地形状圆轮点接触履带近似平面接触

这个表也是我后来做不同底盘时总结的。履带机器人在Gazebo里如果转向迟钝或者直线跑偏,第一排查顺序就是摩擦系数,而不是控制参数。

5.3 Gazebo中的diff_drive驱动配置

在ROS Noetic里,履带底盘最常用的Gazebo插件是gazebo_ros_diff_drive。虽然它的名字是“diff_drive”,实际上很多履带机器人也用它,因为履带差速转向和两轮差速在控制层面上是同一个模型。

示例配置:

<gazebo> <plugin name="diff_drive" filename="libgazebo_ros_diff_drive.so"> <left_joint>left_front_wheel_joint</left_joint> <right_joint>right_front_wheel_joint</right_joint> <wheel_separation>0.4</wheel_separation> <wheel_diameter>0.2</wheel_diameter> <command_topic>cmd_vel</command_topic> <odometry_topic>odom</odometry_topic> <max_wheel_torque>10</max_wheel_torque> </plugin> </gazebo>

这里有个细节很容易被忽略:wheel_separation应该取两条履带中心线之间的距离,而不是左右轮子外侧到外侧的距离。如果你取的是外侧距离,转向半径会明显偏大,明明发的角速度指令是1 rad/s,实际转起来却慢很多。

如果左右各有前后两个驱动轮,diff_drive插件只能指定一个左joint和一个右joint,处理方式是把左右轮分别做同步控制,或者在URDF里只让左前/右前轮作为驱动轮,其他轮跟随转速。两种我都试过,推荐后者,因为插件配置简单,且差速行为基本一致。

5.4 负重轮固定还是旋转:我的选择

负重轮在真实履带中肯定要转,但在URDF里让它们转会带来两个问题:一是每增加一个continuous/revolute关节,控制器就要多处理一路状态;二是在Gazebo里,未驱动的负重轮可能因为初始角速度不为零而产生微小漂移,影响稳定性。

实际做下来,我倾向于把负重轮设为fixed,也就是“视觉上能看出是个轮子,但不参与运动学”。这样关节树简洁很多,调试时更容易定位问题。如果你很追求真实感,可以把负重轮设为continuous,然后通过一个controller让它跟驱动轮转速同步,但这就属于锦上添花了,不是必需。

6. 仿真中各种“跑飞”的排查链路

6.1 模型陷地、落地弹跳:惯性参数的锅

很多人在RViz里检查URDF觉得没问题,一进Gazebo,模型要么陷进地面半截,要么落地后剧烈弹跳停不下来。这个问题的根源通常在于inertial参数缺失或数值离谱。

sw_urdf_exporter对复杂模型有时没法自动计算准确的惯量,导出的mass可能是默认值0.01或者干脆是NaN。Gazebo物理引擎对mass为0的link处理就很怪,有的直接不参与碰撞,有的会无限下沉。

我的处理方法是:每个link都检查mass,至少保证大于0.1kg;对于重量级的底盘,结合SW里的材质和体积估算一个合理质量。惯量矩阵如果算不准,就把link近似成规则几何体套公式,或者用这个在线惯量计算器思路:长方体为Ixx=m*(h^2+d^2)/12、Iyy=m*(w^2+d^2)/12、Izz=m*(w^2+h^2)/12。注意URDF里inertial的xyz一定是相对link原点的,不要填错参考。

6.2 轮子空转、边转边滑:碰撞体与摩擦不一致

模型能落地也能跑,但跑起来像溜冰,这是履带机器人最常见的仿真不一致问题。排查链路按顺序来:

第一,确认每个轮子上都正确添加了gazebo标签里的mu1/mu2,不要只加visual不加collision,或者只加collision没加material。

第二,确认碰撞体是否包住了mesh。如果碰撞体比视觉轮子小很多,轮子悬空,履带和地面之间根本没有接触,驱动轮再转也是空转。

第三,检查两侧轮子的摩擦系数是否一致。哪怕差0.1,跑起来也会偏航。

还有一个常见错误:左右轮配置的是相同joint name前缀,但插件里左和右写反了,导致按下前进时一个轮子向前一个向后,整车原地打转。这个用rostopic echo /odom一眼就能看出来。

6.3 一边转向另一边不动:检查轴方向与joint配置

如果履带机器人只能直线前进,转弯时一侧轮子完全不动,优先怀疑该侧轮子的joint配置。检查一下type是不是fixed,或者axis方向是否和另一侧不一致。如果左右轮的axis在URDF里一个写0 1 0,一个写0 -1 0,那么你的指令方向对于一侧是正转,对另一侧却是反转,表现出来就是转弯时一侧反而在减速。

另一个坑是joint名字。diff_drive插件的left_joint/right_joint一旦填错,它会去控制一个不存在的关节,然后静默失败。用rostopic list查看有没有cmd_vel话题,再用rqt_tf_tree查看关节是否都在tf树里正常发布。

6.4 rqt_tf_tree和rostopic调试组合拳

遇到任何定位不到的问题,我的固定调试顺序是:

rosrun rqt_tf_tree rqt_tf_tree rostopic echo /odom rostopic echo /joint_states

rqt_tf_tree查坐标变换,odom查速度反馈,joint_states查关节实时状态。这三个一出来,绝大多数“仿真跑飞”问题都能定位是出在模型、出在控制还是出在坐标系。

有一次我调了三个小时都没找到为什么履带车转弯半径不对,最后发现是wheel_separation填成了左右轮外侧距离,而不是两履带中心线距离。用odom话题里的实际角速度和指令角速度一比,差距清清楚楚。

7. 模型瘦身与跨场景复用

7.1 碰撞体用primitive,视觉体用减面STL

URDF里每个link可以有visual和collision两部分。很多教程直接让collision引用Mesh,省事,但Gazebo里物理引擎计算要用mesh做碰撞检测,几百KB的STL一多,仿真帧率直接崩。

建议所有碰撞体都用球、圆柱、长方体这类primitive几何体替代。比如底盘底座用一个box包围盒,轮子用cylinder,履带接地段用一段box。这样物理计算量很小,而且碰撞检测更稳定,不容易出现穿模。视觉体保留STL,但也要控制面数——在SolidWorks另存STL时可以设置输出精度,不要导出最高精度的几十万面,用中等精度就够了。

7.2 固定link合并,减少joint数量

URDF里joint数量越多,TF树越复杂,控制器开销越大。如果负重轮全部是fixed,那它们本质上只是底盘的一部分,完全可以合并到底盘link里。

我们之前简化履带链节也是这个思路:删掉不提供自由度的关节,把它们的geometry合并进父link。实际做下来,合并前有30多个joint,合并后只剩10个出头,RViz和Gazebo的性能提升非常明显。视觉上,这些固定件原本在装配体里就是锁死的,合并不会损失任何运动学精度。

分享一个操作技巧:在SolidWorks里用“插入→特征→合并实体”把多个零件合成一个part,再导出这个part的STL作为父link的mesh。这样URDF里的mesh数量也会减少很多。

7.3 给导航和机械臂复用:base_footprint与复合机器人

URDF导出来后不只是给Gazebo玩,后续接导航或者装机械臂都需要在这份模型上做扩展。

接导航前建议先加一个base_footprint,它是底盘在地面上的投影点,固定在z=0的平面上,是AMCL和move_base的全局坐标系基础。具体做法是在URDF里新增一个base_footprint link,用fixed关节连到base_link正下方,只保留位置、不保留碰撞和视觉。

如果你的项目是“履带底盘+机械臂”这种复合机器人,可以在URDF里把机械臂的base_link挂到底盘的某个固定关节上,相当于把两套模型合并。但强烈建议先验证底盘模型的动作,再接机械臂,否则Gazebo里两个系统的物理参数互相干扰,问题会加倍复杂。

7.4 把“转URDF”做成可重复的流程模板

做第二次的时候我就不再从头点了,而是把导出动作固化成一个内部流程清单:

  1. 备份原始装配体,另存一个“_urdf导出”副本。
  2. 副本里合并履带链节、固定件,删除不需要的装饰零件。
  3. 设置单位MKS,检查和修正装配体配合,确保没有浮动零件。
  4. 建好坐标系参考体,确认base_link和各个轮轴的坐标为预期方向。
  5. 运行sw_urdf_exporter,逐个关节核对type、axis、origin。
  6. 导出后用check_urdf、urdf_to_graphiz做结构验证。
  7. RViz里手动转动每个关节,排除轴方向和层级错误。
  8. Gazebo里用diff_drive插件驱动,确认差速转向行为和预期一致。

这个流程现在还在用,每次新车型都能在半小时内跑通首版仿真。

最后说一个小经验:sw_urdf_exporter导出的URDF文本偶尔会带有它自己的命名规则和多余注释,接手别人的URDF时先通读一遍文件结构,别直接拿过来改。至少有一次我是因为文件名大小写不一致(Linux路径区分大小写)导致mesh加载失败,结果整个模型在RViz里只剩一个坐标轴。URDF这种文本格式,出问题大多还是坐标和路径层面的事,排查时保持耐心,按章节里说的链路一步一步来,履带机器人转URDF没有想象中那么难。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询