【ROS教程 007】3D建模與仿真

所有開始之前請安裝erratic_robot功能包集。我們需要在Gazebo中使用 erratic_robot功能包集中的差分不定式機器人驅動來移動機器人模型。

$ sudo apt-get install ros-fuerte-erratic-robot

沒有機會真正接觸到一個機器人時,仿真不失爲最好的選擇。本節我們將學習創建機器人3D模型、爲機器人提供運動 物理控制 慣性 和其他物理響應、爲機器人3D模型添加仿真傳感器、在仿真環境中使用該模型。
(1)自定義機器人在ROS中的3D模型
在ROS中使用機器人3D模型或部分結構模型主要是用於仿真機器人或者是爲了幫助開發者簡化他們的日常工作,當然具體的方法都是通過URDF文件。標準化機器人描述格式(URDF)是一種用於描述機器人、其部分結構、關節、自由度等的XML格式文件。每次在ROS系統中看到3D的機器人都會有對應的URDF文件與之對應,例如PR2(Willow Garage)或者是Robonaut(NASA)。
(2)創建第一個URDF文件
我們將在下面建立的機器人是一種常見的移動機器人,它有四個輪子、一個帶有抓取器的手臂。爲了打好基礎我們先創建一個帶有四個輪子的機器人底座。在chapter5_tutorials/urdf文件夾下創建一個新文件robot1.urdf,內容如下:

<?xml version="1.0"?>
<robot name=" Robot1 ">
<link name="base_link">
  <visual>
  <geometry>
  <box size="0.2 .3 .1"/>
  </geometry>
<origin rpy="0 0 0" xyz="0 0 0.05"/>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
  </visual>
<collision>
<geometry>
  <box size="0.2 .3 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="100"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>

  </link>

  <link name="wheel_1">
  <visual>
  <geometry>
  <cylinder length="0.05" radius="0.05"/>
  </geometry>
<origin rpy="0 1.5 0" xyz="0.1 0.1 0"/>
  <material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
  <cylinder length="0.05" radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="10"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

  <link name="wheel_2">
  <visual>
  <geometry>
  <cylinder length="0.05" radius="0.05"/>
  </geometry>
<origin rpy="0 1.5 0" xyz="-0.1 0.1 0"/>
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="0.05" radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="10"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>

  </link>

  <link name="wheel_3">
  <visual>
  <geometry>
  <cylinder length="0.05" radius="0.05"/>
  </geometry>
<origin rpy="0 1.5 0" xyz="0.1 -0.1 0"/>
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="0.05" radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="10"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

  <link name="wheel_4">
  <visual>
  <geometry>
  <cylinder length="0.05" radius="0.05"/>
  </geometry>
<origin rpy="0 1.5 0" xyz="-0.1 -0.1 0"/>
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="0.05" radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="10"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>

  </link>

  <joint name="base_to_wheel1" type="fixed">
  <parent link="base_link"/>
  <child link="wheel_1"/>
  <origin xyz="0 0 0"/>
  </joint>

  <joint name="base_to_wheel2" type="fixed">
  <parent link="base_link"/>
  <child link="wheel_2"/>
  <origin xyz="0 0 0"/>
  </joint>

  <joint name="base_to_wheel3" type="fixed">
  <parent link="base_link"/>
  <child link="wheel_3"/>
  <origin xyz="0 0 0"/>
  </joint>

  <joint name="base_to_wheel4" type="fixed">
  <parent link="base_link"/>
  <child link="wheel_4"/>
  <origin xyz="0 0 0"/>
  </joint>

<link name="arm_base">
  <visual>
  <geometry>
  <box size="0.1 .1 .1"/>
  </geometry>
<origin rpy="0 0 0" xyz="0 0 0.1"/>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
  </visual>
<collision>
<geometry>
  <box size="0.1 .1 .1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

<joint name="base_to_arm_base" type="continuous">
<parent link="base_link"/>
<child link="arm_base"/>
<axis xyz="0 0 1"/>
<origin xyz="0 0 0"/>
</joint>

<link name="arm_1">
  <visual>
  <geometry>
  <box size="0.05 .05 0.5"/>
  </geometry>
<origin rpy="0 0 0" xyz="0 0 0.25"/>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
  </visual>
<collision>
<geometry>
  <box size="0.05 .05 0.5"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

<joint name="arm_1_to_arm_base" type="revolute">
<parent link="arm_base"/>
<child link="arm_1"/>
<axis xyz="1 0 0"/>
<origin xyz="0 0 0.15"/>
<limit effort ="1000.0" lower="-1.0" upper="1.0" velocity="0.5"/>
</joint>

<link name="arm_2">
  <visual>
  <geometry>
  <box size="0.05 0.05 0.5"/>
  </geometry>
<origin rpy="0 0 0" xyz="0.06 0 0.15"/>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
  </visual>
<collision>
<geometry>
  <box size="0.05 .05 0.5"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

<joint name="arm_2_to_arm_1" type="revolute">
<parent link="arm_1"/>
<child link="arm_2"/>
<axis xyz="1 0 0"/>
<origin xyz="0.0 0 0.45"/>
<limit effort ="1000.0" lower="-2.5" upper="2.5" velocity="0.5"/>
</joint>

  <joint name="left_gripper_joint" type="revolute">
  <axis xyz="0 0 1"/>
  <limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
  <origin rpy="0 -1.57 0" xyz="0.06 0 0.4"/>
  <parent link="arm_2"/>
  <child link="left_gripper"/>
  </joint>

  <link name="left_gripper">
  <visual>
  <origin rpy="0 0 0" xyz="0 0 0"/>
  <geometry>
  <mesh filename="package://pr2_description/meshes/gripper_v0/l_finger.dae"/>
  </geometry>
  </visual>
<collision>
<geometry>
  <box size="0.1 .1 .1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

  <joint name="left_tip_joint" type="fixed">
  <parent link="left_gripper"/>
  <child link="left_tip"/>
  </joint>

  <link name="left_tip">
  <visual>
  <origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
  <geometry>
  <mesh filename="package://pr2_description/meshes/gripper_v0/l_finger_tip.dae"/>
  </geometry>
  </visual>
<collision>
<geometry>
  <box size="0.1 .1 .1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
  </link>

  <joint name="right_gripper_joint" type="revolute">
  <axis xyz="0 0 -1"/>
  <limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
  <origin rpy="0 -1.57 0" xyz="0.06 0 0.4"/>
  <parent link="arm_2"/>
  <child link="right_gripper"/>
  </joint>

  <link name="right_gripper">
  <visual>
  <origin rpy="-3.1415 0 0" xyz="0 0 0"/>
  <geometry>
  <mesh filename="package://pr2_description/meshes/gripper_v0/l_finger.dae"/>
  </geometry>
  </visual>
<collision>
<geometry>
  <box size="0.1 .1 .1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>

  </link>

  <joint name="right_tip_joint" type="fixed">
  <parent link="right_gripper"/>
  <child link="right_tip"/>
  </joint>

  <link name="right_tip">
  <visual>
  <origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
  <geometry>
  <mesh filename="package://pr2_description/meshes/gripper_v0/l_finger_tip.dae"/>
  </geometry>
  </visual>
<collision>
<geometry>
  <box size="0.1 .1 .1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>

  </link>
</robot>

在代碼中有兩種用於描述機器人幾何結構的基本字段:連接(link)和關節(joint)。檢查我們的配置是否正確可以使用

$ rosrun urdf_parser check_urdf robot1.urdf

這裏寫圖片描述
cd進入到chapter5_tutorials文件夾下( 注意路徑問題) , 以圖形的方式來查看它, 可以看到如下圖所示

$ rosrun urdf_parser urdf_to_graphiz "./urdf/robot1.urdf"

這裏寫圖片描述
這裏寫圖片描述
這個工具將會在Fuerte之後被棄用,如果使用的版本比較新,應該使用urdfdom功能包。
num1:在rivz裏查看3D模型。
現在我們有了自己的機器人,使用rviz查看它的3D展示以及它關節的運行。在launch文件夾下創建display.launch文件,並在文件中輸入以下代碼:

<launch>
<arg name="model" />
<arg name="gui" default="False" />
<param name="robot_description" textfile="$(arg model)" />
<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 name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.vcg" />
</launch>

cd進入到chapter5_tutorials文件夾下( 注意路徑問題) ,使用以下命令啓動它

$ roslaunch chapter5_tutorials display.launch model:="./urdf/robot1.urdf"

這裏寫圖片描述
有時希望自己構建的模型更加真實,通過添加更多的元素使模型變得更加豐富和細緻,這就需要加載我們自行創建的圖形或者是使用其他機器人模型的圖形。
(3)寫機器人模型方法xacro
xacro可幫助我們減小URDF文件的尺寸,並增加文件的可讀性和可維護性,我們可以方便地使用常量、數學方法、宏等進行編程。 我們可以使用 SketchUp之類的3D建模程序來創建模型。 SketchUp只能在Windows或Mac系統下運行。
(4)在ROS中仿真
要想在ROS系統中對我們的模型進行仿真,需要使用Gazebo。Gazebo是一種適用於機器人和室外環境的仿真環境。它能夠在三維環境中對多個機器人、傳感器及物體進行仿真,產生實際傳感器反饋和物體之間的物理響應。

  • num1:在Gazebo中使用URDF3D模型

在urdf/robot1_base_01.xacro找到修改後的文件:

<?xml version="1.0"?>

<robot xmlns:xacro="http://www.ros.org/wiki/xacro"
  xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
  xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
  xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"
name="robot1_xacro">

<xacro:property name="length_wheel" value="0.05" />
<xacro:property name="radius_wheel" value="0.05" />
<xacro:macro name="default_inertial" params="mass">
  <inertial>
  <mass value="${mass}" />
  <inertia ixx="1.0" ixy="0.0" ixz="0.0"
  iyy="1.0" iyz="0.0"
  izz="1.0" />
  </inertial>
</xacro:macro>

<link name="base_footprint">
  <visual>
<geometry>
  <box size="0.001 0.001 0.001"/>
  </geometry>
<origin rpy="0 0 0" xyz="0 0 0"/>
  </visual>
<xacro:default_inertial mass="0.0001"/>
  </link>

<gazebo reference="base_footprint">
<material>Gazebo/Green</material>
<turnGravityOff>false</turnGravityOff>
</gazebo>

<joint name="base_footprint_joint" type="fixed">
<origin xyz="0 0 0" />
<parent link="base_footprint" />
<child link="base_link" />
</joint>

<link name="base_link">
  <visual>
<geometry>
  <box size="0.2 .3 .1"/>
  </geometry>
<origin rpy="0 0 1.54" xyz="0 0 0.05"/>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
  </visual>
<collision>
<geometry>
  <box size="0.2 .3 0.1"/>
</geometry>
</collision>
<xacro:default_inertial mass="10"/>
  </link>

  <link name="wheel_1">
  <visual>
  <geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
  </geometry>
<!-- <origin rpy="0 1.5 0" xyz="0.1 0.1 0"/> -->
<origin rpy="0 0 0" xyz="0 0 0"/>
  <material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
</geometry>
</collision>
<xacro:default_inertial mass="1"/>
  </link>

  <link name="wheel_2">
  <visual>
  <geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
  </geometry>
<!-- <origin rpy="0 1.5 0" xyz="-0.1 0.1 0"/> -->
<origin rpy="0 0 0" xyz="0 0 0"/>
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
</geometry>
</collision>
<xacro:default_inertial mass="1"/>

  </link>

  <link name="wheel_3">
  <visual>
  <geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
  </geometry>
<!-- <origin rpy="0 1.5 0" xyz="0.1 -0.1 0"/> -->

<origin rpy="0 0 0" xyz="0 0 0"/>
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
</geometry>
</collision>
<xacro:default_inertial mass="1"/>
  </link>

  <link name="wheel_4">
  <visual>
  <geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
  </geometry>
<!-- <origin rpy="0 1.5 0" xyz="-0.1 -0.1 0"/> -->
<origin rpy="0 0 0" xyz="0 0 0" />
  <material name="black"/>
  </visual>
<collision>
<geometry>
  <cylinder length="${length_wheel}" radius="${radius_wheel}"/>
</geometry>
</collision>
<xacro:default_inertial mass="1"/>

  </link>

 <joint name="base_to_wheel1" type="continuous">
  <parent link="base_link"/>
  <child link="wheel_1"/>
  <origin rpy="1.5707 0 0" xyz="0.1 0.15 0"/>
  <axis xyz="0 0 1" />
 </joint>

 <joint name="base_to_wheel2" type="continuous">
  <axis xyz="0 0 1" />
  <anchor xyz="0 0 0" />
  <limit effort="100" velocity="100" />
  <parent link="base_link"/>
  <child link="wheel_2"/>
  <origin rpy="1.5707 0 0" xyz="-0.1 0.15 0"/>
</joint>

 <joint name="base_to_wheel3" type="continuous">
  <parent link="base_link"/>
  <axis xyz="0 0 1" />
  <child link="wheel_3"/>
  <origin rpy="1.5707 0 0" xyz="0.1 -0.15 0"/>
 </joint>

 <joint name="base_to_wheel4" type="continuous">
  <parent link="base_link"/>
  <axis xyz="0 0 1" />
  <child link="wheel_4"/>
  <origin rpy="1.5707 0 0" xyz="-0.1 -0.15 0"/>
 </joint>
</robot>

這是機器人底盤base_link的新代碼。請注意 collision和 inertial部分對於在Gazebo中運行模型是必需的,這樣才能計算機器人的物理響應。
想要啓動這一切,我們需要創建一個名爲gazebo.launch

<?xml version="1.0"?>
<launch>
  <!-- this launch file corresponds to robot model in ros-pkg/robot_descriptions/pr2/erratic_defs/robots for full erratic -->

  <param name="/use_sim_time" value="true" />

  <!-- start up wg world -->
  <include file="$(find gazebo_worlds)/launch/empty_world.launch"/>

  <arg name="model" />
  <param name="robot_description" command="$(find xacro)/xacro.py $(arg model)" />

  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
  <!-- start robot state publisher -->
  <node pkg="robot_state_publisher" type="state_publisher" name="robot_state_publisher" output="screen" >
  <param name="publish_frequency" type="double" value="50.0" />
  </node>

  <node name="spawn_robot" pkg="gazebo" type="spawn_model" args="-urdf -param robot_description -z 0.1 -model robot_model" respawn="false" output="screen" />

</launch>

想要啓動文件,需要使用以下命令:

$ roslaunch chapter5_tutorials gazebo.launch model:="./urdf/robot1_base_01.xacro"

現在在Gazebo中看到機器人,祝賀,已在虛擬世界中邁出第一步!
這裏寫圖片描述
正如上圖所見,模型並沒有任何的紋理渲染。在rviz中能看到URDF文件中聲明的紋理,但是在Gazebo中卻看不到。將robot1_base_01.xacro文件另存爲robot1_base_02.xacro並添加以下代碼:

 <gazebo reference="base_link">
  <material>Erratic/BlueBrushedAluminum</material>
 </gazebo>

 <gazebo reference="wheel_1">
  <material>Erratic/Black</material>
 </gazebo>

 <gazebo reference="wheel_2">
  <material>Erratic/Black</material>
 </gazebo>

 <gazebo reference="wheel_3">
  <material>Erratic/Black</material>
 </gazebo>

 <gazebo reference="wheel_4">
  <material>Erratic/Black</material>
 </gazebo>

啓動這個新文件將會看到一個帶有紋理的機器人。

  • num2:在Gazebo中添加傳感器

在 Gazebo中能夠對機器人的物理運行進行仿真,同樣還能仿真它的傳感器,本節我們將會向模型中添加一個激光雷達傳感器。這個傳感器將會成爲機器人你的一個新部件,你要選好它的安裝位置。在Gazebo中你會看到一個新的3D模型,它很像Hokuyo激光雷達。我們會從erratic_gazebo_plugins功能包中調用激光雷達。唯一需要做的就是向.xacro文件中增加這些行變爲robot1_base_03.xacro:

<include filename="$(find erratic_description)/urdf/erratic_hokuyo_laser.xacro" />

  <!-- BASE LASER ATTACHMENT -->
  <erratic_hokuyo_laser parent="base_link">
  <origin xyz="0.18 0 0.11" rpy="0 0 0" />
  </erratic_hokuyo_laser>

使用以下命令啓動新的模型將會看到附帶有雷達模塊的機器人:

 $ roslaunch chapter5_tutorials gazebo.launch model:="./urdf/robot1_base_03.xacro"

num3:在Gazebo中加載和使用地圖
在本小節中我們將會使用一張柳樹車庫公司辦公室地圖,這張圖在我們的ROS軟件中默認安裝了。這個3D模型保存在gazebo_words功能包中,爲了檢查模型,需要使用以下命令啓動.launch文件

$ roslaunch gazebo_worlds wg_collada_world.launch

我們需要創建一個新的.launch文件來同時加載地圖和機器人。在launch文件夾下創建gazebo_map_robot.launch,內容如下:

<?xml version="1.0"?>
<launch>
  <!-- this launch file corresponds to robot model in ros-pkg/robot_descriptions/pr2/erratic_defs/robots for full erratic -->

  <param name="/use_sim_time" value="true" />

  <!-- start up wg world -->
  <include file="$(find gazebo_worlds)/launch/wg_collada_world.launch"/>

  <arg name="model" />
  <param name="robot_description" command="$(find xacro)/xacro.py $(arg model)" />

  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
  <!-- start robot state publisher -->
  <node pkg="robot_state_publisher" type="state_publisher" name="robot_state_publisher" output="screen" >
  <param name="publish_frequency" type="double" value="50.0" />
  </node>

  <node name="spawn_robot" pkg="gazebo" type="spawn_model" args="-urdf -param robot_description -z 0.1 -model robot_model" respawn="false" output="screen" />

</launch>

現在運行帶有激光雷達的模型文件,你會在Gazebo GUI中看到機器人和地圖。

$ roslaunch chapter5_tutorials gazebo_map_robot.launch model:="./urdf/robot1_base_03.xacro"

num4: 在Gazebo中移動機器人
差分輪式機器人是一種對機身兩側輪子分別進行驅動的移動機器人。它通過將兩側的輪子控制在不同的轉速進行轉向,而不需要輪子有任何轉向運動。差分驅動通常意味着機器人有2個驅動輪,而我們的機器人有4個輪子,因此在運動中會出現問題,所以要進行一些修改。修改後的文件爲robot1_base_04.xacro,內容如下:
現在我們使用以下命令啓動帶有控制器和地圖的模型:
現在我們將使用節點來移動那個機器人,這個節點在erratic_teleop功能包中,運行以下命令

Refrences:
[1]. Aaron Martinez Enrique Fern andez, ROS機器人程序設計[B], P104-125, 2014.
https://answers.ros.org/question/68203/robot_state_publisher-can-find-robot-element/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章