我刚上手UR3那阵子,被一件事折磨得不轻:网上不少UR3机械臂模型资源都是SolidWorks格式,要么是装配体,要么是散的零件文件,而ROS生态里所有规划、仿真、控制的入口几乎都是URDF。UR3在SolidWorks里看着挺正常,装配约束、材料、质量属性全在,可ROS就是读不了。后来我才想明白,这件事的难点根本不在“转换”这个动作,而在你脑子里得先把“装配体”翻译成“运动学树”。
这篇内容不是一段点击Export按钮的流程记录,而是从SW文件到可仿真URDF的一条完整路线:建模侧该做什么,插件参数该怎么填,导出后哪些数据会骗你,以及最后怎么在RViz和Gazebo里证明你的URDF没问题。适合谁看?手里有SolidWorks版UR3模型、想跑ROS仿真或MoveIt规划的人,以及所有被URDF里奇怪的mesh路径、惯性单位坑过的人。
1. 为什么SolidWorks装配体不能直接当URDF用
1.1 URDF到底在描述什么
URDF(Unified Robot Description Format)本质上是一个XML文件,它把机器人描述成一棵“连杆+关节”的树。连杆叫link,对应一个刚体,每个link里包含三块信息:visual(长什么样)、collision(碰撞形状)、inertial(质量、惯性张量、质心)。关节叫joint,连接两个link,并声明这个连接的约束类型,比如revolute(旋转)、prismatic(移动)、fixed(固定)、continuous(无限制旋转)。
ROS里的TF树、运动学解算、碰撞检测、MoveIt规划,全都要依赖这套描述。URDF里没有“这个件是铝还是钢”这种材料信息,只有抽象的数值,比如质量多少千克、惯性张量是多少kg·m²。所以它不是一个CAD模型,而是给机器人算法吃的“参数卡”。
1.2 装配约束不等于关节
SolidWorks里的装配体,核心是配合关系。同轴心、重合、平行、距离、宽度配合等等,这些配合通过约束自由度来把零件固定成一台机器。问题是,配合关系表达的是“几何约束”,不是“运动约束”。比如两个零件之间用了同轴心配合,它确实留了一个旋转自由度,但这个旋转自由度没有明确的上下限、没有运动方向的定义,SolidWorks也不关心你之后想让它转多少度。
URDF里的revolute关节则要求你给出axis(旋转轴向量)、origin(关节在父link坐标系下的位姿)、limit(lower/upper角度、effort力矩、velocity速度)。这些信息在SolidWorks配合里是找不到的。所以即便SolidWorks能识别出某个配合剩下一个自由度,它也不清楚这个自由度应该叫什么、轴向朝哪、极限在哪。
SW2URDF这类插件做的事,就是让你在SolidWorks界面里手动选择关键几何对象(圆柱面、轴线、基准面),把配合关系转译成URDF关节定义,同时把零件几何导出成STL网格,并按你选定的坐标系算出关节之间的变换矩阵。
1.3 两条路线:插件转换和手工拼装
主流方案是sw2urdfsetup插件。它在SolidWorks里加一个工具栏,可以按图形化流程配置link和joint,导出整套URDF工程文件。优点是坐标变换、STL导出、惯性参数读取都是半自动的,准确度高;缺点是对装配体规范性要求高,配合稍微乱一点就容易识别失败。
另一条路是手工方案:SolidWorks里每个零件单独另存为STL,然后自己想清楚运动学树,用文本编辑器写URDF。优点是完全可控,不受插件版本限制;缺点是坐标原点、姿态欧拉角全靠自己算,一旦某个关节轴的rpy写错,整个机器人就是歪的。
我自己一般先跑插件,导出后再手工校对。插件能解决80%的体力活,剩下20%的坑得靠手动修,比如惯性单位、网格缩放这类老问题。
2. 转换之前先把SW模型捯饬干净,这步决定一半成败
2.1 命名与建模习惯
很多人在SolidWorks里给零件起名很随意,比如“手臂上盖(1)”“底座final_v3”。如果文件名带中文、空格、括号,SW2URDF导出时轻则link名字乱掉,重则STL路径解析失败。URDF里的mesh filename最终要写成package://你的包/meshes/xxx.STL,文件名里的空格在ROS里极容易出幺蛾子。我建议一开始就把所有零件改成英文短名,比如base、shoulder、upper_arm、forearm、wrist1、wrist2、wrist3、flange。
另外,装配体里的零部件层次尽量扁平。SW2URDF在识别每个link时,是按装配体树里的顶层零件来的,如果一个link其实是“子装配体里的子零件”,有些版本会识别不到。我习惯把UR3拆成顶层裸零件再组装配体,不给它搞二级子装配。
2.2 单位问题:毫米模型会秒变“巨型机器人”
这是新人最容易掉进去的坑。SolidWorks的默认模板通常是MMGS,毫米、克、秒。URDF内部标准单位是米、千克、秒,ROS里所有尺寸都按米解释。问题在于STL文件本身没有任何单位信息,它只保存三角形坐标数值。如果模型以毫米为单位建模,UR3臂展大概850左右,导出STL后坐标也是0到850这个量级,ROS会把它当成850米长,Rviz里机器人大得离谱。
SW2URDF新版本在导出时可以选单位,一般会帮你把文档单位换算成米。但如果你的模型是从老版本插件导出的,或者你手工导出STL再拼URDF,就必须自己加scale属性或者事先缩放模型。我验证单位对不对的办法很简单:在RViz里加一个Grid,看模型底盘尺寸是不是0.1到0.3米量级,如果是几千,那肯定没换算。
2.3 base坐标系放哪里
URDF的base_link坐标系非常重要,它几乎是整个机器人的世界原点的锚。SW2URDF导出时,你给base_link选的Reference Coordinate System决定了URDF树里base_link原点的位置和姿态。对UR3这种固定式机械臂,我习惯在SolidWorks里建一个专用坐标系,放在底座安装孔中心或底座底面中心,Z轴竖直向上,X轴指向机器人正前方。
很多人偷懒直接选了SW默认的“原点坐标系”,如果模型当初建模时零件偏离原点很远,导出的URDF里base_link会偏离TF世界原点,后续MoveIt规划、Gazebo固定到地面都会很别扭。好在SolidWorks可以让模型整体移动,把机器人中心挪到装配体原点附近再导,省下后面一堆坐标纠偏工作。
2.4 材料、质量属性与配合约束
URDF的inertial数据是从SolidWorks质量属性里读的,而质量属性靠的是零件材料和密度。如果模型没指定材料,SolidWorks会按默认密度算,质量可能差出好几倍。我给UR3模型里的结构件都指定了铝合金材料,法兰、轴承套件用的钢材,这样SW2URDF读到的质量才靠谱。
配合约束这块,SW2URDF识别旋转轴的方式通常是让你在模型里选圆柱面或轴线。如果某个旋转关节是用“宽度配合”或“路径配合”表达的,插件大概率识别不出轴来。我习惯把所有旋转关节都简化为“同轴心配合+一个基准面对齐”,不让插件猜。
3. sw2urdfsetup插件转换UR3的完整操作流程
3.1 插件安装和加载
SW2URDF插件的安装包是个Setup程序,装的时候最好右键以管理员身份运行,不然可能写不进SolidWorks插件目录。装完后打开SolidWorks,在“工具→插件”里勾选SW2URDF,菜单栏会出现对应工具栏。我见过好几次插件装上但工具栏不显示的情况,基本都是SolidWorks版本和插件版本不匹配。
不同SolidWorks版本对应的插件版本不一样,老版本SW配新版插件经常会启动报错。如果实在装不上,就直接放弃插件走手工路线,别在版本兼容性上耗太久。插件的价值是自动算坐标和导出STL,但这些你确实都能手工完成。
3.2 Link配置:坐标系、STL导出与惯性参数
打开UR3装配体后,点工具栏里的“Export to URDF”,会弹出一个配置窗口。左侧是link树,右侧是当前link的属性面板。第一次进来只显示一个base link,你把它重命名成base_link,然后在Reference Coordinate System那里选择之前建好的底座坐标系。
每个link要做三件事。第一,Visual Mesh,点按钮导出STL,插件会把当前link对应零件的可见几何另存为STL文件。第二,Collision Mesh,可以用同一个STL,也可以后面再换成简化几何。第三,Inertial Properties,建议点“Estimate from Mass Properties”,让插件读SolidWorks的质量属性自动填质量、质心和惯性张量。
UR3有6个旋转关节加末端法兰,对应的link大概是这样:base_link、shoulder_link、upper_arm_link、forearm_link、wrist_1_link、wrist_2_link、wrist_3_link、flange。在link树里依次加进去的时候,注意每个link的坐标系选在关节轴线上,别选到零件质心附近,因为后续joint的origin计算依赖这个坐标系的相对位姿。
3.3 Joint配置:从装配约束到旋转轴和限位
配置Joint时,SW2URDF会让你选择Joint Type,UR3六个关节都是revolute。然后你要在模型里选一个几何特征来定义旋转轴,通常是圆柱面。插件会根据圆柱面的轴线算出axis向量,如果方向跟期望相反,可以直接在面板里把axis取反。
UR3的关节顺序和轴线方向有讲究:
| 关节 | 父子link | 大致轴线 | 作用 |
|---|---|---|---|
| shoulder_pan_joint | base_link -> shoulder_link | 竖直Z轴 | 整机回转 |
| shoulder_lift_joint | shoulder_link -> upper_arm_link | 水平Y轴 | 肩部俯仰 |
| elbow_joint | upper_arm_link -> forearm_link | 水平Y轴 | 肘部俯仰 |
| wrist_1_joint | forearm_link -> wrist_1_link | 沿前臂轴线 | 手腕回转 |
| wrist_2_joint | wrist_1_link -> wrist_2_link | 垂直前臂轴线 | 手腕俯仰 |
| wrist_3_joint | wrist_2_link -> wrist_3_link | 沿末端轴线 | 法兰回转 |
不过实际UR3的腕部结构还涉及一个中间连杆,所以你在SW里选的轴线一定要逐个对照真实的运动学参数检查。另外别忘了填limit,UR3的肩部和肘部关节运动范围通常接近正负360度,腕部甚至可以连续旋转,填的lower和upper要和你后续规划任务匹配。
3.4 导出与文件结构
所有link和joint配置完成后,点Export。插件会在你指定的目录生成一堆文件:一个urdf文件、一个meshes文件夹(放所有STL)、一个config文件夹(放joint限位配置)、一个launch文件夹(通常包含一个测试launch)。老版本插件导出的URDF可能用的是xacro格式,里面有少量宏,如果你不熟悉xacro,建议直接在插件里先生成普通URDF,或者后期把xacro展开。
导出之后别急着关SolidWorks。我都习惯保留这个配置好的模型,因为后续发现哪个STL质量不行或者某条轴线选错,回SW改完一键重新导出,比重头再配一遍高效得多。
4. 导出URDF之后必须做的体检查修
4.1 静态体检:先看路径和单位
导出成功不等于URDF能用。第一步,用任意文本编辑器打开URDF,检查所有mesh的filename是不是package://形式,而不是C:/xxx这种绝对路径。绝对路径在你本机可能跑得通,但一旦换机器或者打包发布,模型就直接消失。
第二步,检查每个mesh是否带scale,或者mesh里的顶点是否已经是米制。如果SW2URDF导出时单位选项没选对,你会发现Rviz里UR3大得像一栋楼,那时候再回去重新导出代价很高。我建议在SolidWorks里导完STL后用3D查看器看一眼文件尺寸,确认在0.01到1米的量级再继续。
4.2 惯性参数:最容易骗人的地方
SW2URDF从SolidWorks质量属性里读惯性数据时,偶尔会直接把值写得不符合URDF单位要求。比如SolidWorks里显示质量是8200克,如果插件没换算,写进URDF就成了8200千克,一台实打实的UR3整机才二十多公斤,8200千克完全没法做动力学控制。
惯性张量的问题更隐蔽。SolidWorks默认的惯性矩单位一般是g·mm²,而URDF要求kg·m²。换算关系是1g·mm² = 1e-9 kg·m²。如果插件没换算,原本0.0005238 kg·m²的数值会被写成523800,这会让Gazebo里的物理仿真是灾难级别的抖动,MoveIt算出来的轨迹也奇奇怪怪。
我的做法是导出后,每个link都对照SolidWorks的质量属性手工核一遍。具体到UR3,底座大概4到6千克,肩部3到4千克,手碗部分轻一些。如果某个link的质量比整机还大,那基本就是单位错了,不用怀疑。
4.3 网格路径、缩放和碰撞体
mesh路径修完之后,看看碰撞体。URDF里visual和collision可以不同。最开始我用同一份STL既当视觉又当碰撞,在RViz里没问题,但到了Gazebo,高精度STL会导致碰撞检测计算量很大,仿真掉帧明显。后来我把每个link的碰撞体都改成了简化几何,底座用圆柱,大臂用长方体,仿真一下就流畅了。
如果你希望机械臂在Rviz里带颜色,用STL时候是没法存颜色的。新版本SW2URDF可以导出DAE格式,DAE自带材质颜色,但DAE文件有时候会在某些ROS版本里加载失败。我的折中方案是STL用于一切物理和路径,颜色这种纯视觉需求放到Gazebo的material标签里或者Rviz的URDF视觉属性里设置,总之别让颜色问题卡住主流程。
4.4 关节限位和速度力矩
URDF的revolute关节里的limit节点,除了lower和upper,还有effort和velocity。effort单位是牛米,velocity单位是弧度每秒。如果这些值缺失,MoveIt配置检测直接报错;如果值严重不合理,控制回路也会受影响。UR3的具体数值可以从官方资料里查到,找不到时先填一个宽裕的估计值,至少保证在Gazebo里规划时不报错,但没法当真值用。
这里提醒一句,URDF里的velocity是指关节最大角速度,不是笛卡尔空间速度,很多人填成度每秒导致MoveIt算出来的轨迹执行时慢得让人怀疑人生。
5. 把UR3的URDF跑起来:RViz看数,Gazebo看物理
5.1 RViz里验证关节树
把URDF放到一个ROS功能包里,路径结构大概这样:ur3_description/urdf/ur3.urdf,ur3_description/meshes/xxx.STL。写一个最简launch:
<launch> <param name="robot_description" textfile="$(find ur3_description)/urdf/ur3.urdf"/> <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher"/> <node pkg="joint_state_publisher" type="joint_state_publisher_gui" name="joint_state_publisher_gui"/> <node pkg="rviz" type="rviz" name="rviz"/> </launch>加载之后,RViz左侧选RobotModel,Fixed Frame选base_link。如果能看到一个完整的UR3模型,说明mesh路径和joint定义没大问题。接下来拖动joint_state_publisher_gui里的滑块,观察每个关节转动的方向对不对。肩部回转应该水平转,肘部俯仰应该带动大臂前臂前后摆,腕部三个关节依次检查。
这里最容易发现的反而是轴反了。比如shoulder_lift关节在URDF里axis填错方向,表现出来是大臂往反方向甩,这种问题在Rviz里一眼就能看到,修的时候直接把URDF里axis的负号改一下,或者正负号取反,再重新加载就行。
5.2 Gazebo物理环境里的验证
RViz只是几何加运动学层面的验证,到了Gazebo才真正检验物理参数。要在Gazebo里用UR3,需要给每个link补充gazebo标签,设置表面摩擦、阻尼、材质的默认参数:
<gazebo reference="base_link"> <material>Gazebo/Red</material> <mu1>1.0</mu1> <mu2>1.0</mu2> <kp>1000000.0</kp> <kd>100.0</kd> <selfCollide>false</selfCollide> </gazebo>如果不设置mu1/mu2,Gazebo里机械臂底座可能跟地面接触时打滑;如果不设置kp/kd,关节会出现高频抖动。UR3这种六关节臂在Gazebo里最常见的现象是一启动就抖成筛子,大概率是惯性参数填得离谱,或者关节阻尼默认值太小。
启动Gazebo后先不要发布任何运动指令,用固定pose保持机械臂自然下垂,观察一分钟。如果模型稳定不飘、不穿地、不抖,物理参数基本及格。然后可以依次给六个关节发小角度正弦信号,看关节跟不跟得上,能不能自然回位。Gazebo对物理参数不敏感到毫米级,但它对数量级错误非常敏感,这也是为什么前面我反复强调惯性单位。
5.3 与MoveIt集成的顺序
URDF准备好之后,下一步通常是用MoveIt Setup Assistant配置机械臂规划。启动配置向导,加载URDF,它会自动生成SRDF(机器人语义描述文件)和规划组配置。对UR3这种6轴臂,规划组一般分成manipulator整臂组和各个腕部组,末端执行器link选flange。
在配置MoveIt之前,URDF里的坐标系初值一定要经得起RViz和Gazebo两轮验证。因为MoveIt会基于URDF构建SRDF里各个link的等价关系、末端执行器的偏移量等等,如果URDF本身就有坐标系歪斜问题,MoveIt规划的路径虽然在运动学上成立,但真实仿真里机械臂会撞到障碍物或者姿态很奇怪。
MoveIt配置完,用demo.launch打开自带的RViz界面,拖拖动规划目标点,看MotionPlanning面板里机械臂能不能算出无碰撞路径。如果规划器报“IK未找到解”,先别急着调采样次数,回URDF里检查关节limit是否过小、末端link名称是否正确。
6. UR3转换避坑清单与快速排查表
6.1 转换前检查清单
我整理了每次处理UR3或者其他SW机械臂模型时都会过一遍的清单,照着做基本能避开大部分坑:
| 检查项 | 说明 |
|---|---|
| 文件名全英文且无空格 | 零件、装配体、坐标系命名都算上 |
| 文档单位明确 | 建议导出前将单位切到米制千克秒 |
| base坐标系存在且Z轴向上 | 底座安装面或底面中心点 |
| 材料已指定 | 结构件用铝合金,衬套用钢 |
| 旋转轴是圆柱面或明确轴线 | 不用宽度配合、路径配合 |
| 导出目录路径无中文 | 插件和ROS都怕中文路径 |
6.2 高频报错与定位方法
真正导出到运行环节,报错就那么几类。我列一个排查表,每个问题都附了定位方向。
| 报错或现象 | 大概率原因 | 处理办法 |
|---|---|---|
| RViz里模型是一个小点 | 单位没换算,模型尺寸小了1000倍 | 检查mesh scale或重新导出STL |
| RViz里模型巨大 | 单位没换算,模型尺寸大了1000倍 | 同上,或URDF里加scale=0.001 |
| 模型部分link缺失 | mesh路径不对,或者文件名大小写不匹配 | 检查package://路径和大小写 |
| 关节转动方向相反 | axis方向取反 | 改axis的正负号 |
| Gazebo里机械臂抖动 | 惯性参数数量级错误,或缺少kd阻尼 | 核对惯性单位,设置kp/kd |
| 底座打滑 | 摩擦系数不足 | 设置mu1/mu2不低于1.0 |
| MoveIt找不到IK解 | 关节limit过小,或者末端link命名不一致 | 检查URDF的joint limit和SRDF末端 |
| 插件无法识别某关节轴 | 装配配合太复杂 | 换成同轴心+重合基准面,或者手工补 |
6.3 实在不行,手工兜底怎么写
如果插件因为版本、许可、模型复杂度等因素一直用不了,手工方案也能救急。流程很简单:SolidWorks里把每个零件单独另存为STL,注意单位换算,然后在文本编辑器里写URDF。
手工写URDF的关键是坐标变换计算。建议先给每个link想好坐标系,base_link写在底座底面上,其他link坐标系都放在关节轴线上。joint的origin里xyz和rpy决定了子link原点相对于父link原点的位姿,这个东西算错很难排查。我的土办法是先全部填零,然后在RViz里一个一个加关节调位置,虽然多花点时间,但至少逻辑清楚。
手工方案最大的好处是自由度大。遇到插件导出一堆用不上的参数,或者坐标系设置不对,直接删掉重来比在SW里反复调试插件快多了。
我自己的习惯是两手准备:先用插件快速出一版,再手工校正关键参数。UR3这个东西的难点从来不在软件操作,而在你对运动学树和单位体系的理解。等到你在RViz里拖动滑块,看着整套机械臂按照预期方向顺畅转动,再回头看这些折腾,就是值得的。