在經歷了昨天插入圖片的教學後,希望大家都有好好的練習,畢竟 gazebo 是個很自由的環境,已經具備改造它的基礎了,還不好好的操作一下就實在太可惜了。那在今天我們要來講講安裝 gazebo 或是前面安裝 ros 時,就會一起安裝的樣板機器人啦!總共會有三個 burger、waffle、waffle_pi,這次教學要用到的是 waffle ,那要用他來做什麼?我們就一起往下看吧!
還記得我們在前些篇xml 語法教學中提到的 xacro,既然已經學會怎麼插入圖片與模型了,那我們就來看看機器人的零部件是如何組成的吧!這邊用的是內建的 waffle 機器人來做介紹,在對 xacro 解析前,大家可以先看過官網對urdf的介紹,它跟 xacro 的功能是一樣的,只是 xacro 更佳方便,轉檔教學我就放在這裡
在完成urdf進行轉檔前,也可以透過ros提供的工具進行檢查$ sudo apt-get install liburdfdom-tools
先將他安裝好後,輸入以下指令check_urdf yourname.urdf
正常狀況下會顯示如圖下的格式
robot name is: yourname_robot
———- Successfully Parsed XML —————
root Link: linkX has 2 child(ren)
child(1): linkY
child(2): linkZ
child(1): linkQ
那對urdf這裡就不做篇幅的敘述了。
通常這些描述檔都會處於叫做discription的資料夾中,我們來看看它的位置
我們先來看看 waffle 在轉檔過後的樣子
<?xml version="1.0" ?>
<robot name="turtlebot3_waffle" xmlns:xacro="http://ros.org/wiki/xacro">
<xacro:include filename="$(find turtlebot3_description)/urdf/common_properties.xacro"/>
<xacro:include filename="$(find turtlebot3_description)/urdf/turtlebot3_waffle.gazebo.xacro"/>
<xacro:property name="r200_cam_rgb_px" value="0.005"/>
<xacro:property name="r200_cam_rgb_py" value="0.018"/>
<xacro:property name="r200_cam_rgb_pz" value="0.013"/>
<xacro:property name="r200_cam_depth_offset" value="0.01"/>
<link name="base_footprint"/>
<joint name="base_joint" type="fixed">
<parent link="base_footprint"/>
<child link="base_link" />
<origin xyz="0 0 0.010" rpy="0 0 0"/>
</joint>
<link name="base_link">
<visual>
<origin xyz="-0.064 0 0.0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://turtlebot3_description/meshes/bases/waffle_base.stl" scale="0.001 0.001 0.001"/>
</geometry>
<material name="light_black"/>
</visual>
<collision>
<origin xyz="-0.064 0 0.047" rpy="0 0 0"/>
<geometry>
<box size="0.266 0.266 0.094"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="1.3729096e+00"/>
<inertia ixx="8.7002718e-03" ixy="-4.7576583e-05" ixz="1.1160499e-04"
iyy="8.6195418e-03" iyz="-3.5422299e-06"
izz="1.4612727e-02" />
</inertial>
</link>
<joint name="wheel_left_joint" type="continuous">
<parent link="base_link"/>
<child link="wheel_left_link"/>
<origin xyz="0.0 0.144 0.023" rpy="-1.57 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<link name="wheel_left_link">
<visual>
<origin xyz="0 0 0" rpy="1.57 0 0"/>
<geometry>
<mesh filename="package://turtlebot3_description/meshes/wheels/left_tire.stl" scale="0.001 0.001 0.001"/>
</geometry>
<material name="dark"/>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<cylinder length="0.018" radius="0.033"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" />
<mass value="2.8498940e-02" />
<inertia ixx="1.1175580e-05" ixy="-4.2369783e-11" ixz="-5.9381719e-09"
iyy="1.1192413e-05" iyz="-1.4400107e-11"
izz="2.0712558e-05" />
</inertial>
</link>
<joint name="wheel_right_joint" type="continuous">
<parent link="base_link"/>
<child link="wheel_right_link"/>
<origin xyz="0.0 -0.144 0.023" rpy="-1.57 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<link name="wheel_right_link">
<visual>
<origin xyz="0 0 0" rpy="1.57 0 0"/>
<geometry>
<mesh filename="package://turtlebot3_description/meshes/wheels/right_tire.stl" scale="0.001 0.001 0.001"/>
</geometry>
<material name="dark"/>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<cylinder length="0.018" radius="0.033"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" />
<mass value="2.8498940e-02" />
<inertia ixx="1.1175580e-05" ixy="-4.2369783e-11" ixz="-5.9381719e-09"
iyy="1.1192413e-05" iyz="-1.4400107e-11"
izz="2.0712558e-05" />
</inertial>
</link>
<joint name="caster_back_right_joint" type="fixed">
<parent link="base_link"/>
<child link="caster_back_right_link"/>
<origin xyz="-0.177 -0.064 -0.004" rpy="-1.57 0 0"/>
</joint>
<link name="caster_back_right_link">
<collision>
<origin xyz="0 0.001 0" rpy="0 0 0"/>
<geometry>
<box size="0.030 0.009 0.020"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" />
<mass value="0.005" />
<inertia ixx="0.001" ixy="0.0" ixz="0.0"
iyy="0.001" iyz="0.0"
izz="0.001" />
</inertial>
</link>
<joint name="caster_back_left_joint" type="fixed">
<parent link="base_link"/>
<child link="caster_back_left_link"/>
<origin xyz="-0.177 0.064 -0.004" rpy="-1.57 0 0"/>
</joint>
<link name="caster_back_left_link">
<collision>
<origin xyz="0 0.001 0" rpy="0 0 0"/>
<geometry>
<box size="0.030 0.009 0.020"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" />
<mass value="0.005" />
<inertia ixx="0.001" ixy="0.0" ixz="0.0"
iyy="0.001" iyz="0.0"
izz="0.001" />
</inertial>
</link>
<joint name="imu_joint" type="fixed">
<parent link="base_link"/>
<child link="imu_link"/>
<origin xyz="0.0 0 0.068" rpy="0 0 0"/>
</joint>
<link name="imu_link"/>
<joint name="scan_joint" type="fixed">
<parent link="base_link"/>
<child link="base_scan"/>
<origin xyz="-0.064 0 0.122" rpy="0 0 0"/>
</joint>
<link name="base_scan">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://turtlebot3_description/meshes/sensors/lds.stl" scale="0.001 0.001 0.001"/>
</geometry>
<material name="dark"/>
</visual>
<collision>
<origin xyz="0.015 0 -0.0065" rpy="0 0 0"/>
<geometry>
<cylinder length="0.0315" radius="0.055"/>
</geometry>
</collision>
<inertial>
<mass value="0.114" />
<origin xyz="0 0 0" />
<inertia ixx="0.001" ixy="0.0" ixz="0.0"
iyy="0.001" iyz="0.0"
izz="0.001" />
</inertial>
</link>
<joint name="camera_joint" type="fixed">
<origin xyz="0.064 -0.065 0.094" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="camera_link"/>
</joint>
<link name="camera_link">
<visual>
<origin xyz="0 0 0" rpy="1.57 0 1.57"/>
<geometry>
<mesh filename="package://turtlebot3_description/meshes/sensors/r200.dae" />
</geometry>
</visual>
<collision>
<origin xyz="0.003 0.065 0.007" rpy="0 0 0"/>
<geometry>
<box size="0.012 0.132 0.020"/>
</geometry>
</collision>
<!-- This inertial field needs doesn't contain reliable data!! -->
<!-- <inertial>
<mass value="0.564" />
<origin xyz="0 0 0" />
<inertia ixx="0.003881243" ixy="0.0" ixz="0.0"
iyy="0.000498940" iyz="0.0"
izz="0.003879257" />
</inertial>-->
</link>
<joint name="camera_rgb_joint" type="fixed">
<origin xyz="${r200_cam_rgb_px} ${r200_cam_rgb_py} ${r200_cam_rgb_pz}" rpy="0 0 0"/>
<parent link="camera_link"/>
<child link="camera_rgb_frame"/>
</joint>
<link name="camera_rgb_frame"/>
<joint name="camera_rgb_optical_joint" type="fixed">
<origin xyz="0 0 0" rpy="-1.57 0 -1.57"/>
<parent link="camera_rgb_frame"/>
<child link="camera_rgb_optical_frame"/>
</joint>
<link name="camera_rgb_optical_frame"/>
<joint name="camera_depth_joint" type="fixed">
<origin xyz="${r200_cam_rgb_px} ${r200_cam_rgb_py + r200_cam_depth_offset} ${r200_cam_rgb_pz}" rpy="0 0 0"/>
<parent link="camera_link"/>
<child link="camera_depth_frame"/>
</joint>
<link name="camera_depth_frame"/>
<joint name="camera_depth_optical_joint" type="fixed">
<origin xyz="0 0 0" rpy="-1.57 0 -1.57"/>
<parent link="camera_depth_frame"/>
<child link="camera_depth_optical_frame"/>
</joint>
<link name="camera_depth_optical_frame"/>
</robot>
接著我們先理解下<link> <joint>
這兩個標籤的涵義,製作了一張類機器人的圖片方便理解
<link>
的存在想像為肢體狀的構造,在裡面我們又可以加入例如:<visual> <geometry> <collision>
... <geometry>
<mesh filename="package://turtlebot3_description/meshes/sensors/r200.dae" />
</geometry>
2.<joint>
一樣藉由上面的可愛機器人圖我們可以看到,它起到的是類似關節的作用
<joint name="camera_depth_joint" type="fixed">
<origin xyz="${r200_cam_rgb_px} ${r200_cam_rgb_py + r200_cam_depth_offset} ${r200_cam_rgb_pz}" rpy="0 0 0"/>
<parent link="camera_link"/>
<child link="camera_depth_frame"/>
</joint>
來看到比較重要的部分<parent link="camera_link"/> <child link="camera_depth_frame"/>
既然是關節那當然有主次,這邊藉由 parent、child 的標籤來做主次的區分,也因為你的每個 joint 都有獨立的座標系統,所以主次的確定,也在進行座標轉換時有個依據。
<origin xyz="0 0 0.010" rpy="0 0 0"/>
除了主座標系統參數 xyz 外,我們看到他還附帶了 rpy 座標系統,也就是(Roll, Pitch, Yaw),在三維空間中的旋轉,在至少一點不動的情況下,都能夠看成是對某軸的繞行,
參考示意圖
圖片來源
且 "0 0 0" 順序也就是分別對應(Row, Pitch, Yaw)三軸的角度。
瞭解這些主要的內容後,裡面的一些小標籤就更方便看懂了,不外乎是座標的設置,重量長寬的設定,且不斷的重複配置,只是<link>``<joint>
的對象不同罷了,當然不是說這些配置不重要,所以在書寫的時候還是要注意他們的格式,推薦先找別人完成的檔案,打開來做為參考,多看才是學習的王道。
這次藉由我們最基本的 waffle 機器人的檔案來介紹描述檔的功用還有要如何閱讀,畢竟一開始操作整個系統或是跟筆者當初一般由新手進入這個世界的話,完全自己創造一台功能齊全的機器人還是有難度的,所以也是藉由別人的或是預設的模型來做修改跟變化,這樣不僅省時,出錯的機會相對來說也較小,免得剛剛有點成就後面又失去了信心。學習是一個循序漸進的過程,太難或太簡單都不好,希望這裡可以幫助到大家。明天我們就來看看他的另一個衍伸檔 gazebo.xacro,本檔是主要是針對機器人本身構造連結的說明,明天的內容則是他與模擬世界做連結的描述,但相對來說檔案不會跟今天一樣複雜,請大家敬請期待!