安装 urdf_tutorial
首先我们需要安装 urdf_tutorial 这个教程包
vim catkin_ws/src & cd catkin_ws/src
git clone https://github.com/ros/urdf_tutorial.git urdf_tutorial
cd ..
catkin_make
根据教程操作,在第2步我们可以得到所有我们需要的文件
(base) zwhy2022@Zwhy:~/work/catkin_ws/src/urdf_tutorial$ ls
CHANGELOG.rst CMakeLists.txt images launch meshes package.xml README.md rviz urdf
但是为什么需要catkin_make呢?其实是需要配置环境变量,笔者现在也不是很了解ros这个中间件到底做了那些事情,因为很多很多,暂时只能做一点补一点.
在我们catkin_make之后执行下面这条指令后,本次终端就能识别到你的ros工作空间了.
source devel/setup.bash
使用ros自带的 urdf_tutorial
zwhy2022@Zwhy:~$ echo $(rospack find urdf_tutorial)
/opt/ros/kinetic/share/urdf_tutorial
这就是为什么之前我说,鱼香ros的一件安装像黑盒,我也不知道ros中就自带了这个pkg(像是小海归一样)
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/01-myfirst.urdf'
因为我在终端的启动脚本中source过ros 环境所以其实我的ros 是能识别到urdf_tutorial这个pkg的,但是由于自带的这个urdf_tutorial是没有默认model的,所以你需要手动导入urdf模型文件的路径.你当然可以使用全局变量,但是我们可以使用ros给我提供的工具.
一种形状
下面的代码片段中,我们可以看到第一行是我没有按回车键,而是按下tab补全之后,出来的参数列表.这几个刚好对应了 display.launch文件中三个arg name! 太神奇啦!这也是ros帮我们做的事情,随后执行这句指令.
(base) zwhy2022@Zwhy:~/work/catkin_ws$ roslaunch urdf_tutorial display.launch
gui model rvizconfig
(base) zwhy2022@Zwhy:~/work/catkin_ws$ roslaunch urdf_tutorial display.launch
这样你的终端将会唤醒,rviz然后给展现一个圆柱体.是不是很神奇?
这是因为 display.launch这个launch文件会有一个默认参数,就如下面的代码片段一般.
(base) zwhy2022@Zwhy:~/work/catkin_ws$ cat src/urdf_tutorial/launch/display.launch
<launch>
<arg name="model" default="$(find urdf_tutorial)/urdf/01-myfirst.urdf"/>
<arg name="gui" default="true" />
<arg name="rvizconfig" default="$(find urdf_tutorial)/rviz/urdf.rviz" />
<param name="robot_description" command="$(find xacro)/xacro $(arg model)" />
<node if="$(arg gui)" name="joint_state_publisher" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" />
<node unless="$(arg gui)" name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
<node name="rviz" pkg="rviz" type="rviz" args="-d $(arg rvizconfig)" required="true" />
</launch>
display.launch 做了三件事。
-
将指定模型加载到参数服务器中
-
运行节点来发布sensor_msgs/JointState并进行转换(稍后将详细介绍)
-
使用配置文件启动 Rviz
多种形状
roslaunch urdf_tutorial display.launch model:=urdf/02-multipleshapes.urdf
好的代码本身就是注释是这么用的,但是并不是说没有注释的代码就是好代码,下面结构很清晰了.
zwhy2022@Zwhy:/opt/ros/kinetic/share/urdf_tutorial$ cat urdf/02-multipleshapes.urdf
<?xml version="1.0"?>
<robot name="multipleshapes">
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.6" radius="0.2"/>
</geometry>
</visual>
</link>
<link name="right_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
</visual>
</link>
<joint name="base_to_right_leg" type="fixed">
<parent link="base_link"/>
<child link="right_leg"/>
</joint>
</robot>
你可以发现我们主要是有两种概念,关节和形状(连接).上述我们就通过一个关节吧两个形状连接到一起,然后其实有parent,child的区分.其实这里涉及到 标准DH(SDH)和改进DH(MDH)的概念,笔者放到文末,可以自行学习.
origin
原谅我真的不知道怎么做翻译…
在多种形状的udrf中,我们只是静态的导入形状,现在我们要做一点点变换.
roslaunch urdf_tutorial display.launch model:=urdf/03-origins.urdf
我们可以看到相较之前,我们多了
zwhy2022@Zwhy:~/work/catkin_ws/src/urdf_tutorial$ cat urdf/03-origins.urdf
<?xml version="1.0"?>
<robot name="origins">
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.6" radius="0.2"/>
</geometry>
</visual>
</link>
<link name="right_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
</visual>
</link>
<joint name="base_to_right_leg" type="fixed">
<parent link="base_link"/>
<child link="right_leg"/>
<origin xyz="0 -0.22 0.25"/>
</joint>
</robot>
在URDF (Unified Robot Description Format) 中,origin 元素用于定义一个局部坐标系相对于其父坐标系的位置和方向。origin 元素通常在定义连接件 (joint) 和视觉/碰撞几何 (visual/collision) 时使用。
origin 元素可以包含以下两个属性:
-
xyz: 表示平移,它定义了相对于父坐标系的位置。这是一个由三个浮点数组成的向量,表示在x、y、z方向上的平移距离。
-
rpy: 表示旋转,它定义了固定角Roll-Pitch-Yaw旋转。这是一个由三个浮点数组成的向量,分别表示绕x、y、z轴的旋转角度。
这里表示right_leg相对于base_link 绕着y轴旋转90°(弧度制),并且在z的负方向平移了-0.3个单位,看上去单位表示的是m.当然urdf_tutorial中,的所有代码你都可以随意修改看看效果,这样反馈很大.
注意: 坐标系的颜色 红-x 绿-y 蓝-z
同样对于关节的变换也是如此,我们可以相互对于父坐标系,做一些平移或者旋转,得到子坐标系.子子孙孙,子承父业,这也是合情合理.所以我们向z平移0.25以及向y平移-0.22后得到了子坐标系的原点.
材质
roslaunch urdf_tutorial display.launch model:=urdf/04-materials.urdf
继续循序渐进,我们只是一葫芦画瓢建立了另一条腿,然后我们给腿和身体上色.
zwhy2022@Zwhy:~/work/catkin_ws/src/urdf_tutorial$ cat urdf/04-materials.urdf
<?xml version="1.0"?>
<robot name="materials">
<material name="blue">
<color rgba="0 0 0.8 1"/>
</material>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.6" radius="0.2"/>
</geometry>
<material name="blue"/>
</visual>
</link>
<link name="right_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
<material name="white"/>
</visual>
</link>
<joint name="base_to_right_leg" type="fixed">
<parent link="base_link"/>
<child link="right_leg"/>
<origin xyz="0 -0.22 0.25"/>
</joint>
<link name="left_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
<material name="white"/>
</visual>
</link>
<joint name="base_to_left_leg" type="fixed">
<parent link="base_link"/>
<child link="left_leg"/>
<origin xyz="0 0.22 0.25"/>
</joint>
</robot>
其中红色、绿色、蓝色和 alpha 通道分别定义为 0、0、0.8 和 1。所有值都可以在 [0,1] 范围内.然后红绿蓝是我们常见的rgb,但是归一化到了[0,1]而已,然后alpha表示透明度.0表示完全透明,1表示完全不透明.
完成模型
roslaunch urdf_tutorial display.launch model:=urdf/05-visual.urdf
zwhy2022@Zwhy:~/work/catkin_ws/src/urdf_tutorial$ cat urdf/05-visual.urdf
<?xml version="1.0"?>
<robot name="visual">
<material name="blue">
<color rgba="0 0 0.8 1"/>
</material>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.6" radius="0.2"/>
</geometry>
<material name="blue"/>
</visual>
</link>
<link name="right_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
<material name="white"/>
</visual>
</link>
<joint name="base_to_right_leg" type="fixed">
<parent link="base_link"/>
<child link="right_leg"/>
<origin xyz="0 -0.22 0.25"/>
</joint>
<link name="right_base">
<visual>
<geometry>
<box size="0.4 0.1 0.1"/>
</geometry>
<material name="white"/>
</visual>
</link>
<joint name="right_base_joint" type="fixed">
<parent link="right_leg"/>
<child link="right_base"/>
<origin xyz="0 0 -0.6"/>
</joint>
<link name="right_front_wheel">
<visual>
<origin rpy="1.57075 0 0" xyz="0 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.035"/>
</geometry>
<material name="black"/>
</visual>
</link>
<joint name="right_front_wheel_joint" type="fixed">
<parent link="right_base"/>
<child link="right_front_wheel"/>
<origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
</joint>
<link name="right_back_wheel">
<visual>
<origin rpy="1.57075 0 0" xyz="0 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.035"/>
</geometry>
<material name="black"/>
</visual>
</link>
<joint name="right_back_wheel_joint" type="fixed">
<parent link="right_base"/>
<child link="right_back_wheel"/>
<origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
</joint>
<link name="left_leg">
<visual>
<geometry>
<box size="0.6 0.1 0.2"/>
</geometry>
<origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
<material name="white"/>
</visual>
</link>
<joint name="base_to_left_leg" type="fixed">
<parent link="base_link"/>
<child link="left_leg"/>
<origin xyz="0 0.22 0.25"/>
</joint>
<link name="left_base">
<visual>
<geometry>
<box size="0.4 0.1 0.1"/>
</geometry>
<material name="white"/>
</visual>
</link>
<joint name="left_base_joint" type="fixed">
<parent link="left_leg"/>
<child link="left_base"/>
<origin xyz="0 0 -0.6"/>
</joint>
<link name="left_front_wheel">
<visual>
<origin rpy="1.57075 0 0" xyz="0 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.035"/>
</geometry>
<material name="black"/>
</visual>
</link>
<joint name="left_front_wheel_joint" type="fixed">
<parent link="left_base"/>
<child link="left_front_wheel"/>
<origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
</joint>
<link name="left_back_wheel">
<visual>
<origin rpy="1.57075 0 0" xyz="0 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.035"/>
</geometry>
<material name="black"/>
</visual>
</link>
<joint name="left_back_wheel_joint" type="fixed">
<parent link="left_base"/>
<child link="left_back_wheel"/>
<origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
</joint>
<joint name="gripper_extension" type="fixed">
<parent link="base_link"/>
<child link="gripper_pole"/>
<origin rpy="0 0 0" xyz="0.19 0 0.2"/>
</joint>
<link name="gripper_pole">
<visual>
<geometry>
<cylinder length="0.2" radius="0.01"/>
</geometry>
<origin rpy="0 1.57075 0 " xyz="0.1 0 0"/>
</visual>
</link>
<joint name="left_gripper_joint" type="fixed">
<origin rpy="0 0 0" xyz="0.2 0.01 0"/>
<parent link="gripper_pole"/>
<child link="left_gripper"/>
</joint>
<link name="left_gripper">
<visual>
<origin rpy="0.0 0 0" xyz="0 0 0"/>
<geometry>
<mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
</geometry>
</visual>
</link>
<joint name="left_tip_joint" type="fixed">
<parent link="left_gripper"/>
<child link="left_tip"/>
</joint>
<link name="left_tip">
<visual>
<origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
<geometry>
<mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
</geometry>
</visual>
</link>
<joint name="right_gripper_joint" type="fixed">
<origin rpy="0 0 0" xyz="0.2 -0.01 0"/>
<parent link="gripper_pole"/>
<child link="right_gripper"/>
</joint>
<link name="right_gripper">
<visual>
<origin rpy="-3.1415 0 0" xyz="0 0 0"/>
<geometry>
<mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
</geometry>
</visual>
</link>
<joint name="right_tip_joint" type="fixed">
<parent link="right_gripper"/>
<child link="right_tip"/>
</joint>
<link name="right_tip">
<visual>
<origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
<geometry>
<mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
</geometry>
</visual>
</link>
<link name="head">
<visual>
<geometry>
<sphere radius="0.2"/>
</geometry>
<material name="white"/>
</visual>
</link>
<joint name="head_swivel" type="fixed">
<parent link="base_link"/>
<child link="head"/>
<origin xyz="0 0 0.3"/>
</joint>
<link name="box">
<visual>
<geometry>
<box size="0.08 0.08 0.08"/>
</geometry>
<material name="blue"/>
</visual>
</link>
<joint name="tobox" type="fixed">
<parent link="head"/>
<child link="box"/>
<origin xyz="0.1814 0 0.1414"/>
</joint>
</robot>
这里添加了机器人的更多细节,轮子啊,手柄等.最重要的是可以到导入STL,dae 等网格文件.这样会极大的方便我们模型的精细度以及制作的便捷性.
题外话
你可能还是需要一些关于旋转矩阵,坐标系的一些相关知识,当然能看到urdf相关教程,那你肯定是对于TF等一些相关知识有所了解.不求甚解以及零碎知识的学习是一个好习惯,与笔者共勉.
文档中,本章结尾的youture视频还介绍了其他有用的技巧,比如vscode的urdf可视化插件等.相关连接中可以找到