0.安装:
sudo apt-get install ros-melodic-urdf-tutorial
1.一个形状
首先,我们将探讨一种简单的形状。 尽可能简单地做到此操作。
切换行号显示
1 <?xml version="1.0"?>
2 <robot name="myfirst">
3 <link name="base_link">
4 <visual>
5 <geometry>
6 <cylinder length="0.6" radius="0.2"/>
7 </geometry>
8 </visual>
9 </link>
10 </robot>
将XML转换为英语,这是一个名为myfirst的机器人,它仅包含一个链接(也称为部件),其可视组件仅为0.6米长的圆柱体,半径为0.2米。 对于一个简单的“ hello world”类型的示例来说,这看起来好像包含了很多标签,但是请相信,它将变得更加复杂。
要检查模型,请启动display.launch文件:
roslaunch urdf_tutorial display.launch model:=urdf/01-myfirst.urdf
这做三件事:
- 将指定的模型加载到参数服务器中
- 运行节点以发布sensor_msgs / JointState并进行转换(稍后会详细介绍)
- 用配置文件启动Rviz
请注意,上面的roslaunch行假定您正在urdf_tutorial软件包目录中执行它(即urdf目录是当前工作目录的直接子目录)。 如果不是这种情况,则指向01-myfirst.urdf的相对路径将无效,当roslaunch尝试将urdf加载到参数服务器时,您将收到如下错误消息:
输入之后,就遇到了如下问题:
No such file or directory: urdf/01-myfirst.urdf
RLException: Invalid <param> tag: Cannot load command parameter [robot_description]: command [['/opt/ros/melodic/share/xacro/xacro.py', 'urdf/01-myfirst.urdf']] returned with code [2].
Param xml is <param command="$(find xacro)/xacro.py $(arg model)" name="robot_description"/>
The traceback for the exception was written to the log file
需要稍加修改的参数使它不管当前的工作目录如何都可以工作:
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/01-myfirst.urdf'
接着出现了新的问题,但可以出现RVIZ图像:
[ERROR] [1593878383.918701]: Could not find the GUI, install the 'joint_state_publisher_gui' package
[joint_state_publisher-1] process has died [pid 16100, exit code 1, cmd /opt/ros/melodic/lib/joint_state_publisher/joint_state_publisher __name:=joint_state_publisher __log:=/home/li/.ros/log/96f100ec-be0d-11ea-938c-c83dd494a8c1/joint_state_publisher-1.log].
log file: /home/li/.ros/log/96f100ec-be0d-11ea-938c-c83dd494a8c1/joint_state_publisher-1*.log
解决方法:sudo apt-get install ros-melodic-joint-state-publisher-gui
注意事项:
- 固定框架是网格中心所在的变换框架。 在这里,这是由我们的一个链接base_link定义的框架。
- 默认情况下,视觉元素(圆柱体)的原点位于其几何形状的中心。 因此,一半的圆柱体位于栅格下方。
2.多个形状
现在让我们看一下如何添加多个形状/链接。 如果我们仅向urdf添加更多链接元素,则解析器将不知道将它们放在何处。 因此,我们必须添加关节。 关节元件可以指柔性和非柔性关节。 我们将从固定不动的关节开始。
切换行号显示
1 <?xml version="1.0"?>
2 <robot name="multipleshapes">
3 <link name="base_link">
4 <visual>
5 <geometry>
6 <cylinder length="0.6" radius="0.2"/>
7 </geometry>
8 </visual>
9 </link>
10
11 <link name="right_leg">
12 <visual>
13 <geometry>
14 <box size="0.6 0.1 0.2"/>
15 </geometry>
16 </visual>
17 </link>
18
19 <joint name="base_to_right_leg" type="fixed">
20 <parent link="base_link"/>
21 <child link="right_leg"/>
22 </joint>
23
24 </robot>
- 请注意我们如何定义0.6m x 0.1m x 0.2m的盒子
- 关节是根据父母和孩子定义的。 URDF最终是具有一个根链接的树结构。 这意味着腿的位置取决于base_link的位置。
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/02-multipleshapes.urdf'
这两个形状彼此重叠,因为它们共享相同的原点。 如果我们不希望它们重叠,则必须定义更多的原点。
3.初始形状
因此,R2D2的腿在侧面附着在他的躯干的上半部分。 这就是我们指定JOINT的原点的地方。 另外,它不附着在腿的中部,而是附着在腿的上部,因此我们也必须偏移腿的原点。 我们还旋转了腿使其直立。
切换行号显示
1 <?xml version="1.0"?>
2 <robot name="origins">
3 <link name="base_link">
4 <visual>
5 <geometry>
6 <cylinder length="0.6" radius="0.2"/>
7 </geometry>
8 </visual>
9 </link>
10
11 <link name="right_leg">
12 <visual>
13 <geometry>
14 <box size="0.6 0.1 0.2"/>
15 </geometry>
16 <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
17 </visual>
18 </link>
19
20 <joint name="base_to_right_leg" type="fixed">
21 <parent link="base_link"/>
22 <child link="right_leg"/>
23 <origin xyz="0 -0.22 0.25"/>
24 </joint>
25
26 </robot>
- 首先检查关节的原点。 它是根据父母的参照系定义的。 因此,我们在y方向上为-0.22米(向左,但相对于轴为右侧),在z方向上(向上)为0.25米。 这意味着,无论子链接的视觉原点标签如何,子链接的原点都将在右上方。 由于我们未指定rpy(横摆偏航)属性,因此默认情况下,子框架的方向与父框架的方向相同。
- 现在,查看腿部的视觉原点,它具有xyz和rpy偏移量。 这定义了视觉元素相对于其原点应位于的中心。 由于我们希望将腿连接到顶部,因此可以通过将z偏移设置为-0.3米来向下偏移原点。 并且由于我们希望腿的长部分平行于z轴,因此我们绕Y轴旋转可视部分PI / 2。
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/03-origins.urdf'
- 启动文件运行的程序包将基于URDF为模型中的每个链接创建TF框架。 Rviz使用此信息来找出每种形状的显示位置。
- 如果给定的URDF链接不存在TF帧,则它将以白色放置在原点(请参阅相关问题)。
4.材料
“好吧,”我听到你说。 “这很可爱,但并不是每个人都拥有B21。 我的机器人和R2D2不是红色的!” 那是个很好的观点。 让我们看一下材料标签。
切换行号显示
1 <?xml version="1.0"?>
2 <robot name="materials">
3
4 <material name="blue">
5 <color rgba="0 0 0.8 1"/>
6 </material>
7
8 <material name="white">
9 <color rgba="1 1 1 1"/>
10 </material>
11
12
13 <link name="base_link">
14 <visual>
15 <geometry>
16 <cylinder length="0.6" radius="0.2"/>
17 </geometry>
18 <material name="blue"/>
19 </visual>
20 </link>
21
22 <link name="right_leg">
23 <visual>
24 <geometry>
25 <box size="0.6 0.1 0.2"/>
26 </geometry>
27 <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
28 <material name="white"/>
29 </visual>
30 </link>
31
32 <joint name="base_to_right_leg" type="fixed">
33 <parent link="base_link"/>
34 <child link="right_leg"/>
35 <origin xyz="0 -0.22 0.25"/>
36 </joint>
37
38 <link name="left_leg">
39 <visual>
40 <geometry>
41 <box size="0.6 0.1 0.2"/>
42 </geometry>
43 <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
44 <material name="white"/>
45 </visual>
46 </link>
47
48 <joint name="base_to_left_leg" type="fixed">
49 <parent link="base_link"/>
50 <child link="left_leg"/>
51 <origin xyz="0 0.22 0.25"/>
52 </joint>
53
54 </robot>
- 身体现在是蓝色的。 我们定义了一种称为“蓝色”的新材质,其中红色,绿色,蓝色和Alpha通道分别定义为0、0、0.8和1。 所有值都可以在[0,1]范围内。 然后,base_link的视觉元素会引用此材料。 白色材料的定义类似
- 您还可以从视觉元素中定义材料标签,甚至可以在其他链接中引用它。 即使重新定义,也没有人会抱怨。
- 您还可以使用纹理来指定用于为对象着色的图像文件
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/04-materials.urdf'
5.完成模型
现在,我们以更多的形状完成模型:脚,轮子和头。 最值得注意的是,我们添加了一个球体和一些网格。 我们还将添加其他一些片段,稍后再使用。
切换行号显示
1 <?xml version="1.0"?>
2 <robot name="visual">
3
4 <material name="blue">
5 <color rgba="0 0 0.8 1"/>
6 </material>
7 <material name="black">
8 <color rgba="0 0 0 1"/>
9 </material>
10 <material name="white">
11 <color rgba="1 1 1 1"/>
12 </material>
13
14 <link name="base_link">
15 <visual>
16 <geometry>
17 <cylinder length="0.6" radius="0.2"/>
18 </geometry>
19 <material name="blue"/>
20 </visual>
21 </link>
22
23 <link name="right_leg">
24 <visual>
25 <geometry>
26 <box size="0.6 0.1 0.2"/>
27 </geometry>
28 <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
29 <material name="white"/>
30 </visual>
31 </link>
32
33 <joint name="base_to_right_leg" type="fixed">
34 <parent link="base_link"/>
35 <child link="right_leg"/>
36 <origin xyz="0 -0.22 0.25"/>
37 </joint>
38
39 <link name="right_base">
40 <visual>
41 <geometry>
42 <box size="0.4 0.1 0.1"/>
43 </geometry>
44 <material name="white"/>
45 </visual>
46 </link>
47
48 <joint name="right_base_joint" type="fixed">
49 <parent link="right_leg"/>
50 <child link="right_base"/>
51 <origin xyz="0 0 -0.6"/>
52 </joint>
53
54 <link name="right_front_wheel">
55 <visual>
56 <origin rpy="1.57075 0 0" xyz="0 0 0"/>
57 <geometry>
58 <cylinder length="0.1" radius="0.035"/>
59 </geometry>
60 <material name="black"/>
61 <origin rpy="0 0 0" xyz="0 0 0"/>
62 </visual>
63 </link>
64 <joint name="right_front_wheel_joint" type="fixed">
65 <parent link="right_base"/>
66 <child link="right_front_wheel"/>
67 <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
68 </joint>
69
70 <link name="right_back_wheel">
71 <visual>
72 <origin rpy="1.57075 0 0" xyz="0 0 0"/>
73 <geometry>
74 <cylinder length="0.1" radius="0.035"/>
75 </geometry>
76 <material name="black"/>
77 </visual>
78 </link>
79 <joint name="right_back_wheel_joint" type="fixed">
80 <parent link="right_base"/>
81 <child link="right_back_wheel"/>
82 <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
83 </joint>
84
85 <link name="left_leg">
86 <visual>
87 <geometry>
88 <box size="0.6 0.1 0.2"/>
89 </geometry>
90 <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
91 <material name="white"/>
92 </visual>
93 </link>
94
95 <joint name="base_to_left_leg" type="fixed">
96 <parent link="base_link"/>
97 <child link="left_leg"/>
98 <origin xyz="0 0.22 0.25"/>
99 </joint>
100
101 <link name="left_base">
102 <visual>
103 <geometry>
104 <box size="0.4 0.1 0.1"/>
105 </geometry>
106 <material name="white"/>
107 </visual>
108 </link>
109
110 <joint name="left_base_joint" type="fixed">
111 <parent link="left_leg"/>
112 <child link="left_base"/>
113 <origin xyz="0 0 -0.6"/>
114 </joint>
115
116 <link name="left_front_wheel">
117 <visual>
118 <origin rpy="1.57075 0 0" xyz="0 0 0"/>
119 <geometry>
120 <cylinder length="0.1" radius="0.035"/>
121 </geometry>
122 <material name="black"/>
123 </visual>
124 </link>
125 <joint name="left_front_wheel_joint" type="fixed">
126 <parent link="left_base"/>
127 <child link="left_front_wheel"/>
128 <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
129 </joint>
130
131 <link name="left_back_wheel">
132 <visual>
133 <origin rpy="1.57075 0 0" xyz="0 0 0"/>
134 <geometry>
135 <cylinder length="0.1" radius="0.035"/>
136 </geometry>
137 <material name="black"/>
138 </visual>
139 </link>
140 <joint name="left_back_wheel_joint" type="fixed">
141 <parent link="left_base"/>
142 <child link="left_back_wheel"/>
143 <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
144 </joint>
145
146 <joint name="gripper_extension" type="fixed">
147 <parent link="base_link"/>
148 <child link="gripper_pole"/>
149 <origin rpy="0 0 0" xyz="0.19 0 0.2"/>
150 </joint>
151
152 <link name="gripper_pole">
153 <visual>
154 <geometry>
155 <cylinder length="0.2" radius="0.01"/>
156 </geometry>
157 <origin rpy="0 1.57075 0 " xyz="0.1 0 0"/>
158 </visual>
159 </link>
160
161 <joint name="left_gripper_joint" type="fixed">
162 <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
163 <parent link="gripper_pole"/>
164 <child link="left_gripper"/>
165 </joint>
166
167 <link name="left_gripper">
168 <visual>
169 <origin rpy="0.0 0 0" xyz="0 0 0"/>
170 <geometry>
171 <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
172 </geometry>
173 </visual>
174 </link>
175
176 <joint name="left_tip_joint" type="fixed">
177 <parent link="left_gripper"/>
178 <child link="left_tip"/>
179 </joint>
180
181 <link name="left_tip">
182 <visual>
183 <origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
184 <geometry>
185 <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
186 </geometry>
187 </visual>
188 </link>
189 <joint name="right_gripper_joint" type="fixed">
190 <origin rpy="0 0 0" xyz="0.2 -0.01 0"/>
191 <parent link="gripper_pole"/>
192 <child link="right_gripper"/>
193 </joint>
194
195 <link name="right_gripper">
196 <visual>
197 <origin rpy="-3.1415 0 0" xyz="0 0 0"/>
198 <geometry>
199 <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
200 </geometry>
201 </visual>
202 </link>
203
204 <joint name="right_tip_joint" type="fixed">
205 <parent link="right_gripper"/>
206 <child link="right_tip"/>
207 </joint>
208
209 <link name="right_tip">
210 <visual>
211 <origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
212 <geometry>
213 <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
214 </geometry>
215 </visual>
216 </link>
217
218 <link name="head">
219 <visual>
220 <geometry>
221 <sphere radius="0.2"/>
222 </geometry>
223 <material name="white"/>
224 </visual>
225 </link>
226 <joint name="head_swivel" type="fixed">
227 <parent link="base_link"/>
228 <child link="head"/>
229 <origin xyz="0 0 0.3"/>
230 </joint>
231
232 <link name="box">
233 <visual>
234 <geometry>
235 <box size="0.08 0.08 0.08"/>
236 </geometry>
237 <material name="blue"/>
238 </visual>
239 </link>
240
241 <joint name="tobox" type="fixed">
242 <parent link="head"/>
243 <child link="box"/>
244 <origin xyz="0.1814 0 0.1414"/>
245 </joint>
246 </robot>
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/05-visual.urdf'
6.使用URDF构建可移动机器人模型
在本教程中,我们将修改在上一教程中制作的R2D2模型,使其具有活动关节。 在以前的模型中,所有关节都是固定的。 现在,我们将探讨三种其他重要的关节类型:连续关节,旋转关节和棱柱关节。
roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/06-flexible.urdf'
6.1 头部
切换行号显示
1 <joint name="head_swivel" type="continuous">
2 <parent link="base_link"/>
3 <child link="head"/>
4 <axis xyz="0 0 1"/>
5 <origin xyz="0 0 0.3"/>
6 </joint>
身体和头部之间的连接是连续的关节,这意味着它可以采用从负无穷大到正无穷大的任意角度。 车轮也这样建模,以便它们可以永远在两个方向上滚动。
我们唯一需要添加的其他信息是旋转轴,此处由xyz三元组指定,该轴指定了头部将围绕其旋转的向量。 因为我们希望它绕z轴运动,所以我们指定矢量“ 0 0 1”。
6.2 夹爪
切换行号显示
1 <joint name="left_gripper_joint" type="revolute">
2 <axis xyz="0 0 1"/>
3 <limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
4 <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
5 <parent link="gripper_pole"/>
6 <child link="left_gripper"/>
7 </joint>
左右抓爪关节均建模为旋转关节。 这意味着它们以与连续关节相同的方式旋转,但是它们具有严格的限制。 因此,我们必须包含limit标签,以指定关节的上限和下限(以弧度为单位)。 我们还必须为此关节指定最大速度和最大力度,但是实际值对我们的目的并不重要。
6.3夹臂
切换行号显示
1 <joint name="gripper_extension" type="prismatic">
2 <parent link="base_link"/>
3 <child link="gripper_pole"/>
4 <limit effort="1000.0" lower="-0.38" upper="0" velocity="0.5"/>
5 <origin rpy="0 0 0" xyz="0.19 0 0.2"/>
6 </joint>
夹臂是另一种关节,即棱柱形关节。 这意味着它沿轴运动,而不是绕轴运动。 这种平移运动使我们的机器人模型可以伸展和缩回其抓臂。
棱柱形臂的极限以与旋转关节相同的方式指定,除了单位是米而非弧度。
6.4 其他类型的关节
还有两种其他关节在太空中移动。 棱柱形接头只能沿一维运动,而平面形接头可以在一个平面或二维中运动。 此外,浮动接头不受限制,并且可以在这三个维度中的任何一个处移动。 这些关节不能仅用一个数字指定,因此本教程中不包括。
6.5 指定姿势
在GUI中四处移动滑块时,模型将在Rviz中移动。 怎么做? 首先,GUI解析URDF,并找到所有非固定关节及其边界。 然后,它使用滑块的值来发布sensor_msgs / JointState消息。 然后,robot_state_publisher使用这些变量来计算不同部分之间的所有转换。 然后将生成的变换树用于显示Rviz中的所有形状。
7.向URDF模型添加物理和碰撞属性
在本教程中,我们将研究如何向URDF模型添加一些基本的物理属性以及如何指定其碰撞属性。
7.1 碰撞
到目前为止,我们仅用单个子元素指定了链接,即视觉元素,该元素定义了机器人的外观(毫不奇怪)。 但是,为了使碰撞检测正常工作或在Gazebo之类的设备中模拟机器人,我们还需要定义一个碰撞元素。 这是具有碰撞和物理特性的新urdf。
这是我们新的基本链接的代码。
切换行号显示
1 <link name="base_link">
2 <visual>
3 <geometry>
4 <cylinder length="0.6" radius="0.2"/>
5 </geometry>
6 <material name="blue">
7 <color rgba="0 0 .8 1"/>
8 </material>
9 </visual>
10 <collision>
11 <geometry>
12 <cylinder length="0.6" radius="0.2"/>
13 </geometry>
14 </collision>
15 </link>
-
冲突元素是链接对象的直接子元素,与可视标签处于同一级别
-
碰撞元素以与视觉元素相同的方式定义其形状,并带有一个几何标签。几何标签的格式在这里与视觉格式完全相同。
-
您还可以使用与碰撞标签的子元素相同的方式指定原点(与视觉标记一样)
在许多情况下,您希望碰撞的几何图形和原点与视觉的几何图形和原点完全相同。但是,在两种主要情况下您不会这样做。
- 更快的处理-与两个简单的几何体相比,对两个网格进行碰撞检测的计算复杂度要高得多。因此,您可能需要在碰撞元素中用更简单的几何形状替换网格。
- 安全区-您可能希望限制移动靠近敏感设备。例如,如果我们不希望任何东西与R2D2的头部碰撞,则可以将碰撞几何定义为圆柱体,将其头部包裹住,以防止任何东西靠近他的头部。
7.2 物理性质
为了使您的模型正确仿真,您需要定义机器人的几个物理属性,即像Gazebo这样的物理引擎所需的属性。
7.2.1 惯性
每个要模拟的链接元素都需要一个惯性标签。 这是一个简单的例子。
切换行号显示
1 <link name="base_link">
2 <visual>
3 <geometry>
4 <cylinder length="0.6" radius="0.2"/>
5 </geometry>
6 <material name="blue">
7 <color rgba="0 0 .8 1"/>
8 </material>
9 </visual>
10 <collision>
11 <geometry>
12 <cylinder length="0.6" radius="0.2"/>
13 </geometry>
14 </collision>
15 <inertial>
16 <mass value="10"/>
17 <inertia ixx="0.4" ixy="0.0" ixz="0.0" iyy="0.4" iyz="0.0" izz="0.2"/>
18 </inertial>
19 </link>
- 此元素也是链接对象的子元素。
- 质量以千克定义。
- 3x3旋转惯量矩阵由惯性元素指定。 由于这是对称的,因此只能由6个元素表示。
ixx ixy ixz
ixy iyy iyz
ixz iyz izz
- 可以通过对诸如MeshLab之类的程序进行建模来提供此信息。可以使用Wikipedia的惯性矩张量列表(在上面的示例中使用)来计算几何图元(圆柱体,盒子,球体)的惯性。
- 惯性张量取决于物体的质量和质量分布。一个好的第一近似方法是假设物体的体积中的质量分布均匀,并根据物体的形状计算惯性张量,如上所述。
- 如果不确定放置什么,则对于中型链接(通常对应于边长0.1 m,质量为0.6 kg的盒子),ixx / iyy / izz = 1e-3或更小的矩阵通常是合理的默认值。虽然经常选择,但单位矩阵是一个特别糟糕的默认值,因为它通常太高(对应于边长为0.1 m且质量为600 kg的盒子!)。
- 您还可以指定一个原点标签,以指定重心和惯性参考系(相对于链接的参考系)。
- 当使用实时控制器时,零(或几乎为零)的惯性元素会导致机器人模型崩溃而不会发出警告,并且所有链接都将以其原点与世界原点一致的方式出现。
7.2.2 接触系数
您还可以定义链接相互接触时的行为。 这是通过碰撞标签的一个名为contact_coefficients的子元素完成的。 有三个属性可以指定:
- mu——摩擦系数
- kp——刚度系数
- kd——阻尼系数
7.2.3 关节动力
关节如何通过关节的动力学标签定义。 这里有两个属性:
- 摩擦-物理静摩擦。 对于棱柱形接头,单位为牛顿。 对于旋转关节,单位为牛顿米。
- 阻尼-物理阻尼值。 对于棱柱形接头,单位是每米牛顿秒。 对于旋转关节,牛顿米每弧度secons。
如果未指定,则这些系数默认为零。
7.3 其他标签
在纯URDF领域(即不包括 Gazebo-specific tags),剩下的两个标签可用于定义关节:校准和安全控制器。 查看spc,因为它们未包含在本教程中。
8.使用Xacro清理URDF文件
到现在为止,如果您在家中按照自己的机器人设计步骤执行所有这些步骤,则可能会厌倦了进行各种数学运算以获得非常简单的机器人描述以正确解析的方法。 幸运的是,您可以使用xacro软件包来简化您的生活。 它做三件事非常有帮助。
- Constants
- Simple Math
- Macros
在本教程中,我们将介绍所有这些快捷方式,以帮助减少URDF文件的整体大小并使其更易于阅读和维护。
8.1 使用Xacro
顾名思义,xacro是一种宏语言。 xacro程序将运行所有宏并输出结果。 典型用法如下所示:
xacro --inorder model.xacro> model.urdf
您还可以在启动文件中自动生成urdf。 这很方便,因为它可以保持最新状态并且不占用硬盘驱动器空间。 但是,生成确实需要时间,因此请注意,启动文件可能需要更长的时间才能启动。
切换行号显示
1 <param name="robot_description"
2 command="xacro --inorder '$(find pr2_description)/robots/pr2.urdf.xacro'" />
在URDF文件的顶部,必须指定名称空间,以便文件能够正确解析。 例如,以下是有效的xacro文件的前两行:
切换行号显示
1 <?xml version="1.0"?>
2 <robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">
8.2 Constants
让我们快速浏览一下R2D2中的base_link。
切换行号显示
1 <link name="base_link">
2 <visual>
3 <geometry>
4 <cylinder length="0.6" radius="0.2"/>
5 </geometry>
6 <material name="blue"/>
7 </visual>
8 <collision>
9 <geometry>
10 <cylinder length="0.6" radius="0.2"/>
11 </geometry>
12 </collision>
13 </link>
这里的信息有点多余。 我们指定圆柱体的长度和半径两次。 更糟糕的是,如果我们想更改它,我们需要在两个不同的地方进行更改。
幸运的是,xacro允许您指定用作常量的属性。 相反,我们可以编写以上代码。
切换行号显示
1 <xacro:property name="width" value="0.2" />
2 <xacro:property name="bodylen" value="0.6" />
3 <link name="base_link">
4 <visual>
5 <geometry>
6 <cylinder radius="${width}" length="${bodylen}"/>
7 </geometry>
8 <material name="blue"/>
9 </visual>
10 <collision>
11 <geometry>
12 <cylinder radius="${width}" length="${bodylen}"/>
13 </geometry>
14 </collision>
15 </link>
-
这两个值在前两行中指定。 在使用它们之前或之后,可以在任何位置,任何级别(假定有效的XML)对其进行定义。 通常他们排在最前面。
-
我们没有在几何元素中指定实际半径,而是使用美元符号和大括号来表示值。
-
该代码将生成上面显示的相同代码。
然后,使用$ {}构造的内容值替换$ {}。 这意味着您可以将其与属性中的其他文本组合。
切换行号显示
1 <xacro:property name=”robotname” value=”marvin” />
2 <link name=”${robotname}s_leg” />
这将产生
切换行号显示
1 <link name=”marvins_leg” />
但是,$ {}中的内容不必只是一个属性,这使我们进入了下一个观点…
8.3 Math
您可以使用四个基本运算符(+,-,*,/),一元减号和括号在$ {}构造中构建任意复杂的表达式。 例子:
切换行号显示
1 <cylinder radius="${wheeldiam/2}" length="0.1"/>
2 <origin xyz="${reflect*(width+.02)} 0 0.25" />
所有的数学运算都是使用浮点数完成的,因此
切换行号显示
1 <link name="${5/6}"/>
评估为:
切换行号显示
1 <link name="0.833333333333"/>
8.4 Macros
这是xacro软件包最大,最有用的组件。
8.4.1 Simple Macro
让我们看一个简单的无用的macro。
切换行号显示
1 <xacro:macro name="default_origin">
2 <origin xyz="0 0 0" rpy="0 0 0"/>
3 </xacro:macro>
4 <xacro:default_origin />
(这是没有用的,因为如果未指定原点,则它具有与此相同的值。)此代码将生成以下内容。
切换行号显示
1 <origin rpy="0 0 0" xyz="0 0 0"/>
- 从技术上讲,该名称不是必需的元素,但是您需要指定该名称才能使用它。
- <xacro:$ NAME />的每个实例都被xacro:macro标记的内容替换。
- 请注意,即使其不完全相同(两个属性具有切换顺序),生成的XML也是等效的。
- 如果未找到具有指定名称的xacro,则它将不会扩展并且不会产生错误。
8.4.2 参数化 Macro
您还可以参数化宏,以使它们不会每次都生成完全相同的文本。 与数学功能结合使用时,它的功能更加强大。
首先,让我们以R2D2中使用的简单宏为例。
切换行号显示
1 <xacro:macro name="default_inertial" params="mass">
2 <inertial>
3 <mass value="${mass}" />
4 <inertia ixx="1.0" ixy="0.0" ixz="0.0"
5 iyy="1.0" iyz="0.0"
6 izz="1.0" />
7 </inertial>
8 </xacro:macro>
可以与代码一起使用
切换行号显示
1 <xacro:default_inertial mass="10"/>
参数的行为就像属性一样,您可以在表达式中使用它们
您也可以将整个块用作参数。
切换行号显示
1 <xacro:macro name="blue_shape" params="name *shape">
2 <link name="${name}">
3 <visual>
4 <geometry>
5 <xacro:insert_block name="shape" />
6 </geometry>
7 <material name="blue"/>
8 </visual>
9 <collision>
10 <geometry>
11 <xacro:insert_block name="shape" />
12 </geometry>
13 </collision>
14 </link>
15 </xacro:macro>
16
17 <xacro:blue_shape name="base_link">
18 <cylinder radius=".42" length=".01" />
19 </xacro:blue_shape>
- 要指定块参数,请在其参数名称前添加星号。
- 可以使用insert_block命令插入一个块
- 任意插入块。
8.5 实际使用
xacro语言在允许您执行操作时非常灵活。 除了上面显示的默认惯性宏以外,还有一些在R2D2模型中使用xacro的有用方法。
要查看xacro文件生成的模型,请运行与以前的教程相同的命令:
roslaunch urdf_tutorial display.launch model:= '$(find urdf_tutorial)/urdf/08-macroed.urdf.xacro'
(启动文件一直在运行xacro命令,但是由于没有宏要扩展,所以没关系)
8.5.1 Leg macro
通常,您想在不同位置创建多个外观相似的对象。 通常,这些位置会有些对称。 您可以使用宏和一些简单的数学运算来减少必须编写的代码量,就像R2的两条腿一样。
切换行号显示
1 <xacro:macro name="leg" params="prefix reflect">
2 <link name="${prefix}_leg">
3 <visual>
4 <geometry>
5 <box size="${leglen} 0.1 0.2"/>
6 </geometry>
7 <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
8 <material name="white"/>
9 </visual>
10 <collision>
11 <geometry>
12 <box size="${leglen} 0.1 0.2"/>
13 </geometry>
14 <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
15 </collision>
16 <xacro:default_inertial mass="10"/>
17 </link>
18
19 <joint name="base_to_${prefix}_leg" type="fixed">
20 <parent link="base_link"/>
21 <child link="${prefix}_leg"/>
22 <origin xyz="0 ${reflect*(width+.02)} 0.25" />
23 </joint>
24 <!-- A bunch of stuff cut -->
25 </xacro:macro>
26 <xacro:leg prefix="right" reflect="1" />
27 <xacro:leg prefix="left" reflect="-1" />
- 通用技巧1:使用名称prefix获取两个名称相似的对象
- 通用技巧2:使用数学计算关节原点。 如果您更改了机器人的大小,则可以通过一些数学运算来更改属性以计算关节偏移,这将省去很多麻烦。
- 通用技巧3:使用反射参数并将其设置为1或-1。 了解我们如何使用reflect参数将腿放在base_to _ $ {prefix} _leg起点的身体的两侧。
8.5.2 Other tricks
随时在此处添加您自己的技巧。
9.在Gazebo中使用URDF
请从github或使用aptitude下载URDF模拟教程,即用于ROS melodic:
sudo apt-get install ros-melodic-urdf-sim-tutorial
9.1 无功能的Gazebo接口
我们可以使用gazebo.launch将已经创建的模型生成到Gazebo中:
roslaunch urdf_sim_tutorial gazebo.launch
这个启动文件
-
将宏教程中的urdf加载到参数描述中(如前所述)
-
启动一个空的Gazebo世界
-
运行脚本以从参数读取urdf并将其生成在Gazebo中。
-
默认情况下,Gazebo gui也将显示,如下所示:
注意:如果直接从git下载软件包,请创建一个工作区并将这两个文件夹放在$ your work space folder / src下,并使用catkin_make命令进行编译。
但是,它无能为力,并且缺少ROS使用此机器人所需的许多关键信息。 以前,我们一直使用joint_state_publisher来指定每个关节的姿势。 但是,机器人本身应在现实世界或Gazebo中提供该信息。 但是,如果不指定具体信息,Gazebo不知道要发布这些信息。
为了使机器人能够与您和ROS进行交互,我们需要指定两件事:插件和传输。(Plugins and Transmissions)
9.2 Gazebo Plugin(插件)
为了使ROS与Gazebo进行交互,我们必须动态链接到ROS库,该库将告诉Gazebo该怎么做。 从理论上讲,这允许其他机器人操作系统以通用方式与Gazebo进行交互。 实际上,它只是ROS。
要链接Gazebo和ROS,我们在UR </ robot>标记之前指定URDF中的插件:
切换行号显示
1 <gazebo>
2 <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
3 <robotNamespace>/</robotNamespace>
4 </plugin>
5 </gazebo>
您可以在https://github.com/ros/urdf_sim_tutorial/blob/master/urdf/09-publishjoints.urdf.xacro并运行:
roslaunch urdf_sim_tutorial gazebo.launch model:='$(find urdf_sim_tutorial)/urdf/09-publishjoints.urdf.xacro'
但是,这不会做任何新的事情。 为此,我们需要在URDF之外指定更多信息。
9.3 生成控制器
现在我们已经将ROS和Gazebo链接起来,我们需要指定要在Gazebo中运行的ROS代码的一些位,我们通常将其称为控制器。 这些最初被加载到ROS参数空间中。 我们有一个yaml文件joints.yaml,它指定了我们的第一个控制器。
type: "joint_state_controller/JointStateController"
publish_rate: 50
该控制器位于joint_state_controller程序包中,可直接从Gazebo将机器人关节的状态发布到ROS中。在09-joints.launch中,您可以看到如何将这个yaml文件加载到r2d2_joint_state_controller命名空间中。 然后,我们使用该名称空间调用controller_manager / spawner`脚本,将其加载到Gazebo中。您可以启动它,但是它仍然还不够。
roslaunch urdf_sim_tutorial 09-joints.launch
这将运行控制器,并实际上在/ joint_states主题上发布…但其中没有任何内容。
header:
seq: 652
stamp:
secs: 13
nsecs: 331000000
frame_id: ''
name: []
position: []
velocity: []
effort: []
您还想要Gazebo吗? 好吧,它想知道要发布有关哪些关节的信息。
9.4 Transmissions
对于每个非固定关节,我们都需要指定一种传输方式,该方式告诉Gazebo如何处理关节。 让我们从头部关节开始。 将以下内容添加到您的URDF中:
切换行号显示
1 <transmission name="head_swivel_trans">
2 <type>transmission_interface/SimpleTransmission</type>
3 <actuator name="$head_swivel_motor">
4 <mechanicalReduction>1</mechanicalReduction>
5 </actuator>
6 <joint name="head_swivel">
7 <hardwareInterface>PositionJointInterface</hardwareInterface>
8 </joint>
9 </transmission>
- 为了介绍起见,只需将大部分代码视为样板即可。
- 首先要注意的是关节元素。 名称应与先前声明的关节匹配。
- 当我们探索插件时,hardwareInterface将很重要。
您可以使用我们先前的启动配置来运行此URDF。
roslaunch urdf_sim_tutorial 09-joints.launch model:='$(find urdf_sim_tutorial)/urdf/10-firsttransmission.urdf.xacro '
现在,因为在joint_states消息中列出了头部关节,所以头部可以在RViz中正确显示。
header:
seq: 220
stamp:
secs: 4
nsecs: 707000000
frame_id: ''
name: ['head_swivel']
position: [-2.9051283156888985e-08]
velocity: [7.575990694887896e-06]
effort: [0.0]
我们可以继续为所有非固定关节添加变速箱(并且我们将这样做),以便所有关节均已正确发布。 但是,生活不仅限于看机器人。 我们要控制它们。 因此,让我们在这里获得另一个控制器。
9.5 关节控制
这是我们要添加的下一个控制器配置。
type: "position_controllers/JointPositionController"
joint: head_swivel
这指定使用position_controllers包中的JointPositionController来控制head_swivel传输。 请注意,此接口的URDF中的硬件接口与控制器类型匹配。
现在,我们可以像roslaunch urdf_sim_tutorial 10-head.launch
之前那样使用添加的配置启动它。
现在,Gazebo已订阅了一个新主题,然后您可以通过在ROS中发布一个值来控制头部的位置。 rostopic pub / r2d2_head_controller / command std_msgs / Float64“ data:-0.707”
发布此命令后,位置将立即更改为指定值。 这是因为我们没有在urdf中指定关节的任何限制。 但是,如果更改关节,它将逐渐移动。
切换行号显示
1 <joint name="head_swivel" type="continuous">
2 <parent link="base_link"/>
3 <child link="head"/>
4 <axis xyz="0 0 1"/>
5 <origin xyz="0 0 ${bodylen/2}"/>
6 <limit effort="30" velocity="1.0"/>
7 </joint>
roslaunch urdf_sim_tutorial 10-head.launch model:='$(find urdf_sim_tutorial)/urdf/11-limittransmission.urdf.xacro'
9.6 Another Controller
我们可以以类似的方式更改夹爪接头的URDF。 但是,我们可能希望将它们分组在一起,而不是用其自己的ROS主题单独控制抓爪的每个关节。 为此,我们只需要在ROS参数中指定其他控制器即可。
type: "position_controllers/JointGroupPositionController"
joints:
- gripper_extension
- left_gripper_joint
- right_gripper_joint
要启动此程序:
roslaunch urdf_sim_tutorial 12-gripper.launch
这样,我们可以改为使用浮点数数组指定位置。 打开和退出:
rostopic pub /r2d2_gripper_controller/command std_msgs/Float64MultiArray "layout:
dim:
- label: ''
size: 3
stride: 1
data_offset: 0
data: [0, 0.5, 0.5]"
关闭和缩回:
rostopic pub /r2d2_gripper_controller/command std_msgs/Float64MultiArray "layout:
dim:
- label: ''
size: 3
stride: 1
data_offset: 0
data: [-0.4, 0, 0]"
9.7 The Wheels on the Droid Go Round and Round
为了驱动机器人,我们从车轮宏中为每个车轮指定了另一个传动装置。
切换行号显示
1 <transmission name="${prefix}_${suffix}_wheel_trans">
2 <type>transmission_interface/SimpleTransmission</type>
3 <actuator name="${prefix}_${suffix}_wheel_motor">
4 <mechanicalReduction>1</mechanicalReduction>
5 </actuator>
6 <joint name="${prefix}_${suffix}_wheel_joint">
7 <hardwareInterface>VelocityJointInterface</hardwareInterface>
8 </joint>
9 </transmission>
就像其他传输一样,除了
- 它使用宏参数指定名称
- 它使用VelocityJointInterface。
由于车轮实际上将要接触地面并因此与地面进行物理交互,因此我们还指定了一些有关车轮材料的附加信息。
切换行号显示
1 <gazebo reference="${prefix}_${suffix}_wheel">
2 <mu1 value="200.0"/>
3 <mu2 value="100.0"/>
4 <kp value="10000000.0" />
5 <kd value="1.0" />
6 <material>Gazebo/Grey</material>
7 </gazebo>
有关更多详细信息,请参见http://gazebosim.org/tutorials/?tut=ros_urdf。
我们可以为每个单独的车轮指定控制器,但是这样做的乐趣何在? 相反,我们想一起控制所有轮子。 为此,我们将需要更多的ROS参数。
type: "diff_drive_controller/DiffDriveController"
publish_rate: 50
left_wheel: ['left_front_wheel_joint', 'left_back_wheel_joint']
right_wheel: ['right_front_wheel_joint', 'right_back_wheel_joint']
wheel_separation: 0.44
# Odometry covariances for the encoder output of the robot. These values should
# be tuned to your robot's sample odometry data, but these values are a good place
# to start
pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]
twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]
# Top level frame (link) of the robot description
base_frame_id: base_link
# Velocity and acceleration limits for the robot
linear:
x:
has_velocity_limits : true
max_velocity : 0.2 # m/s
has_acceleration_limits: true
max_acceleration : 0.6 # m/s^2
angular:
z:
has_velocity_limits : true
max_velocity : 2.0 # rad/s
has_acceleration_limits: true
max_acceleration : 6.0 # rad/s^2
DiffDriveController订阅标准的Twist cmd_vel消息,并相应地移动机器人。
roslaunch urdf_sim_tutorial 13-diffdrive.launch
除了加载上述配置之外,这还会打开RobotSteering面板,使您可以绕开R2D2机器人,同时观察其实际行为(在Gazebo中)和可视化行为(在RViz中):