1. 程式人生 > 其它 >11機器人系統模擬

11機器人系統模擬

機器人系統模擬

對於ROS新手而言,可能會有疑問:學習機器人作業系統,實體機器人是必須的嗎?答案是否定的,機器人一般價格不菲,為了降低機器人學習、除錯成本,在ROS中提供了系統的機器人模擬實現,通過模擬,可以實現大部分需求,本章主要就是圍繞“模擬”展開的,比如,本章會介紹:

  • 如何建立並顯示機器人模型;
  • 如何搭建模擬環境;
  • 如何實現機器人模型與模擬環境的互動。

本章預期的學習目標如下:

  • 能夠獨立使用URDF建立機器人模型,並在Rviz和Gazebo中分別顯示;
  • 能夠使用Gazebo搭建模擬環境;
  • 能夠使用機器人模型中的感測器(雷達、攝像頭、編碼器...)獲取模擬環境資料。

概述

機器人作業系統學習、開發與測試過程中,會遇到諸多問題,比如:

場景1:機器人一般價格不菲,學習ROS要購買一臺機器人嗎?

場景2:機器人與之互動的外界環境具有多樣性,如何實現複雜的環境設計?

場景3:測試時,直接將未經驗證的程式部署到實體機器人執行,安全嗎?

...

在諸如此類的場景中,ROS中的模擬就顯得尤為重要了。

概念

機器人系統模擬:是通過計算機對實體機器人系統進行模擬的技術,在 ROS 中,模擬實現涉及的內容主要有三:對機器人建模(URDF)、建立模擬環境(Gazebo)以及感知環境(Rviz)等系統性實現。

作用

模擬優勢:

模擬在機器人系統研發過程中佔有舉足輕重的地位,在研發與測試中較之於實體機器人實現,模擬有如下幾點的顯著優勢:

  1. 低成本:
    當前機器人成本居高不下,動輒幾十萬,模擬可以大大降低成本,減小風險
  2. 高效:搭建的環境更為多樣且靈活,可以提高測試效率以及測試覆蓋率
  3. 高安全性:模擬環境下,無需考慮耗損問題

模擬缺陷:

機器人在模擬環境與實際環境下的表現差異較大,換言之,模擬並不能完全做到模擬真實的物理世界,存在一些"失真"的情況,原因:

  1. 模擬器所使用的物理引擎目前還不能夠完全精確模擬真實世界的物理情況
  2. 模擬器構建的是關節驅動器(電機&齒輪箱)、感測器與訊號通訊的絕對理想情況,目前不支援模擬實際硬體缺陷或者一些臨界狀態等情形

相關元件

1.URDF

URDF是 Unified Robot Description Format 的首字母縮寫,直譯為統一(標準化)機器人描述格式

,可以以一種 XML 的方式描述機器人的部分結構,比如底盤、攝像頭、鐳射雷達、機械臂以及不同關節的自由度.....,該檔案可以被 C++ 內建的直譯器轉換成視覺化的機器人模型,是 ROS 中實現機器人模擬的重要元件

2.rviz

RViz 是 ROS Visualization Tool 的首字母縮寫,直譯為ROS的三維視覺化工具。它的主要目的是以三維方式顯示ROS訊息,可以將 資料進行視覺化表達。例如:可以顯示機器人模型,可以無需程式設計就能表達鐳射測距儀(LRF)感測器中的感測 器到障礙物的距離,RealSense、Kinect或Xtion等三維距離感測器的點雲資料(PCD, Point Cloud Data),從相機獲取的影象值等

以“ros- [ROS_DISTRO] -desktop-full”命令安裝ROS時,RViz會預設被安裝。

執行使用命令rvizrosrun rviz rviz

*如果rviz沒有安裝,請呼叫如下命令自行安裝:*

sudo apt install ros-[ROS_DISTRO]-rviz

3.gazebo

Gazebo是一款3D動態模擬器,用於顯示機器人模型並建立模擬環境,能夠在複雜的室內和室外環境中準確有效地模擬機器人。與遊戲引擎提供高保真度的視覺模擬類似,Gazebo提供高保真度的物理模擬,其提供一整套感測器模型,以及對使用者和程式非常友好的互動方式。

以“ros- [ROS_DISTRO] -desktop-full”命令安裝ROS時,gzebo會預設被安裝。

執行使用命令gazeborosrun gazebo_ros gazebo

**注意1:**在 Ubuntu20.04 與 ROS Noetic 環境下,gazebo 啟動異常以及解決

  • 問題1:VMware: vmw_ioctl_command error Invalid argument(無效的引數)

    解決:

    echo "export SVGA_VGPU10=0" >> ~/.bashrc

    source .bashrc

  • 問題2:[Err] [REST.cc:205] Error in REST request

    解決:sudo gedit ~/.ignition/fuel/config.yaml

    然後將url : https://api.ignitionfuel.org使用 # 註釋

    再新增url: https://api.ignitionrobotics.org

  • 問題3:啟動時丟擲異常:[gazebo-2] process has died [pid xxx, exit code 255, cmd.....

    解決:killall gzserverkillall gzclient

**注意2:**如果 gazebo沒有安裝,請自行安裝:

1.新增源:

sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" 
>
 /etc/apt/sources.list.d/gazebo-stable.list'

wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -

2.安裝:

sudo apt update

sudo apt install gazebo11 
sudo apt install libgazebo11-dev

另請參考:

課程說明:

機器人的系統模擬是一種整合實現,主要包含三部分:

  • URDF 用於建立機器人模型
  • Gzebo 用於搭建模擬環境
  • Rviz 圖形化的顯示機器人各種感測器感知到的環境資訊

三者應用中,只是建立 URDF 意義不大,一般需要結合 Gazebo 或 Rviz 使用,在 Gazebo 或 Rviz 中可以將 URDF 檔案解析為圖形化的機器人模型,一般的使用組合為:

  • 如果非模擬環境,那麼使用 URDF 結合 Rviz 直接顯示感知的真實環境資訊
  • 如果是模擬環境,那麼需要使用 URDF 結合 Gazebo 搭建模擬環境,並結合 Rviz 顯示感知的虛擬環境資訊

後續課程安排:

  • 先介紹 URDF 與 Rviz 整合使用,在 Rviz 中只是顯示機器人模型,主要用於學習 URDF 語法
  • 再介紹 URDF 與 Gazebo 整合,主要學習 URDF 模擬相關語法以及模擬環境搭建
  • 最後整合 URDF 與 Gazebo 與 Rviz,實現綜合應用

機器外形素材連結:

URDF整合Rviz基本流程

前面介紹過,URDF 不能單獨使用,需要結合 Rviz 或 Gazebo,URDF 只是一個檔案,需要在 Rviz 或 Gazebo
中渲染成圖形化的機器人模型,當前,首先演示URDF與Rviz的整合使用,因為URDF與Rviz的整合較之於URDF與Gazebo的整合更為簡單,後期,基於Rviz的整合實現,我們再進一步介紹URDF語法。

需求描述:

在 Rviz 中顯示一個盒狀機器人

實現流程:

  1. 準備:新建功能包,匯入依賴
  2. 核心:編寫 urdf 檔案
  3. 核心:在 launch 檔案整合 URDF 與 Rviz
  4. 在 Rviz 中顯示機器人模型

建立功能包,匯入依賴

建立一個新的功能包,名稱自定義,匯入依賴包:urdfxacro

在當前功能包下,再新建幾個目錄:

urdf: 儲存 urdf 檔案的目錄

meshes:機器人模型渲染檔案(暫不使用)

config: 配置檔案

launch: 儲存 launch 啟動檔案

編寫 URDF 檔案

新建一個子級資料夾:urdf(可選),資料夾中新增一個.urdf檔案,複製如下內容:

<robot name="mycar">
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.5 0.2 0.1" />
            </geometry>
        </visual>
    </link>
</robot>

在 launch 檔案中整合 URDF 與 Rviz

launch目錄下,新建一個 launch 檔案,該 launch 檔案需要啟動 Rviz,並匯入 urdf 檔案,Rviz 啟動後可以自動載入解析urdf檔案,並顯示機器人模型,核心問題:如何匯入 urdf 檔案? 在 ROS 中,可以將 urdf 檔案的路徑設定到引數伺服器,使用的引數名是:robot_description,示例程式碼如下:

<launch>

    <!-- 設定引數 -->
    <param name="robot_description" textfile="$(find 包名)/urdf/urdf/urdf01_HelloWorld.urdf" />

    <!-- 啟動 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" />

</launch>

在 Rviz 中顯示機器人模型

rviz 啟動後,會發現並沒有盒裝的機器人模型,這是因為預設情況下沒有新增機器人顯示元件,需要手動新增,新增方式如下:

設定完畢後,可以正常顯示了

優化 rviz 啟動

重複啟動launch檔案時,Rviz 之前的元件配置資訊不會自動儲存,需要重複執行步驟4的操作,為了方便使用,可以使用如下方式優化:

首先,將當前配置儲存進config目錄

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-m9qjC2I5-1649728244963)(D:\Linux互動\Picture\螢幕截圖_2.png)]

然後,launch檔案中 Rviz 的啟動配置新增引數:args,值設定為-d 配置檔案路徑

<launch>
    <param name="robot_description" textfile="$(find 包名)/urdf/urdf/urdf01_HelloWorld.urdf" />
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find 包名)/config/rviz/show_mycar.rviz" />
</launch>

再啟動時,就可以包含之前的元件配置了,使用更方便快捷。

URDF語法詳解

URDF 檔案是一個標準的 XML 檔案,在 ROS 中預定義了一系列的標籤用於描述機器人模型,機器人模型可能較為複雜,但是 ROS 的 URDF 中機器人的組成卻是較為簡單,可以主要簡化為兩部分:連桿(link標籤) 與 關節(joint標籤),接下來我們就通過案例瞭解一下 URDF 中的不同標籤:

  • robot 根標籤,類似於 launch檔案中的launch標籤
  • link 連桿標籤
  • joint 關節標籤
  • gazebo 整合gazebo需要使用的標籤

關於gazebo標籤,後期在使用 gazebo 模擬時,才需要使用到,用於配置模擬環境所需引數,比如: 機器人材料屬性、gazebo外掛等,但是該標籤不是機器人模型必須的,只有在模擬時才需設定

另請參考:

URDF語法詳解01_robot

robot

urdf 中為了保證 xml 語法的完整性,使用了robot標籤作為根標籤,所有的 link 和 joint 以及其他標籤都必須包含在 robot 標籤內,在該標籤內可以通過 name 屬性設定機器人模型的名稱

屬性

name: 指定機器人模型的名稱

子標籤

其他標籤都是子級標籤

urdf 中的 link 標籤用於描述機器人某個部件(也即剛體部分)的外觀和物理屬性,比如: 機器人底座、輪子、鐳射雷達、攝像頭...每一個部件都對應一個 link, 在 link 標籤內,可以設計該部件的形狀、尺寸、顏色、慣性矩陣、碰撞引數等一系列屬性

屬性

  • name ---> 為連桿命名

子標籤

  • visual ---> 描述外觀(對應的資料是可視的)
    • geometry 設定連桿的形狀
      • 標籤1: box(盒狀)
        • 屬性:size=長(x) 寬(y) 高(z)
      • 標籤2: cylinder(圓柱)
        • 屬性:radius=半徑 length=高度
      • 標籤3: sphere(球體)
        • 屬性:radius=半徑
      • 標籤4: mesh(為連桿新增面板)
        • 屬性: filename=資源路徑(格式:package:////檔案)
    • origin 設定偏移量與傾斜弧度
      • 屬性1: xyz=x偏移 y便宜 z偏移
      • 屬性2: rpy=x翻滾 y俯仰 z偏航 (單位是弧度)
    • metrial 設定材料屬性(顏色)
      • 屬性: name
      • 標籤: color
        • 屬性: rgba=紅綠藍權重值與透明度 (每個權重值以及透明度取值[0,1])
  • collision ---> 連桿的碰撞屬性
  • Inertial ---> 連桿的慣性矩陣

在此,只演示visual使用。

案例

需求:分別生成長方體、圓柱與球體的機器人部件

link

<!-- 需求:設定不同形狀的機器人屬性 -->
<robot name="mycar">
    <link name="base_link">
        <!-- 視覺化標籤 -->
        <visual>
            <!-- 1.形狀 -->
            <geometry>
                <!-- 1.長方體的長寬高  -->
                <!-- <box size="0.3 0.2 0.1" /> -->
                <!-- 2.圓柱體 ,半徑和長度-->
                <!-- <cylinder radius="0.5" length="0.1" /> -->
                <!-- 3.球體,半徑 -->
                <!-- <sphere radius="0.5" /> -->
                <!-- 4.面板 -->
                <mesh filename="package://urdt01_rviz/meshes/autolabor_mini.stl" />

            </geometry>
            <!-- 2.偏移量與傾斜幅度rpy翻滾俯仰與偏航角度(3.14=180度 1.57=90度)-->
            <origin xyz="0 0 0" rpy="1.57 0 1.57" />
            <!-- 3.顏色 -->
            <material name="black">
            <!-- 
                r=red
                g=green
                b=black
                a=透明度
                四者取值在【0,1】
             -->
                <color rgba="0.7 0.5 0 0.5" />
            </material>


        </visual>
    </link>
</robot>

URDF語法詳解03_joint

joint

urdf 中的 joint 標籤用於描述機器人關節的運動學和動力學屬性,還可以指定關節運動的安全極限,機器人的兩個部件(分別稱之為 parent link 與 child link)以"關節"的形式相連線,不同的關節有不同的運動形式: 旋轉、滑動、固定、旋轉速度、旋轉角度限制....,比如:安裝在底座上的輪子可以360度旋轉,而攝像頭則可能是完全固定在底座上。

joint標籤對應的資料在模型中是不可見的

屬性

  • name ---> 為關節命名
  • type ---> 關節運動形式
    • continuous: 旋轉關節,可以繞單軸無限旋轉
    • revolute: 旋轉關節,類似於 continues,但是有旋轉角度限制
    • prismatic: 滑動關節,沿某一軸線移動的關節,有位置極限
    • planer: 平面關節,允許在平面正交方向上平移或旋轉
    • floating: 浮動關節,允許進行平移、旋轉運動
    • fixed: 固定關節,不允許運動的特殊關節

子標籤

  • parent(必需的)

    parent link的名字是一個強制的屬性:

    • link:父級連桿的名字,是這個link在機器人結構樹中的名字。
  • child(必需的)

    child link的名字是一個強制的屬性:

    • link:子級連桿的名字,是這個link在機器人結構樹中的名字。
  • origin

    • 屬性: xyz=各軸線上的偏移量 rpy=各軸線上的偏移弧度。
  • axis

    • 屬性: xyz用於設定圍繞哪個關節軸運動。

案例

需求:建立機器人模型,底盤為長方體,在長方體的前面新增一攝像頭,攝像頭可以沿著 Z 軸 360 度旋轉。

URDF檔案示例如下:

注意:(此程式碼真實應用時要把中文註釋刪除不然會報錯)

<!-- 
    需求: 建立機器人模型,底盤為長方體,
         在長方體的前面新增一攝像頭,
         攝像頭可以沿著 Z 軸 360 度旋轉

 -->
<robot name="mycar">
    <!-- 1.底盤link --> 
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.5 0.2 0.1" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="blue">
                <color rgba="0 0 1.0 0.5" />
            </material>
        </visual>
    </link>

    <!-- 2.攝像頭link -->
    <link name="camera">
        <visual>
            <geometry>
                <box size="0.02 0.05 0.05" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="red">
                <color rgba="1 0 0 0.5" />
            </material>
        </visual>
    </link>

    <!-- 3.關節 -->
    <joint name="camera2baselink" type="continuous">
        <!-- 父級link -->
        <parent link="base_link" />
        <!-- 子級link -->
        <child link="camera" />
        <!-- 設定偏移量 -->
        <origin xyz="0.2 0 0.075" rpy="0 0 0" />
        <!-- 設定關節旋轉參考的座標軸 -->
         <axis xyz="0 0 1" />
    </joint>
</robot>

使用joint_state_publisher_gui之前需要安裝。

sudo apt-get install ros-melodic-joint-state-publisher-gui
--------------------------------------------------------------------------------
sudo apt-get install ros-kinetic-joint-state-publisher-gui

launch檔案示例如下:

<launch>

    <!-- 設定引數 -->
    <param name="robot_description" textfile="$(find urdt01_rviz)/urdf/urdf/demo03_joint.urdf" />

    <!-- 啟動 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdt01_rviz)/config/show_mycar.rviz" />

        <!-- 新增關節狀態釋出節點 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 新增機器人狀態釋出節點 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
    <!-- 可選:用於控制關節運動的節點 -->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />


</launch>

PS:

1.狀態釋出節點在此是必須的:

    <!-- 新增關節狀態釋出節點 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 新增機器人狀態釋出節點 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />

2.關節運動控制節點(可選),會生成關節控制的UI,用於測試關節運動是否正常。

    <!-- 可選:用於控制關節運動的節點 -->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui

base_footprint優化urdf

前面實現的機器人模型是半沉到地下的,因為預設情況下: 底盤的中心點位於地圖原點上,所以會導致這種情況產生,可以使用的優化策略,將初始 link 設定為一個尺寸極小的 link(比如半徑為 0.001m 的球體,或邊長為 0.001m 的立方體),然後再在初始 link 上新增底盤等剛體,這樣實現,雖然仍然存在初始link半沉的現象,但是基本可以忽略了。這個初始 link 一般稱之為 base_footprint


<robot name="mycar">
        <!-- Add a link with a very small size, 
            and then de associate the initial link with the base_ Link, 
            the height of the joint is just the same as that of the base_ The sinking height is the same
    -->
     <link name="base_footprint">
        <visual>
            <geometry>
                <box size="0.01 0.01 0.01" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="blue">
                <color rgba="0 0 1.0 0.5" />
            </material>
        </visual>
    </link>   

    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.3 0.2 0.1" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="blue">
                <color rgba="0.8 0.5 0 0.5" />
            </material>
        </visual>
    </link>

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

    <link name="camera">
        <visual>
            <geometry>
                <box size="0.02 0.05 0.05" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="red">
                <color rgba="0 0 1 0.5" />
            </material>
        </visual>
    </link>
	
   <!-- association base_footprint and base_link -->
    <joint name="camera2baselink" type="continuous">
        <parent link="base_link"/>
        <child link="camera" />
        <origin xyz="0.12 0 0.075" rpy="0 0 0" />
        <axis xyz="0 0 1" />
    </joint>

</robot>
    

遇到問題以及解決

問題1:

命令列輸出如下錯誤提示

UnicodeEncodeError: 'ascii' codec can't encode characters in position 463-464: ordinal not in range(128)
[joint_state_publisher-3] process has died [pid 4443, exit code 1, cmd /opt/ros/melodic/lib/joint_state_publisher/joint_state_publisher __name:=joint_state_publisher __log:=/home/rosmelodic/.ros/log/b38967c0-0acb-11eb-aee3-0800278ee10c/joint_state_publisher-3.log].
log file: /home/rosmelodic/.ros/log/b38967c0-0acb-11eb-aee3-0800278ee10c/joint_state_publisher-3*.log

rviz中提示座標變換異常,導致機器人部件顯示結構異常

原因:編碼問題導致的

解決:去除URDF中的中文註釋

問題2:[ERROR] [1584370263.037038]: Could not find the GUI, install the 'joint_state_publisher_gui' package

解決:sudo apt-get install ros-kinetic-joint-state-publisher-gui

URDF練習

需求描述:

建立一個四輪圓柱狀機器人模型,機器人蔘數如下,底盤為圓柱狀,半徑 10cm,高 8cm,四輪由兩個驅動輪和兩個萬向支撐輪組成,兩個驅動輪半徑為 3.25cm,輪胎寬度1.5cm,兩個萬向輪為球狀,半徑 0.75cm,底盤離地間距為 1.5cm(與萬向輪直徑一致)

實現流程:

建立機器人模型可以分步驟實現

  1. 新建 urdf 檔案,並與 launch 檔案整合
  2. 搭建底盤
  3. 在底盤上新增兩個驅動輪
  4. 在底盤上新增兩個萬向輪
<robot name="mycar">
    <!-- set base_footprint  -->
    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="0.001" />
            </geometry>
        </visual>
    </link>

    <!-- Add chassis -->
    <!-- 
        shape: cylinder
        radius: 0.1m
        length: 0.08m
     -->
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="0.1" length="0.08" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="yellow">
                <color rgba="0.8 0.5 0 0.5" />
            </material>
        </visual>
    </link>

    <!-- Add drive wheel -->
    <!-- 
        shape: cyliner
        radius: 0.035
        length: 0.015
     -->
    <link name="left_drive_wheel">
        <visual>
            <geometry>
                <cylinder radius="0.0325" length="0.015" />
            </geometry>
            <origin xyz="0 0 0" rpy="1.5708 0 0" />
            <material name="black">
                <color rgba="0 0 0 1" />
            </material>
        </visual>
    </link>   
    <link name="right_drive_wheel">
        <visual>
            <geometry>
                <cylinder radius="0.035" length="0.015" />
            </geometry>
            <origin xyz="0 0 0" rpy="1.5708 0 0" />
            <material name="black">
                <color rgba="0 0 0 1" />
            </material>
        </visual>
    </link>

    <!-- Add Cardan wheel -->
    <!-- 
        shape: ball
        radius: 0.0075m
     -->
    <link name="front_cardan_ball">
        <visual>
            <geometry>
                <sphere radius="0.0075" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0 0 0 1" />
            </material>
        </visual>
    </link>
    <link name="back_cardan_ball">
        <visual>
            <geometry>
                <sphere radius="0.0075" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0 0 0 1" />
            </material>
        </visual>
    </link>


    <!-- joint -->
    <!-- joint  base_footprint and base_link-->
    <!-- 
        chassis height 0.015m
        z = length/2 + 0.015
     -->
    <joint name="base_link2base_footprint" type="fixed">
        <parent link="base_footprint" />
        <child link="base_link" />
        <origin xyz="0 0 0.055" />
    </joint>

    <!-- joint base_link and whell -->
    <!-- 
        left
        x= 0
        y=0.1
        z=0.055-0.0325=0.0225
     -->
    <joint name="left_drive_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="left_drive_wheel" />
        <origin xyz="0 0.1 -0.0225" />
        <axis xyz="0 1 0" />
    </joint>
    <joint name="right_drive_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="right_drive_wheel" />
        <origin xyz="0 -0.1 -0.0225" />
        <axis xyz="0 1 0" />
    </joint>

    <!-- joint base_link and whell -->
    <!-- 
        left
        x= 0.08
        y= 0
        z=0.055-0.0075=0.0475
     -->
    <joint name="front_cardan_ball2base_link" type="continuous">
        <parent link="base_link" />
        <child link="front_cardan_ball" />
        <origin xyz="0.08 0 -0.0475" />
        <axis xyz="0 1 0" />
    </joint>
    <joint name="back_cardan_ball2base_link" type="continuous">
        <parent link="base_link" />
        <child link="back_cardan_ball" />
        <origin xyz="-0.08 0 -0.0475" />
        <axis xyz="0 1 0" />
    </joint>

</robot>
   

URDF工具

在 ROS 中,提供了一些工具來方便 URDF 檔案的編寫,比如:

  • check_urdf命令可以檢查複雜的 urdf 檔案是否存在語法問題
  • urdf_to_graphiz命令可以檢視 urdf 模型結構,顯示不同 link 的層級關係

當然,要使用工具之前,首先需要安裝,安裝命令:sudo apt install liburdfdom-tools

sudo apt autoremove'來解除安裝它(它們)。

check_urdf 語法檢查

進入urdf檔案所屬目錄,呼叫:check_urdf urdf檔案,如果不丟擲異常,說明檔案合法,否則非法

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-YKnu72nV-1649728244969)(/media/zjh/48FD1B0C4A4CA998/互動_行動硬碟/ROS筆記/p/04_URDF檔案檢查_異常.png)]

urdf_to_graphiz 結構檢視

進入urdf檔案所屬目錄,呼叫:urdf_to_graphiz urdf檔案,當前目錄下會生成 pdf 檔案

URDF優化_xacro

前面 URDF 檔案構建機器人模型的過程中,存在若干問題。

問題1:在設計關節的位置時,需要按照一定的公式計算,公式是固定的,但是在 URDF 中依賴於人工計算,存在不便,容易計算失誤,且當某些引數發生改變時,還需要重新計算。

問題2:URDF 中的部分內容是高度重複的,驅動輪與支撐輪的設計實現,不同輪子只是部分引數不同,形狀、顏色、翻轉量都是一致的,在實際應用中,構建複雜的機器人模型時,更是易於出現高度重複的設計,按照一般的程式設計涉及到重複程式碼應該考慮封裝。

......

如果在程式語言中,可以通過變數結合函式直接解決上述問題,在 ROS 中,已經給出了類似程式設計的優化方案,稱之為:Xacro

概念

Xacro 是 XML Macros 的縮寫,Xacro 是一種 XML 巨集語言,是可程式設計的 XML。

原理

Xacro 可以宣告變數,可以通過數學運算求解,使用流程控制控制執行順序,還可以通過類似函式的實現,封裝固定的邏輯,將邏輯中需要的可變的資料以引數的方式暴露出去,從而提高程式碼複用率以及程式的安全性。

作用

較之於純粹的 URDF 實現,可以編寫更安全、精簡、易讀性更強的機器人模型檔案,且可以提高編寫效率。


另請參考:

Xacro_快速體驗

目的:簡單瞭解 xacro 的基本語法。

需求描述:

使用xacro優化上一節案例中驅動輪實現,需要使用變數封裝底盤的半徑、高度,使用數學公式動態計算底盤的關節點座標,使用 Xacro 巨集封裝輪子重複的程式碼並呼叫巨集建立兩個輪子(注意: 在此,演示 Xacro 的基本使用,不必要生成合法的 URDF )。

準備:

建立功能包,匯入 urdf 與 xacro。

Xacro檔案編寫

編寫 Xacro 檔案,以變數的方式封裝屬性(常量半徑、高度、車輪半徑...),以函式的方式封裝重複實現(車輪的新增)。


<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 屬性封裝 -->
    <xacro:property name="wheel_radius" value="0.0325" />
    <xacro:property name="wheel_length" value="0.0015" />
    <xacro:property name="PI" value="3.1415927" />
    <xacro:property name="base_link_length" value="0.08" />
    <xacro:property name="lidi_space" value="0.015" />

    <!-- 巨集 -->
    <xacro:macro name="wheel_func" params="wheel_name flag" >
        <link name="${wheel_name}_wheel">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}" />
                </geometry>

                <origin xyz="0 0 0" rpy="${PI / 2} 0 0" />

                <material name="wheel_color">
                    <color rgba="0 0 0 0.3" />
                </material>
            </visual>
        </link>

        <!-- 3-2.joint -->
        <joint name="${wheel_name}2link" type="continuous">
            <parent link="base_link"  />
            <child link="${wheel_name}_wheel" />
            <!-- 
                x 無偏移
                y 車體半徑
                z z= 車體高度 / 2 + 離地間距 - 車輪半徑

            -->
            <origin xyz="0 ${0.1 * flag} ${(base_link_length / 2 + lidi_space - wheel_radius) * -1}" rpy="0 0 0" />
            <axis xyz="0 1 0" />
        </joint>

    </xacro:macro>
    <xacro:wheel_func wheel_name="left" flag="1" />
    <xacro:wheel_func wheel_name="right" flag="-1" />
</robot>

Xacro檔案轉換成 urdf 檔案

前提是開啟roscre

命令列進入 xacro檔案 所屬目錄,執行:rosrun xacro xacro xxx.xacro > xxx.urdf, 會將 xacro 檔案解析為 urdf 檔案,內容如下:

例如:

 rosrun xacro xacro demo01_helloworld.xacro > demo01_helloworld.urdf
<?xml version="1.0" encoding="utf-8"?>
<!-- =================================================================================== -->
<!-- |    This document was autogenerated by xacro from demo01_helloworld.xacro        | -->
<!-- |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED                                 | -->
<!-- =================================================================================== -->
<robot name="mycar">
  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder length="0.0015" radius="0.0325"/>
      </geometry>
      <origin rpy="1.57079635 0 0" xyz="0 0 0"/>
      <material name="wheel_color">
        <color rgba="0 0 0 0.3"/>
      </material>
    </visual>
  </link>
  <!-- 3-2.joint -->
  <joint name="left2link" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <!-- 
                x 無偏移
                y 車體半徑
                z z= 車體高度 / 2 + 離地間距 - 車輪半徑

            -->
    <origin rpy="0 0 0" xyz="0 0.1 -0.0225"/>
    <axis xyz="0 1 0"/>
  </joint>
  <link name="right_wheel">
    <visual>
      <geometry>
        <cylinder length="0.0015" radius="0.0325"/>
      </geometry>
      <origin rpy="1.57079635 0 0" xyz="0 0 0"/>
      <material name="wheel_color">
        <color rgba="0 0 0 0.3"/>
      </material>
    </visual>
  </link>
  <!-- 3-2.joint -->
  <joint name="right2link" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <!-- 
                x 無偏移
                y 車體半徑
                z z= 車體高度 / 2 + 離地間距 - 車輪半徑

            -->
    <origin rpy="0 0 0" xyz="0 -0.1 -0.0225"/>
    <axis xyz="0 1 0"/>
  </joint>
</robot>

Xacro_語法詳解

xacro 提供了可程式設計介面,類似於計算機語言,包括變數宣告呼叫、函式宣告與呼叫等語法實現。在使用 xacro 生成 urdf 時,根標籤robot中必須包含名稱空間宣告:xmlns:xacro="http://wiki.ros.org/xacro"

屬性與算數運算

用於封裝 URDF 中的一些欄位,比如: PI 值,小車的尺寸,輪子半徑 ....

屬性定義

屬性定義後必須呼叫才能生成urdf檔案

<xacro:property name="xxxx" value="yyyy" />

屬性呼叫

${屬性名稱}

算數運算

${數學表示式}

例子:

**屬性定義**
<xacro:property name="PI" value="3.1415926" />
**屬性呼叫**
<myexample name="${PI}" />
**算數運算**
<myexampleresult result="${PI/2}" />

巨集

類似於函式實現,提高程式碼複用率,優化程式碼結構,提高安全性

巨集定義

<xacro:macro name="巨集名稱" params="引數列表(多引數之間使用空格分隔)">

    .....

    引數呼叫格式: ${引數名}

</xacro:macro>

巨集呼叫

<xacro:巨集名稱 引數1=xxx 引數2=xxx/>

例子:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 1.巨集的定義 -->
    <xacro:macro name="getSum" params="num1 num2">
        <result value="${num1+num2}" />
    </xacro:macro>
    <!-- 2.巨集呼叫 -->
    <xacro:getSum num1="1" num2="2" />
</robot>

生成的urdf檔案:

<robot name="mycar">
  <result value="3"/>
</robot>

檔案包含

機器人由多部件組成,不同部件可能封裝為單獨的 xacro 檔案,最後再將不同的檔案整合,組合為完整機器人,可以使用檔案包含實現

檔案包含

<robot name="xxx" xmlns:xacro="http://wiki.ros.org/xacro">
      <xacro:include filename="my_base.xacro" />
      <xacro:include filename="my_camera.xacro" />
      <xacro:include filename="my_laser.xacro" />
      ....
</robot>

Xacro_完整使用流程示例

需求描述:

使用 Xacro 優化 URDF 版的小車底盤模型實現

編寫 Xacro 檔案

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- set base_footprint  -->
    <xacro:property name="footprint_radius" value="0.001" />
    <link name="base_footprint">
        <visual>
            <geometry
                <sphere radius="${footprint_radius}" />
            </geometry>
        </visual>
    </link>

    <!-- Add chassis -->
    <!-- define property -->
    <xacro:property name="base_radius" value="0.1" />
    <xacro:property name="base_length" value="0.08" />
    <xacro:property name="lidi" value="0.015" />
    <xacro:property name="base_joint" value="${base_length/2+lidi}" />

    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="${base_radius}" length="${base_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="yellow">
                <color rgba="0.8 0.5 0 0.5" />
            </material>
        </visual>
    </link>
    <!-- joint -->
    <joint name="base_link2base_footprint" type="fixed">
        <parent link="base_footprint" />
        <child link="base_link" />
        <origin xyz="0 0 ${base_joint}" />
    </joint>

    <!-- Add drive wheel -->
    <!-- 
        shape: cyliner
        radius: 0.035
        length: 0.015
     -->
    <xacro:property name="wheel_radius" value="0.0325" />
    <xacro:property name="wheel_length" value="0.015" />
    <xacro:property name="PI" value="${3.1415926/2}" />
    <xacro:property name="base_rjoint_z" value="${-(base_length/2 + lidi - wheel_radius) }" />
     <!-- define macro  
                        wheel_name: left or right
                         flag: -1 or 1
     
     -->
    <xacro:macro name="wheel_func" params="wheel_name flag">

        <link name="${wheel_name}_wheel">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}" />
                </geometry>
                <origin xyz="0 0 0" rpy="${PI} 0 0" />
                <material name="black">
                    <color rgba="0 0 0 1" />
                </material>
            </visual>
        </link>   
        <!-- joint base_link and whell -->
        <joint name="${wheel_name}2base_link" type="continuous">
            <parent link="base_link" />
            <child link="${wheel_name}_wheel" />
            <origin xyz="0 ${0.1*flag} ${base_rjoint_z}" />
            <axis xyz="0 1 0" />
        </joint>
    </xacro:macro>
    <!-- call macro-->
    <xacro:wheel_func wheel_name="left" flag="1" />
    <xacro:wheel_func wheel_name="right" flag="-1" />


    <!-- Add Cardan wheel -->
    <!-- define property -->
    <xacro:property name="ball_radius" value="0.0075" />
    <xacro:property name="ball_distance" value="0.08" />
    <xacro:property name="ball_hight" value="${-(base_length/2+lidi-ball_radius)}" />

    <!-- define macro
                cardan_ball_name: front or back
                flag: 1 or -1
    -->
    <xacro:macro name="cardan_ball_func" params="cardan_ball_name flag">
        <link name="${cardan_ball_name}_cardan_ball">
            <visual>
                <geometry>
                    <sphere radius="${ball_radius}" />
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0" />
                <material name="black">
                    <color rgba="0 0 0 1" />
                </material>
            </visual>
        </link>
        <!-- joint base_link and whell -->
        <joint name="${cardan_ball_name}2base_link" type="continuous">
            <parent link="base_link" />
            <child link="${cardan_ball_name}_cardan_ball" />
            <origin xyz="${flag*ball_distance} 0 ${ball_hight}" />
            <axis xyz="0 1 0" />
        </joint>
    </xacro:macro>
    <!-- call macro -->
    <xacro:cardan_ball_func cardan_ball_name="front" flag="1" />
    <xacro:cardan_ball_func cardan_ball_name="back" flag="-1" />

</robot>

整合launch檔案

方式1:先將 xacro 檔案轉換出 urdf 檔案,然後整合

先將 xacro 檔案解析成 urdf 檔案:rosrun xacro xacro xxx.xacro > xxx.urdf然後再按照之前的整合方式直接整合 launch 檔案,內容示例:

核心程式碼:

<launch>
    <param name="robot_description" textfile="$(find demo01_urdf_helloworld)/urdf/xacro/my_base.urdf" />

    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find demo01_urdf_helloworld)/config/helloworld.rviz" />
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" output="screen" />
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen" />
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen" />

</launch>

方式2:在 launch 檔案中直接載入 xacro(建議使用)


<launch>

    <!-- 設定引數 -->
    <param name="robot_description" command="$(find xacro)/xacro $(find urdt01_rviz)/urdf/xacro/demo02_car.urdf.xacro" />

    <!-- 啟動 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdt01_rviz)/config/show_mycar.rviz" />

    <!-- 新增關節狀態釋出節點 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 新增機器人狀態釋出節點 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
    <!-- 新增控制關節運動節點 -->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />

    


</launch>

核心程式碼:

    <param name="robot_description" command="$(find xacro)/xacro $(find urdt01_rviz)/urdf/xacro/demo02_car.urdf.xacro" />

載入robot_description時使用command屬性,屬性值就是呼叫 xacro 功能包的 xacro 程式直接解析 xacro 檔案。

Xacro_實操

需求描述:

在前面小車底盤基礎之上,新增攝像頭和雷達感測器。

實現分析:

機器人模型由多部件組成,可以將不同元件設定進單獨檔案,最終通過檔案包含實現元件的拼裝。

實現流程:

  1. 首先編寫攝像頭和雷達的 xacro 檔案
  2. 然後再編寫一個組合檔案,組合底盤、攝像頭與雷達
  3. 最後,通過 launch 檔案啟動 Rviz 並顯示模型

攝像頭 xacro 檔案:

<robot name="mycamera" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- Add chassis -->
    <!-- define property -->
    <xacro:property name="camera_length" value="0.01" />
    <xacro:property name="camera_width" value="0.025" />
    <xacro:property name="camera_height" value="0.025" />
    <xacro:property name="camera_x" value="0.08" />
    <xacro:property name="camera_y" value="0.0" />
    <xacro:property name="camera_z" value="${base_length/2 + camera_height/2}" />


    <link name="camera">
        <visual>
            <geometry>
                <box size="${camera_length} ${camera_width} ${camera_height}" /> 
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0 0 0 1" />
            </material>
        </visual>
    </link>
    <!-- joint -->
    <joint name="camera2base_footprint" type="fixed">
        <parent link="base_link" />
        <child link="camera" />
        <origin xyz="${camera_x} ${camera_y} ${camera_z}" />
    </joint>

  
</robot>

雷達 xacro 檔案:

組合底盤攝像頭與雷達的 xacro 檔案

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
      <xacro:include filename="demo02_car.urdf.xacro" />
      <xacro:include filename="demo02_camera.urdf.xacro" />
      <xacro:include filename="demo02_laser.urdf.xacro" />

</robot>

launch 檔案


<launch>

    <!-- 設定引數 -->
    <param name="robot_description" command="$(find xacro)/xacro $(find urdt01_rviz)/urdf/xacro/merge.urdf.xacro" />

    <!-- 啟動 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdt01_rviz)/config/show_mycar.rviz" />

    <!-- 新增關節狀態釋出節點 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 新增機器人狀態釋出節點 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
    <!-- 新增控制關節運動節點 -->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />

    


</launch>

Rviz中控制機器人模型運動

通過 URDF 結合 rviz 可以建立並顯示機器人模型,不過,當前實現的只是靜態模型,如何控制模型的運動呢?在此,可以呼叫 Arbotix 實現此功能。


簡介

Arbotix:Arbotix 是一款控制電機、舵機的控制板,並提供相應的 ros 功能包,這個功能包的功能不僅可以驅動真實的 Arbotix 控制板,它還提供一個差速控制器,通過接受速度控制指令更新機器人的 joint 狀態,從而幫助我們實現機器人在 rviz 中的運動。

這個差速控制器在 arbotix_python 程式包中,完整的 arbotix 程式包還包括多種控制器,分別對應 dynamixel 電機、多關節機械臂以及不同形狀的夾持器。

Arbotix使用流程

接下來,通過一個案例演示 arbotix 的使用。

需求描述:

控制機器人模型在 rviz 中做圓周運動

實現流程:

  1. 安裝 Arbotix
  2. 建立新功能包,準備機器人 urdf、xacro 檔案
  3. 新增 Arbotix 配置檔案
  4. 編寫 launch 檔案配置 Arbotix
  5. 啟動 launch 檔案並控制機器人模型運動

安裝 Arbotix

方式1:命令列呼叫

sudo apt-get install ros-<<VersionName()>>-arbotix

將 <<VsersionName()>> 替換成當前 ROS 版本名稱,如果提示功能包無法定位,請採用方式2。

方式2:原始碼安裝

先從 github 下載原始碼,然後呼叫 catkin_make 編譯

git clone https://github.com/vanadiumlabs/arbotix_ros.git

下載好的arbotix_ros資料夾 複製到 工作空間src目錄中

建立新功能包,準備機器人 urdf、xacro

urdf 和 xacro 呼叫上一講實現即可

新增 arbotix 所需的配置檔案

新增 arbotix 所需配置檔案.yaml檔案

# 該檔案是控制器配置,一個機器人模型可能有多個控制器,比如: 底盤、機械臂、夾持器(機械手)....
# 因此,根 name 是 controller
controllers: {
   # 單控制器設定
   base_controller: {
          #型別: 差速控制器
       type: diff_controller,
       #參考座標
       base_frame_id: base_footprint, 
       #兩個輪子之間的間距
       base_width: 0.2,
       #控制頻率
       ticks_meter: 2000, 
       #PID控制引數,使機器人車輪快速達到預期速度
       Kp: 12, 
       Kd: 12, 
       Ki: 0, 
       Ko: 50, 
       #加速限制
       accel_limit: 1.0 
    }
}

launch 檔案中配置 arbotix 節點

launch 示例程式碼

<node name="arbotix" pkg="arbotix_python" type="arbotix_driver" output="screen">
     <rosparam file="$(find my_urdf05_rviz)/config/hello.yaml" command="load" />
     <param name="sim" value="true" />
</node>

程式碼解釋:

呼叫了 arbotix_python 功能包下的 arbotix_driver 節點

arbotix 驅動機器人執行時,需要獲取機器人資訊,可以通過 file 載入配置檔案

在模擬環境下,需要配置 sim 為 true

啟動 launch 檔案並控制機器人模型運動

**啟動launch: oslaunch xxxx ....launch

配置 rviz:

控制小車運動:

此時呼叫 rostopic list 會發現一個熟悉的話題: /cmd_vel

也就說我們可以釋出 cmd_vel 話題訊息控制小陳運動了,該實現策略有多種,可以另行編寫節點,或者更簡單些可以直接通過如下命令釋出訊息:

rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.2, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0.5}}'

現在,小車就可以運動起來了。


另請參考:

URDF整合Gazebo

URDF 需要整合進 Rviz 或 Gazebo 才能顯示視覺化的機器人模型,前面已經介紹了URDF 與 Rviz 的整合,本節主要介紹:

  • URDF 與 Gazebo 的基本整合流程;
  • 如果要在 Gazebo 中顯示機器人模型,URDF 需要做的一些額外配置;
  • 關於Gazebo模擬環境的搭建。

URDF與Gazebo基本整合流程

URDF 與 Gazebo 整合流程與 Rviz 實現類似,主要步驟如下:

  1. 建立功能包,匯入依賴項
  2. 編寫 URDF 或 Xacro 檔案
  3. 啟動 Gazebo 並顯示機器人模型

建立功能包

建立新功能包,匯入依賴包: urdf、xacro、gazebo_ros、gazebo_ros_control、gazebo_plugins

編寫URDF檔案

<robot name="mycar">
    <link name="base_link">
        <visual>
            <geometry>
            <box size="0.5 0.3 0.1" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="yellow">
                <color rgba="0.5 0.3 0 0.5" />
            </material>
        </visual>

        <!-- set collision -->
        <!-- if it is standard geometry, copy geometry and origin of visual directly-->
        <collision>
            <geometry>
                <box size="0.5 0.3 0.1" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </collision>

        <!-- set inertial -->
        <inertial>
            <origin xyz="0 0 0" />
            <mass value="2" />
            <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" />
        </inertial>

    </link>

    <!-- gazebo has its own color setting label -->
    <gazebo reference="base_link">
        <material>Gazebo/Red</material>
    </gazebo>


</robot>

注意, 當 URDF 需要與 Gazebo 整合時,和 Rviz 有明顯區別:

1.必須使用 collision 標籤,因為既然是模擬環境,那麼必然涉及到碰撞檢測,collision 提供碰撞檢測的依據。

2.必須使用 inertial 標籤,此標籤標註了當前機器人某個剛體部分的慣性矩陣,用於一些力學相關的模擬計算。

3.顏色設定,也需要重新使用 gazebo 標籤標註,因為之前的顏色設定為了方便除錯包含透明度,模擬環境下沒有此選項。

啟動Gazebo並顯示模型

launch 檔案實現:

<launch>

    <!-- 將 Urdf 檔案的內容載入到引數伺服器 -->
    <param name="robot_description" textfile="$(find urdf02_gazebo)/urdf/demo01_helloworld.urdf" />

    <!-- 啟動 gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch" />

    <!-- 在 gazebo 中顯示機器人模型 -->
    <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description"  />
</launch>

程式碼解釋:

<include file="$(find gazebo_ros)/launch/empty_world.launch" />
<!-- 啟動 Gazebo 的模擬環境,當前環境為空環境 -->
<node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description"  />

<!-- 
    在 Gazebo 中載入一個機器人模型,該功能由 gazebo_ros 下的 spawn_model 提供:
    -urdf 載入的是 urdf 檔案
    -model mycar 模型名稱是 mycar
    -param robot_description 從引數 robot_description 中載入模型
    -x 模型載入的 x 座標
    -y 模型載入的 y 座標
    -z 模型載入的 z 座標
-->

URDF整合Gazebo相關設定

較之於 rviz,gazebo在整合 URDF 時,需要做些許修改,比如:必須新增 collision 碰撞屬性相關引數、必須新增 inertial 慣性矩陣相關引數,另外,如果直接移植 Rviz 中機器人的顏色設定是沒有顯示的,顏色設定也必須做相應的變更。

collision

如果機器人link是標準的幾何體形狀,和link的 visual 屬性設定一致即可。

inertial

慣性矩陣的設定需要結合link的質量與外形引數動態生成,標準的球體、圓柱與立方體的慣性矩陣公式如下(已經封裝為 xacro 實現):

球體慣性矩陣

<!-- Macro for inertia matrix -->
    <xacro:macro name="sphere_inertial_matrix" params="m r">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
                iyy="${2*m*r*r/5}" iyz="0" 
                izz="${2*m*r*r/5}" />
        </inertial>
    </xacro:macro>

圓柱慣性矩陣

<xacro:macro name="cylinder_inertial_matrix" params="m r h">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
                iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
                izz="${m*r*r/2}" /> 
        </inertial>
    </xacro:macro>

立方體慣性矩陣

 <xacro:macro name="Box_inertial_matrix" params="m l w h">
       <inertial>
               <mass value="${m}" />
               <inertia ixx="${m*(h*h + l*l)/12}" ixy = "0" ixz = "0"
                   iyy="${m*(w*w + l*l)/12}" iyz= "0"
                   izz="${m*(w*w + h*h)/12}" />
       </inertial>
   </xacro:macro>

需要注意的是,原則上,除了 base_footprint 外,機器人的每個剛體部分都需要設定慣性矩陣,且慣性矩陣必須經計算得出,如果隨意定義剛體部分的慣性矩陣,那麼可能會導致機器人在 Gazebo 中出現抖動,移動等現象。

顏色設定

在 gazebo 中顯示 link 的顏色,必須要使用指定的標籤:

<gazebo reference="link節點名稱">
     <material>Gazebo/Blue</material>
</gazebo>

PS:material 標籤中,設定的值區分大小寫,顏色可以設定為 Red Blue Green Black .....

URDF整合Gazebo實操

需求描述:

將之前的機器人模型(xacro版)顯示在 gazebo 中

實現流程:

  1. 需要編寫封裝慣性矩陣演算法的 xacro 檔案
  2. 為機器人模型中的每一個 link 新增 collision 和 inertial 標籤,並且重置顏色屬性
  3. 在 launch 檔案中啟動 gazebo 並新增機器人模型

編寫封裝慣性矩陣演算法的 xacro 檔案head.xacro

<robot name="base" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- Macro for inertia matrix -->
    <xacro:macro name="sphere_inertial_matrix" params="m r">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
                iyy="${2*m*r*r/5}" iyz="0" 
                izz="${2*m*r*r/5}" />
        </inertial>
    </xacro:macro>

    <xacro:macro name="cylinder_inertial_matrix" params="m r h">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
                iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
                izz="${m*r*r/2}" /> 
        </inertial>
    </xacro:macro>

    <xacro:macro name="Box_inertial_matrix" params="m l w h">
       <inertial>
               <mass value="${m}" />
               <inertia ixx="${m*(h*h + l*l)/12}" ixy = "0" ixz = "0"
                   iyy="${m*(w*w + l*l)/12}" iyz= "0"
                   izz="${m*(w*w + h*h)/12}" />
       </inertial>
   </xacro:macro>
</robot>

複製相關 xacro 檔案,並設定 collision inertial 以及 color 等引數

A.底盤 Xacro 檔案demo02_car.urdf.xacro
<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- set base_footprint  -->
    <xacro:property name="footprint_radius" value="0.001" />
    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="${footprint_radius}" />
            </geometry>
        </visual>
    </link>

    <!-- Add chassis -->
    <!-- define property -->
    <xacro:property name="base_radius" value="0.1" />
    <xacro:property name="base_length" value="0.08" />
    <xacro:property name="base_mass" value="3" />
    <xacro:property name="lidi" value="0.015" />
    <xacro:property name="base_joint" value="${base_length/2+lidi}" />

    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="${base_radius}" length="${base_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </visual>
        <!-- gazebo...collosion -->
        <collision>
            <geometry>
                <cylinder radius="${base_radius}" length="${base_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </collision>
        <!-- gazebo...call inertia matrix function -->
        <xacro:cylinder_inertial_matrix  m="${base_mass}" r="${base_radius}" h="${base_length}" />
    </link>
    <!--gazebo...set color -->
    <gazebo reference="base_link">
        <material>Gazebo/Yellow</material>
    </gazebo>
    <!-- joint -->
    <joint name="base_link2base_footprint" type="fixed">
        <parent link="base_footprint" />
        <child link="base_link" />
        <origin xyz="0 0 ${base_joint}" />
    </joint>



    <!-- Add drive wheel -->
    <!-- 
        shape: cyliner
        radius: 0.035
        length: 0.015
        mass:0.5
     -->
    <xacro:property name="wheel_radius" value="0.0325" />
    <xacro:property name="wheel_length" value="0.015" />
    <xacro:property name="wheel_mass" value="0.05" />
    <xacro:property name="PI" value="${3.1415926/2}" />
    <xacro:property name="base_rjoint_z" value="${-(base_length/2 + lidi - wheel_radius) }" />
     <!-- define macro  
                        wheel_name: left or right
                         flag: -1 or 1
     
     -->
    <xacro:macro name="wheel_func" params="wheel_name flag">

        <link name="${wheel_name}_wheel">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}" />
                </geometry>
                <origin xyz="0 0 0" rpy="${PI} 0 0" />
                <material name="black">
                    <color rgba="0 0 0 1" />
                </material>
            </visual>
            <!-- gazebo...collosion -->
            <collision>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}" />
                </geometry>
                <origin xyz="0 0 0" rpy="${PI} 0 0" />
            </collision>
            <!-- gazebo...call inertia matrix function -->
            <xacro:cylinder_inertial_matrix m="${wheel_mass}" r="${wheel_radius}" h="${wheel_length}" />
        </link>  
        <!--gazebo...set color -->
        <gazebo reference="${wheel_name}_wheel">
            <material>Gazebo/Red</material>
        </gazebo>
        <!-- joint base_link and whell -->
        <joint name="${wheel_name}2base_link" type="continuous">
            <parent link="base_link" />
            <child link="${wheel_name}_wheel" />
            <origin xyz="0 ${0.1*flag} ${base_rjoint_z}" />
            <axis xyz="0 1 0" />
        </joint>
    </xacro:macro>
    <!-- call macro-->
    <xacro:wheel_func wheel_name="left" flag="1" />
    <xacro:wheel_func wheel_name="right" flag="-1" />


    <!-- Add Cardan wheel -->
    <!-- define property -->
    <xacro:property name="ball_radius" value="0.0075" />
    <xacro:property name="ball_distance" value="0.08" />
    <xacro:property name="ball_mass" value="0.1" />
    <xacro:property name="ball_hight" value="${-(base_length/2+lidi-ball_radius)}" />

    <!-- define macro
                cardan_ball_name: front or back
                flag: 1 or -1
    -->
    <xacro:macro name="cardan_ball_func" params="cardan_ball_name flag">
        <link name="${cardan_ball_name}_cardan_ball">
            <visual>
                <geometry>
                    <sphere radius="${ball_radius}" />
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0" />
            </visual>
            <!-- gazebo...collision -->
            <collision>
                <geometry>
                    <sphere radius="${ball_radius}" />
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0" />
            </collision>
            <!-- gazebo...call inertia matrix function -->
            <xacro:sphere_inertial_matrix m="${ball_mass}" r="${ball_radius}" />
        </link>
        <!--gazebo...set color -->
        <gazebo reference="${cardan_ball_name}_cardan_ball">
            <material>Gazebo/Red</material>
        </gazebo>
        <!-- joint base_link and whell -->
        <joint name="${cardan_ball_name}2base_link" type="continuous">
            <parent link="base_link" />
            <child link="${cardan_ball_name}_cardan_ball" />
            <origin xyz="${flag*ball_distance} 0 ${ball_hight}" />
            <axis xyz="0 1 0" />
        </joint>
    </xacro:macro>
    <!-- call macro -->
    <xacro:cardan_ball_func cardan_ball_name="front" flag="1" />
    <xacro:cardan_ball_func cardan_ball_name="back" flag="-1" />

</robot>

注意: 如果機器人模型在 Gazebo 中產生了抖動,滑動,緩慢位移 .... 諸如此類情況,請檢視

  1. 慣性矩陣是否設定了,且設定是否正確合理
  2. 車輪翻轉需要依賴於 PI 值,如果 PI 值精度偏低,也可能導致上述情況產生
B.攝像頭 Xacro 檔案demo02_camera.urdf.xacro
<robot name="mycamera" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- Add chassis -->
    <!-- define property -->
    <xacro:property name="camera_mass" value="0.1" />
    <xacro:property name="camera_length" value="0.01" />
    <xacro:property name="camera_width" value="0.025" />
    <xacro:property name="camera_height" value="0.025" />
    <xacro:property name="camera_x" value="0.08" />
    <xacro:property name="camera_y" value="0.0" />
    <xacro:property name="camera_z" value="${base_length/2 + camera_height/2}" />


    <link name="camera">
        <visual>
            <geometry>
                <box size="${camera_length} ${camera_width} ${camera_height}" /> 
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </visual>
        <!-- gazebo...collision -->
        <collision>
            <geometry>
                <box size="${camera_length} ${camera_width} ${camera_height}" /> 
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </collision>
        <!-- gazebo...call inertia matrix function -->
        <xacro:Box_inertial_matrix m="${camera_mass}" l="${camera_length}" w="${camera_width}" h="${camera_height}" />  
    </link>
    <!--gazebo...set color -->
    <gazebo reference="camera">
        <material>Gazebo/Blue</material>
    </gazebo>

    <!-- joint -->
    <joint name="camera2base_footprint" type="fixed">
        <parent link="base_link" />
        <child link="camera" />
        <origin xyz="${camera_x} ${camera_y} ${camera_z}" />
    </joint>

  
</robot>
C.雷達 Xacro 檔案demo02_laser.urdf.xacro
<robot name="mylaser" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- Add support -->
    <!-- define property -->
    <xacro:property name="support_radius" value="0.01" />
    <xacro:property name="support_length" value="0.15" />
    <xacro:property name="support_mass" value="0.05" />
    <xacro:property name="support_x" value="0.0" />
    <xacro:property name="support_y" value="0.0" />
    <xacro:property name="support_z" value="${base_length/2 + support_length/2}" />


    <link name="support">
        <visual>
            <geometry>
                <cylinder radius="${support_radius}" length="${support_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </visual>
        <!-- gazebo...collision -->
        <collision>
            <geometry>
                <cylinder radius="${support_radius}" length="${support_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </collision>
        <!-- gazebo...call inertia matrix function -->
        <xacro:cylinder_inertial_matrix m="${support_mass}" r="${support_radius}" h="${support_length}" />
    </link>
    <!-- joint -->
    <joint name="support2base_link" type="fixed">
        <parent link="base_link" />
        <child link="support" />
        <origin xyz="${support_x} ${support_y} ${support_z}" />
    </joint>


    <!-- Add laser -->
    <!-- define property -->
    <xacro:property name="laser_radius" value="0.03" />
    <xacro:property name="laser_length" value="0.05" />
    <xacro:property name="laser_mass" value="0.05" />
    <xacro:property name="laser_x" value="0.0" />
    <xacro:property name="laser_y" value="0.0" />
    <xacro:property name="laser_z" value="${support_length + laser_length/2}" />


    <link name="laser">
        <visual>
            <geometry>
                <cylinder radius="${laser_radius}" length="${laser_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </visual>
        <!-- gazebo...collision -->
        <collision>
            <geometry>
                <cylinder radius="${laser_radius}" length="${laser_length}" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
        </collision>
        <!-- gazebo...call inertia matrix function -->
        <xacro:cylinder_inertial_matrix m="${laser_mass}" r="${laser_radius}" h="${laser_length}" />
    </link>
    <!--gazebo...set color -->
    <gazebo reference="laser">
        <material>Gazebo/Black</material>
    </gazebo>
    <!-- joint -->
    <joint name="laser2base_link" type="fixed">
        <parent link="base_link" />
        <child link="laser" />
        <origin xyz="${laser_x} ${laser_y} ${laser_z}" />
    </joint>

</robot>
D.組合底盤、攝像頭與雷達的 Xacro 檔案
<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
      <xacro:include filename="head.xacro" />   
      <xacro:include filename="demo02_car.urdf.xacro" />
      <xacro:include filename="demo02_camera.urdf.xacro" />
      <xacro:include filename="demo02_laser.urdf.xacro" />
</robot>

在 gazebo 中執行

launch 檔案:

<launch>

    <!-- 將 Urdf 檔案的內容載入到引數伺服器 -->
    <param name="robot_description" command="$(find xacro)/xacro $(find urdf02_gazebo)/urdf/merge.urdf.xacro" />

    <!-- 啟動 gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch" />

    <!-- 在 gazebo 中顯示機器人模型 -->
    <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description"  />
</launch>

Gazebo模擬環境搭建

到目前為止,我們已經可以將機器人模型顯示在 Gazebo 之中了,但是當前預設情況下,在 Gazebo 中機器人模型是在 empty world 中,並沒有類似於房間、傢俱、道路、樹木... 之類的模擬物,如何在 Gazebo 中建立模擬環境呢?

Gazebo 中建立模擬實現方式有兩種:

  • 方式1: 直接新增內建元件建立模擬環境
  • 方式2: 手動繪製模擬環境(更為靈活)

也還可以直接下載使用官方或第三方提高的模擬環境外掛。

新增內建元件建立模擬環境

1.1啟動 Gazebo 並新增元件
儲存模擬環境

新增完畢後,選擇 file ---> Save World as 選擇儲存路徑(功能包下: worlds 目錄),檔名自定義,字尾名設定為 .world

載入已經建好的.world檔案

1.在工程中建立world資料夾,將建立好的world檔案放入資料夾中

2.編輯launch檔案demo03_environment.launch

<launch>

    <!-- 將 Urdf 檔案的內容載入到引數伺服器 -->
    <param name="robot_description" command="$(find xacro)/xacro $(find urdf02_gazebo)/urdf/merge.urdf.xacro" />

    <!-- 啟動 gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch" >
        <arg name="world_name" value="$(find urdf02_gazebo)/worlds/box_house.world" />
    </include>
    <!-- 在 gazebo 中顯示機器人模型 -->
    <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description"  />
</launch>

注意:arg name="world_name" ,此處名字不能隨便命名,要與已經建立好的.world檔案裡面的名字一致

        <arg name="world_name" value="$(find urdf02_gazebo)/worlds/box_house.world" />

3.執行launch檔案並檢視gazebo

核心程式碼: 啟動 empty_world 後,再根據arg載入自定義的模擬環境

<!-- 啟動 gazebo -->
<include file="$(find gazebo_ros)/launch/empty_world.launch" >
    <arg name="world_name" value="$(find urdf02_gazebo)/worlds/box_house.world" />

自定義模擬環境

啟動 gazebo 開啟構建面板,繪製模擬環境
儲存構建的環境

點選: 左上角 file ---> Save (儲存路徑功能包下的: models)

然後 file ---> Exit Building Editor

儲存為 world 檔案

可以像方式1一樣再新增一些外掛,然後儲存為 world 檔案(儲存路徑功能包下的: worlds)

啟動

同方式1

使用官方提供的外掛

當前 Gazebo 提供的模擬道具有限,還可以下載官方支援,可以提供更為豐富的模擬實現,具體實現如下:

下載官方模型庫
git clone https://github.com/osrf/gazebo_models

之前是:hg clone https://bitbucket.org/osrf/gazebo_models但是已經不可用

注意: 此過程可能比較耗時

將模型庫複製進 gazebo

將得到的gazebo_models資料夾內容複製到 /usr/share/gazebo-*/models

應用

重啟 Gazebo,選擇左側選單欄的 insert 可以選擇並插入相關道具了

URDF、Gazebo與Rviz綜合應用

關於URDF(Xacro)、Rviz 和 Gazebo 三者的關係,前面已有闡述: URDF 用於建立機器人模型、Rviz 可以顯示機器人感知到的環境資訊,Gazebo 用於模擬,可以模擬外界環境,以及機器人的一些感測器,如何在 Gazebo 中執行這些感測器,並顯示這些感測器的資料(機器人的視角)呢?本節主要介紹的重點就是將三者結合:通過 Gazebo 模擬機器人的感測器,然後在 Rviz 中顯示這些感測器感知到的資料。主要內容包括:

  • 運動控制以及里程計資訊顯示
  • 雷達資訊模擬以及顯示
  • 攝像頭資訊模擬以及顯示
  • kinect 資訊模擬以及顯示

另請參考:

機器人運動控制以及里程計資訊顯示

gazebo 中已經可以正常顯示機器人模型了,那麼如何像在 rviz 中一樣控制機器人運動呢?在此,需要涉及到ros中的元件: ros_control。

ros_control 簡介

介面

場景:同一套 ROS 程式,如何部署在不同的機器人系統上,比如:開發階段為了提高效率是在模擬平臺上測試的,部署時又有不同的實體機器人平臺,不同平臺的實現是有差異的,如何保證 ROS 程式的可移植性?ROS 內建的解決方式是 ros_control。

ros_control:是一組軟體包,它包含了控制器介面,控制器管理器,傳輸和硬體介面。ros_control 是一套機器人控制的中介軟體,是一套規範,不同的機器人平臺只要按照這套規範實現,那麼就可以保證 與ROS 程式相容,通過這套規範,實現了一種可插拔的架構設計,大大提高了程式設計的效率與靈活性。

gazebo 已經實現了 ros_control 的相關介面,如果需要在 gazebo 中控制機器人運動,直接呼叫相關介面即可

運動控制實現流程(Gazebo)

承上,運動控制基本流程:

  1. 已經建立完畢的機器人模型,編寫一個單獨的 xacro 檔案,為機器人模型新增傳動裝置以及控制器
  2. 將此檔案整合進xacro檔案
  3. 啟動 Gazebo 併發布 /cmd_vel 訊息控制機器人運動
為 joint 新增傳動裝置以及控制器

兩輪差速配置

更多配置:

http://gazebosim.org/tutorials?tut=ros_gzplugins

<robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- 傳動實現:用於連線控制器與關節 -->
    <xacro:macro name="joint_trans" params="joint_name">
        <!-- Transmission is important to link the joints and the controller -->
        <transmission name="${joint_name}_trans">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="${joint_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${joint_name}_motor">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
                <mechanicalReduction>1</mechanicalReduction>
            </actuator>
        </transmission>
    </xacro:macro>

    <!-- 每一個驅動輪都需要配置傳動裝置 -->
    <xacro:joint_trans joint_name="left_wheel2base_link" />
    <xacro:joint_trans joint_name="right_wheel2base_link" />

    <!-- 控制器 -->
    <gazebo>
        <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
            <rosDebugLevel>Debug</rosDebugLevel>
            <publishWheelTF>true</publishWheelTF>
            <robotNamespace>/</robotNamespace>
            <publishTf>1</publishTf>
            <publishWheelJointState>true</publishWheelJointState>
            <alwaysOn>true</alwaysOn>
            <updateRate>100.0</updateRate>
            <legacyMode>true</legacyMode>
            <leftJoint>left_wheel2base_link</leftJoint> <!-- 左輪 -->
            <rightJoint>right_wheel2base_link</rightJoint> <!-- 右輪 -->
            <wheelSeparation>${base_link_radius * 2}</wheelSeparation> <!-- 車輪間距 -->
            <wheelDiameter>${wheel_radius * 2}</wheelDiameter> <!-- 車輪直徑 -->
            <broadcastTF>1</broadcastTF>
            <wheelTorque>30</wheelTorque>
            <wheelAcceleration>1.8</wheelAcceleration>
            <commandTopic>cmd_vel</commandTopic> <!-- 運動控制話題 -->
            <odometryFrame>odom</odometryFrame> 
            <odometryTopic>odom</odometryTopic> <!-- 里程計話題 -->
            <robotBaseFrame>base_footprint</robotBaseFrame> <!-- 根座標系 -->
        </plugin>
    </gazebo>

</robot>

需要與配置檔案進行匹配

<robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- Transmission realization: it is used to connect the controller and the switch -->
    <xacro:macro name="joint_trans" params="joint_name">
        <!-- Transmission is important to link the joints and the controller -->
        <transmission name="${joint_name}_trans">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="${joint_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${joint_name}_motor">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
                <mechanicalReduction>1</mechanicalReduction>
            </actuator>
        </transmission>
    </xacro:macro>

    <!-- Each drive wheel needs to be equipped with a transmission device -->
    <!--  Modify match -->
    <xacro:joint_trans joint_name="left2base_link" />
    <xacro:joint_trans joint_name="right2base_link" />

    <!-- controller -->
    <gazebo>
        <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
            <rosDebugLevel>Debug</rosDebugLevel>
            <publishWheelTF>true</publishWheelTF>
            <robotNamespace>/</robotNamespace>
            <publishTf>1</publishTf>
            <publishWheelJointState>true</publishWheelJointState>
            <alwaysOn>true</alwaysOn>
            <updateRate>100.0</updateRate>
            <legacyMode>true</legacyMode>
            <leftJoint>left2base_link</leftJoint> <!--left wheel -->
            <rightJoint>right2base_link</rightJoint> <!-- right  wheel -->
            <wheelSeparation>${base_radius * 2}</wheelSeparation> <!-- Wheel spacing -->
            <wheelDiameter>${wheel_radius * 2}</wheelDiameter> <!-- Wheel diameter -->
            <broadcastTF>1</broadcastTF>
            <wheelTorque>30</wheelTorque>
            <wheelAcceleration>1.8</wheelAcceleration>
            <commandTopic>cmd_vel</commandTopic> <!-- Motion control topics -->
            <odometryFrame>odom</odometryFrame> 
            <odometryTopic>odom</odometryTopic> <!-- Odometer topic -->
            <robotBaseFrame>base_footprint</robotBaseFrame> <!-- root coordinate system -->
        </plugin>
    </gazebo>

</robot>

報錯:Error:Unable to convert from SDF version 1.7 to 1.6

解決:box_house.world

檢視話題:

rostopic list 

有/cmd_vel話題

鍵盤控制並設定速度與角速度:

 rosrun teleop_twist_keyboard teleop_twist_keyboard.py _speed:=0.3 _turn:=0.1

Rviz檢視里程計資訊

在 Gazebo 的模擬環境中,機器人的里程計資訊以及運動朝向等資訊是無法獲取的,可以通過 Rviz 顯示機器人的里程計資訊以及運動朝向

里程計: 機器人相對出發點座標系的位姿狀態(X 座標 Y 座標 Z座標以及朝向)。

啟動 Rviz
<launch>
    <!-- 啟動 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" />

    <!-- 關節以及機器人狀態釋出節點 -->
    <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />

</launch>
新增元件

執行 launch 檔案後,在 Rviz 中新增圖示元件:

雷達資訊模擬以及顯示

通過 Gazebo 模擬鐳射雷達感測器,並在 Rviz 中顯示鐳射資料。

實現流程:

雷達模擬基本流程:

  1. 已經建立完畢的機器人模型,編寫一個單獨的 xacro 檔案,為機器人模型新增雷達配置;
  2. 將此檔案整合進xacro檔案;
  3. 啟動 Gazebo,使用 Rviz 顯示雷達資訊。

1.Gazebo 模擬雷達

新建 Xacro 檔案,配置雷達感測器資訊
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">

  <!-- 雷達 -->
  <gazebo reference="laser"> <!-- 此處name參考 link name -->
      
    <sensor type="ray" name="rplidar">
      <pose>0 0 0 0 0 0</pose>
      <visualize>true</visualize>
      <update_rate>5.5</update_rate>
      <ray>
        <scan>
          <horizontal>
            <samples>360</samples>
            <resolution>1</resolution>
            <min_angle>-3</min_angle>
            <max_angle>3</max_angle>
          </horizontal>
        </scan>
        <range>
          <min>0.10</min>
          <max>30.0</max>
          <resolution>0.01</resolution>
        </range>
        <noise>
          <type>gaussian</type>
          <mean>0.0</mean>
          <stddev>0.01</stddev>
        </noise>
      </ray>
      <plugin name="gazebo_rplidar" filename="libgazebo_ros_laser.so">
        <topicName>/scan</topicName>
        <frameName>laser</frameName>
      </plugin>
    </sensor>
  </gazebo>

</robot>
xacro 檔案整合

將步驟1的 Xacro 檔案整合進總的機器人模型檔案,程式碼示例如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
      <xacro:include filename="head.xacro" />   
      <xacro:include filename="demo02_car.urdf.xacro" />
      <xacro:include filename="demo02_camera.urdf.xacro" />
      <xacro:include filename="demo02_laser.urdf.xacro" />
      
      <xacro:include filename="gazebo/move.xacro" />
      <xacro:include filename="gazebo/laser.xacro" />

</robot>

啟動模擬環境

編寫launch檔案,啟動gazebo,此處略...

Rviz 顯示雷達資料

先啟動 rviz,新增雷達資訊顯示外掛

攝像頭資訊模擬以及顯示

通過 Gazebo 模擬攝像頭感測器,並在 Rviz 中顯示攝像頭資料。

實現流程:

攝像頭模擬基本流程:

  1. 已經建立完畢的機器人模型,編寫一個單獨的 xacro 檔案,為機器人模型新增攝像頭配置;
  2. 將此檔案整合進xacro檔案;
  3. 啟動 Gazebo,使用 Rviz 顯示攝像頭資訊。

Gazebo 模擬攝像頭

新建 Xacro 檔案,配置攝像頭感測器資訊
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">
  <!-- 被引用的link -->
  <gazebo reference="camera">
    <!-- 型別設定為 camara -->
    <sensor type="camera" name="camera_node">
      <update_rate>30.0</update_rate> <!-- 更新頻率 -->
      <!-- 攝像頭基本資訊設定 -->
      <camera name="head">
        <horizontal_fov>1.3962634</horizontal_fov>
        <image>
          <width>1280</width>
          <height>720</height>
          <format>R8G8B8</format>
        </image>
        <clip>
          <near>0.02</near>
          <far>300</far>
        </clip>
        <noise>
          <type>gaussian</type>
          <mean>0.0</mean>
          <stddev>0.007</stddev>
        </noise>
      </camera>
      <!-- 核心外掛 -->
      <plugin name="gazebo_camera" filename="libgazebo_ros_camera.so">
        <alwaysOn>true</alwaysOn>
        <updateRate>0.0</updateRate>
        <cameraName>/camera</cameraName>
        <imageTopicName>image_raw</imageTopicName>
        <cameraInfoTopicName>camera_info</cameraInfoTopicName>
        <frameName>camera</frameName>
        <hackBaseline>0.07</hackBaseline>
        <distortionK1>0.0</distortionK1>
        <distortionK2>0.0</distortionK2>
        <distortionK3>0.0</distortionK3>
        <distortionT1>0.0</distortionT1>
        <distortionT2>0.0</distortionT2>
      </plugin>
    </sensor>
  </gazebo>
</robot>
xacro 檔案整合

將步驟1的 Xacro 檔案整合進總的機器人模型檔案,程式碼示例如下:

<robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
      <xacro:include filename="head.xacro" />   
      <xacro:include filename="demo02_car.urdf.xacro" />
      <xacro:include filename="demo02_camera.urdf.xacro" />
      <xacro:include filename="demo02_laser.urdf.xacro" />
      
      <xacro:include filename="gazebo/move.xacro" />
      <xacro:include filename="gazebo/laser.xacro" />
      <xacro:include filename="gazebo/camera.xacro" />

</robot>

啟動模擬環境

編寫launch檔案,啟動gazebo,此處略...

Rviz 顯示攝像頭資料

執行 gazebo 並啟動 Rviz,在 Rviz 中新增攝像頭元件。

kinect資訊模擬以及顯示

通過 Gazebo 模擬kinect攝像頭,並在 Rviz 中顯示kinect攝像頭資料。

實現流程:

kinect攝像頭模擬基本流程:

  1. 已經建立完畢的機器人模型,編寫一個單獨的 xacro 檔案,為機器人模型新增kinect攝像頭配置;
  2. 將此檔案整合進xacro檔案;
  3. 啟動 Gazebo,使用 Rviz 顯示kinect攝像頭資訊。

Gazebo模擬Kinect

新建 Xacro 檔案,配置 kinetic感測器資訊
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">
    <gazebo reference="kinect link名稱">  
      <sensor type="depth" name="camera">
        <always_on>true</always_on>
        <update_rate>20.0</update_rate>
        <camera>
          <horizontal_fov>${60.0*PI/180.0}</horizontal_fov>
          <image>
            <format>R8G8B8</format>
            <width>640</width>
            <height>480</height>
          </image>
          <clip>
            <near>0.05</near>
            <far>8.0</far>
          </clip>
        </camera>
        <plugin name="kinect_camera_controller" filename="libgazebo_ros_openni_kinect.so">
          <cameraName>camera</cameraName>
          <alwaysOn>true</alwaysOn>
          <updateRate>10</updateRate>
          <imageTopicName>rgb/image_raw</imageTopicName>
          <depthImageTopicName>depth/image_raw</depthImageTopicName>
          <pointCloudTopicName>depth/points</pointCloudTopicName>
          <cameraInfoTopicName>rgb/camera_info</cameraInfoTopicName>
          <depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
          <frameName>kinect link名稱</frameName>
          <baseline>0.1</baseline>
          <distortion_k1>0.0</distortion_k1>
          <distortion_k2>0.0</distortion_k2>
          <distortion_k3>0.0</distortion_k3>
          <distortion_t1>0.0</distortion_t1>
          <distortion_t2>0.0</distortion_t2>
          <pointCloudCutoff>0.4</pointCloudCutoff>
        </plugin>
      </sensor>
    </gazebo>

</robot>
xacro 檔案整合

將步驟1的 Xacro 檔案整合進總的機器人模型檔案,程式碼示例如下:

<!-- 組合小車底盤與感測器 -->
<robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
    <xacro:include filename="my_head.urdf.xacro" />
    <xacro:include filename="my_base.urdf.xacro" />
    <xacro:include filename="my_camera.urdf.xacro" />
    <xacro:include filename="my_laser.urdf.xacro" />
    <xacro:include filename="move.urdf.xacro" />
    <!-- kinect模擬的 xacro 檔案 -->
    <xacro:include filename="my_sensors_kinect.urdf.xacro" />
</robot>
啟動模擬環境

編寫launch檔案,啟動gazebo,此處略...

Rviz 顯示 Kinect 資料

啟動 rviz,新增攝像頭元件檢視資料

kinect 點雲資料顯示

在kinect中也可以以點雲的方式顯示感知周圍環境,在 rviz 中操作如下:

問題:在rviz中顯示時錯位。

原因:在kinect中影象資料與點雲資料使用了兩套座標系統,且兩套座標系統位姿並不一致。

解決:

相當於新建一個子座標系kinect_depth

1.在外掛中為kinect設定座標系,修改配置檔案的<frameName>標籤內容:

<frameName>kinect_depth</frameName>

2.釋出新設定的座標系到kinect連桿的座標變換關係,在啟動rviz的launch中,新增:

<node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 -1.57 0 -1.57 /kinect /kinect_depth" />

3.啟動rviz,重新顯示。

本章小結

本章主要介紹了ROS中模擬實現涉及的三大知識點:

  • URDF(Xacro)
  • Rviz
  • Gazebo

URDF 是用於描述機器人模型的 xml 檔案,可以使用不同的標籤具代表不同含義,URDF 編寫機器人模型程式碼冗餘,xacro 可以優化 URDF 實現,程式碼實現更為精簡、高效、易讀。容易混淆的是Rviz與Gazebo,在此我們著重比較以下二者的區別:

rviz是三維視覺化工具,強調把已有的資料視覺化顯示;

gazebo是三維物理模擬平臺,強調的是建立一個虛擬的模擬環境。

rviz需要已有資料

rviz提供了很多外掛,這些外掛可以顯示影象、模型、路徑等資訊,但是前提都是這些資料已經以話題、引數的形式釋出,rviz做的事情就是訂閱這些資料,並完成視覺化的渲染,讓開發者更容易理解資料的意義。

gazebo不是顯示工具,強調的是模擬,它不需要資料,而是創造資料

我們可以在gazebo中免費建立一個機器人世界,不僅可以模擬機器人的運動功能,還可以模擬機器人的感測器資料。而這些資料就可以放到rviz中顯示,所以使用gazebo的時候,經常也會和rviz配合使用。當我們手上沒有機器人硬體或實驗環境難以搭建時,模擬往往是非常有用的利器。

綜上,如果你手上已經有機器人硬體平臺,並且在上邊可以完成需要的功能,用rviz應該就可以滿足開發需求。

如果你手上沒有機器人硬體,或者想在模擬環境中做一些演算法、應用的測試,gazebo+rviz應該是你需要的。

另外,rviz配合其他功能包也可以建立一個簡單的模擬環境,比如rviz+ArbotiX。
opicName>
depth/camera_info
kinect link名稱
0.1
<distortion_k1>0.0</distortion_k1>
<distortion_k2>0.0</distortion_k2>
<distortion_k3>0.0</distortion_k3>
<distortion_t1>0.0</distortion_t1>
<distortion_t2>0.0</distortion_t2>
0.4


```
xacro 檔案整合

將步驟1的 Xacro 檔案整合進總的機器人模型檔案,程式碼示例如下:

<!-- 組合小車底盤與感測器 -->
<robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
    <xacro:include filename="my_head.urdf.xacro" />
    <xacro:include filename="my_base.urdf.xacro" />
    <xacro:include filename="my_camera.urdf.xacro" />
    <xacro:include filename="my_laser.urdf.xacro" />
    <xacro:include filename="move.urdf.xacro" />
    <!-- kinect模擬的 xacro 檔案 -->
    <xacro:include filename="my_sensors_kinect.urdf.xacro" />
</robot>
啟動模擬環境

編寫launch檔案,啟動gazebo,此處略...

Rviz 顯示 Kinect 資料

啟動 rviz,新增攝像頭元件檢視資料

[外鏈圖片轉存中...(img-eFtObIky-1649728244993)]

[外鏈圖片轉存中...(img-t0EOpXOu-1649728244995)]

kinect 點雲資料顯示

在kinect中也可以以點雲的方式顯示感知周圍環境,在 rviz 中操作如下:

[外鏈圖片轉存中...(img-Vvuddrrz-1649728244997)]

問題:在rviz中顯示時錯位。

原因:在kinect中影象資料與點雲資料使用了兩套座標系統,且兩套座標系統位姿並不一致。

解決:

相當於新建一個子座標系kinect_depth

1.在外掛中為kinect設定座標系,修改配置檔案的<frameName>標籤內容:

<frameName>kinect_depth</frameName>

2.釋出新設定的座標系到kinect連桿的座標變換關係,在啟動rviz的launch中,新增:

<node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 -1.57 0 -1.57 /kinect /kinect_depth" />

3.啟動rviz,重新顯示。

[外鏈圖片轉存中...(img-NJ8NJ3Ld-1649728244999)]

本章小結

本章主要介紹了ROS中模擬實現涉及的三大知識點:

  • URDF(Xacro)
  • Rviz
  • Gazebo

URDF 是用於描述機器人模型的 xml 檔案,可以使用不同的標籤具代表不同含義,URDF 編寫機器人模型程式碼冗餘,xacro 可以優化 URDF 實現,程式碼實現更為精簡、高效、易讀。容易混淆的是Rviz與Gazebo,在此我們著重比較以下二者的區別:

rviz是三維視覺化工具,強調把已有的資料視覺化顯示;

gazebo是三維物理模擬平臺,強調的是建立一個虛擬的模擬環境。

rviz需要已有資料

rviz提供了很多外掛,這些外掛可以顯示影象、模型、路徑等資訊,但是前提都是這些資料已經以話題、引數的形式釋出,rviz做的事情就是訂閱這些資料,並完成視覺化的渲染,讓開發者更容易理解資料的意義。

gazebo不是顯示工具,強調的是模擬,它不需要資料,而是創造資料

我們可以在gazebo中免費建立一個機器人世界,不僅可以模擬機器人的運動功能,還可以模擬機器人的感測器資料。而這些資料就可以放到rviz中顯示,所以使用gazebo的時候,經常也會和rviz配合使用。當我們手上沒有機器人硬體或實驗環境難以搭建時,模擬往往是非常有用的利器。

綜上,如果你手上已經有機器人硬體平臺,並且在上邊可以完成需要的功能,用rviz應該就可以滿足開發需求。

如果你手上沒有機器人硬體,或者想在模擬環境中做一些演算法、應用的測試,gazebo+rviz應該是你需要的。

另外,rviz配合其他功能包也可以建立一個簡單的模擬環境,比如rviz+ArbotiX。