ROS 第三讲 在模拟器中构建第一个机器人

  • [ ] todo: origin的翻译

目录

作为第一个模拟机器人, 我们先来构建一个简单的双轮机器人.

使用URDF(Unified Robot Description Format)格式的文件来描述所模拟机器人的主要部分. rviz与gazebo 可以读取URDF类型文件. rviz是一个可视化工具, 可以展示URDF文件中所模拟的机器人. 而gazebo是一个模拟器, 在gazebo中可以研究模拟机器人在特定的模拟环境中的物理性质.

在这章中,我们会讨论以下几点内容:

  1. rviz介绍与基本操作
  2. URDF的构建与使用
  3. gazebo的介绍与基本操作
  4. 修改URDF
  5. 核查URDF与SDF文件
  6. 让机器人在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的类型,旋转轴,摩擦和阻尼的量,等等)。

sample 包中创建名为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 sample)/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 sample)/urdf.rviz" required="true" />
   <!-- (required = "true") if rviz dies, entire roslaunch will be killed -->
</launch>

使用如下命名执行:

roslaunch sample ddrobot_rviz.launch model:=dd_robot.urdf

此时会弹出rviz的窗口,不过刚刚构建的方体应该还没有展示在窗口内,需要手动添加:

•选择“Display”面板下的“Add”按钮(左下角)并添加 RobotModel;
•选择“Display”面板下的“Add”按钮并添加 TF;
•修改“Fixed Frame”的值为"base_link"(在“ Global Options”下,其默认值为“map”).

ROS 第三讲  在模拟器中构建第一个机器人

  • 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>

ROS 第三讲  在模拟器中构建第一个机器人

  • 每个*在视觉上都定义为半径为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

ROS 第三讲  在模拟器中构建第一个机器人

上面的展示都将机器人涂成红色, 这样对于区分各个部分来说不是很友好,好在我们可以为不同部分涂上不同颜色:

<?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

ROS 第三讲  在模拟器中构建第一个机器人

  • <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_publisherrobot_state_publisher和rviz。 joint_state_publisher节点查找所有非固定joint,并发布定义了所有这些joint的JointState消息。 到目前为止,JointState消息中的值是恒定的,以防止车轮旋转。 我们在rviz中调出一个GUI界面来更改每个JointState的值,并观察车轮旋转。

可能您已经发现在ddrobot_rviz.launch中有一个use_gui的参数,默认是False, 将共值设置成True即可:

roslaunch sample 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

ROS 第三讲  在模拟器中构建第一个机器人

出现以上信息说明是正确的.

urdf_to_graphiz 可以根据urdf文件创建一个graphviz可用格式的表格及一个pdf格式的表格(cd 到 urdf文件夹):

urdf_to_graphiz dd_robot6.urdf

会生成Created file dd_robot.gvCreated file dd_robot.pdf 两人份文件,其中.pdf文件中的图表如下:

ROS 第三讲  在模拟器中构建第一个机器人

除了上面说的一些物理性质,还需要对URDF文件进行一些修改,以添加特定的用于仿真的标签,以使其在Gazebo中正常运行。 Gazebo使用类似于URDF的SDF,但是通过添加特定的Gazebo信息,我们可以将dd_robot模型文件转换为SDF类型的格式。

  • [ ] Gazebo 介绍信息

需要将<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 sample)/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 sample)/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 sample ddrobot_gazebo.launch
上一篇:locobot快速使用


下一篇:【古月居ROS21讲】17 机器人中的坐标变化