ROS Efficient Advanced Chapter 2-Take differential wheeled robot as an example to learn URDF robot modeling and xacro optimization

1 resource

This article is the second chapter of ROS Efficient Advanced. We use URDF language (xml format) to make a differential wheeled robot model, and use the enhanced version of URDF xacro to perform secondary optimization on the robot model file.
Differential wheel robot: The two-wheel differential chassis consists of two power wheels located on the left and right sides of the chassis. The two wheels independently control the speed, and the steering control of the chassis is realized by giving different speeds. Generally, it will be equipped with one or two universal wheels for auxiliary support.
In this modeling, no algorithm is introduced, only the appearance of the robot model is made, so only rivz is used for visual display.
References for this article:
(0) Two-wheel differential robot kinematics model
(1) Chapter 5 and Chapter 6 of "ROS Robot Development Practice" Hu Chunxu (
2) ROS Exploration Summary: Interpretation of URDF
(3) ROS Exploration Summary: How to start from zero Create a robot model (robot arm)
(4) ROS Efficient Advanced Chapter 1 – rviz of ROS Advanced Components

2 text

2.1 Definition and composition of robots

(1) Definition of robot: A robot is an automated machine. The difference is that this machine has some intelligent abilities similar to humans or creatures, such as perception, planning, action, and coordination. It is an advanced Automated machines for flexibility.
Currently, self-driving cars are also considered a type of robot.
(2) Composition of robots: Robots are usually divided into four parts, namely actuators, drive systems, sensing systems and control systems.
Taking self-driving cars as an example, the actuator is the accelerator, steering and brake; the driving system is the motor; the sensing system is various sensors: lidar, radar, camera, uss, imu, GNSS; the control system is the intelligent driving algorithm system: perception , positioning, planning and control.
(3) The control loops of the four major parts of the robot are roughly as shown in the figure:
insert image description here

2.2 URDF modeling routine

(1) URDF: Unified Robot Description Format, a unified robot description file format. urdf files use xml format.
(2) Using urdf to describe the robot, the routine is as follows: each robot is composed of multiple links (connecting rods) and joints (joints). The link and joint here are very broad, and the shapes are not necessarily rods and axes. For example, a table, tabletop and legs are all links, and the joints are fixed joints.

<?xml version="1.0" ?>
<robot name="name of robot">
	<link> ... </link>
	<joint> ... </joint>
	...
</robot>

insert image description here
(3) link: Describe the appearance and physical properties of a rigid body part of the robot. Appearance includes: size, color, shape. Physical properties include: inertia matrix (inertial matrix) and collision parameters (collision properties). In robot modeling, each link is a coordinate system.
The following is the modeling of the differential wheel robot chassis, which is generally called base.

  <link name="base_link">
  	// visual 标签就是外观
    <visual>
      // base_link本身是个坐标系,这也是差速轮式机器人各组成部分的根坐标系,一般会把他的坐标原点设置在rviz的中心处
      // origin表示底盘在其base_link坐标系下的原始位置和旋转状态
      // xyz表示底盘质心在base_link坐标系的偏移位置,rpy(roll,pitch,yaw)是底盘绕base_link的x,y,z三个轴的旋转值
      <origin xyz="0 0 0" rpy="0 0 0"/>
      // geometry是物体几何外形
      <geometry>
      	// 这里的底盘,用圆柱体表示,length值为高度,radius是半径值
        <cylinder length="0.16" radius="0.2"/>
      </geometry>
      // material是材料,这里指定底盘颜色为红色,rgba是三色+透明度表示法,三色的范围是0~1,而不是0-255
      <material name="red">
        <color rgba="1 0 0 1"/>
      </material>
    </visual>
  </link>

Supplement: Here we only do appearance modeling, so we don't involve physical attribute configuration for the time being. When simulating on gazebo in the next chapter, we will add physical attributes to the link in the sample.
(4) joint: Describes the relationship between two links, including kinematics and dynamics attributes. Here we only focus on kinematics attributes. Usually, the relationship between two links is generally divided into six types:

continuous:旋转关节,可以围绕单轴360度无限旋转,比如轮子的轴
revolute:旋转关节,但是有旋转角度的范围限制,比如钟摆
prismatic:滑动关节,也叫活塞关节,沿某一轴线移动的关节,有位置限制,强调一维,比如打气筒
planar:平面关节,允许在平面正交方向上平移或旋转,强调平面,比如抽屉内外滑动
floating:浮动关节,允许进行平移和旋转运动,比如人体的肩关节
fixed:固定关节,比如桌子腿和桌面

The following is an example of the joint between the driving wheel and the chassis of the differential wheel robot:

  // joint标签就是关节,type表示链接关系
  <joint name="left_wheel_joint" type="continuous">
    // origin表示轮子在base_link坐标系下的偏移和旋转
    <origin xyz="0 0.19 -0.05" rpy="0 0 0" />
    // 根link是底盘,子link是轮子
    <parent link="base_link" />
    <child link="left_wheel_link" />
    // axis描述的轮子相对于其自身坐标系的 y 轴旋转,=
    <axis xyz="0 1 0" />
  </joint>
  
  // 这是轮子link
  <link name="left_wheel_link">
    <visual>
      // 轮子相当于其x轴,旋转90度,也就是立起来
      <origin xyz="0 0 0" rpy="1.5707 0 0"/>
      <geometry>
        <cylinder length="0.06" radius="0.06"/>
      </geometry>
      <material name="white">
        <color rgba="1 1 1 0.9"/>
      </material>
    </visual>
  </link>

2.3 Use URDF to make a differential wheeled robot model

(1) Create the mbot_description package and related files

cd ~/catkin_ws/src
catkin_create_pkg mbot_description urdf xacro

cd mbot_description 
mkdir -p config doc launch meshes urdf/sensor
touch launch/display_mbot_urdf.launch launch/display_mbot_xacro.launch
touch urdf/mbot_base.urdf urdf/mbot_base.xacro
touch urdf/sensor/camera.xacro urdf/sensor/kinect.xacro urdf/sensor/laser.xacro

(2) mbot_base.urdf: This is the entire mbot modeling file, including the chassis, two power wheels, two universal wheels, a camera, a kinect (depth camera), and a lidar. For the specific grammar, refer to the introduction in the previous section, so I won't repeat it here.

<?xml version="1.0" ?>
<robot name="mbot">

  <link name="base_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <cylinder length="0.16" radius="0.2"/>
      </geometry>
      <material name="red">
        <color rgba="1 0 0 1"/>
      </material>
    </visual>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <origin xyz="0 0.19 -0.05" rpy="0 0 0" />
    <parent link="base_link" />
    <child link="left_wheel_link" />
    <axis xyz="0 1 0" />
  </joint>

  <link name="left_wheel_link">
    <visual>
      <origin xyz="0 0 0" rpy="1.5707 0 0"/>
      <geometry>
        <cylinder length="0.06" radius="0.06"/>
      </geometry>
      <material name="white">
        <color rgba="1 1 1 0.9"/>
      </material>
    </visual>
  </link>

  <joint name="right_wheel_joint" type="continuous">
    <origin xyz="0 -0.19 -0.05" rpy="0 0 0" />
    <parent link="base_link" />
    <child link="right_wheel_link" />
    <axis xyz="0 1 0" />
  </joint>

  <link name="right_wheel_link">
    <visual>
      <origin xyz="0 0 0" rpy="1.5707 0 0"/>
      <geometry>
        <cylinder length="0.025" radius="0.06" />
      </geometry>
      <material name="white">
        <color rgba="1 1 1 0.9"/>
      </material>
    </visual>
  </link>

  <joint name="front_caster_joint" type="continuous">
    <origin xyz="0.18 0 -0.095" rpy="0 0 0" />
    <parent link="base_link"/>
    <child link="front_caster_link" />
    <axis xyz="0 1 0" />
  </joint>

  <link name="front_caster_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0" />
      <geometry>
        <sphere radius="0.015" />
      </geometry>
      <material name="white">
        <color rgba="1 1 1 0.9"/>
      </material>
    </visual>
  </link>

  <joint name="back_caster_joint" type="continuous">
    <origin xyz="-0.18 0 -0.095" rpy="0 0 0" />
    <parent link="base_link"/>
    <child link="back_caster_link" />
    <axis xyz="0 1 0" />
  </joint>

  <link name="back_caster_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0" />
      <geometry>
        <sphere radius="0.015" />
      </geometry>
      <material name="white">
        <color rgba="1 1 1 0.9"/>
      </material>
    </visual>
  </link>

  <joint name="camera_joint" type="fixed">
    <origin xyz="-0.17 0 0.1" rpy="0 0 0" />
    <parent link="base_link"/>
    <child link="camera_link" />    
  </joint>

  <link name="camera_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0" />
      <geometry>
        <box size="0.03 0.04 0.04" />
      </geometry>
      <material name="grey">
        <color rgba="0.5 0.5 0.5 1"/>
      </material>
    </visual>
  </link>

  <joint name="stage_joint" type="fixed">
    <origin xyz="0 0 0.14" rpy="0 0 0" />
    <parent link="base_link"/>
    <child link="stage_link" />    
  </joint>

  <link name="stage_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <cylinder length="0.12" radius="0.1"/>
      </geometry>
      <material name="red">
        <color rgba="1 0 0 1"/>
      </material>
    </visual>
  </link>

  <joint name="laser_joint" type="fixed">
    <origin xyz="0 0 0.085" rpy="0 0 0" />
    <parent link="stage_link"/>
    <child link="laser_link" />    
  </joint>

  <link name="laser_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 0" />
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
      <material name="grey">
        <color rgba="0.5 0.5 0.5 1"/>
      </material>
    </visual>
  </link>

  <joint name="kinect_joint" type="fixed">
    <origin xyz="0.15 0 0.11" rpy="0 0 0" />
    <parent link="base_link"/>
    <child link="kinect_link" />    
  </joint>

  <link name="kinect_link">
    <visual>
      <origin xyz="0 0 0" rpy="0 0 1.5708" />
      <geometry>
        // 使用三维软件导出的模型文件
        <mesh filename="package://mbot_description/meshes/kinect.dae" />
      </geometry>
    </visual>
  </link>
</robot>

(3)display_mbot_urdf.launch

<launch>
  // 设置ros的全局参数robot_description,指定机器人模型文件
  <param name="robot_description" textfile="$(find mbot_description)/urdf/mbot_base.urdf" />

	<!-- 设置GUI参数,显示关节控制插件 -->
	// 用这个可以控制机器人关节,但本文的demo没看到这个,有点遗憾
	<param name="use_gui" value="true"/>

	<!-- 运行joint_state_publisher节点,发布机器人的关节状态  -->
	<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />

	<!-- 运行robot_state_publisher节点,发布tf  -->
	<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />

	// robot_state_publisher结合joint_state_publisher可以实时把机器人各关节和各坐标系关系发布出来,让rviz显示。如果不设置,rviz无法完整加载机器人模型。
	// rviz显示后会生成配置文件,保存后再打开,就不用频繁设置了。
	<!-- 运行rviz可视化界面 -->
	<node name="rviz" pkg="rviz" type="rviz" args="-d $(find mbot_description)/config/mbot_urdf.rviz" required="true" />

</launch>

(4) Use the urdf_to_graphiz command line tool to dump the contents of the urdf file in the form of a tree in pdf format. Use this to quickly read the link and joint of urdf, the following figure is the node tree diagram of the above example.

cd ~/catkin_ws/
urdf_to_graphiz src/mbot_description/urdf/mbot_base.urdf

insert image description here

(5) Compile and run

cd ~/catkin_ws/
catkin_make --source src/mbot_description
source devel/setup.bash
roslaunch mbot_description display_mbot_urdf.launch

insert image description here
insert image description here

2.4 Using xacro to optimize the differential wheeled robot model

(1) The original urdf syntax is relatively simple, resulting in long-winded robot model files. For example, the writing of two power wheels and two universal wheels is very repetitive. ROS proposes the xacro syntax to allow robot model files to be programmable, such as setting parameters, defining macro functions and calling them, and file inclusion. The following is an example of classification:
setting and calling parameters:

   // xacro:property设置参数
  <xacro:property name="M_PI" value="3.1415926" />
  // 引用参数用${}
  <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/>

Set up the macro function and call:

  // xacro:macro设置宏函数,名字是wheel,参数是prefix 和 reflect
  <xacro:macro name="wheel" params="prefix reflect">
    <joint name="${prefix}_wheel_joint" type="continuous">
      <origin xyz="${wheel_joint_x} ${reflect*wheel_joint_y} ${-wheel_joint_z}" rpy="0 0 0" />
      <parent link="base_link" />
      <child link="${prefix}_wheel_link" />
      <axis xyz="0 1 0" />
    </joint>

    <link name="${prefix}_wheel_link">
      <visual>
        <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/>
        <geometry>
          <cylinder length="${wheel_length}" radius="${wheel_radius}"/>
        </geometry>
        <material name="white" />
      </visual>
    </link>
  </xacro:macro>
  // 调用wheel宏函数
  <xacro:wheel prefix="left"  reflect="1"/>  
  <xacro:wheel prefix="right"  reflect="-1"/>  

file contains

  // xacro:include是文件包含,camera.xacro里面定义了一个宏函数
  <xacro:include filename="$(find mbot_description)/urdf/sensor/camera.xacro" />
  // 调用camera.xacro里面的宏函数
  <xacro:usb_camera joint_x="${camera_joint_x}" joint_y="${camera_joint_y}" joint_z="${camera_joint_z}"/>  

(2) The several files here are the rewriting of the above mbot_base.urdf, using xacro, see the explanation above for the specific syntax.
mbot_base.xacro

<?xml version="1.0" ?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:property name="M_PI" value="3.1415926" />

  <xacro:property name="wheel_joint_x" value="0" />
  <xacro:property name="wheel_joint_y" value="0.19" />
  <xacro:property name="wheel_joint_z" value="0.05" />

  <xacro:property name="wheel_length" value="0.06" />
  <xacro:property name="wheel_radius" value="0.06" />

  <xacro:property name="caster_joint_x" value="0.18" />
  <xacro:property name="caster_joint_y" value="0" />
  <xacro:property name="caster_joint_z" value="0.095" />  

  <xacro:property name="caster_radius" value="0.015" />

  <xacro:property name="base_length" value="0.16" />
  <xacro:property name="base_radius" value="0.2" />

  <xacro:property name="stage_length" value="0.12" />
  <xacro:property name="stage_radius" value="0.1" />

  <xacro:property name="camera_joint_x" value="0.17" />
  <xacro:property name="camera_joint_y" value="0" />
  <xacro:property name="camera_joint_z" value="0.1" />  

  <xacro:property name="kinect_joint_x" value="0.15" />
  <xacro:property name="kinect_joint_y" value="0" />
  <xacro:property name="kinect_joint_z" value="0.11" />  

  <xacro:property name="laser_joint_x" value="0" />
  <xacro:property name="laser_joint_y" value="0" />
  <xacro:property name="laser_joint_z" value="0.085" />  

  <material name="white">
    <color rgba="1 1 1 0.9"/>
  </material>
  <material name="red">
    <color rgba="1 0 0 1"/>
  </material>

  <material name="grey">
    <color rgba="0.5 0.5 0.5 1"/>
  </material>

  <xacro:macro name="base_stage">
    <link name="base_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <geometry>
          <cylinder length="${base_length}" radius="${base_radius}"/>
        </geometry>
        <material name="red" />
      </visual>
    </link>

    <joint name="stage_joint" type="fixed">
      <origin xyz="0 0 ${(base_length + stage_length)/2}" rpy="0 0 0" />
      <parent link="base_link"/>
      <child link="stage_link" />    
    </joint>

    <link name="stage_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <geometry>
          <cylinder length="${stage_length}" radius="${stage_radius}"/>
        </geometry>
        <material name="red" />
      </visual>
    </link>
  </xacro:macro>

  <xacro:macro name="wheel" params="prefix reflect">
    <joint name="${prefix}_wheel_joint" type="continuous">
      <origin xyz="${wheel_joint_x} ${reflect*wheel_joint_y} ${-wheel_joint_z}" rpy="0 0 0" />
      <parent link="base_link" />
      <child link="${prefix}_wheel_link" />
      <axis xyz="0 1 0" />
    </joint>

    <link name="${prefix}_wheel_link">
      <visual>
        <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/>
        <geometry>
          <cylinder length="${wheel_length}" radius="${wheel_radius}"/>
        </geometry>
        <material name="white" />
      </visual>
    </link>
  </xacro:macro>

  <xacro:macro name="caster" params="prefix reflect">
    <joint name="${prefix}_caster_joint" type="continuous">
      <origin xyz="${reflect*caster_joint_x} ${caster_joint_y} ${-caster_joint_z}" rpy="0 0 0" />
      <parent link="base_link"/>
      <child link="${prefix}_caster_link" />
      <axis xyz="0 1 0" />
    </joint>

    <link name="${prefix}_caster_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <geometry>
          <sphere radius="${caster_radius}" />
        </geometry>
        <material name="white" />
      </visual>
    </link>
  </xacro:macro>

  <xacro:base_stage />  
  <xacro:wheel prefix="left"  reflect="1"/>  
  <xacro:wheel prefix="right"  reflect="-1"/>  

  <xacro:caster prefix="front"  reflect="1"/>  
  <xacro:caster prefix="back"  reflect="-1"/>  

  <xacro:include filename="$(find mbot_description)/urdf/sensor/camera.xacro" />
  <xacro:usb_camera joint_x="${camera_joint_x}" joint_y="${camera_joint_y}" joint_z="${camera_joint_z}"/>  

  <xacro:include filename="$(find mbot_description)/urdf/sensor/kinect.xacro" />
  <xacro:kinect joint_x="${kinect_joint_x}" joint_y="${kinect_joint_y}" joint_z="${kinect_joint_z}"/>  

  <xacro:include filename="$(find mbot_description)/urdf/sensor/laser.xacro" />
  <xacro:laser joint_x="${laser_joint_x}" joint_y="${laser_joint_y}" joint_z="${laser_joint_z}"/>  

</robot>

camera.xacro

<?xml version="1.0" ?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:macro name="usb_camera" params="joint_x joint_y joint_z">
    <joint name="camera_joint" type="fixed">
      <origin xyz="${-joint_x} ${joint_y} ${joint_z}" rpy="0 0 0" />
      <parent link="base_link"/>
      <child link="camera_link" />    
    </joint>

    <link name="camera_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <geometry>
          <box size="0.03 0.04 0.04" />
        </geometry>
        <material name="grey" />
      </visual>
    </link>
  </xacro:macro>
</robot>

kinect.xacro

<?xml version="1.0" ?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <xacro:macro name="kinect" params="joint_x joint_y joint_z">
    <joint name="kinect_joint" type="fixed">
      <origin xyz="${joint_x} ${joint_y} ${joint_z}" rpy="0 0 0" />
      <parent link="base_link"/>
      <child link="kinect_link" />    
    </joint>

    <link name="kinect_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 1.5708" />
        <geometry>
          <mesh filename="package://mbot_description/meshes/kinect.dae" />
        </geometry>
      </visual>
    </link>
  </xacro:macro>

</robot>

laser.xacro

<?xml version="1.0" ?>
<robot name="mbot" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <xacro:macro name="laser" params="joint_x joint_y joint_z">
    <joint name="laser_joint" type="fixed">
      <origin xyz="${joint_x} ${joint_y} ${joint_z}" rpy="0 0 0" />
      <parent link="stage_link"/>
      <child link="laser_link" />    
    </joint>

    <link name="laser_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <geometry>
          <cylinder length="0.05" radius="0.05"/>
        </geometry>
        <material name="grey"/>
      </visual>
    </link>
  </xacro:macro>
</robot>

(3)display_mbot_xacro.launch

<launch>
	// 引入xacro的解释器,不然无法读取 .xacro文件
	<arg name="model" default="$(find xacro)/xacro '$(find mbot_description)/urdf/mbot_base.xacro'" />

	<param name="robot_description" command="$(arg model)" />

	<!-- 设置GUI参数,显示关节控制插件 -->
	<param name="use_gui" value="true"/>

	<!-- 运行joint_state_publisher节点,发布机器人的关节状态  -->
	<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />

	<!-- 运行robot_state_publisher节点,发布tf  -->
	<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />

	<!-- 运行rviz可视化界面 -->
	<node name="rviz" pkg="rviz" type="rviz" args="-d $(find mbot_description)/config/mbot_xacro.rviz" required="true" />

</launch>

(4) The running effect is as follows, where the axes of the coordinate system are shown
insert image description here
insert image description here

3 Summary

The code for this article is hosted on my github: mbot_description

Guess you like

Origin blog.csdn.net/cy1641395022/article/details/131830631