ROS是机器人操作系统,当然要给机器人使用啦,不过在使用之前,还得让ROS认识下我们使用的机器人,如何把一个机器人介绍给ROS呢?
为此,ROS专门提供了一种机器人建模方法——URDF,用来描述机器人外观、性能等各方面属性。
一、URDF语法
1.1 机器人的组成
建模描述机器人的过程中,我们自己需要先熟悉机器人的组成和参数,比如机器人一般是由硬件结构、驱动系统、传感器系统、控制系统四大部分组成,市面上一些常见的机器人,无论是移动机器人还是机械臂,我们都可以按照这四大组成部分进行分解。
其中:
- 硬件结构就是底盘、外壳、电机等实打实可以看到的设备;
- 驱动系统就是可以驱使这些设备正常使用的装置,比如电机的驱动器,电源管理系统等;
- 传感系统包括电机上的编码器、板载的IMU、安装的摄像头、雷达等等,便于机器人感知自己的状态和外部的环境;
- 控制系统就是我们开发过程的主要载体了,一般是树莓派、电脑等计算平台,以及里边的操作系统和应用软件。
机器人建模的过程,其实就是按照类似的思路,通过建模语言,把机器人每一个部分都描述清楚,再组合起来的过程。
1.2 什么是URDF
URDF(Unified Robot Description Format,统一机器人描述格式)是一种XML格式的文件,用于从物理和逻辑上描述一个机器人模型。
你可以把它理解为机器人的数字说明书或三维装配图,它告诉计算机:
- 机器人由哪些零件(连杆、关节)组成;
- 这些零件长什么样(形状、尺寸、颜色);
- 零件之间如何连接(位置、旋转、运动类型);
- 零件的物理属性(质量、惯性);
1.3 URDF组成
URDF主要描述两大核心元素:
- 连杆(Link):代表机器人的刚性部件,如机械臂的每一节臂杆、底盘、轮子、传感器支架等,包括:
- 视觉属性:形状(立方体、圆柱体、网格模型)、尺寸、颜色、纹理;
- 碰撞属性:用于物理仿真的简化几何形状;
- 惯性属性:质量、转动惯量(对仿真至关重要)。
- 关节(Joint):定义连杆之间的连接方式和运动关系,主要类型:
- 固定关节(fixed):完全固定连接;
- 旋转关节(revolute):绕单轴旋转,有角度限制(如机械臂关节);
- 连续关节(continuous):无限旋转(如轮子);
- 平移关节(prismatic):线性滑动;
- 平面关节(planar):在平面内运动;
- 浮动关节(floating):完全自由(6自由度)。
机器人描述由一组连杆元素和一组将连杆连接起来的关节元素组成;
因此,典型的机器人描述大致如下所示:- <?xml version="1.0"?>
- <?xml-model href="https://raw.githubusercontent.com/ros/urdfdom/master/xsd/urdf.xsd" ?>
- <robot name="pr2" xmlns="http://www.ros.org">
- <link> ... </link>
- <link> ... </link>
- <link> ... </link>
- <joint> .... </joint>
- <joint> .... </joint>
- <joint> .... </joint>
- </robot>
复制代码 可以看到,URDF格式的根元素是一个 元素。
1.3.1 link元素
link元素描述了一个具有惯性、视觉特征和碰撞属性的刚体。以下是一个link元素的示例:- <link name="my_link">
- <inertial>
- <origin xyz="0 0 0.5" rpy="0 0 0"/>
- <mass value="1"/>
- <inertia ixx="100" ixy="0" ixz="0" iyy="100" iyz="0" izz="100" />
- </inertial>
- <visual>
- <origin xyz="0 0 0" rpy="0 0 0" />
- <geometry>
- <box size="1 1 1" />
- </geometry>
- <material name="Cyan">
- <color rgba="0 1.0 1.0 1.0"/>
- </material>
- </visual>
- <collision>
- <origin xyz="0 0 0" rpy="0 0 0"/>
- <geometry>
- <cylinder radius="1" length="0.5"/>
- </geometry>
- </collision>
- </link>
复制代码 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 元素的示例:- <joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint>
复制代码 下面图中,蓝色关节表示出一个运动的轴,蓝色关节是可以围绕蓝色的轴旋转的,也就是child这个link是可以围绕joint上下旋转。
joint连接两个link,需要分一个主次关系,主关节是parent link,子关节是child link, 在xml形式的描述中这个两个link是必须存在的。
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描述子连杆名称,元素属性有:
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版本的功能包;- pi@NanoPC-T6:~/dev_ws$ cd src
- 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文件,添加配置文件:- import os
- from glob import glob
- ...
- data_files=[
- ('share/ament_index/resource_index/packages',
- ['resource/' + package_name]),
- ('share/' + package_name, ['package.xml']),
- (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
- (os.path.join('share', package_name, 'urdf'), glob(os.path.join('urdf', '*.*'))),
- (os.path.join('share', package_name, 'urdf/sensors'), glob(os.path.join('urdf/sensors', '*.*'))),
- (os.path.join('share', package_name, 'meshes'), glob(os.path.join('meshes', '*.*'))),
- (os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.rviz'))),
- ],
- ...
复制代码 2.1 模型文件
在urdf下新建文件mbot_base.urdf;这将会创建一个两轮差分驱动机器人的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文件;- 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">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </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">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </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">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> description='Absolute path to rviz config file') # 关键:使用xacro命令解析URDF文件(支持参数化、宏等高级特性) robot_description = ParameterValue(Command(['xacro ', LaunchConfiguration('model')]),<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </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 数据流与节点关系
数据流与节点关系:- 用户通过滑动条/GUI或程序 → joint_state_publisher(_gui)<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> ↓ 发布/joint_states话题<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> robot_state_publisher<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> ↓ 计算并发布TF变换<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> rviz2 和其他节点<joint name="my_joint" type="floating">
- <origin xyz="0 0 1" rpy="0 0 3.1416"/>
- <parent link="link1"/>
- <child link="link2"/>
- <calibration rising="0.0"/>
- <dynamics damping="0.0" friction="0.0"/>
- <limit effort="30" velocity="1.0" lower="-2.2" upper="0.7" />
- <safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
- </joint> ↓ 接收TF并可视化
复制代码 2.3 urdf.rviz
在rviz目录下新建urdf.rviz文件;- Panels:
- - Class: rviz_common/Displays
- Name: Displays
- - Class: rviz_common/Views
- Name: Views
- Visualization Manager:
- Class: ""
- Displays:
- - Class: rviz_default_plugins/Grid
- Name: Grid
- Value: true
- - Alpha: 0.8
- Class: rviz_default_plugins/RobotModel
- Description Source: Topic
- Description Topic:
- Value: /robot_description
- Enabled: true
- Name: RobotModel
- Value: true
- - Class: rviz_default_plugins/TF
- Name: TF
- Value: true
- Global Options:
- Fixed Frame: base_link
- Frame Rate: 30
- Name: root
- Tools:
- - Class: rviz_default_plugins/MoveCamera
- Value: true
- Views:
- Current:
- Class: rviz_default_plugins/Orbit
- Distance: 1.7
- Name: Current View
- Pitch: 0.33
- Value: Orbit (rviz)
- Yaw: 5.5
- Window Geometry:
- Height: 800
- Width: 1200
复制代码 2.4 编译运行
编译程序:- pi@NanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_urdf
- pi@NanoPC-T6:~/dev_ws$ source install/setup.sh
复制代码 2.4.1 可视化
启动终端,运行如下命令;- pi@NanoPC-T6:~/dev_ws$ ros2 launch my_learning_urdf display.launch.py
复制代码 很快就可以看到rviz中显示的机器人模型啦,大家可以使用鼠标拖拽观察;
从可视化的效果来看,这个机器人由五个link和4个joint组成。
2.4.2 查看URDF模型结构
我们分析的对不对呢,可以在模型文件的路径下,使用urdf_to_graphviz这个小工具来分析下;- pi@NanoPC-T6:~/dev_ws/src/my_learning_urdf/urdf$ urdf_to_graphviz mbot_base.urdf
- 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.
- Created file mbot.gv
- Created file mbot.pdf
- pi@NanoPC-T6:~/dev_ws/src/my_learning_urdf/urdf$ ls
- mbot_base.urdf mbot.gv mbot.pdf
复制代码 运行成功后会产生一个pdf文件,打开之后就可以看到URDF模型分析的结果啦,是不是和我们的猜测完全相同呢!
参考文章
[1] 古月居ROS2入门教程学习笔记
[2] ROS中阶笔记(二):机器人系统设计—URDF机器人建模
[3] XML Robot Description Format (URDF)
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |