SW 三维模型转 URDF 完整指南:从 SolidWorks 到 CoppeliaSim 的运动学建模
2026/9/16 12:59:16 网站建设 项目流程

简介:针对UR5六轴工业机器人在仿真环境中集成需求而整理的URDF模型转换资源包,适合机器人开发者、ROS学习者以及使用Matlab或Gazebo开展运动规划、动力学验证的工程师。包内提供UR5完整URDF描述文件,并且包含base_link与Link1至Link6等核心部件的STL三维网格模型,可直接用于可视化与碰撞检测;同时附带launch启动文件和YAML关节配置,便于快速加载至ROS或Gazebo环境,省去手动编写XML的繁琐过程。资源共13个文件,以STL几何模型为主,辅以URDF、launch、yaml等配置说明,压缩包仅5.5MB,轻量且结构清晰。当前已有549人学习浏览,适合需要将SolidWorks等CAD模型规范化并转换为可仿真URDF的入门及进阶用户。通过分析模型文件与配置之间的对应关系,还可加深对机器人连杆坐标系、关节类型及运动范围定义的理解。

1. 为什么手里有 UR5 的三维模型不等于有能用的 URDF

很多工程师拿到 ur5_sw2urdf.zip 这类资源包,解压后看到 SolidWorks 的 SLDPRT 和 SLDASM 文件,下意识认为把这些模型原封不动放进 ROS 或 CoppeliaSim 就能跑通。真到运行阶段才会发现,URDF 不只是一堆网格文件的集合,而是一棵用<link><joint>严格写出来的运动学树。UR5 作为六轴协作臂,每个关节旋转轴的方向、限位、父子关系在 SolidWorks 的配合关系里都有,却不会自动变成 URDF 里的<joint>标签。直接把 STL 文件改名为 .urdf 的话,加载器只会画出一堆没有结构的碎片。下面从一个常见的 ur5_sw2urdf 包出发,讲清楚把 SolidWorks 三维模型转化为可仿真 URDF 的完整路径,包括坐标映射、单位换算、参数修正,以及在 CoppeliaSim 中验证 UR5 运动学建模是否正确的具体方法。

2. URDF 的树形结构与 SolidWorks 装配体的坐标映射

2.1 先把 UR5 的 link 和 joint 在脑子里拆一遍

UR5 一共有 6 个旋转关节,从底座往上依次是 shoulder_pan、shoulder_lift、elbow、wrist_1、wrist_2、wrist_3,对应 7 个 link,末端一般是 tool0。URDF 里每个 joint 必须声明 parent link 和 child link,然后用<origin>描述关节坐标系在父坐标系中的偏移,用<axis>描述旋转轴。SolidWorks 装配体中的配合并不直接等价于 URDF 的 joint。比如肩关节在 SW 里可能是“两个圆柱面同心”加“两个平面平行”共同限制出来的,而 URDF 只需要一个 revolute joint 加一个轴向量。

转换之前我会先把 SW 的基准面和 UR5 底座安装面对齐,否则导出的每个<origin>都会带一个 90 度的 rpy 偏移,后续做运动学建模时很容易绕晕。还有一个容易漏掉的地方:UR5 的 tool0 坐标系原点并不在法兰中心,而是在法兰中心再往前一段距离。如果你在 SW 模型里直接取法兰圆心作为末端坐标,最后算出来的 TCP 位置会固定偏几厘米,在抓取任务里这个误差非常致命。

2.2 毫米到米的单位转换和网格导出

SolidWorks 默认使用毫米,URDF 和 ROS 统一使用米。如果在手工拼 URDF 时漏掉单位换算,模型在 RViz 里会突然放大 1000 倍。使用 SolidWorks URDF Exporter 导出时,插件内部会负责把 mm 转成 m,但如果你拿到的是别人从 SW 导出的 STL,再自己组装 URDF,就必须在<mesh>标签里加scale="0.001 0.001 0.001"

我一般用下面这段 Python 快速判断一个 STL 文件的当前尺寸单位:

# 读取 STL 的包围盒最大值,判断当前单位是 mm 还是 m import trimesh mesh = trimesh.load('base_link.STL') bounds_max = mesh.bounds.max() print('max coordinate:', bounds_max) # UR5 高度在 1m 量级,如果最大坐标是 1400 左右说明是 mm scale = 0.001 if bounds_max > 10.0 else 1.0 print('URDF mesh scale should be', scale)

代码先加载 STL 文件,然后输出模型坐标的最大值。UR5 的 base_link 在最下方,但整个机器人高度大约 1.4 米,所以如果这个值是 1400 或者 1900 这种量级,就说明文件单位还是毫米。scale参数在 URDF 中会同时作用于视觉网格和碰撞网格,所以只要这一处设对,很多模型瞬间飞出去的报错都能解决。

网格导出的格式选择也很重要,下面是三种常用格式的对比:

网格格式是否包含颜色是否携带单位推荐用途
STL无单位,通常为 mm碰撞检测模型
DAE有单位信息UR5 外观展示、CoppeliaSim 导入
OBJ可选无统一标准中间格式,需二次处理

如果你只是想先跑通运动学,STL 足够;如果你希望模型在 CoppeliaSim 里看起来像真实的 UR5 金属质感,DAE 会让工作量大为减少。DAE 文件里的单位信息有时候会被软件忽略,所以即使导出了 DAE,仍然建议检查一下<mesh>scale字段。

2.3 从配合关系到 joint 类型的映射规则

SW 里的配合类型和 URDF 关节类型并不是一一对应的。把装配关系映射出来时,通用规则是:两个圆柱面同心配合且允许相对转动,对应 revolute joint;两个面对齐并允许一条直线滑动,对应 prismatic joint;固定配合对应 fixed joint。UR5 全身上下只有旋转关节,相对简单,但难点在于旋转轴向量从哪里取。

我一般会在 SW 里临时给旋转配合添加一个马达,让零件实际转起来,然后观察它在全局坐标系中的转动方向。比如 shoulder_lift 的旋转轴通常平行于机器人底座的 Y 轴,但有的 SW 模型因为装配基准面定义不同,实际转轴会落在 XZ 平面里。把这个方向向量记录下来,原样填到<axis xyz="..."/>里。这个步骤不能省,因为 URDF 的<axis>向量一旦方向反了,ROS 里的 MoveIt 规划出来的关节方向和真实机器人完全相反,轻则仿真乱撞,重则直接反扭矩保护。

3. 用 SolidWorks URDF Exporter 完成 sw 转 urdf 并修正生成结果

3.1 安装插件和导出前的模型整理

SolidWorks 没有内置的 URDF 导出功能,常见做法是安装 ros-industrial 的 solidworks_urdf_exporter 插件。插件装好后,右键装配体根节点,选 Export to URDF 就能打开转换界面。这里有个很关键的准备工作:先把 SW 装配体的全局坐标系移动到 UR5 底座安装面的中心,同时让 Z 轴朝上、X 轴朝机器人正前方。

如果没有重新定位坐标系,导出的 URDF 整体坐标会带着一个很大的平移偏置,在 CoppeliaSim 里表现为模型不在世界原点附近。插件界面里会列出所有 link 和 joint,你需要在左侧面板拖拽出正确的父子层级。很多人在这里直接沿用 SW FeatureManager 的顺序,结果 base_link 被放在树中间,URDF 解析时出现环状依赖。正确的做法是保证 base_link 位于根节点,然后 shoulder_link 挂在 base_link 下,之后的链路依次展开。

3.2 导出后的 check_urdf 与单位向量检查

导出完成后,在 ROS 环境里先跑两个命令做体检:

# 检查 URDF 是否合法,并打印运动学树 check_urdf ur5.urdf # 生成关节依赖图,辅助检查父子层级 urdf_to_graphiz ur5.urdf

check_urdf会输出每个 joint 连接的父子 link,如果发现某个 joint 指向不存在的 link,或者<origin>的 rpy 超过正常范围,它会直接在终端报错。urdf_to_graphiz生成一张 SVG 依赖图,可以一眼看出是否有循环或者孤立节点。但这两个工具都不检查 axis 向量是否归一化。

不带 ROS 的环境下,可以用 urdf_parser_py 做一次更细的检查:

# 检查轴向量是否为单位向量 from urdf_parser_py.urdf import URDF robot = URDF.from_xml_file('ur5.urdf') for joint in robot.joints: if joint.axis is None: continue norm = (joint.axis.x ** 2 + joint.axis.y ** 2 + joint.axis.z ** 2) ** 0.5 if abs(norm - 1.0) > 1e-6: print(f'joint {joint.name} axis not normalized: {joint.axis}')

这段脚本会逐个读取 joint 的 axis 向量,计算模长。URDF 规范要求 axis 必须是单位向量,但 SolidWorks 导出时经常会把某个特征边向量直接写上,长度并不是 1。这个隐患在查不出明显错误,一旦做速度级运动学计算,关节角速度就会出现固定的比例偏差,而且每个关节偏差不一样。

3.3 关节限位核对表

UR5 的六个关节范围都很大,肩关节、肘关节和腕关节几乎都能旋转超过一整圈。插件导出时有时会把限位写成默认的-3.143.14,有些版本甚至不写<limit>,导致 MoveIt 在采样时直接崩。手动整理时可以用一张表把每个关节的父 link、子 link、轴方向和限位列出来,方便逐项核对:

关节名parent linkchild linkaxis (x y z)最小值(rad)最大值(rad)
shoulder_pan_jointbase_linkshoulder_link0 0 1-6.2836.283
shoulder_lift_jointshoulder_linkupper_arm_link0 1 0-6.2836.283
elbow_jointupper_arm_linkforearm_link0 1 0-6.2836.283
wrist_1_jointforearm_linkwrist_1_link0 1 0-6.2836.283
wrist_2_jointwrist_1_linkwrist_2_link0 0 1-6.2836.283
wrist_3_jointwrist_2_linkwrist_3_link0 1 0-6.2836.283

表格中的数值是按 ur_description 包中最常见的写法给出的,不同资源包里的命名可能有差异,但检查顺序是一样的。除了限位,还要确认<limit effort="150" velocity="3.14"/>这类字段没有留空,否则一些规划库会把 effort 当作 0 处理,导致所有关节都不可驱动。

注意:UR5 的真实关节范围并非所有版本都完全一致,最终应以官方手册为准。URDF 的职责是让你在相同物理输入下得到一致的输出,而不是替手册背书。

4. 在 CoppeliaSim 中正确导入 UR5 的 URDF 并调整惯性参数

4.1 从 SW 质量属性到 URDF 惯性张量的单位换算

SolidWorks 的质量属性窗口默认使用 kg·mm² 作为惯性张量单位,而 URDF 要求 kg·m²,两者差 10⁶ 倍。很多人从 SW 复制惯性数据后直接填进<inertial>块,仿真一开始模型就开始剧烈抖动,这是最常见的错误之一。

正确的做法是在 SolidWorks 质量属性窗口里把单位改成 kg·m²,或者把 Ixx、Iyy、Izz 同时除以 1e6。另一个经常被忽略的点是惯性坐标系的原点。URDF 的<inertial>里面的<origin>表示惯性主轴坐标系相对于 link 坐标系的偏移,如果你直接把 SW 的质量中心坐标写进去,必须注意这个坐标是相对哪个基准面的。UR5 的每个 link 重心位置都不在关节轴上,写错之后重力会对关节产生一个很大的附加力矩。

常见单位换算关系如下:

物理量SolidWorks 默认单位URDF 要求单位换算系数
长度mmm0.001
质量kgkg1
惯性张量kg·mm²kg·m²1e-6
角度degradπ/180

一个更工程化的做法是给 base_link 也写一个很小的质量,比如 0.1kg,而不是让 base_link 的<inertial>被省略。CoppeliaSim 在动态仿真时如果遇到质量为零的刚体,会把它当成固定约束来处理,有些时候这反而是你想要的,但如果你只是想验证运动学建模,固定底座会让后续的对比更简单。

4.2 CoppeliaSim 的 URDF 导入选项与 joint 设置

新版 CoppeliaSim 支持直接从菜单导入 URDF:File -> Import -> URDF。导入时它会自动把每个 link 转成一个 shape,每个 joint 转成一个 revolute joint 对象。但自动转换后的 joint 默认可能处于 kinematic mode,或者没有正确设置 motor。对于纯运动学验证,我建议在导入之后把所有 joint 设为 passive 模式,然后用鼠标拖动各个关节,观察模型是否按照预期的自由度运动。

如果导入后发现 link 直接飞开,第一件事不是去调仿真参数,而是先检查 URDF 里的坐标系是否连续。在 CoppeliaSim 中执行一段 Lua 脚本可以快速读取关节角度:

-- 读取两个关键关节的角度,确认 joint 是否被正确解析 local joint_handles = { sim.getObjectHandle('shoulder_pan_joint'), sim.getObjectHandle('shoulder_lift_joint') } for i, h in ipairs(joint_handles) do local pos = sim.getJointPosition(h) print(string.format('joint %s current pos: %.4f rad', sim.getObjectName(h), pos)) end

脚本调用sim.getJointPosition读取每个 joint 在当前状态下的关节角。注意 CoppeliaSim 的 API 对 joint 名称大小写敏感,如果你的 URDF 里 joint 名和这里不一致,需要先改成实际名称。这段脚本的价值在于验证 URDF 导入后 joint 和 link 是否正确配对,如果 CoppeliaSim 解析错了 joint,getObjectHandle会直接返回错误,而不是给你一个看似正常的 0 值。

4.3 碰撞网格简化建议

UR5 的 SolidWorks 模型细节很多,尤其是底座散热孔、腕关节的线缆出口这种地方,STL 面数可能高达几万。URDF 要求同时提供<visual><collision>,如果<collision>没有单独指定网格,CoppeliaSim 会复用视觉网格做碰撞检测,配合求解速度会掉到帧率个位数。

对于纯运动学建模,碰撞网格可以简化成球、圆柱和盒子的组合。以 base_link 为例,用圆柱体替代不规则底座:

<link name="base_link"> <visual> <geometry> <mesh filename="package://ur5_description/meshes/base_link.STL" scale="0.001 0.001 0.001"/> </geometry> <origin xyz="0 0 0" rpy="0 0 0"/> </visual> <collision> <geometry> <cylinder radius="0.08" length="0.12"/> </geometry> <origin xyz="0 0 0.06" rpy="0 0 0"/> </collision> </link>

这段 XML 里的radiuslength只是示例,真正的 UR5 底座底面有定位销孔,但在运动学仿真中完全不需要。关键点是<collision><visual>使用完全不同的几何表达,CoppeliaSim 在加载时会把圆柱体转成一个原生 shape,而不是一个高精度 mesh。这样仿真速度能提升一个数量级,而且在做避障规划时,碰撞检测的计算量会显著降低。

5. 用 PyBullet 和 CoppeliaSim 双重验证 UR5 运动学建模

5.1 给定一组非对称关节角,对比末端坐标

URDF 转换完成后,最有效的验证方式不是盯着模型发呆,而是给机器人设置一组非对称关节角,用两个独立环境计算末端坐标,再对比结果。PyBullet 是一个轻量的物理引擎,加载 URDF 不用启动 ROS,非常适合这件事。下面这段代码给 UR5 设置一组确定的角度,然后读取 tool0 的位置:

import pybullet as p p.connect(p.GUI) robot = p.loadURDF('ur5.urdf', useFixedBase=True) # 设置一组非对称关节角,便于暴露轴方向错误 joint_angles = [0.0, -1.5, 1.2, -0.6, 0.8, 0.3] for i, angle in enumerate(joint_angles): p.resetJointState(robot, i, angle) # 让物理引擎稳定一步后再读取状态 for _ in range(10): p.stepSimulation() # 获取最后一个 link 的位姿,通常对应 tool0 link_state = p.getLinkState(robot, p.getNumJoints(robot) - 1) print('tool0 position:', link_state[0]) print('tool0 orientation:', link_state[1])

resetJointState把每个关节的角度直接写到目标值,然后stepSimulation让内部刚体状态同步一次。这里选择-1.51.2这种非对称角度,是为了让多个关节同时偏转,任何一个轴方向写反都会在末端坐标上放大出明显差异。

5.2 坐标对不上时优先检查的三个字段

如果 PyBullet 计算的末端位置和 CoppeliaSim 中同样的角度对不上,不要急着调 PID,按顺序检查三个字段。

第一个是<origin>里的rpy,URDF 使用固定轴欧拉角,顺序是 roll、pitch、yaw,而 SolidWorks 导出插件有时会把旋转顺序变成 pitch、yaw、roll,造成若干度的偏差。

第二个是<axis>的向量方向,特别是 shoulder_lift 和 elbow 这两个关节,它们轴向量写成0 1 0还是0 -1 0,直接决定整个机械臂在仿真中是否会反向折叠。

第三个是<mesh>scale。有些 STL 文件在导出时已经被预缩放为米,你又补了一个0.001,模型会变得看不见;反过来,该加没加,模型会膨胀到超出视野。检查方法很简单:在 CoppeliaSim 中用测量工具量一下 base_link 的高度,应该和你手里真实 UR5 的底座高度一致。

把这三个字段全部核过一遍后,再回到 PyBullet 里运行上面的脚本,你会看到两个环境给出的 tool0 坐标差异缩小到毫米级别。到这一步,sw 转 urdf 的工作才算真正完成。

本文还有配套的精品资源,点击获取

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

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

立即咨询