天天看點

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

寫在前面

通過上一節的部落格,相信朋友們已經對urdf有了一個較為完整的認識,應該也可以自主的寫一個urdf檔案在ros和gazebo看到了,但是僅僅是這樣,如果我們志在讓機器人在gazebo中運作的話,其實還是差很多東西,原因還是那句話,gazebo是靠實體引擎驅動的,我們現在的urdf檔案還差一些實體定律所需要的最基本的屬性。

那麼本節的主要目的就是給我們的urdf添加上更多的屬性,讓gazebo更加“歡迎”我們給予它的機器人描述檔案。

tips:再次說明一下,本系列主要是想幫助朋友們更好的了解ros和gazebo是怎麼聯系在一起的(在我獨自探索的時候,覺得這條主線的捋順是最重要的),重點不在程式,也不在各式各樣的标簽上,是以對于标簽和程式,這裡不做過多講解,有興趣的可以更多的參考部落格中給出的連結,那裡面講的要比我全面的多。

整體流程架構

依舊祭出官方的架構圖

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

在上個部落格中,雖然放上了該圖,但是似乎并沒有什麼内容是與該圖想對應的。誠然,上節的内容大多數是urdf的東西,在該圖裡面就是一個小方塊,但是本節的内容就能在這裡面展現的更多了。

廢話不多說,下面開始我們的探索之旅。

把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性

這一步的目的其實很明顯,就是為了讓我們的機器人具備更多的屬性,進而讓我們的機器人在gazebo的仿真中能表現的更像在真實世界中一樣!

對link使用gezebo标簽

作用

我們知道,在現實世界中,一個物體光有品質和旋轉慣量是完全不夠的,這兩個元素隻是最基本的屬性,

表征這個物體可以被實體引擎觀測到,但是僅僅如此是達不到我們想用gazebo的初衷的——通過這個平台模拟機器人在真實世界中的表現。舉個簡單的例子,一個物體除了品質外,另一個很重要的屬性就是表面摩擦系數了,而這個屬性link标簽根本沒有對其進行定義,那麼這時候gazebo标簽就派上了用場。

流程

1.找到上節的urdf檔案

2.将wheel的link和joint去掉,這時候運作下面的指令:

3.這時候在gazebo中你應該能看到白色的box,右鍵你的模型,在快捷菜單中點選“Apply Force/Torque”,這時候我們就能看到這樣的情景

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加
這裡提醒一下,因為上節的時候,最後将base_link和car_link固連在了一起,中間差了一個輪子的高度,此時你力的着力點很有可能不在物體上,這時候你需要調整面闆中的Application Point的XYZ值讓着力點在模型上

之後我們在Force下面的X的編輯欄中填入10000N,之後點選Apply Force或者Apply All,就可以看到模型向X軸運動了,當然你也可以嘗試編輯Torque中的值,如果你修改的是X或者Y軸的數值,你會看到模型彈騰一下,但是如果你修改的是Z軸的值,那麼你就會看到模型的旋轉啦!

特别注意的是,修改值的時候盡可能的大一些,雖然我們給予的外力很大,但是由于仿真中一步的時間很短,是以很小的力是根本看不出效果的

到這裡,你可能會說:咦,說好的gazebo标簽呢?那麼下面開始我們的正題,在urdf的最後面(當然要在robot标簽内!)中添加一個geazbo的标簽。

4.在代碼中添加如下的語句:

<!-- gazebo -->
<gazebo reference="car_link">
    <material>Gazebo/WoodFloor</material>
    <mu1>0.5</mu1>
    <mu2>0.5</mu2>
</gazebo>
           

這時候輸入gazebo的顯示指令之後,你就能看到一個木質地闆做的模型:D 關于模型的材料,更詳細的内容可以移步到here

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

但是,如果你此時在rviz中打開模型的話,你會發現模型并沒有這麼漂亮:( 還是原來那個樣子

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

這也就是說,gazebo标簽隻是告訴gazebo怎麼顯示,并不會管ros中模型的形态以及屬性,是以,這兩個子產品之間毫無疑問是有一個巨大的鴻溝隔着的!而能填補這個鴻溝的,就是整體架構圖中的ros_control,不過這就是下節的内容了:D

不過話說回來,添加這個标簽裡面還有兩個mu的值,我們似乎還沒有看到他的作用呢,其實很簡單,你隻需要重複上面的給力操作的話,你就能發現,同樣是10000N的力,這次能夠移動的更遠了~沒錯!預設情況下,當我們沒有對gazebo标簽内的屬性指派的話,gazebo會給予一個預設的值,讓模型能夠工作,例如這裡表面摩擦系數就預設是1.0,是以當我們修改摩擦系數為0.5的時候,相同的力我們就能給予更大的加速度,是以推的就更遠,感興趣的也可以試試給0.0哈,gazebo會告訴你什麼叫不可能:)

關于gazebo可以給link加的屬性,因為比較多,也不能一一介紹,上面的代碼給出的就是最常用的标簽,其他的标簽可以看下圖,官方關于這個地方的講解可以參考here

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加
tips:如果對于标簽的值不确定的話,最好的方式就是敬而遠之,不要填寫,gazebo會給予一個預設可用的值的!擅自的修改會導緻不好的結果。

對joint使用gazebo标簽

實際上,這部分目前接觸的不是很多,是以這部分就一筆帶過了,各個屬性值可以看下面的圖檔

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

更詳細的參考here

給joint添加真正的執行裝置——transmission标簽

這部分算是本部落格的比較重要的部分了,因為一再強調,gazebo中的仿真都是基于實體引擎的,那麼你想讓一個模型運動,從本質上講,必須要有力施加在模型上,就實際而言,我們必須在模型上加上執行器(通常情況下就是電機了),讓模型運動起來。

作用

transmission标簽主要的針對對象是joint(因為一般兩個link連接配接處的地方如果是非固定的,那麼一定會存在一個執行裝置來改變兩個link的相對位置),transmission标簽的作用就是給這個joint打上某種執行器的标簽,有了執行器,gazebo就可以在實體層面上對模型進行驅動了。

流程

  1. 修改上面的urdf,把整個機器人建立成一個四輪式的機器人
  2. 對于每一個joint,我們在下面添加它的transmission标簽,這裡直接給出我修改之後的程式
<?xml version="1.0"?>
<robot name="rbo" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- variable -->
    <xacro:property name="PI" value="3.1415926"/>
    <xacro:property name="car_width" value="1.0"/>
    <xacro:property name="car_length" value="2.0"/>
    <xacro:property name="car_height" value="0.3"/>
    <xacro:property name="wheel_length" value="0.13"/>
    <xacro:property name="wheel_radius" value="0.25"/>
    <xacro:property name="wheel_origin_xyz" value="0.0 0.0 0.0"/>
    <xacro:property name="wheel_origin_rpy" value="0.0 ${PI/2} 0.0"/>

    <!-- rviz color -->
    <material name="blue">
        <color rgba="0 0 1 1"/>
    </material>

    <material name="black">
        <color rgba="0 0 0 1"/>
    </material>

    <!-- macro -->
    <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>

    <xacro:macro name="box_geometry" params="width length height">
        <geometry>
            <box size="${width} ${length} ${height}"/>
        </geometry>
    </xacro:macro>

    <xacro:macro name="cylinder_geometry" params="length radius">
        <geometry>
            <cylinder length="${length}" radius="${radius}"/>
        </geometry>
    </xacro:macro>

    <xacro:macro name="default_origin" params="xyz rpyaw">
        <origin xyz="${xyz}" rpy="${rpyaw}"/>
    </xacro:macro>

    <!-- links -->
    <link name="car_link">
        <visual>
            <xacro:box_geometry width="${car_width}" length="${car_length}" height="${car_height}"/>
            <material name="blue"/>
        </visual>
        <collision>
            <xacro:box_geometry width="${car_width}" length="${car_length}" height="${car_height}"/>
        </collision>
        <xacro:default_inertial mass="3.0"/>

    </link>

    <!-- gazebo -->
    <gazebo reference="car_link">
        <material>Gazebo/SkyBlue</material>
        <mu1>0.5</mu1>
        <mu2>0.5</mu2>
    </gazebo>

    <!-- wheel joint macro -->
    <!-- right:1 left:-1 -->
    <xacro:macro name="wheel_car_joint" params="wheel_name front_end left_right">
        <link name="${wheel_name}">
            <visual>
                <xacro:cylinder_geometry length="${wheel_length}" radius="${wheel_radius}"/>
                <xacro:default_origin xyz="${wheel_origin_xyz}" rpyaw="${wheel_origin_rpy}" />
                <material name="black"/>
            </visual>
            <collision>
                <xacro:cylinder_geometry length="${wheel_length}" radius="${wheel_radius}"/>
                <xacro:default_origin xyz="${wheel_origin_xyz}" rpyaw="${wheel_origin_rpy}" />
            </collision>
            <xacro:default_inertial mass="1.0"/>
        </link>

        <!-- joints -->
        <joint name="car_base_${wheel_name}" type="continuous">
            <origin xyz="${left_right*(wheel_length+car_width)/2.0} ${front_end*car_length*0.6/2.0} 0.0" rpy="0.0 0.0 0.0"/>
            <parent link="car_link"/>
            <child link="${wheel_name}"/>
            <axis xyz="0.0 1.0 0.0"/>
        </joint>

        <gazebo reference="${wheel_name}">
            <material>Gazebo/Black</material>
            <mu1>0.5</mu1>
            <mu2>0.5</mu2>
        </gazebo>

        <transmission name="${wheel_name}_transmission">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="car_base_${wheel_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${wheel_name}_motor">
                <mechanicalReducction>1</mechanicalReducction>
            </actuator>
        </transmission>
    </xacro:macro>

    <xacro:wheel_car_joint wheel_name="front_right_wheel" front_end="1.0" left_right="1.0"/>
    <xacro:wheel_car_joint wheel_name="front_left_wheel" front_end="1.0" left_right="-1.0"/>
    <xacro:wheel_car_joint wheel_name="end_right_wheel" front_end="-1.0" left_right="1.0"/>
    <xacro:wheel_car_joint wheel_name="end_left_wheel" front_end="-1.0" left_right="-1.0"/>

    <!-- base_link -->
    <link name="base_link"/>
    <joint name="base_link_car" type="fixed">
        <origin xyz="0.0 0.0 ${wheel_radius}" rpy="0.0 0.0 0.0"/>
        <parent link="base_link"/>
        <child link="car_link"/>
    </joint>

</robot>
           

這個程式的運作結果就是如下圖

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

由于我在程式也在link标簽内部加入了material的值,是以在rviz中,大家應該也可以看到一個相同顔色的小車

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

這裡對transmission标簽内部的屬性值稍作介紹:

1. type: 這個标簽不用擔心了,隻有一個值:transmission_interface/SimpleTransmission

2. joint:首先要指明transmission服務的joint的名稱,之後其中包含一個必填屬性

- hardwareInterface:該屬性表明了這個joint是什麼類型的,目前使用最多的(我的感覺是差不多隻有這三種類型)是以下三個屬性值:EffortJointInterface(通過輸入功率控制電機),VelocityJointInterface(控制電機的轉速),PositionJointInterface(控制電機的位置)。

3. actuator:首先要為你的執行器起一個名字(一般就是什麼什麼motor),之後指定執行器的内部屬性

- mechanicalReduction:指明電機的減速比

- hardwareInterface:這個可以不指明,因為在joint中已經指明了

以上三個内部屬性就是transmission的全部标簽了,當然,有的朋友可能會問,作為執行器,必然是會有速度,功率的限制的,這個标簽裡面為什麼沒有這些參數?答:這些參數其實都有,隻不過你要在上一節的joint标簽中賦予相應的值,因為這些值說真的是屬于joint的,并不屬于transmission這個映射的屬性,相應設定如下圖,具體可以參考here:

ROS與GAZEBO實時硬體仿真(2)——urdf的gazebo屬性寫在前面整體流程架構把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性總結附加

讓執行器真正的能夠進行硬體仿真——libgazebo_ros_control.so

回到最上面的整體流程圖,我們可以看到,在simulaition那麼方框内,gazebo的作用其實僅僅是一個simulator的作用,它需要writeSim這個接口來接受一些東西之後,才能在實體引擎的作用下模仿出真實的場景,完事兒之後,再把一些東西送出去,直接負責與之互動的就是這裡的RobotHWSim。

作用

負責将上層應用程式的信号量傳輸給gazebo進行仿真。例如,PID Loop計算得到了name=“wheel”的這個執行器需要輸入10W的功率,那麼經過JointCommand這個接口之後,信号就轉化為了隻有Effort Joint才能識别的信号,送給RobotHWSim,RobotHWSim接到這個信号之後,會找這個節點對應的transmission的是否也是Effort類型的,如果不是的話,gazebo就跪給你看了(當然并不是退出,而是你的這個信号就根本不會産生價值);如果是的話,信号的取值也很合理,那就可以開心的把它轉化為gazebo能識别的信号給它了;一段時間後,gazebo将仿真的結果送回來,RobotHWSim拿着這個結果一算:Oh,這個關節運動了多少多少,就開開心心的吧這個結果送給JointState接口,由它轉化為ros的信号。當然上面全部是我的個人猜測,如果有大神知道裡面的實際情況,也請在這裡指導一下~不勝感激!

流程

在代碼的任意位置添加如下代碼:

<!-- plagin -->
 <gazebo>
     <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
         <robotNamespace>/</robotNamespace>
         <robotSimType>gazebo_ros_control/DefaultRobotHWSim</robotSimType>
     </plugin>
 </gazebo>
           

這裡命名空間是一個比較重要的東西,不過目前的内容還不涉及,到了下節的時候再詳細的說明一下他的用處。

總結

那麼到這裡,今天的内容基本上就這些了,這節的内容着實不多,同時很多情況下修改了代碼還看不出任何的效果。。。個人覺得這就是造機器人的過程,我們看到的永遠都是外表,而内在的電機啊,傳感器啊等等的,他們的安裝也是搭建機器人的環節中不可或缺的一部分,而這節内容就類似于這個過程。。。

還是那句話,這個系列意在理清楚我們要想在gazebo中仿真需要做的主線任務,希望能對朋友們有所幫助。

附加

gazebo官方的material标簽值:gazebo顔色标簽

tips:根據上面的标簽值,我們很容易的就可以将其轉化到rviz上進行顯示了,不過要在urdf中聲明一下才能用,并不gazebo标簽内可以直接使用