RDF全称(United Robotics Description Format)统一机器人描述格式,是一个XML语法框架下用来描述机器人的语言格式,URDF在ROS界很流行。我们可以通过URDF对机器人建模然后放到ROS里面进行仿真与分析把一个URDF文件转换成simscape模型,在Simulink里面进行仿真分析或者控制器设计。把simscape模型转化成urdf格式
URDF文件里面有着与XML语言格式,一个机器人主要由连杆(link)和关节(joint)组成, URDF具有类似XML树状结构的,比如下面的例子:
<robot>
<link>
...
link>
<link>
...
link>
<joint>
...
joint>
robot>
上面的 link 与 joint 是 robot 下面的子分量(应该有比‘子分量’更好的描述),换句话说 joint 和 link 隶属于 robot 。知道了机器人的基本构成之后还不够,还需要知道基本组成部分的一些物理信息,例如连杆的质量属性,惯量属性,颜色,以及关节的种类,这到底是转动关节还是平动关节。因此 link 和 joint 也要有自己的子分量,比如 inertial 和 visual , visual 下面还可以再次细分子分量 geometry 和 material ,然后 material 下面还可以有自己的子分量,由此往复我们就可以用URDF来充分定义好一个机器人的各个信息。所以一个增加了这些额外信息的URDF文件内容例子如下
<robot>
<link>
<inertial>
...
inertial>
<visual>
<geometry>
...
geometry>
<material>
<color />
material>
visual>
link>
...
robot>
我们定义好了机器人的组成部分以及各个部分所具有的信息,接着还需要有属性描述这些量。比如 robot,link,joint 都有 name属性,一个用来辨识模块的字符串。 color 有 rgba 属性,用来定义连杆的外表颜色。添加了相关信息的URDF文件长这个样子:
<robot name = "linkage">
<link name = "root link">
<inertial>
...
inertial>
<visual>
<geometry>
...
geometry>
<material>
<color rgba = "1 0 0 1" />
material>
visual>
link>
...
robot>
把这些属性附上对应的数值之后,一个机器人的 urdf 模型中各个模块的外表和物理属性就建立好了。
接下来我们来描述关节连杆之间的关系。
URDF文件里,就像XML一样,link 通过 joint 按一定的层次一个个联系在一起。 joint 通过 parent-child 关系把上下 link 联系起来,parent link可以同时作为其他 link 的child link,而child link也可以同时作为其他link的parent link,举例:
<parent> and <child> Joint Elements
<robot name = "linkage">
<joint name = "joint A ... >
" link A" />
<child link = "link B" />
joint>
<joint name = "joint B ... >
" link A" />
<child link = "link C" />
joint>
<joint name = "joint C ... >
" link C" />
<child link = "link D" />
joint>
robot>
上述URDF语法建立了一个这样的连杆模型:
连杆A通过关节A连接着连杆B,连杆A是父连杆
连杆C通过关节B连接着连杆A,连杆A是父连杆
连杆D通过关节C连接着连杆C,连杆C是父连杆
我们可以通过connectivity graph来展示 link 之间的从属和连接关系,用圆代表link,箭头代表joint,joint 从 parent link流出,指向child link,于是上述URDF文件可以用图表示为:
描述好关系之后,一个加上上面所说的物理和外表属性,一个完整的机器人 URDF 模型就建立好了。
但是在URDF里面,模型的拓扑结构也受到着一定的限制:那就是URDF不能定义一个闭环的连杆模型。翻译成URDF说法就是:
一个child 只能有一个parent link
只有root link(也就是connectivity graph的起源)可以有多个分支
一个模型只能由一个root link
举例:
Kinematic Loop URDF Example
<robot name = "linkage">
<joint name = "joint A ... >
" link A" />
<child link = "link B" />
joint>
<joint name = "joint B ... >
" link A" />
<child link = "link C" />
joint>
<joint name = "joint C ... >
" link C" />
<child link = "link D" />
joint>
<joint name = "joint D ... >
" link B" />
<child link = "link D" />
joint>
robot>
它有一个child link D具有两个parent link, 因此该模型不能用URDF来建模
URDF里面并不是所有的信息都需要定义,一些信息比如 link 下面的 inertial 信息就是可选的,可以定义也可以不定义。下面的例子中绿色代表可选的信息,可填可不填:
学习古月老师的创建简单的机器人模型smartcar, 调试urdf 代码,需要的可以直接下载,github
smartcar.urdf.xacro
<robot name="smartcar"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:gazebo="http://playerstage.sourceforge.net/gazebo/xmlschema/#gz"
xmlns:model="http://playerstage.sourceforge.net/gazebo/xmlschema/#model"
xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
xmlns:body="http://playerstage.sourceforge.net/gazebo/xmlschema/#body"
xmlns:geom="http://playerstage.sourceforge.net/gazebo/xmlschema/#geom"
xmlns:joint="http://playerstage.sourceforge.net/gazebo/xmlschema/#joint"
xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"
xmlns:rendering="http://playerstage.sourceforge.net/gazebo/xmlschema/#rendering"
xmlns:renderable="http://playerstage.sourceforge.net/gazebo/xmlschema/#renderable"
xmlns:physics="http://playerstage.sourceforge.net/gazebo/xmlschema/#physics"
xmlns:xacro="http://ros.org/wiki/xacro">
<xacro:include filename="$(find smartcar_description)/urdf/smartcar_body.urdf.xacro" />
<xacro:smartcar_body/>
robot>
gazebo.urdf.xacro
<robot name="smartcar"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:gazebo="http://playerstage.sourceforge.net/gazebo/xmlschema/#gz"
xmlns:model="http://playerstage.sourceforge.net/gazebo/xmlschema/#model"
xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
xmlns:body="http://playerstage.sourceforge.net/gazebo/xmlschema/#body"
xmlns:geom="http://playerstage.sourceforge.net/gazebo/xmlschema/#geom"
xmlns:joint="http://playerstage.sourceforge.net/gazebo/xmlschema/#joint"
xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"
xmlns:rendering="http://playerstage.sourceforge.net/gazebo/xmlschema/#rendering"
xmlns:renderable="http://playerstage.sourceforge.net/gazebo/xmlschema/#renderable"
xmlns:physics="http://playerstage.sourceforge.net/gazebo/xmlschema/#physics"
xmlns:xacro="http://ros.org/wiki/xacro">
<xacro:include filename="$(find smartcar_description)/urdf/smartcar_body.urdf.xacro" />
<xacro:smartcar_body/>
robot>
smartcar_body.urdf.xacro
<robot name="smartcar" xmlns:xacro="http://ros.org/wiki/xacro">
<property name="M_PI" value="3.14159"/>
<include filename="$(find smartcar_description)/urdf/gazebo.urdf.xacro"/>
<property name="base_x" value="0.33" />
<property name="base_y" value="0.33" />
<xacro:macro name="smartcar_body">
<link name="base_link">
<inertial>
<origin xyz="0 0 0.055"/>
<mass value="100.0" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<box size="0.25 .16 .05"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 0.055"/>
<material name="blue">
<color rgba="0 0 .8 1"/>
material>
visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.055"/>
<geometry>
<box size="0.25 .16 .05" />
geometry>
collision>
link>
<link name="left_front_wheel">
<inertial>
<origin xyz="0.08 0.08 0.025"/>
<mass value="1" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
<material name="black">
<color rgba="0 0 0 1"/>
material>
visual>
<collision>
<origin rpy="0 1.57075 1.57075" xyz="0.08 0.08 0.025"/>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
collision>
link>
<joint name="left_front_wheel_joint" type="continuous">
<axis xyz="0 0 1"/>
<parent link="base_link"/>
<child link="left_front_wheel"/>
<origin rpy="0 1.57075 1.57075" xyz="0.08 0.08 0.025"/>
<limit effort="100" velocity="100"/>
<joint_properties damping="0.0" friction="0.0"/>
joint>
<link name="right_front_wheel">
<inertial>
<origin xyz="0.08 -0.08 0.025"/>
<mass value="1" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
<material name="black">
<color rgba="0 0 0 1"/>
material>
visual>
<collision>
<origin rpy="0 1.57075 1.57075" xyz="0.08 -0.08 0.025"/>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
collision>
link>
<joint name="right_front_wheel_joint" type="continuous">
<axis xyz="0 0 1"/>
<parent link="base_link"/>
<child link="right_front_wheel"/>
<origin rpy="0 1.57075 1.57075" xyz="0.08 -0.08 0.025"/>
<limit effort="100" velocity="100"/>
<joint_properties damping="0.0" friction="0.0"/>
joint>
<link name="left_back_wheel">
<inertial>
<origin xyz="-0.08 0.08 0.025"/>
<mass value="1" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
<material name="black">
<color rgba="0 0 0 1"/>
material>
visual>
<collision>
<origin rpy="0 1.57075 1.57075" xyz="-0.08 0.08 0.025"/>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
collision>
link>
<joint name="left_back_wheel_joint" type="continuous">
<axis xyz="0 0 1"/>
<parent link="base_link"/>
<child link="left_back_wheel"/>
<origin rpy="0 1.57075 1.57075" xyz="-0.08 0.08 0.025"/>
<limit effort="100" velocity="100"/>
<joint_properties damping="0.0" friction="0.0"/>
joint>
<link name="right_back_wheel">
<inertial>
<origin xyz="-0.08 -0.08 0.025"/>
<mass value="1" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
<material name="black">
<color rgba="0 0 0 1"/>
material>
visual>
<collision>
<origin rpy="0 1.57075 1.57075" xyz="-0.08 -0.08 0.025"/>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
collision>
link>
<joint name="right_back_wheel_joint" type="continuous">
<axis xyz="0 0 1"/>
<parent link="base_link"/>
<child link="right_back_wheel"/>
<origin rpy="0 1.57075 1.57075" xyz="-0.08 -0.08 0.025"/>
<limit effort="100" velocity="100"/>
<joint_properties damping="0.0" friction="0.0"/>
joint>
<link name="head">
<inertial>
<origin xyz="0.08 0 0.08"/>
<mass value="1" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
inertial>
<visual>
<geometry>
<box size=".02 .03 .03"/>
geometry>
<material name="white">
<color rgba="1 1 1 1"/>
material>
visual>
<collision>
<origin xyz="0.08 0 0.08"/>
<geometry>
<cylinder length=".02" radius="0.025"/>
geometry>
collision>
link>
<joint name="tobox" type="fixed">
<parent link="base_link"/>
<child link="head"/>
<origin xyz="0.08 0 0.08"/>
joint>
xacro:macro>
robot>
display.rviz.launch
<launch>
<param name="/use_sim_time" value="false" />
<arg name="urdf_file" default="$(find xacro)/xacro.py '$(find smartcar_description)/urdf/smartcar.urdf.xacro'" />
<arg name="gui" default="true" />
<param name="robot_description" command="$(arg urdf_file)" />
<param name="use_gui" value="$(arg gui)"/>
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" >
node>
<node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher">
node>
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.rviz" />
launch>
smartcar_display.rviz.launch
<launch>
<param name="/use_sim_time" value="false" />
<arg name="urdf_file" default="$(find xacro)/xacro.py '$(find smartcar_description)/urdf/smartcar.urdf.xacro'" />
<arg name="gui" default="false" />
<param name="robot_description" command="$(arg urdf_file)" />
<param name="use_gui" value="$(arg gui)"/>
<node name="arbotix" pkg="arbotix_python" type="arbotix_driver" output="screen">
<rosparam command="delete" param="/arbotix" />
<rosparam file="$(find smartcar_description)/config/smartcar_arbotix.yaml" command="load" />
<param name="sim" value="true"/>
node>
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" >
node>
<node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher">
<param name="publish_frequency" type="double" value="20.0" />
node>
<node pkg="tf" type="static_transform_publisher" name="odom_left_wheel_broadcaster" args="0 0 0 0 0 0 /base_link /left_front_link 100" />
<node pkg="tf" type="static_transform_publisher" name="odom_right_wheel_broadcaster" args="0 0 0 0 0 0 /base_link /right_front_link 100" />
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find smartcar_description)/urdf.rviz" />
launch>
首先运行lanuch,既可以看到rviz中的机器人:
roslaunch smartcar_description smartcar_display.rviz.launch
发布一条动作的消息。
rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.5, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0.5}}'
参考1. 「Wo看见常威在打来福
参考2. 创建简单的机器人模型smartcar