找回密码
 立即注册
首页 业界区 业界 ROS2之URDF建模

ROS2之URDF建模

肿抢 2025-12-22 23:30:06
ROS是机器人操作系统,当然要给机器人使用啦,不过在使用之前,还得让ROS认识下我们使用的机器人,如何把一个机器人介绍给ROS呢?
为此,ROS专门提供了一种机器人建模方法——URDF,用来描述机器人外观、性能等各方面属性。
一、URDF语法

1.1 机器人的组成

建模描述机器人的过程中,我们自己需要先熟悉机器人的组成和参数,比如机器人一般是由硬件结构、驱动系统、传感器系统、控制系统四大部分组成,市面上一些常见的机器人,无论是移动机器人还是机械臂,我们都可以按照这四大组成部分进行分解。
1.png
其中:

  • 硬件结构就是底盘、外壳、电机等实打实可以看到的设备;
  • 驱动系统就是可以驱使这些设备正常使用的装置,比如电机的驱动器,电源管理系统等;
  • 传感系统包括电机上的编码器、板载的IMU、安装的摄像头、雷达等等,便于机器人感知自己的状态和外部的环境;
  • 控制系统就是我们开发过程的主要载体了,一般是树莓派、电脑等计算平台,以及里边的操作系统和应用软件。
机器人建模的过程,其实就是按照类似的思路,通过建模语言,把机器人每一个部分都描述清楚,再组合起来的过程。
1.2 什么是URDF

URDF(Unified Robot Description Format,统一机器人描述格式)是一种XML格式的文件,用于从物理和逻辑上描述一个机器人模型。
你可以把它理解为机器人的数字说明书或三维装配图,它告诉计算机:

  • 机器人由哪些零件(连杆、关节)组成;
  • 这些零件长什么样(形状、尺寸、颜色);
  • 零件之间如何连接(位置、旋转、运动类型);
  • 零件的物理属性(质量、惯性);
1.3 URDF组成

URDF主要描述两大核心元素:

  • 连杆(Link):代表机器人的刚性部件,如机械臂的每一节臂杆、底盘、轮子、传感器支架等,包括:

    • 视觉属性:形状(立方体、圆柱体、网格模型)、尺寸、颜色、纹理;
    • 碰撞属性:用于物理仿真的简化几何形状;
    • 惯性属性:质量、转动惯量(对仿真至关重要)。

  • 关节(Joint):定义连杆之间的连接方式和运动关系,主要类型:

    • 固定关节(fixed):完全固定连接;
    • 旋转关节(revolute):绕单轴旋转,有角度限制(如机械臂关节);
    • 连续关节(continuous):无限旋转(如轮子);
    • 平移关节(prismatic):线性滑动;
    • 平面关节(planar):在平面内运动;
    • 浮动关节(floating):完全自由(6自由度)。

机器人描述由一组连杆元素和一组将连杆连接起来的关节元素组成;
2.png
因此,典型的机器人描述大致如下所示:
  1. <?xml version="1.0"?>
  2. <?xml-model href="https://raw.githubusercontent.com/ros/urdfdom/master/xsd/urdf.xsd" ?>
  3. <robot name="pr2" xmlns="http://www.ros.org">
  4.   <link> ... </link>
  5.   <link> ... </link>
  6.   <link> ... </link>
  7.   <joint>  ....  </joint>
  8.   <joint>  ....  </joint>
  9.   <joint>  ....  </joint>
  10. </robot>
复制代码
可以看到,URDF格式的根元素是一个  元素。
1.3.1 link元素

link元素描述了一个具有惯性、视觉特征和碰撞属性的刚体。以下是一个link元素的示例:
  1. <link name="my_link">
  2.   <inertial>
  3.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  4.     <mass value="1"/>
  5.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  6.   </inertial>
  7.   <visual>
  8.     <origin xyz="0 0 0" rpy="0 0 0" />
  9.     <geometry>
  10.       <box size="1 1 1" />
  11.     </geometry>
  12.     <material name="Cyan">
  13.       <color rgba="0 1.0 1.0 1.0"/>
  14.     </material>
  15.   </visual>
  16.   <collision>
  17.     <origin xyz="0 0 0" rpy="0 0 0"/>
  18.     <geometry>
  19.       <cylinder radius="1" length="0.5"/>
  20.     </geometry>
  21.   </collision>
  22. </link>
复制代码
3.png
link元素有一个属性,即name(必选):用来描述连杆本身的名称.。此外,link包含若干部元素,接下来我们一一介绍。
1.3.1.1  惯性属性inertial

inertial(可选):用于描述连杆的质量、其质心的位置以及其中心惯性属性。
其下可以包含如下元素:

  • origin(可选):此位姿(平移、旋转)描述了连杆质心坐标系C相对于连杆坐标系L的位置和方向。

    • xyz (可选):表示从Lo(连杆坐标系原点)到Co(连杆质心)的位置向量,形式为 x L̂x + y L̂y + z L̂z,其中 L̂x、L̂y、L̂z 是连杆坐标系L的正交单位向量;
    • rpy(可选):表示C的单位向量Ĉx、Ĉy、Ĉz相对于连杆坐标系L的方向,以欧拉旋转(横滚roll、俯仰pitch、偏航yaw)序列表示,单位为弧度。注意:Ĉx、Ĉy、Ĉz不需要与连杆的惯性主轴对齐;

  • mass:连杆的质量由该元素的value属性表示;
  • inertia:此连杆关于Co(连杆质心)的惯性矩ixx、iyy、izz和惯性积 ixy、ixz、iyz,这些值对应于固定在质心坐标系C中的单位向量Ĉx、Ĉy、Ĉz。注意:Ĉx、Ĉy、Ĉz相对于L̂x、L̂y、L̂z 的方向由  标签中的rpy值指定。
1.3.1.2 视觉属性visual

visual(可选):连杆的视觉属性,此元素指定了用于可视化目的的对象形状(长方体、圆柱体等)。
注意:同一个连杆可以存在多个  标签实例。它们定义的几何体的并集形成了该连杆的视觉表示。
其下可以包含如下元素:

  • origin (可选):视觉元素相对于连杆坐标系的参考坐标系;

    • xyz (可选):分别是x、y、z方向上的平移;
    • py (可选):表示固定轴的横滚、俯仰和偏航角度,单位为弧度;

  • geometry(必选):表示几何形状,可以是以下之一:



      • size属性包含长方体的三个边长,长方体的原点位于其中心;



      • 指定半径和长度。圆柱体的原点位于其中心;



      • 指定半径。球体的原点位于其中心;



      • 由文件名指定的三角网格元素,以及一个可选的缩放比例,用于缩放网格的轴对齐边界框。任何几何格式都可以接受,但具体应用程序的兼容性取决于实现。对于最佳纹理和颜色支持,推荐的格式是 Collada .dae文件。引用同一模型的机器之间不会传输网格文件。它必须是本地文件。在文件名前加上 package:/// 可以使网格文件的路径相对于包 。


  • material(可选):视觉元素的材质,其name属性可以用于指定材质的名称;

    • (可选)

      • rgba由一组四个数字(代表红/绿/蓝/透明度alpha)指定的材质颜色,每个数字的范围为 [0,1];

    • (可选)

      • 材质的纹理由文件名指定。


1.3.1.3 碰撞属性collision

collision用于描述碰撞参数,里边的内容似乎和一样,也有和,看似相同,其实区别还是比较大的;

  • origin (可选):碰撞元素相对于连杆坐标系的参考坐标系;

    • xyz (可选):分别是x、y、z方向上的平移;
    • py (可选):表示固定轴的横滚、俯仰和偏航角度,单位为弧度;

  • geometry:请参见上述视觉元素中的几何描述。
1.3.2 joint元素

joint元素描述了关节的运动学和动力学特性,并指定了关节的安全限制。
以下是一个 joint 元素的示例:
  1. <joint name="my_joint" type="floating">
  2.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  3.    <parent link="link1"/>
  4.    <child link="link2"/>
  5.    <calibration rising="0.0"/>
  6.    <dynamics damping="0.0" friction="0.0"/>
  7.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  8.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  9. </joint>
复制代码
下面图中,蓝色关节表示出一个运动的轴,蓝色关节是可以围绕蓝色的轴旋转的,也就是child这个link是可以围绕joint上下旋转。
joint连接两个link,需要分一个主次关系,主关节是parent link,子关节是child link, 在xml形式的描述中这个两个link是必须存在的。
4.png
joint元素有两个属性:

  • name(必须):指定关节的唯一名称;
  • type(必须):指定关节的类型,类型可以是以下之一;

    • revolute :旋转关节,和continuous类型的区别在于不能无限旋转,而是带有角度限制,比如机械臂的两个连杆,就属于这种运动;
    • continuous:旋转关节,可以围绕单轴无限旋转;比如小车的轮子,就属于这种类型;
    • prismatic:滑动关节,可以沿某一个轴平移,也带有位置的极限,一般直线电机就是这种运动方式;
    • fixed:固定关节,是唯一一种不允许运动的关节,不过使用还是比较频繁的,比如相机这个连杆,安装在机器人上,相对位置是不会变化的,此时使用的连接方式就是fixed;
    • floating:浮动关节,允许进行平移、旋转运动;
    • planar :平面关节,允许在平面正交方向上平移或者旋转;

此外,joint包含若干部元素,接下来我们挑选部分介绍介绍。
1.3.2.1 origin

origin(可选):表示从父连杆到子连杆的变换,元素属性有:

  • xyz (可选):表示x、y、z 偏移量,所有位置均以米为单位指定;
  • rpy (可选):表示绕固定轴的旋转:先绕x轴横滚(roll),然后绕y轴俯仰(pitch),最后绕z轴偏航(yaw),所有角度均以弧度为单位指定。
1.3.2.2 parent

parent描述父连杆名称,元素属性有:

  • link:在机器人树结构中作为此连杆父连杆的连杆名称。
1.3.2.3 child

child描述子连杆名称,元素属性有:

  • link:作为子连杆的连杆名称。
1.3.2.4 calibration

关节的参考位置,用来校准关节的绝对位置。
1.3.2.5 dynamics  

描述关节的物理属性,例如阻尼值、物理静摩擦力等,经常在动力学仿真中用到。
1.3.2.6 limit   

描述运动的一些极限值,包括关节运动的上下限位置、速度限制、力矩限制等。
1.3.2.7 mimic   

描述该关节与已有关节的关系。
1.3.2.8 safety_controller  

描述安全控制器参数。保护机器人关节的运动。
二、URDF案例

创建my_learning_urdf的Python版本的功能包;
  1. pi@NanoPC-T6:~/dev_ws$ cd src
  2. pi@NanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_urdf
复制代码
在包中创建如下文件夹:

  • urdf:存放机器人模型的URDF或xacro文件;
  • meshes:放置URDF中引用的模型渲染文件;
  • launch:保存相关启动文件;
  • rviz:保存rviz的配置文件。
我们需要修改setup.py文件,添加配置文件:
  1. import os
  2. from glob import glob
  3.     ...
  4.     data_files=[
  5.         ('share/ament_index/resource_index/packages',
  6.             ['resource/' + package_name]),
  7.         ('share/' + package_name, ['package.xml']),
  8.         (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
  9.         (os.path.join('share', package_name, 'urdf'), glob(os.path.join('urdf', '*.*'))),
  10.         (os.path.join('share', package_name, 'urdf/sensors'), glob(os.path.join('urdf/sensors', '*.*'))),
  11.         (os.path.join('share', package_name, 'meshes'), glob(os.path.join('meshes', '*.*'))),
  12.         (os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.rviz'))),
  13.     ],
  14.     ...
复制代码
2.1 模型文件

在urdf下新建文件mbot_base.urdf;
  1. <link name="my_link">
  2.   <inertial>
  3.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  4.     <mass value="1"/>
  5.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  6.   </inertial>
  7.   <visual>
  8.     <origin xyz="0 0 0" rpy="0 0 0" />
  9.     <geometry>
  10.       <box size="1 1 1" />
  11.     </geometry>
  12.     <material name="Cyan">
  13.       <color rgba="0 1.0 1.0 1.0"/>
  14.     </material>
  15.   </visual>
  16.   <collision>
  17.     <origin xyz="0 0 0" rpy="0 0 0"/>
  18.     <geometry>
  19.       <cylinder radius="1" length="0.5"/>
  20.     </geometry>
  21.   </collision>
  22. </link><link name="my_link">
  23.   <inertial>
  24.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  25.     <mass value="1"/>
  26.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  27.   </inertial>
  28.   <visual>
  29.     <origin xyz="0 0 0" rpy="0 0 0" />
  30.     <geometry>
  31.       <box size="1 1 1" />
  32.     </geometry>
  33.     <material name="Cyan">
  34.       <color rgba="0 1.0 1.0 1.0"/>
  35.     </material>
  36.   </visual>
  37.   <collision>
  38.     <origin xyz="0 0 0" rpy="0 0 0"/>
  39.     <geometry>
  40.       <cylinder radius="1" length="0.5"/>
  41.     </geometry>
  42.   </collision>
  43. </link><link name="my_link">
  44.   <inertial>
  45.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  46.     <mass value="1"/>
  47.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  48.   </inertial>
  49.   <visual>
  50.     <origin xyz="0 0 0" rpy="0 0 0" />
  51.     <geometry>
  52.       <box size="1 1 1" />
  53.     </geometry>
  54.     <material name="Cyan">
  55.       <color rgba="0 1.0 1.0 1.0"/>
  56.     </material>
  57.   </visual>
  58.   <collision>
  59.     <origin xyz="0 0 0" rpy="0 0 0"/>
  60.     <geometry>
  61.       <cylinder radius="1" length="0.5"/>
  62.     </geometry>
  63.   </collision>
  64. </link><link name="my_link">
  65.   <inertial>
  66.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  67.     <mass value="1"/>
  68.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  69.   </inertial>
  70.   <visual>
  71.     <origin xyz="0 0 0" rpy="0 0 0" />
  72.     <geometry>
  73.       <box size="1 1 1" />
  74.     </geometry>
  75.     <material name="Cyan">
  76.       <color rgba="0 1.0 1.0 1.0"/>
  77.     </material>
  78.   </visual>
  79.   <collision>
  80.     <origin xyz="0 0 0" rpy="0 0 0"/>
  81.     <geometry>
  82.       <cylinder radius="1" length="0.5"/>
  83.     </geometry>
  84.   </collision>
  85. </link><link name="my_link">
  86.   <inertial>
  87.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  88.     <mass value="1"/>
  89.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  90.   </inertial>
  91.   <visual>
  92.     <origin xyz="0 0 0" rpy="0 0 0" />
  93.     <geometry>
  94.       <box size="1 1 1" />
  95.     </geometry>
  96.     <material name="Cyan">
  97.       <color rgba="0 1.0 1.0 1.0"/>
  98.     </material>
  99.   </visual>
  100.   <collision>
  101.     <origin xyz="0 0 0" rpy="0 0 0"/>
  102.     <geometry>
  103.       <cylinder radius="1" length="0.5"/>
  104.     </geometry>
  105.   </collision>
  106. </link><link name="my_link">
  107.   <inertial>
  108.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  109.     <mass value="1"/>
  110.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  111.   </inertial>
  112.   <visual>
  113.     <origin xyz="0 0 0" rpy="0 0 0" />
  114.     <geometry>
  115.       <box size="1 1 1" />
  116.     </geometry>
  117.     <material name="Cyan">
  118.       <color rgba="0 1.0 1.0 1.0"/>
  119.     </material>
  120.   </visual>
  121.   <collision>
  122.     <origin xyz="0 0 0" rpy="0 0 0"/>
  123.     <geometry>
  124.       <cylinder radius="1" length="0.5"/>
  125.     </geometry>
  126.   </collision>
  127. </link><link name="my_link">
  128.   <inertial>
  129.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  130.     <mass value="1"/>
  131.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  132.   </inertial>
  133.   <visual>
  134.     <origin xyz="0 0 0" rpy="0 0 0" />
  135.     <geometry>
  136.       <box size="1 1 1" />
  137.     </geometry>
  138.     <material name="Cyan">
  139.       <color rgba="0 1.0 1.0 1.0"/>
  140.     </material>
  141.   </visual>
  142.   <collision>
  143.     <origin xyz="0 0 0" rpy="0 0 0"/>
  144.     <geometry>
  145.       <cylinder radius="1" length="0.5"/>
  146.     </geometry>
  147.   </collision>
  148. </link><link name="my_link">
  149.   <inertial>
  150.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  151.     <mass value="1"/>
  152.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  153.   </inertial>
  154.   <visual>
  155.     <origin xyz="0 0 0" rpy="0 0 0" />
  156.     <geometry>
  157.       <box size="1 1 1" />
  158.     </geometry>
  159.     <material name="Cyan">
  160.       <color rgba="0 1.0 1.0 1.0"/>
  161.     </material>
  162.   </visual>
  163.   <collision>
  164.     <origin xyz="0 0 0" rpy="0 0 0"/>
  165.     <geometry>
  166.       <cylinder radius="1" length="0.5"/>
  167.     </geometry>
  168.   </collision>
  169. </link><link name="my_link">
  170.   <inertial>
  171.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  172.     <mass value="1"/>
  173.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  174.   </inertial>
  175.   <visual>
  176.     <origin xyz="0 0 0" rpy="0 0 0" />
  177.     <geometry>
  178.       <box size="1 1 1" />
  179.     </geometry>
  180.     <material name="Cyan">
  181.       <color rgba="0 1.0 1.0 1.0"/>
  182.     </material>
  183.   </visual>
  184.   <collision>
  185.     <origin xyz="0 0 0" rpy="0 0 0"/>
  186.     <geometry>
  187.       <cylinder radius="1" length="0.5"/>
  188.     </geometry>
  189.   </collision>
  190. </link><link name="my_link">
  191.   <inertial>
  192.     <origin xyz="0 0 0.5" rpy="0 0 0"/>
  193.     <mass value="1"/>
  194.     <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
  195.   </inertial>
  196.   <visual>
  197.     <origin xyz="0 0 0" rpy="0 0 0" />
  198.     <geometry>
  199.       <box size="1 1 1" />
  200.     </geometry>
  201.     <material name="Cyan">
  202.       <color rgba="0 1.0 1.0 1.0"/>
  203.     </material>
  204.   </visual>
  205.   <collision>
  206.     <origin xyz="0 0 0" rpy="0 0 0"/>
  207.     <geometry>
  208.       <cylinder radius="1" length="0.5"/>
  209.     </geometry>
  210.   </collision>
  211. </link>        
复制代码
这将会创建一个两轮差分驱动机器人的URDF模型,包含若干个部分。
2.1.1 1个主体base_link

圆柱体(直径0.4米,高0.16米),橙黄色,机器人中心,坐标系原点。
2.1.2 2个驱动轮(左右轮)

分别为left_wheel_link、right_wheel_link:

  • left_wheel_link:

    • 圆柱体(半径0.06米,厚度0.025米);
    • 在基座坐标系中 (0, 0.19, -0.05);
    • 关节类型:continuous(连续旋转关节,无限旋转);
    • 旋转轴:绕Y轴 (0, 1, 0);
    • 视觉旋转:rpy="1.5707 0 0" 将圆柱旋转90度,使其直立(假设原始圆柱是平放的);

  • right_wheel_link:与左轮对称布置,Y坐标为负;
2.1.3 2个万向轮(前后脚轮,用于支撑)

分别为front_caster_link、back_caster_link:

  • front_caster_link:

    • 形状:小球体(半径0.015米),模拟万向轮;
    • 在基座坐标系中前方 (0.18, 0, -0.095);
    • 颜色:黑色;

  • back_caster_link:与前万向轮对称布置,X坐标为负(-0.18)。
2.2 launch文件

在launch文件夹下创建display.launch.py文件;
  1. from ament_index_python.packages import get_package_share_pathfrom launch import LaunchDescriptionfrom launch.actions import DeclareLaunchArgumentfrom launch.conditions import IfCondition, UnlessConditionfrom launch.substitutions import Command, LaunchConfigurationfrom launch_ros.actions import Nodefrom launch_ros.parameter_descriptions import ParameterValuedef generate_launch_description():    urdf_tutorial_path = get_package_share_path('my_learning_urdf')    # 设置默认的URDF文件和RViz配置文件路径    default_model_path = urdf_tutorial_path / 'urdf/mbot_base.urdf'    default_rviz_config_path = urdf_tutorial_path / 'rviz/urdf.rviz'    # 命令行参数:--gui true/false,控制是否使用GUI界面发布关节状态    gui_arg = DeclareLaunchArgument(name='gui', default_value='false', choices=['true', 'false'],<joint name="my_joint" type="floating">
  2.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  3.    <parent link="link1"/>
  4.    <child link="link2"/>
  5.    <calibration rising="0.0"/>
  6.    <dynamics damping="0.0" friction="0.0"/>
  7.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  8.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  9. </joint>               description='Flag to enable joint_state_publisher_gui')        # 命令行参数:--model ,指定URDF文件路径    model_arg = DeclareLaunchArgument(name='model', default_value=str(default_model_path),<joint name="my_joint" type="floating">
  10.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  11.    <parent link="link1"/>
  12.    <child link="link2"/>
  13.    <calibration rising="0.0"/>
  14.    <dynamics damping="0.0" friction="0.0"/>
  15.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  16.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  17. </joint>                 description='Absolute path to robot urdf file')        # 命令行参数:--rvizconfig ,指定RViz配置文件    rviz_arg = DeclareLaunchArgument(name='rvizconfig', default_value=str(default_rviz_config_path),<joint name="my_joint" type="floating">
  18.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  19.    <parent link="link1"/>
  20.    <child link="link2"/>
  21.    <calibration rising="0.0"/>
  22.    <dynamics damping="0.0" friction="0.0"/>
  23.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  24.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  25. </joint>                description='Absolute path to rviz config file')    # 关键:使用xacro命令解析URDF文件(支持参数化、宏等高级特性)    robot_description = ParameterValue(Command(['xacro ', LaunchConfiguration('model')]),<joint name="my_joint" type="floating">
  26.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  27.    <parent link="link1"/>
  28.    <child link="link2"/>
  29.    <calibration rising="0.0"/>
  30.    <dynamics damping="0.0" friction="0.0"/>
  31.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  32.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  33. </joint>                  value_type=str)            # robot_state_publisher 节点    robot_state_publisher_node = Node(        package='robot_state_publisher',        executable='robot_state_publisher',        parameters=[{'robot_description': robot_description}]    )    # 关节状态发布器(二选一)    # 文本版本(无GUI)    joint_state_publisher_node = Node(        package='joint_state_publisher',        executable='joint_state_publisher',        condition=UnlessCondition(LaunchConfiguration('gui'))    )    # GUI版本(带滑动条控制)    joint_state_publisher_gui_node = Node(        package='joint_state_publisher_gui',        executable='joint_state_publisher_gui',        condition=IfCondition(LaunchConfiguration('gui'))    )    # rviz2 可视化节点    rviz_node = Node(        package='rviz2',        executable='rviz2',        name='rviz2',        output='screen',        arguments=['-d', LaunchConfiguration('rvizconfig')],    )    return LaunchDescription([        gui_arg,        model_arg,        rviz_arg,        joint_state_publisher_node,        joint_state_publisher_gui_node,        robot_state_publisher_node,        rviz_node    ])
复制代码
这个Launch文件主要做三件事:

  • 加载机器人URDF模型(支持xacro格式);
  • 发布机器人的状态变换(TF);
  • 在rviz2中可视化机器人。
2.2.1 节点

脚本运行会创建以下几个节点:

  • joint_state_publisher:发布每个joint(除fixed类型)的状态,一个无界面的、基础版的关节状态发布器;
  • joint_state_publisher_gui:发布每个joint(除fixed类型)的状态,可以通过UI界面对joint进行控制;
  • robot_state_publisher:将机器人各个links、joints之间的关系,通过TF的形式,整理成三维姿态信息发布。
  • rviz2:在rviz2中可视化机器人;
joint_state_publisher这是一个官方ROS2包,主要功能:

  • 输入:

    • 读取URDF中的关节定义;
    • 接收用户或程序指定的关节角度;

  • 输出:

    • 发布 /joint_states 话题,消息类型为 sensor_msgs/msg/JointState;
    • 包含所有关节的名称、位置、速度、力等信息。

2.2.2 数据流与节点关系

数据流与节点关系:
  1. 用户通过滑动条/GUI或程序 → joint_state_publisher(_gui)<joint name="my_joint" type="floating">
  2.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  3.    <parent link="link1"/>
  4.    <child link="link2"/>
  5.    <calibration rising="0.0"/>
  6.    <dynamics damping="0.0" friction="0.0"/>
  7.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  8.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  9. </joint>                ↓ 发布/joint_states话题<joint name="my_joint" type="floating">
  10.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  11.    <parent link="link1"/>
  12.    <child link="link2"/>
  13.    <calibration rising="0.0"/>
  14.    <dynamics damping="0.0" friction="0.0"/>
  15.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  16.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  17. </joint>   robot_state_publisher<joint name="my_joint" type="floating">
  18.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  19.    <parent link="link1"/>
  20.    <child link="link2"/>
  21.    <calibration rising="0.0"/>
  22.    <dynamics damping="0.0" friction="0.0"/>
  23.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  24.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  25. </joint>                ↓ 计算并发布TF变换<joint name="my_joint" type="floating">
  26.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  27.    <parent link="link1"/>
  28.    <child link="link2"/>
  29.    <calibration rising="0.0"/>
  30.    <dynamics damping="0.0" friction="0.0"/>
  31.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  32.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  33. </joint>         rviz2 和其他节点<joint name="my_joint" type="floating">
  34.    <origin xyz="0 0 1" rpy="0 0 3.1416"/>
  35.    <parent link="link1"/>
  36.    <child link="link2"/>
  37.    <calibration rising="0.0"/>
  38.    <dynamics damping="0.0" friction="0.0"/>
  39.    <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
  40.    <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
  41. </joint>                ↓ 接收TF并可视化
复制代码
2.3 urdf.rviz

在rviz目录下新建urdf.rviz文件;
  1. Panels:
  2.   - Class: rviz_common/Displays
  3.     Name: Displays
  4.   - Class: rviz_common/Views
  5.     Name: Views
  6. Visualization Manager:
  7.   Class: ""
  8.   Displays:
  9.     - Class: rviz_default_plugins/Grid
  10.       Name: Grid
  11.       Value: true
  12.     - Alpha: 0.8
  13.       Class: rviz_default_plugins/RobotModel
  14.       Description Source: Topic
  15.       Description Topic:
  16.         Value: /robot_description
  17.       Enabled: true
  18.       Name: RobotModel
  19.       Value: true
  20.     - Class: rviz_default_plugins/TF
  21.       Name: TF
  22.       Value: true
  23.   Global Options:
  24.     Fixed Frame: base_link
  25.     Frame Rate: 30
  26.   Name: root
  27.   Tools:
  28.     - Class: rviz_default_plugins/MoveCamera
  29.   Value: true
  30.   Views:
  31.     Current:
  32.       Class: rviz_default_plugins/Orbit
  33.       Distance: 1.7
  34.       Name: Current View
  35.       Pitch: 0.33
  36.       Value: Orbit (rviz)
  37.       Yaw: 5.5
  38. Window Geometry:
  39.   Height: 800
  40.   Width: 1200
复制代码
2.4 编译运行

编译程序:
  1. pi@NanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_urdf
  2. pi@NanoPC-T6:~/dev_ws$ source install/setup.sh
复制代码
2.4.1 可视化

启动终端,运行如下命令;
  1. pi@NanoPC-T6:~/dev_ws$ ros2 launch my_learning_urdf display.launch.py
复制代码
很快就可以看到rviz中显示的机器人模型啦,大家可以使用鼠标拖拽观察;
5.png
从可视化的效果来看,这个机器人由五个link和4个joint组成。
2.4.2 查看URDF模型结构

我们分析的对不对呢,可以在模型文件的路径下,使用urdf_to_graphviz这个小工具来分析下;
  1. pi@NanoPC-T6:~/dev_ws/src/my_learning_urdf/urdf$ urdf_to_graphviz mbot_base.urdf
  2. WARNING: OUTPUT not given. This type of usage is deprecated!Usage: urdf_to_graphviz input.xml [OUTPUT]  Will create either $ROBOT_NAME.gv & $ROBOT_NAME.pdf in CWD  or OUTPUT.gv & OUTPUT.pdf.
  3. Created file mbot.gv
  4. Created file mbot.pdf
  5. pi@NanoPC-T6:~/dev_ws/src/my_learning_urdf/urdf$ ls
  6. mbot_base.urdf  mbot.gv  mbot.pdf
复制代码
运行成功后会产生一个pdf文件,打开之后就可以看到URDF模型分析的结果啦,是不是和我们的猜测完全相同呢!
6.png
参考文章
[1] 古月居ROS2入门教程学习笔记
[2] ROS中阶笔记(二):机器人系统设计—URDF机器人建模
[3] XML Robot Description Format (URDF)

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册