寫在前面
通過上一節的部落格,相信朋友們已經對urdf有了一個較為完整的認識,應該也可以自主的寫一個urdf檔案在ros和gazebo看到了,但是僅僅是這樣,如果我們志在讓機器人在gazebo中運作的話,其實還是差很多東西,原因還是那句話,gazebo是靠實體引擎驅動的,我們現在的urdf檔案還差一些實體定律所需要的最基本的屬性。
那麼本節的主要目的就是給我們的urdf添加上更多的屬性,讓gazebo更加“歡迎”我們給予它的機器人描述檔案。
tips:再次說明一下,本系列主要是想幫助朋友們更好的了解ros和gazebo是怎麼聯系在一起的(在我獨自探索的時候,覺得這條主線的捋順是最重要的),重點不在程式,也不在各式各樣的标簽上,是以對于标簽和程式,這裡不做過多講解,有興趣的可以更多的參考部落格中給出的連結,那裡面講的要比我全面的多。
整體流程架構
依舊祭出官方的架構圖
在上個部落格中,雖然放上了該圖,但是似乎并沒有什麼内容是與該圖想對應的。誠然,上節的内容大多數是urdf的東西,在該圖裡面就是一個小方塊,但是本節的内容就能在這裡面展現的更多了。
廢話不多說,下面開始我們的探索之旅。
把大象裝進冰箱裡第二步——給urdf打上gazebo的屬性
這一步的目的其實很明顯,就是為了讓我們的機器人具備更多的屬性,進而讓我們的機器人在gazebo的仿真中能表現的更像在真實世界中一樣!
對link使用gezebo标簽
作用
我們知道,在現實世界中,一個物體光有品質和旋轉慣量是完全不夠的,這兩個元素隻是最基本的屬性,
表征這個物體可以被實體引擎觀測到,但是僅僅如此是達不到我們想用gazebo的初衷的——通過這個平台模拟機器人在真實世界中的表現。舉個簡單的例子,一個物體除了品質外,另一個很重要的屬性就是表面摩擦系數了,而這個屬性link标簽根本沒有對其進行定義,那麼這時候gazebo标簽就派上了用場。
流程
1.找到上節的urdf檔案
2.将wheel的link和joint去掉,這時候運作下面的指令:
3.這時候在gazebo中你應該能看到白色的box,右鍵你的模型,在快捷菜單中點選“Apply Force/Torque”,這時候我們就能看到這樣的情景
這裡提醒一下,因為上節的時候,最後将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
但是,如果你此時在rviz中打開模型的話,你會發現模型并沒有這麼漂亮:( 還是原來那個樣子
這也就是說,gazebo标簽隻是告訴gazebo怎麼顯示,并不會管ros中模型的形态以及屬性,是以,這兩個子產品之間毫無疑問是有一個巨大的鴻溝隔着的!而能填補這個鴻溝的,就是整體架構圖中的ros_control,不過這就是下節的内容了:D
不過話說回來,添加這個标簽裡面還有兩個mu的值,我們似乎還沒有看到他的作用呢,其實很簡單,你隻需要重複上面的給力操作的話,你就能發現,同樣是10000N的力,這次能夠移動的更遠了~沒錯!預設情況下,當我們沒有對gazebo标簽内的屬性指派的話,gazebo會給予一個預設的值,讓模型能夠工作,例如這裡表面摩擦系數就預設是1.0,是以當我們修改摩擦系數為0.5的時候,相同的力我們就能給予更大的加速度,是以推的就更遠,感興趣的也可以試試給0.0哈,gazebo會告訴你什麼叫不可能:)
關于gazebo可以給link加的屬性,因為比較多,也不能一一介紹,上面的代碼給出的就是最常用的标簽,其他的标簽可以看下圖,官方關于這個地方的講解可以參考here
tips:如果對于标簽的值不确定的話,最好的方式就是敬而遠之,不要填寫,gazebo會給予一個預設可用的值的!擅自的修改會導緻不好的結果。
對joint使用gazebo标簽
實際上,這部分目前接觸的不是很多,是以這部分就一筆帶過了,各個屬性值可以看下面的圖檔
更詳細的參考here
給joint添加真正的執行裝置——transmission标簽
這部分算是本部落格的比較重要的部分了,因為一再強調,gazebo中的仿真都是基于實體引擎的,那麼你想讓一個模型運動,從本質上講,必須要有力施加在模型上,就實際而言,我們必須在模型上加上執行器(通常情況下就是電機了),讓模型運動起來。
作用
transmission标簽主要的針對對象是joint(因為一般兩個link連接配接處的地方如果是非固定的,那麼一定會存在一個執行裝置來改變兩個link的相對位置),transmission标簽的作用就是給這個joint打上某種執行器的标簽,有了執行器,gazebo就可以在實體層面上對模型進行驅動了。
流程
- 修改上面的urdf,把整個機器人建立成一個四輪式的機器人
- 對于每一個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>
這個程式的運作結果就是如下圖
由于我在程式也在link标簽内部加入了material的值,是以在rviz中,大家應該也可以看到一個相同顔色的小車
這裡對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:
讓執行器真正的能夠進行硬體仿真——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标簽内可以直接使用