作为第一个模拟机器人, 我们先来构建一个简单的双轮机器人.
使用URDF(Unified Robot Description Format)格式的文件来描述所模拟机器人的主要部分. rviz与gazebo 可以读取URDF类型文件. rviz是一个可视化工具, 可以展示URDF文件中所模拟的机器人. 而gazebo是一个模拟器, 在gazebo中可以研究模拟机器人在特定的模拟环境中的物理性质.
在这章中,我们会讨论以下几点内容:
- rviz介绍与基本操作
- URDF的构建与使用
- gazebo的介绍与基本操作
- 修改URDF
- 核查URDF与SDF文件
- 让机器人在gazebo中动起来
Rviz
Rviz(Ros visualization) 是一个强大的3D可视化工具,它可展示机器模型, 记录, 回放传感器信息.有助于研究人员进行调试.
启动:
roscore
rosrun rviz rviz
控制:
- 鼠标左键:单击并拖动以围绕焦点旋转。
- 鼠标滚轮(如果有的话):单击并拖动以移动焦点在由相机的上下矢量形成的平面上。 (Shift键和 鼠标左键组合也会调用此模式。)
- 鼠标右键:单击并拖动以放大/缩小焦点。上下拖动可放大缩小。 (滚轮还会调用此模式。)
URDF
URDF文件其实就是是一种XML格式文件,只是专门用于定义,表示机器人模型。 在复杂的机器人系统上,这些URDF文件可能会变得冗长且繁琐。 Xacro(XML宏)是一种XML宏语言,其创建目的是使这些机器人描述文件更易于阅读和维护。 Xacro可帮助您减少文件内信息的重复.
URDF使用两个基本组件(link与joint)以树结构的方式来定义,描述机器人模型。 link组件通过其物理属性(尺寸,其原点位置,颜色等)来描述刚体。 link通过joint组件连接在一起。 joint组件描述了连接的运动学和动力学特性(即,连接起来的link,joint的类型,旋转轴,摩擦和阻尼的量,等等)。
在 practice2
包中创建名为urdf
的文件夹,然后在其中建立一个dd_robot.urdf
文件:
<?xml version="1.0" encoding="utf-8" ?>
<robot name = 'dd_robot'>
<!-- Base Link -->
<link name = 'base_link'>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size ="0.5 0.5 0.25"/>
</geometry>
</visual>
</link>
</robot>
在这个文件中描述了一个非常简单的机器人, 这个机器人只包含一个部分(一个link,名为base_link),其可见部分是个长0.5米,宽0.5米,高0.25米的方体. 其初始位置在模拟环境的正中央即原点(0, 0, 0).
尽管非常简单,我们也要在rviz里面展示一下, 为方便,我们首先写一个.launch
文件(放在lauch文件夹中):
<launch>
<!-- values passed by command line input -->
<arg name="model" />
<arg name="gui" default="False" />
<!-- set these parameters on Parameter Server -->
<param name="robot_description" textfile="$(find pracetice2)/urdf/$(arg model)" />
<param name="use_gui" value="$(arg gui)"/>
<!-- Start 3 nodes: joint_state_publisher, robot_state_publisher and rviz -->
<node 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 $(find pracetice2)/urdf.rviz" required="true" />
<!-- (required = "true") if rviz dies, entire roslaunch will be killed -->
</launch>
使用如下命名执行:
roslaunch pracetice2 ddrobot_rviz.launch model:=dd_robot.urdf
此时会弹出rviz的窗口,不过刚刚构建的方体应该还没有展示在窗口内,需要手动添加:
•选择“Display”面板下的“Add”按钮(左下角)并添加 RobotModel;
•选择“Display”面板下的“Add”按钮并添加 TF;
•修改“Fixed Frame”的值为"base_link"(在“ Global Options”下,其默认值为“map”).
Fixed Frame
是网格中心所在的转换框架(transform frame);- 在URDF文件中的
<origin>
标签定义了base_link即方体的初始位置.
单单一个方体很难动起来的, 我们可以加上两人个轮子. 同样的两个轮子在URDF文件中也是用link
来表示,不过在两个有关联的部分(link
)之间需要使用joint
来描述其二者关系. joint
可以定义其自身是可活动的还是固定的. 有六种joint
类型可供选择:
Fixed
: 没有自由度,单纯地将两个link
连接起来;Revolute
: 可绕一个轴旋转,其活动角度受限;Continuous
可绕一个轴旋转,没有角度限制;Floating
可在任意角度活动;Planar
可在垂直于轴的平面内运动。
为方体加上轮子,轮子与方体之间的joint
的类型使用`continuous:
<?xml version='1.0' encoding="utf-8" ?>
<robot name="dd_robot">
<!-- Base Link -->
<link name="base_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</visual>
</link>
<!-- Right Wheel -->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2" />
</geometry>
</visual>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0" />
<axis xyz="0 1 0" />
</joint>
<!-- Left Wheel -->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2" />
</geometry>
</visual>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0" />
<axis xyz="0 1 0" />
</joint>
</robot>
- 每个轮子在视觉上都定义为半径为0.2米,长度为0.1米的圆柱体。 轮子的视觉原点定义了视觉元素相对于其原点的中心位置。 每个车轮的原点位于(0,0,0),并绕x轴旋转1.560795弧度(= pi / 2 = 90度);
joint
是根据父link和孩子link定义的。URDF文件最终是具有一个根link的树结构。base_link
link
是我们机器人的根link
,车轮的位置取决于base_link的位置.
为保证这个机器人底盘平衡,可以再加上一个滚轮, 这个滚轮在地面上滑动,不用加入joint
,而只将其视为底盘(base_link
)的一部分(故其位置应在base_link
内部), 在原文件上加上下面代码,并命名dd_robot3.urdf
:
<?xml version='1.0'?>
<robot name="dd_robot">
<!-- Base Link -->
...
<!-- Caster -->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0" />
<geometry>
<sphere radius="0.05" />
</geometry>
</visual>
</link>
<!-- Right Wheel -->
...
<!-- Left Wheel -->
...
</robot>
执行:
roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot3.urdf
上面的展示都将机器人涂成红色, 这样对于区分各个部分来说不是很友好,好在我们可以为不同部分涂上不同颜色:
<?xml version='1.0'?>
<robot name="dd_robot">
<!-- Base Link -->
...
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
<!-- Caster -->
...
</link>
<!-- Right Wheel -->
<link name="right_wheel">
<visual>
...
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
</link>
...
<!-- Left Wheel -->
<link name="left_wheel">
<visual>
...
<material name="black"/>
</visual>
</link>
...
</robot>
命名dd_robot4.urdf
放在URDF
文件夹内,然后执行:
roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot4.urdf
- 在
<material>
标签中,可以定义<color>
即颜色,<color>
标签有四分参数:红/绿/蓝/透明度
(ragba), 参数取值范围都是[0,1]
, 当一个<color>
标签设定好之后,我们可以根据其name
反复调用, 如上面名为black
的color标签,其在右轮被定义之后,在左轮中即可直接使用,而不需要再为其设定参数.
接下来,我们将<collision>
属性添加到每个<link>
元素中。 即使我们已经定义了元素的视觉属性,Gazebo的碰撞检测引擎仍会使用碰撞属性来识别对象的边界。 如果对象具有复杂的视觉属性(例如网格),则应定义简化的碰撞属性,以提高碰撞检测性能。
<?xml version='1.0'?>
<robot name="dd_robot">
<!-- Base Link -->
...
<!-- Base collision -->
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</collision>
<!-- Caster -->
...
<!-- Caster collision -->
<collision>
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</collision>
</link>
<!-- Right Wheel -->
<link name="right_wheel">
...
<!-- Right Wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
...
<!-- Left Wheel -->
<link name="left_wheel">
...
<!-- Left Wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0"/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
...
</robot>
加入<collisioin>
属性不会在视觉上有什么变化,暂不展示了.
一个非常简单的机器小车基本完成, 现在可以控制两个轮子与底盘相连的joint
让小车动起来. 在ddrobot_rviz.launch
中,启动了三个ROS节点:joint_state_publisher
,robot_state_publisher
和rviz。 joint_state_publisher
节点查找所有非固定joint
,并发布定义了所有这些joint
的JointState消息。 到目前为止,JointState消息中的值是恒定的,以防止车轮旋转。 我们在rviz中调出一个GUI界面来更改每个JointState的值,并观察车轮旋转。
可能您已经发现在ddrobot_rviz.launch
中有一个use_gui
的参数,默认是False
, 将共值设置成True
即可:
roslaunch pracetice2 ddrobot_rviz.launch model:=dd_robot5.urdf gui:=True
哈,仔细看,轮子是在动的,比如每点一下randomize
轮子就会变换一个角度,轮子上面的点有助于你发现变化,别急.
要让URDF文件可以在Gazebo中运行,需要加入如质量与惯性等物理性质.<mass>
定义质量,以kilogram
为单位, <inertia>
定义惯性,其用一3x3的矩阵来定义,因其是对称阵,其实只需6个值即可
ixx | ixy | ixz |
---|---|---|
ixy | iyy | iyz |
ixz | iyz | izz |
<?xml version='1.0'?>
<robot name="dd_robot">
<!-- Base Link -->
<link name="base_link">
...
<!-- Base collision, mass and inertia -->
...
<inertial>
<mass value="5"/>
<inertia ixx="0.13" ixy="0.0" ixz="0.0" iyy="0.21" iyz="0.0" izz="0.13"/>
</inertial>
<!-- Caster -->
...
<!-- Caster collision, mass and inertia -->
...
<inertial>
<mass value="0.5"/>
<inertia ixx="0.0001" ixy="0.0" ixz="0.0" iyy="0.0001" iyz="0.0" izz="0.0001"/>
</inertial>
</link>
<!-- Right Wheel -->
<link name="right_wheel">
...
<!-- Right Wheel collision, mass and inertia -->
...
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
<!-- Left Wheel -->
<link name="left_wheel">
...
<!-- Left Wheel collision, mass and inertia -->
...
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
</robot>
同样地,加上质量与惯性,机器人在外观上没有任何变化,也暂不展示了.
ROS提供了command-line
工具来核查与可视化URDF文件信息(cd 到 urdf文件夹):
check_urdf dd_robot6.urdf
出现以上信息说明是正确的.
urdf_to_graphiz
可以根据urdf文件创建一个graphviz可用格式的表格及一个pdf格式的表格(cd 到 urdf文件夹):
urdf_to_graphiz dd_robot6.urdf
会生成Created file dd_robot.gv
与Created file dd_robot.pdf
两人份文件,其中.pdf
文件中的图表如下:
除了上面说的一些物理性质,还需要对URDF文件进行一些修改,以添加特定的用于仿真的标签,以使其在Gazebo中正常运行。 Gazebo使用类似于URDF的SDF,但是通过添加特定的Gazebo信息,我们可以将dd_robot模型文件转换为SDF类型的格式。
需要将<gaezbo>
这个标签加入到URDF文件中, 其有参数reference
, reference
的值是某个link
的名字,其默认为整个模型.下面这些标签需要加在之前URDF文件(只需在</robot>
之前即可)中:
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="right_wheel">
<material>Gazebo/Black</material>
</gazebo>
<gazebo reference="left_wheel">
<material>Gazebo/Black</material>
</gazebo>
如没有明确的指定,Gazebo不会使用riviz中使用的<visual>
与<collision>
属性.然后将文件保存成.gazebo
的格式. 可以使用如下命令来检查文件是否正确.
gz sdf -p dd_robot.gazebo
此命令将打印完整的sdf文件.
我们可以使用.launch
文件在Gazebo中运行机器人.
<launch>
<!-- We resume the logic in gazebo_ros package empty_world.launch, -->
<!-- changing only the name of the world to be launched -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find pracetice2)/urdf/ddrobot.world"/>
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
</include>
<!-- Spawn dd_robot into Gazebo -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" output="screen"
args="-file $(find pracetice2)/urdf/dd_robot.gazebo -urdf -model ddrobot"/>
</launch>
为使用机器人跑起来,我们需为它提供一个环境:
<?xml version="1.0" ?>
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>-3.0 0 0 0 0 0</pose>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>3.0 0 0 0 0 0</pose>
</include>
</world>
</sdf>
执行:
roslaunch pracetice2 ddrobot_gazebo.launch