O(∩_∩)O哈哈哈~ 特想放張偉!我是什麼顏色???
文章目錄
參考功能包鏈接
https://github.com/XFFer/ROS_Resource
1. 優化物理仿真模型
使用xacro文件優化URDF模型
連載(四) 中我們使用URDF建模遇到了很多問題,比如多個輪子需要重複書寫代碼;不能進行參數計算,各個link的位置需要逐個輸入參數。
URDF模型的進化版本——xacro模型文件
- 精簡模型代碼
- 創建宏定義
- 文件包含
- 提供可編程接口
- 常量
- 變量
- 數學計算
- 條件語句
- …
① 常量的定義與使用
常量定義
<xacro:property name="M_PI" value="3.14159" />
舉例:
<!-- PROPERTY LIST -->
<xacro:property name="M_PI" value="3.1415926" />
<xacro:property name="base_radius" value="0.20" />
<xacro:property name="base_length" value="0.16" />
<xacro:property name="wheel_radius" value="0.06" />
<xacro:property name="wheel_length" value="0.025" />
<xacro:property name="wheel_joint_y" value="0.19" />
<xacro:property name="wheel_joint_z" value="0.05" />
<xacro:property name="caster_radius" value="0.015" />
<xacro:property name="caster_joint_x" value="0.18" />
常量使用
<origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/>
舉例:
<joint name="base_footprint_joint" type="fixed">
<origin xyz="0 0 ${base_length/2 + caster_radius*2}" rpy="0 0 0" />
<parent link="base_footprint" />
<child link="base_link" />
</joint>
<link name="base_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="${base_radius}" />
</geometry>
<material name="yellow" />
</visual>
</link>
② 數學計算
所有數學運算都會轉換成浮點數進行,以保證運算精度。
<origin xyz="0 ${(motor_length+wheel_length)/2} 0" rpy="0 0 0" />
舉例:
<joint name="base_footprint_joint" type="fixed">
<origin xyz="0 0 ${base_length/2 + caster_radius*2}" rpy="0 0 0" />
<parent link="base_footprint" />
<child link="base_link" />
</joint>
③ 宏
宏定義
類似於函數,可以實現創建一個輪子的模型,通過再次調用修改參數,創建相同形狀,多個輪子模型。
<xacro:macro name="name" params="A B C">
......
</xacro:macro>
舉例:
<!--Macro for robot wheel-->
<xacro:macro name="wheel" param="prefix reflect">
<joint name="${prefix}_wheel_joint" type="continuous">
<origin xyz="0 ${reflect*wheel_joint_y} ${-wheel_joint_z}" rpy="0 0 0" />
<parent link="base_link" />
<child link="${prefix}_wheel_link" />
<axis xyz="0 1 0" />
</joint>
<link name="${prefix}_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="${M_PI/2} 0 0" />
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_length}" />
</geometry>
<material name="gray" />
</visual>
</link>
</xacro:macro>
宏調用
<name A="A_value" B="B_value" C="C_value" />
舉例:
<wheel prefix="left" reflect="1" />
<wheel prefix="right" reflect="-1" />
④ 文件包含
<xacro:include filename="$(find mbot_description)/urdf/mbot_base_gazebo.xacro" />
舉例:
<xacro:include filename="$(find mbot_description)/urdf/sensors/camera_gazebo.xacro" />
<xacro:include filename="$(find mbot_description)/urdf/mbot_base_gazebo.xacro" />
ros_control
- ros_control是ROS爲開發者提供的機器人控制中間件
- 包含一系列控制器接口、傳動裝置接口、硬件接口、控制器工具箱等
- 可以幫助我們將上層功能包裏的指令發送給機器人
由於硬件包括各種有刷無刷電機、機械臂、激光雷達、視覺傳感器,驅動方式都有很大的差別。故硬件抽象層是對硬件進行包裝,使它更容易能夠和上層控制層綁定在一起。
- 控制器管理器 Controller Manager
- 提供一種通用的接口來管理不同的控制器。
- 控制器 Controller
- 讀取硬件狀態,發送控制命令,完成每個joint的控制。
- 硬件資源 Hardware Resource Interface Layer
- 爲上下兩層提供硬件資源的接口。
- 機器人硬件抽象 DefaultRobotHWSim/hardware_interface::RobotHW
- 機器人硬件抽象和硬件資源直接打交道,通過write和read方法完成硬件操作。
- 真實機器人 Reality
- 執行接收到的命令。
上圖中包含了上述的幾個模塊,Controller Manager可以幫助管理不同的控制器,如:底盤控制器,機械臂等的啓動、暫停、運行、停止;具體的是一個PID Loops,這個閉環PID更像在應用層面,會向下發指令會通過Hardware Resource Interface Layer這個硬件資源的接口,以不同的形式發佈;在仿真器中會有DefaultRobotHWSim默認硬件抽象,但對真實機器人,就需要自己去構建這個硬件抽象RobotHW,這裏也存在一個PID閉環控制,但偏向於控制板,如STM32對某個電機的控制,再通過解碼器Encoders得到關節的狀態信息反饋給Controller。
前面MoveIt的插入課,我們用到過joint_position_controller,對機械臂進行MotionPlanning。這裏我們列舉控制器的所有類型,可參考 https://github.com/ros-controls/ros_control/wiki/controller_interface
- joint_state_controller
- joint_effort_controller
- joint_position_controller
- joint_velocity_controller
第一步:爲link添加慣性參數和碰撞屬性
轉動慣量是大學物理的內容研究的是2D平面的,公式爲:,,是角速度,而這裏的慣性參數是三維的,用一個慣性矩陣來描述。推了一下圓柱體的公式,同樣長方體和球體也可以使用三次積分的方式求出。
<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>
<link name="base_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="{base_radius}" />
</geometry>
<material name="yellow" />
</visual>
<collison>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="${base_length}" radius="{base_radius}" />
</geometry>
</collision>
<cylinder_inertial_matrix m="${base_mass}" r="${base_radius}" h="${base_length}" />
</link>
第二步:爲link添加gazebo標籤
Gazebo中需要添加色彩標籤。由於rviz和gazebo的色彩空間不同,描述形式不一樣,不能通用,如果不標記標籤,Gazebo內的模型都爲灰色。
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="${prefix}_wheel_link">
<material>Gazebo/Gray</material>
</gazebo>
<gazebo reference="base_footprint">
<turnGravityoff>false</turnGravityoff>
</gazebo>
“base_footprint”是對底盤在地面的一個映射,這裏需要把這個影子的重力設置爲無。
<gazebo reference="${prefix}_caster_link">
<material>Gazebo/Black</material>
</gazebo>
第三步:爲joint添加傳動裝置
爲每一個joint添加虛擬電機(傳動裝置)。這裏使用了硬件接口——速度控制接口hardware_interface/VelocityJointInterface。
<!-- Transmission is important to link the joints and the controller -->
<transmission name="${prefix}_wheel_joint_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="${prefix}_name_wheel_joint">
<hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
</joint>
<actuator name="${prefix}_wheel_joint_motor">
<hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
第四步:添加gazebo控制器插件
- <robotNamespace>:機器人的命名空間。
- <leftJoint>和<rightJoint>:左右輪轉動的關節joint。
- <whellSeparation>和<wheelDiameter>:機器人模型的相關尺寸,在計算差速參數時需要用到。
- <commandTopic>:控制器訂閱的速度控制指令,生成全局命名時需要結合<robotNamespace>中設置的命名空間。
- <odometryFrame>:里程計數據的參考座標系,ROS中一般命名爲odom。
<!-- controller -->
<gazebo>
<!--控制器插件,差速控制libgazebo_ros_diff_drive.so-->
<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_wheel_joint</leftJoint>
<rightJoint>right_wheel_joint</rightJoint>
<!--兩個輪子的輪距-->
<wheelSeparation>${wheel_joint_y*2}</wheelSeparation>
<wheelDiameter>${wheel_radius*2}</wheelDiameter>
<broadcastTF>1</broadcastTF>
<!--轉矩Torque-->
<wheelTorque>30</wheelTorque>
<wheelAcceleration>1.8</wheelAcceleration>
<!--需要發佈的速度信息-->
<commandTopic>cmd_vel</commandTopic>
<!--使用里程計,計算仿真中機器人的位置-->
<odometryFrame>odom</odometryFrame>
<odometryTopic>odom</odometryTopic>
<robotBaseFrame>base_footprint</robotBaseFrame>
</plugin>
</gazebo>
全向移動使用libgazebo_ros_planar_move這個插件,具體gazebo插件可以參考官方網站。
第五步:編輯.launch文件
在gazebo中加載機器人模型需要首先將.xacro文件寫入.launch文件中用來執行。
示例:
<launch>
<!--設置launch文件的參數-->
<arg name="paused" default="false" />
<arg name="use_sim_time" default="true" />
<arg name="gui" default="true" />
<arg name="headless" default="false" />
<arg name="debug" default="false" />
<!-- 運行gazebo仿真環境 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="debug" value="$(arg debug)" />
<arg name="paused" value="$(arg paused)" />
<arg name="use_sim_time" value="$(arg use_sim_time)" />
<arg name="gui" value="$(arg gui)" />
<arg name="headless" value="$(arg headless)" />
</include>
<!-- 加載機器人模型描述參數 -->
<!-- xacro --inorder解釋器作用於.xacro文件 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mobot_description)/urdf/mbot_gazebo.xacro'"/>
<!-- 運行joint_state_publisher節點,發佈機器人的關節狀態 -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
<!-- 運行robot_state_publisher節點,發佈tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen" >
<param name="publish_frequency" type="double" value="50.0" />
</node>
<!-- 在gazebo中加載機器人模型 -->
<!-- spawn_model功能包,-urdf說明模型由URDF格式構建,-model後跟機器人名,-param參數爲上面加載的模型描述參數 -->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model mrobot -param robot_description" />
</launch>
運行
$ roslaunch mbot_gazebo view_mbot_gazebo_empty_world.launch
終端輸入
$ rostopic list
會發現/cmd_vel,那麼就可以通過
$ rostopic pub /cmd_vel geometry_msgs/Twist "linear:
x: 0.6
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.5"
發佈運動指令了。
2. 創建物理仿真環境
第一種方法
從https://bitbucket.org/osrf/gazebo_models/downloads/下載,提前放到模型~/.gazebo/models下,.gazebo文件夾一般是隱藏的,點擊ctrl+h
可以顯示隱藏文件夾。下載的模型包解壓後需要把文件內的所有文件散開放,每個文件夾都是一個模型。
在Gazebo仿真環境,點擊左上角的Insert插入,就可以放置物理環境了,通過左上角的Save World As可以保存當前設置的仿真環境。
第二種方法:使用Building Editor
首先需要打開一個Gazebo World。可以使用
$ roslaunch mbot_gazebo view_mbot_gazebo_empty_world.launch
但是要事先把功能包放置到工作空間下。(功能包已經在全文開頭給出了github地址)
點擊File中的Building Editor
通過左邊的牆體、窗戶、門,顏色,質感等,構建一個虛擬的物理環境。
下面我們運行一個gazebo提供的仿真環境,只不過也就是放了幾個東西而已。
$ roslaunch mbot_gazebo view_mbot_gazebo_play_ground.launch
然後運行一個gazebo提供的鍵盤控制小車移動的腳本。
$ roslaunch mbot_teleop mbot_teleop.launch
你會發現使用i
前進(紅色X軸),使用,
後退,使用j
向左轉,l
右轉,q
加速等等,kinetic中左右是相反的,你會發現小車是具有慣性的,這就是慣性矩陣的作用,同樣小車碰撞物體時,可能推動物體前進(在物體質量較輕時),小車對物體有力的作用。
3. 傳感器仿真及應用
①攝像頭仿真
- <sensor>標籤:描述仿真器
- type:傳感器類型,camera
- name:攝像頭命名,自由設置
- <camera>標籤:描述攝像頭參數
- 分辨率,編碼格式,圖像範圍,噪音參數等
- <plugin>標籤:加載攝像頭仿真插件
- 設置插件的命名空間、發佈圖像的話題、參考座標系等
示例:(示例中僅包含傳感器設置,並不包含其他模型構建,不是完整的)
<gazebo reference="${prefix}_link">
<sensor type="camera" name="camera_node">
<!--每秒30幀-->
<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>
<!--最近和最遠(m)-->
<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</alwayOn>
<updateRate>0.0</updateRate>
<!--命名空間-->
<cameraName>/camera</cameraName>
<!--對外發布話題名爲image_raw-->
<imageTopicName>image_raw</imageTopicName>
<cameraInfoTopicName>camera_info</cmaeraInfoTopicName>
<frameName>camera_link</framName>
<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>
可以運行一下給出功能包裏的程序
$ roslaunch mbot_gazebo view_mbot_with_camera_gazebo.launch
隨後運行
$ rostopic list
可以看到多出很多由camera開頭的話題,我們用rqt_image_view顯示話題仿真的圖像
$ rqt_image_view
②RGB-D攝像頭仿真(Kinect)
Kinect通過紅外感知周圍物體的深度信息。
示例:(示例中僅包含傳感器設置,並不包含其他模型構建,不是完整的)
<gazebo reference="${prefix}_link">
<sensor type="depth" name="${prefix}">
<always_on>true</always_on>
<update_rate>20.0</update_rate>
<camera>
<!--俯仰角-->
<horizontal_fov>${60.0*M_PI/180.0}</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<!--最近和最遠(m)-->
<near>0.05</near>
<far>8.0</far>
</clip>
</camera>
<plugin name="kinect_${prefix}_controller" filename="libgazebo_ros_openni_kinect.so">
<alwaysOn>true</alwayOn>
<updateRate>10</updateRate>
<!--命名空間-->
<cameraName>${prefix}</cameraName>
<!--創建rgb彩色圖像話題-->
<imageTopicName>rgb/image_raw</imageTopicName>
<!--創建深度圖像話題-->
<depthImageTopicName>depth/image_raw</depthImageTopicName>
<!--創建點雲圖像話題-->
<pointCloudTopicName>depth/points</pointCloudTopicName>
<depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
<cameraInfoTopicName>rgb/camera_info</cmaeraInfoTopicName>
<frameName>${prefix}_frame_optical</framName>
<baseline>0.1</beseline>
<distortionk1>0.0</distortionk1>
<distortionk2>0.0</distortionk2>
<distortionk3>0.0</distortionk3>
<distortiont1>0.0</distortiont1>
<distortiont2>0.0</distortiont2>
<pointCloudCutoff>0.4</pointCloudCutoff>
</plugin>
</sensor>
</gazebo>
同樣可以執行給出功能包中的.launch文件
$ roslaunch mbot_gazebo view_mbot_with_kinect_gazebo.launch
使用rostopic list輸出的話題中由kinect開頭的都是該仿真攝像頭提供的話題。我們可以通過rviz進行顯示。
$ rosrun rviz rviz
添加PointCloud2和Image選擇Kinect發佈的話題,就可以在rviz中顯示出來。
③激光雷達仿真
示例:這裏也只列出仿真傳感器的設置,其他設置大差不差。
這裏是一個二維的雷達,可以得到二維的深度信息。
<gazebo reference="${prefix}_link">
<sensor type="ray" name="rplidar">
<pose>0 0 0 0 0 0</pose>
<visualize>false</visualize>
<update_rate>5.5</update_rate>
<ray>
<scan>
<horizontal>
<!--每一幀360個點-->
<samples>360</samples>
<!--每一度一個點-->
<resolution>1</resolution>
<min_angle>-3</min_angle>
<max_angle>3</max_angle>
</horizontal>
</scan>
<range>
<!--最近0.10m,最遠6.0m-->
<min>0.10</min>
<max>6.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>
<!--雷達信息都在laser_link下做描述-->
<frameName>laser_link</frameName>
</plugin>
</sensor>
</gazebo>
推薦閱讀