在学习之前需要了解一下坐标系和坐标变换transform,tf的内容。
让机器人模型在rviz中可视化
先建立一个包用来学习
catkin_create_pkg myurdf controller_manager joint_state_controller robot_state_publisher
在包里新建一个文件夹用来保存URDF文件
mkdir robot
建立一个只有一个几何体的模型文件
gedit myfirstrobot.urdf
输入以下内容,保存。
<robot name="myfirstrobot">
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
visual>
link>
robot>
把这段话翻译成汉语就是什么呢,你猜?其实就是定义了一个长 x=0.1m x = 0.1 m ,宽 y=0.1m y = 0.1 m ,高 z=2m z = 2 m 的长方体。
下面我们想办法观察一下建立的机器人模型是什么样的。
在包下新建一个launch文件夹,保存启动文件。新建一个display.launch文件。输入以下内容
<launch>
<param
name="robot_description"
textfile="$(find myurdf)/robot/myfirstrobot.urdf" />
<node
name="joint_state_publisher"
pkg="joint_state_publisher"
type="joint_state_publisher">
<param name="use_gui" value="TRUE"/>
node>
<node
name="robot_state_publisher"
pkg="robot_state_publisher"
type="state_publisher" />
<node
name="rviz"
pkg="rviz"
type="rviz"
respawn="false"
output="screen"
args="-d $(find myurdf)/urdf.rviz" />
launch>
运行下列命令启动
roslaunch myurdf display.launch
可以观察到定义的模型是一个细长的长方体,如下图
模型坐标系的原点默认在模型的中心,所以就显示成了这个样子。
我们再增加一个连杆
<robot name="myfirstrobot">
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
visual>
link>
<joint name="joint1" type="fixed">
<parent link="base_link"/>
<child link="middle_link"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="0.2 0.2 1"/>
geometry>
visual>
link>
robot>
URDF好像只有一个根节点,加入另一个连杆之后,就要定义一个joint确定两个连杆之间的关系,一个是父节点一个是子节点。可以看到下图的界面
两个叠在一起,显然没有连杆机器人的样子。下面我们得定义连杆和关节的原点以及他们之间的关系,来改变他们之间的相对关系了。
机器人模型的源码就修改成了如下的内容
<robot name="myfirstrobot">
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
visual>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 1"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="0.2 0.2 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
visual>
link>
robot>
我们的机器人不想是红色的,红色的是默认强加给我的,怎么改呢
<robot name="myfirstrobot">
<material name="blue">
<color rgba="0 0 0.8 1"/>
material>
<material name="white">
<color rgba="1 1 1 1"/>
material>
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
<material name="blue"/>
visual>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 1"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="0.2 0.2 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
<material name="white"/>
visual>
link>
robot>
其他的稍微调整了一下
<robot name="myfirstrobot">
<material name="blue">
<color rgba="0 0 0.8 0.6"/>
material>
<material name="white">
<color rgba="1 1 1 0.6"/>
material>
<material name="orange">
<color rgba="1 0.4 0.1 0.6"/>
material>
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 1"/>
<material name="blue"/>
visual>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 2"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="0.1 0.1 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
<material name="white"/>
visual>
link>
<joint name="joint2" type="continuous">
<parent link="middle_link"/>
<child link="top_link"/>
<origin rpy="0 0 0" xyz="1 0 0"/>
<axis xyz="0 1 0"/>
joint>
<link name="top_link">
<visual>
<geometry>
<box size="0.1 0.1 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
<material name="orange"/>
visual>
link>
<joint name="end" type="fixed">
<parent link="top_link"/>
<child link="end_link"/>
<origin rpy="0 0 0" xyz="1 0 0"/>
joint>
<link name="end_link">
<visual>
<geometry>
<sphere radius="0.1"/>
geometry>
<material name="white"/>
visual>
link>
robot>
上面我们把关节的类型都设成了type="continuous"
的,现在单独讨论以下关节的设置。二连杆中关节当然都是旋转类型的,可以无限旋转,所以设为continuous类型。但是有的机器人旋转是要有限制的,比如末端手柄,这里只做个例子。
<joint name="end" type="revolute">
<axis xyz="1 0 0"/>
<limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
<parent link="top_link"/>
<child link="end_link"/>
<origin rpy="0 0 0" xyz="1 0 0"/>
joint>
主要是为连杆添加碰撞和转动惯量属性,为关节添加动力学属性
以上,每个连杆link的子元素只有视觉上的visual,如果要进行碰撞检测或是在Gazebo中进行仿真的话,就需要定义碰撞属性了。
我用下面这样定义,用一个圆柱把原来的长条给包起来
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 1"/>
<material name="blue"/>
visual>
<collision>
<geometry>
<cylinder length="2" radius="0.2"/>
geometry>
collision>
link>
碰撞模型可以个视觉模型设成一样的,有以下两点注意:
主要是质量和转动惯量
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 1"/>
<material name="blue"/>
visual>
<collision>
<geometry>
<cylinder length="2" radius="0.2"/>
geometry>
collision>
<inertial>
<origin xyz="0 0 1" rpy="0 0 0"/>
<mass value="1"/>
<inertia
ixx="0.3342" ixy="0.0" ixz="0.0"
iyy="0.3342" iyz="0.0"
izz="0.0017"/>
inertial>
link>
质量的单位是千克kg, 3×3 3 × 3 的惯性矩阵是对称的,所以只需要六个元素就可以了
也可以定义当机器人模型与其他物体发生接触时,应该如何反应,有三个参数:
有两个属性:
- 摩擦力,friction:对于平移单位是牛顿,对于旋转单位是牛米
- 阻尼,damping:对于平移 Ns/m N s / m ,对于旋转 Nms/rad N m s / r a d 。
如果没特殊说明,这些都被设为0。
urdf文件最后为:
<robot name="myfirstrobot">
<material name="blue">
<color rgba="0 0 0.8 0.6"/>
material>
<material name="white">
<color rgba="1 1 1 0.6"/>
material>
<material name="orange">
<color rgba="1 0.4 0.1 0.6"/>
material>
<link name="base_link">
<visual>
<geometry>
<box size="0.1 0.1 2"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 1"/>
<material name="blue"/>
visual>
<collision>
<geometry>
<cylinder length="2" radius="0.2"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 1"/>
collision>
<inertial>
<origin xyz="0 0 1" rpy="0 0 0"/>
<mass value="1"/>
<inertia
ixx="0.3342" ixy="0.0" ixz="0.0"
iyy="0.3342" iyz="0.0"
izz="0.0017"/>
inertial>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 2"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="0.1 0.1 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
<material name="white"/>
visual>
<collision>
<geometry>
<cylinder length="1" radius="0.2"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
collision>
<inertial>
<origin xyz="0.5 0 0" rpy="0 0 0"/>
<mass value="1"/>
<inertia
ixx="0.0017" ixy="0.0" ixz="0.0"
iyy="0.085" iyz="0.0"
izz="0.085"/>
inertial>
link>
<joint name="joint2" type="continuous">
<parent link="middle_link"/>
<child link="top_link"/>
<origin rpy="0 0 0" xyz="1 0 0"/>
<axis xyz="0 1 0"/>
joint>
<link name="top_link">
<visual>
<geometry>
<box size="0.1 0.1 1"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
<material name="orange"/>
visual>
<collision>
<geometry>
<cylinder length="1" radius="0.2"/>
geometry>
<origin rpy="0 1.57075 0" xyz="0.5 0 0"/>
collision>
<inertial>
<origin xyz="0.5 0 0" rpy="0 0 0"/>
<mass value="1"/>
<inertia
ixx="0.0017" ixy="0.0" ixz="0.0"
iyy="0.085" iyz="0.0"
izz="0.085"/>
inertial>
link>
<joint name="end" type="revolute">
<axis xyz="1 0 0"/>
<limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
<parent link="top_link"/>
<child link="end_link"/>
<origin rpy="0 0 0" xyz="1 0 0"/>
joint>
<link name="end_link">
<visual>
<geometry>
<sphere radius="0.1"/>
geometry>
<material name="white"/>
visual>
<collision>
<geometry>
<sphere radius="0.15"/>
geometry>
collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="1"/>
<inertia
ixx="0.0017" ixy="0.0" ixz="0.0"
iyy="0.0017" iyz="0.0"
izz="0.0017"/>
inertial>
link>
robot>
使用xacro可以做三件事
我们新建一个myfirstrobot.xacro文件。有很多可以用的属性,特别是宏,可以整个模块都用宏,可以参考
http://wiki.ros.org/urdf/Tutorials/Using%20Xacro%20to%20Clean%20Up%20a%20URDF%20File
下面宏用的不多,基本没用
<robot name="myfirstrobot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:property name="PI" value="3.1415926535897931"/>
<xacro:property name="mass" value="1" />
<xacro:property name="width" value="0.1" />
<xacro:property name="height1" value="4" />
<xacro:property name="height2" value="2" />
<xacro:property name="height3" value="1" />
<xacro:include filename="$(find myurdf)/robot/materials.xacro" />
<link name="base_link">
<visual>
<geometry>
<box size="${width} ${width} ${height1}"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 ${height1/2}"/>
<material name="blue"/>
visual>
<collision>
<geometry>
<cylinder length="${height1}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 ${height1/2}"/>
collision>
<inertial>
<origin xyz="0 0 ${height1/2}" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + height1*height1)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height1*height1 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + width*width)}"/>
inertial>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 ${height1}"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="${width} ${width} ${height2}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height2/2} 0 0"/>
<material name="white"/>
visual>
<collision>
<geometry>
<cylinder length="${height2}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height2/2} 0 0"/>
collision>
<inertial>
<origin xyz="${height2/2} 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height2*height2 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + height2*height2)}"/>
inertial>
link>
<joint name="joint2" type="continuous">
<parent link="middle_link"/>
<child link="top_link"/>
<origin rpy="0 0 0" xyz="${height2} 0 0"/>
<axis xyz="0 1 0"/>
joint>
<link name="top_link">
<visual>
<geometry>
<box size="${width} ${width} ${height3}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height3/2} 0 0"/>
<material name="orange"/>
visual>
<collision>
<geometry>
<cylinder length="${height3}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height3/2} 0 0"/>
collision>
<inertial>
<origin xyz="${height3/2} 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height3*height3 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + height3*height3)}"/>
inertial>
link>
<joint name="end" type="revolute">
<axis xyz="1 0 0"/>
<limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
<parent link="top_link"/>
<child link="end_link"/>
<origin rpy="0 0 0" xyz="${height3} 0 0"/>
joint>
<link name="end_link">
<visual>
<geometry>
<sphere radius="${width}"/>
geometry>
<material name="white"/>
visual>
<collision>
<geometry>
<sphere radius="${width+0.05}"/>
geometry>
collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (width*width + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + width*width)}"/>
inertial>
link>
robot>
需要再定义个xacro的启动文件display_xacro.launch
<launch>
<param
name="robot_description"
command="$(find xacro)/xacro --inorder '$(find myurdf)/robot/myfirstrobot.xacro'" />
<node
name="joint_state_publisher"
pkg="joint_state_publisher"
type="joint_state_publisher">
<param name="use_gui" value="TRUE"/>
node>
<node
name="robot_state_publisher"
pkg="robot_state_publisher"
type="state_publisher" />
<node
name="rviz"
pkg="rviz"
type="rviz"
respawn="false"
output="screen"
args="-d $(find myurdf)/launch/xacro.rviz" />
launch>
运行
roslaunch myurdf display_xacro.launch
可以观察到跟上面一样的界面,这时改变连杆长度只需要在定义常数的地方修改即可。改变长度后的各个连杆如下
怎样在gazebo中启动并且控制我们的机器人呢
先写一个在gazebo中启动的launch文件gazebo.launch
<launch>
<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 file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="headless" value="$(arg headless)"/>
include>
<param name="robot_description"
command="$(find xacro)/xacro --inorder '$(find myurdf)/robot/myfirstrobot.xacro'" />
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model myfirstrobot -param robot_description"/>
<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
<param name="publish_frequency" type="double" value="30.0" />
node>
launch>
运行roslaunch myurdf gazebo.launch
是下面的这样。
这是啥玩意儿,我不认识啊。
然后一顿修改啊
<robot name="myfirstrobot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:property name="PI" value="3.1415926535897931"/>
<xacro:property name="mass" value="1" />
<xacro:property name="width" value="0.1" />
<xacro:property name="height1" value="4" />
<xacro:property name="height2" value="2" />
<xacro:property name="height3" value="1" />
<gazebo>
<plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
<robotNamespace>/myfirstrobotrobotNamespace>
<robotSimType>gazebo_ros_control/DefaultRobotHWSimrobotSimType>
plugin>
gazebo>
<gazebo reference="base_link">
<material>Gazebo/Orangematerial>
gazebo>
<gazebo reference="middle_link">
<mu1>0.2mu1>
<mu2>0.2mu2>
<material>Gazebo/Bluematerial>
gazebo>
<gazebo reference="top_link">
<mu1>0.2mu1>
<mu2>0.2mu2>
<material>Gazebo/Orangematerial>
gazebo>
<xacro:include filename="$(find myurdf)/robot/materials.xacro" />
<link name="world"/>
<joint name="fixed" type="fixed">
<parent link="world"/>
<child link="base_link"/>
joint>
<link name="base_link">
<visual>
<geometry>
<box size="${width} ${width} ${height1}"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 ${height1/2}"/>
<material name="blue"/>
visual>
<collision>
<geometry>
<cylinder length="${height1}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 0 0" xyz="0 0 ${height1/2}"/>
collision>
<inertial>
<origin xyz="0 0 ${height1/2}" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + height1*height1)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height1*height1 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + width*width)}"/>
inertial>
link>
<joint name="joint1" type="continuous">
<parent link="base_link"/>
<child link="middle_link"/>
<origin rpy="0 0 0" xyz="0 0 ${height1}"/>
<axis xyz="0 1 0"/>
joint>
<link name="middle_link">
<visual>
<geometry>
<box size="${width} ${width} ${height2}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height2/2} 0 0"/>
<material name="white"/>
visual>
<collision>
<geometry>
<cylinder length="${height2}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height2/2} 0 0"/>
collision>
<inertial>
<origin xyz="${height2/2} 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height2*height2 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + height2*height2)}"/>
inertial>
link>
<joint name="joint2" type="continuous">
<parent link="middle_link"/>
<child link="top_link"/>
<origin rpy="0 0 0" xyz="${height2} 0 0"/>
<axis xyz="0 1 0"/>
joint>
<link name="top_link">
<visual>
<geometry>
<box size="${width} ${width} ${height3}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height3/2} 0 0"/>
<material name="orange"/>
visual>
<collision>
<geometry>
<cylinder length="${height3}" radius="${width+0.1}"/>
geometry>
<origin rpy="0 ${PI/2} 0" xyz="${height3/2} 0 0"/>
collision>
<inertial>
<origin xyz="${height3/2} 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (height3*height3 + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + height3*height3)}"/>
inertial>
link>
<joint name="end" type="revolute">
<axis xyz="1 0 0"/>
<limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
<parent link="top_link"/>
<child link="end_link"/>
<origin rpy="0 0 0" xyz="${height3} 0 0"/>
joint>
<link name="end_link">
<visual>
<geometry>
<sphere radius="${width}"/>
geometry>
<material name="white"/>
visual>
<collision>
<geometry>
<sphere radius="${width+0.05}"/>
geometry>
collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="${mass}"/>
<inertia
ixx="${mass / 12.0 * (width*width + width*width)}" ixy="0.0" ixz="0.0"
iyy="${mass / 12.0 * (width*width + width*width)}" iyz="0.0"
izz="${mass / 12.0 * (width*width + width*width)}"/>
inertial>
link>
<transmission name="tran1">
<type>transmission_interface/SimpleTransmissiontype>
<joint name="joint1">
<hardwareInterface>hardware_interface/EffortJointInterfacehardwareInterface>
joint>
<actuator name="motor1">
<hardwareInterface>hardware_interface/EffortJointInterfacehardwareInterface>
<mechanicalReduction>1mechanicalReduction>
actuator>
transmission>
<transmission name="tran2">
<type>transmission_interface/SimpleTransmissiontype>
<joint name="joint2">
<hardwareInterface>hardware_interface/EffortJointInterfacehardwareInterface>
joint>
<actuator name="motor2">
<hardwareInterface>hardware_interface/EffortJointInterfacehardwareInterface>
<mechanicalReduction>1mechanicalReduction>
actuator>
transmission>
robot>
然后这样我认识了
自由摆动,不行吧,能不能加点控制。
答案是能
这篇写的有点长,准备加在ros_control里