赞
踩
机器人操作系统学习、开发与测试过程中,会遇到诸多问题,比如:
在诸如此类的场景中,ROS 中的仿真就显得尤为重要
仿真优势
仿真缺陷
URDF
rviz
Gazebo
- 机器人的系统仿真是一种集成实现,主要包含三部分:
- URDF 用于创建机器人模型
- Gzebo 用于搭建仿真环境
- rviz 图形化的显示机器人各种传感器感知到的环境信息- 三者应用中,只是创建 URDF 意义不大,一般需要结合 Gazebo 或 rviz 使用,在 Gazebo 或 rviz 中可以将 URDF 文件解析为图形化的机器人模型,一般的使用组合为:
- 如果非仿真环境,那么使用 URDF 结合 rviz 直接显示感知的真实环境信息
- 如果是仿真环境,那么需要使用 URDF 结合 Gazebo 搭建仿真环境,并结合 rviz 显示感知的虚拟环境信息
需求描述:在 rviz 中显示一个盒状机器人
实现流程
创建新的工作空间与功能包,并导入依赖包 urdf 和 xacro
$ mkdir -p demo05_ws/src
$ cd demo05_ws
$ catkin_make
$ code .
在功能包的 src 下新建如下几个目录
编写 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>
<!-- 设置参数 -->
<param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo01_helloworld.urdf" />
<!-- 启动 rviz -->
<node pkg = "rviz" type = "rviz" name = "rviz" />
</launch>
在 rviz 中显示机器人模型
$ source ./devel/setup.bash
$ roslaunch urdf01_rviz demo01_helloworld.launch
```
优化 rviz 启动
重复启动 launch 文件时,rviz 之前的组件配置信息不会自动保存,需要重复执行上一步的操作,为方便使用可以使用如下方式优化,再启动时,就可以包含之前的组件配置了,使用更方便快捷
- 首先,将当前配置保存进 config 目录,命名为 show_mycar.rviz
- 然后在 launch 文件中 rviz 的启动配置添加参数:args
<launch>
<!-- 设置参数 -->
<param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo01_helloworld.urdf" />
<!-- 启动 rviz -->
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_rviz)/config/show_mycar.rviz" />
</launch>
urdf 中的 link 标签用于描述机器人某个部件(也即刚体部分)的外观和物理属性,比如:机器人底座、轮子、激光雷达、摄像头。每一个部件都对应一个 link, 在 link 标签内,可以设计该部件的形状、尺寸、颜色、惯性矩阵、碰撞参数等一系列属性
属性
子标签
visual:描述外观(对应的数据是可视的)
geometry 设置连杆的形状
标签1:box(盒状)
属性:size = 长(x) 宽(y) 高(z)
标签2:cylinder(圆柱)
属性:radius = 半径 length = 高度
标签3:sphere(球体)
属性:radius = 半径
标签4:mesh(为连杆添加皮肤)
属性:filename = 资源路径(格式:package://<packagename>/<path>/文件)
origin:设置偏移量与倾斜弧度
属性1:xyz = x偏移 y便宜 z偏移
属性2:rpy = x翻滚 y俯仰 z偏航 (单位是弧度)
metrial:设置材料属性(颜色)
属性:name
标签:color
属性: rgba=红绿蓝权重值与透明度 (每个权重值以及透明度取值[0,1])
collision:连杆的碰撞属性
Inertial:连杆的惯性矩阵
示例:分别生成长方体、圆柱与球体的机器人部件
demo02_link.urdf
<robot name = "mycar"> <link name = "base_link"> <visual> <geometry> <!-- <box size = "0.3 0.2 0.1" /> --> <!-- <cylinder radius = "0.5" length = "0.1" /> --> <!-- <sphere radius = "0.3" /> --> <mesh filename = "package://urdf01_rviz/meshes/autolabor_mini.stl" /> </geometry> <!-- xyz 坐标 rpy 翻滚俯仰与偏航角度(3.14 = 180度 1.57 = 90度) --> <origin xyz = "0 0 0" rpy = "1.57 0 1.57" /> <!-- 颜色: r = red g = green b = blue a = alpha --> <material name = "car_color"> <color rgba = "0 1 0 0.5" /> </material> </visual> </link> </robot>
demo02_link.launch
<launch>
<!-- 设置参数 -->
<param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo02_link.urdf" />
<!-- 启动 rviz -->
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_rviz)/config/show_mycar.rviz" />
</launch>
joint 标签对应的数据在模型中是不可见的
属性
name:为关节命名
type:关节运动形式
子标签
parent (必需的)
parent link 的名字是一个强制的属性:
child (必需的)
child link的名字是一个强制的属性:
origin
axis
示例:创建机器人模型,底盘为长方体,在长方体的前面添加一摄像头,摄像头可以沿着 z 轴 360 度旋转
demo03_joint.urdf
<robot name = "mycar"> <!-- 底盘 --> <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 = "car_color"> <color rgb = "0.8 0.5 0 0.5" /> </material> </visual> </link> <!-- 摄像头 --> <link name = "camera"> <visual> <geometry> <box size = "0.02 0.05 0.05" /> </geometry> <origin xyz = "0 0 0.025" rpy = "0 0 0" /> <material name = "camera_color"> <color rgba = "0 0 1 0.5" /> </material> </visual> </link> <!-- 关节 --> <joint name = "camera2base" type = "continuous"> <parent link = "base_link"/> <child link = "camera" /> <!-- 需要计算两个 link 的物理中心之间的偏移量 --> <origin xyz = "0.12 0 0.05" rpy = "0 0 0" /> <axis xyz = "0 0 1" /> </joint> </robot>
demo03_joint.launch
<launch> <!-- 设置参数 --> <param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo03_joint.urdf" /> <!-- 启动 rviz --> <node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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" /> <!-- 可选:用于控制关节运动的节点,会生成关节控制的UI,用于测试关节运动是否正常 --> <node pkg = "joint_state_publisher_gui" type = "joint_state_publisher_gui" name = "joint_state_publisher_gui" /> </launch>
base_footprint 优化 urdf
前面实现的机器人模型是半沉到地下的,因为默认情况下:底盘的中心点位于地图原点上,所以会导致这种情况产生,可以使用的优化策略,将初始 link 设置为一个尺寸极小的 link (比如半径为 0.001m 的球体,或边长为 0.001m 的立方体),然后再在初始 link 上添加底盘等刚体,这样实现,虽然仍然存在初始 link 半沉的现象,但是基本可以忽略了,这个初始 link 称为 base_footprint(启动 rviz 后记得将 fixed frame 改为 base_footprint)
demo04_base_footprint.urdf
<robot name = "mycar"> <!-- 添加一个尺寸极小的 link ,再关联初始 link 和 base_link,关节的高度刚好和 base_link 下沉的高度一致 --> <link name = "base_footprint"> <visual> <geometry> <box size = "0.001 0.001 0.001" /> </geometry> </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 = "car_color"> <color rgb = "0.8 0.5 0 0.5" /> </material> </visual> </link> <!-- 摄像头 --> <link name = "camera"> <visual> <geometry> <box size = "0.02 0.05 0.05" /> </geometry> <origin xyz = "0 0 0.025" rpy = "0 0 0" /> <material name = "camera_color"> <color rgba = "0 0 1 0.5" /> </material> </visual> </link> <!-- 关联 base_footprint 和 base_link --> <joint name = "link2footprint" type = "fixed"> <parent link = "base_footprint"/> <child link = "base_link" /> <!-- 设置偏移量,z 方向为半个 base_link 的高度 --> <origin xyz = "0 0 0.05" rpy = "0 0 0" /> </joint> <!-- 关节 --> <joint name = "camera2base" type = "continuous"> <parent link = "base_link"/> <child link = "camera" /> <!-- 需要计算两个 link 的物理中心之间的偏移量 --> <origin xyz = "0.12 0 0.05" rpy = "0 0 0" /> <!-- 设置关节旋转参考的坐标轴 --> <axis xyz = "0 0 1" /> </joint> </robot>
demo04_base_footprint.launch
<launch>
<!-- 设置参数 -->
<param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo04_base_footprint.urdf" />
<!-- 启动 rviz -->
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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" />
</launch>
问题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 install ros-melodic-joint-state-publisher-gui
需求
创建一个四轮圆柱状机器人模型,机器人参数如下:底盘为圆柱状,半径 10cm,高 8cm,四轮由两个驱动轮和两个万向支撑轮组成,两个驱动轮半径为 3.25cm,轮胎宽度1.5cm,两个万向轮为球状,半径 0.75cm,底盘离地间距为 1.5cm(与万向轮直径一致)
demo05_test.urdf
<robot name = "mycar"> <!-- 设置 base_footprint --> <link name = "base_footprint"> <visual> <geometry> <sphere radius = "0.001" /> </geometry> </visual> </link> <!-- 添加底盘 --> <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 = "baselink_color"> <color rgba = "1.0 0.5 0.2 0.5" /> </material> </visual> </link> <joint name = "link2footprint" type = "fixed"> <parent link = "base_footprint" /> <child link = "base_link"/> <!-- 关节 z 上设置 = 车体高度(0.08)/2 + 离地间隙(0.015)--> <origin xyz = "0 0 0.055" rpy = "0 0 0" /> </joint> <!-- 添加驱动轮 --> <link name = "left_wheel"> <visual> <geometry> <cylinder radius = "0.0325" length = "0.015" /> </geometry> <origin xyz = "0 0 0" rpy = "1.5708 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <link name = "right_wheel"> <visual> <geometry> <cylinder radius = "0.0325" length = "0.015" /> </geometry> <origin xyz = "0 0 0" rpy = "1.5708 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <joint name = "left2link" type = "continuous"> <parent link = "base_link" /> <child link = "left_wheel" /> <!-- z = 车体高度 / 2 + 离地间隙 - 车轮半径 --> <origin xyz = "0 0.1 -0.0225" rpy = "0 0 0" /> <axis xyz = "0 1 0" /> </joint> <joint name = "right2link" type = "continuous"> <parent link = "base_link" /> <child link = "right_wheel" /> <origin xyz = "0 -0.1 -0.0225" rpy = "0 0 0" /> <axis xyz = "0 1 0" /> </joint> <!-- 添加万向轮(支撑轮) --> <link name = "front_wheel"> <visual> <geometry> <sphere radius = "0.0075" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <link name = "back_wheel"> <visual> <geometry> <sphere radius = "0.0075" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <joint name = "front2link" type = "continuous"> <parent link = "base_link" /> <child link = "front_wheel" /> <origin xyz = "0.08 0 -0.0475" rpy = "0 0 0" /> <axis xyz = "1 1 1" /> </joint> <joint name = "back2link" type = "continuous"> <parent link = "base_link" /> <child link = "back_wheel" /> <origin xyz = "-0.08 0 -0.0475" rpy = "0 0 0" /> <axis xyz = "1 1 1" /> </joint> </robot>
demo05_test.launch
<launch> <!-- 在参数服务器中载入 urdf --> <param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/urdf/demo05_test.urdf" /> <!-- 启动 rviz --> <node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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" /> <!-- 可选:用于控制关节运动的节点,会生成关节控制的UI,用于测试关节运动是否正常 --> <node pkg = "joint_state_publisher_gui" type = "joint_state_publisher_gui" name = "joint_state_publisher_gui" /> </launch>
在 ROS 中,提供了一些工具来方便 URDF 文件的编写,比如:
check_urdf 命令可以检查复杂的 urdf 文件是否存在语法问题
urdf_to_graphiz 命令可以查看 urdf 模型结构,显示不同 link 的层级关系
当然,要使用工具之前,首先需要安装,安装命令
$ sudo apt install liburdfdom-tools
check_urdf 语法检查
urdf_to_graphiz 结构查看
$ evince mycar.pdf
前面 URDF 文件构建机器人模型的过程中,存在若干问题
问题1:在设计关节的位置时,需要按照一定的公式计算,公式是固定的,但是在 URDF 中依赖于人工计算,存在不便且容易计算失误,且当某些参数发生改变时,还需要重新计算
问题2:URDF 中的部分内容是高度重复的,驱动轮与支撑轮的设计实现,不同轮子只是部分参数不同,形状、颜色、翻转量都是一致的,在实际应用中,构建复杂的机器人模型时,更是易于出现高度重复的设计,按照一般的编程涉及到重复代码应该考虑封装
如果在编程语言中,可以通过变量结合函数直接解决上述问题,在 ROS 中,已经给出了类似编程的优化方案,称之为:Xacro
概念
原理
作用
xmlns:xacro = "http://wiki.ros.org/xacro"
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<!-- 属性定义 -->
<xacro:property name = "PI" value = "3.1415926" />
<xacro:property name = "radius" value = "0.03" />
<!-- 属性调用 -->
<myUsePropertyXxx name = "${PI}" />
<myUsePropertyXxx name = "${radius}" />
<!-- 算术运算 -->
<myUsePropertyYyy result = "${PI / 2}" />
<myUsePropertyYyy result = "${radius * 2}" />
</robot>
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<!-- 宏定义:<xacro:macro name="宏名称" params="参数列表(多参数之间使用空格分隔)"></xacro:macro> -->
<xacro:macro name = "getSum" params = "num1 num2">
<result value = "${num1 + num2}" />
</xacro:macro>
<!-- 宏调用:<xacro:宏名称 参数1=xxx 参数2=xxx/> -->
<xacro:getSum num1 = "1" num2 = "5" />
</robot>
<robot name = "mycar" 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 文件:demo05_car_base.urdf.xacro
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name="footprint_radius" value="0.001" /> <link name="base_footprint"> <visual> <geometry> <sphere radius = "${footprint_radius}" /> </geometry> </visual> </link> <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_z" 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 = "baselink_color"> <color rgba = "1.0 0.5 0.2 0.5" /> </material> </visual> </link> <joint name = "link2footprint" type = "fixed"> <parent link = "base_footprint" /> <child link = "base_link"/> <origin xyz = "0 0 ${base_joint_z}" rpy = "0 0 0" /> </joint> <xacro:property name = "wheel_radius" value = "0.0325" /> <xacro:property name = "wheel_length" value = "0.015" /> <xacro:property name = "PI" value = "3.1415927" /> <xacro:property name = "wheel_joint_z" value = "${(base_length / 2 + lidi - wheel_radius) * -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 / 2} 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <joint name = "${wheel_name}2link" type = "continuous"> <parent link = "base_link" /> <child link = "${wheel_name}_wheel" /> <origin xyz = "0 ${0.1 * flag} ${wheel_joint_z}" 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" /> <xacro:property name = "small_wheel_radius" value = "0.0075" /> <xacro:property name = "small_joint_z" value = "${(base_length / 2 + lidi - small_wheel_radius) * -1}" /> <xacro:macro name = "small_wheel_func" params = "small_wheel_name flag"> <link name = "${small_wheel_name}_wheel"> <visual> <geometry> <sphere radius = "${small_wheel_radius}" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> </link> <joint name = "${small_wheel_name}2link" type = "continuous"> <parent link = "base_link" /> <child link = "${small_wheel_name}_wheel" /> <origin xyz = "${0.08 * flag} 0 ${small_joint_z}" rpy = "0 0 0" /> <axis xyz = "1 1 1" /> </joint> </xacro:macro> <xacro:small_wheel_func small_wheel_name = "front" flag = "1" /> <xacro:small_wheel_func small_wheel_name = "back" flag = "-1" /> </robot>
集成 launch 文件
<launch>
<!-- <param name = "robot_description" textfile = "$(find urdf01_rviz)/urdf/xacro/demo05_car_base.urdf" /> -->
<param name = "robot_description" command = "$(find xacro)/xacro $(find urdf01_rviz)/urdf/xacro/demo05_car_base.urdf.xacro"/>
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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>
摄像头和雷达 Xacro 文件实现:demo06_car_camera.urdf.xacro & demo07_car_laser.urdf.xacro
<!-- demo06_car_camera.urdf.xacro --> <robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name = "camera_length" value = "0.02" /> <xacro:property name = "camera_width" value = "0.05" /> <xacro:property name = "camera_height" value = "0.05" /> <xacro:property name = "joint_camera_x" value = "0.08" /> <xacro:property name = "joint_camera_y" value = "0" /> <xacro:property name = "joint_camera_z" value = "${base_length / 2 + camera_height / 2}" /> <link name = "camera"> <visual> <geometry> <box size = "${camera_length} ${camera_width} ${camera_height}" /> </geometry> <material name = "black"> <color rgba = "0 0 0 0.8" /> </material> </visual> </link> <joint name = "camera2base" type = "fixed"> <parent link = "base_link" /> <child link = "camera" /> <origin xyz = "${joint_camera_x} ${joint_camera_y} ${joint_camera_z}" rpy = "0 0 0" /> </joint> </robot>
<!-- demo07_car_laser.urdf.xacro --> <robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name = "support_radius" value = "0.01" /> <xacro:property name = "support_length" value = "0.15" /> <xacro:property name = "laser_radius" value = "0.03" /> <xacro:property name = "laser_length" value = "0.05" /> <xacro:property name = "joint_support_x" value = "0" /> <xacro:property name = "joint_support_y" value = "0" /> <xacro:property name = "joint_support_z" value = "${base_length / 2 + support_length / 2}" /> <xacro:property name = "joint_laser_x" value = "0" /> <xacro:property name = "joint_laser_y" value = "0" /> <xacro:property name = "joint_laser_z" value = "${support_length / 2 + laser_length / 2}" /> <link name = "support"> <visual> <geometry> <cylinder radius = "${support_radius}" length = "${support_length}" /> </geometry> <material name = "yellow"> <color rgba = "0.8 0.5 0.0 0.5" /> </material> </visual> </link> <joint name = "support2base" type = "fixed"> <parent link = "base_link" /> <child link = "support" /> <origin xyz = "${joint_support_x} ${joint_support_y} ${joint_support_z}" rpy = "0 0 0" /> </joint> <link name = "laser"> <visual> <geometry> <cylinder radius = "${laser_radius}" length = "${laser_length}" /> </geometry> <material name = "black"> <color rgba = "0 0 0 0.5" /> </material> </visual> </link> <joint name = "laser2support" type = "fixed"> <parent link = "support" /> <child link = "laser" /> <origin xyz = "${joint_laser_x} ${joint_laser_y} ${joint_laser_z}" rpy = "0 0 0" /> </joint> </robot>
组合底盘摄像头与雷达的 xacro 文件:car.urdf.xacro
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
</robot>
launch 文件:car.launch
<launch>
<param name = "robot_description" command = "$(find xacro)/xacro $(find urdf01_rviz)/urdf/xacro/car.urdf.xacro"/>
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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>
Arbotix:Arbotix 是一款控制电机、舵机的控制板,并提供相应的 ros 功能包,这个功能包的功能不仅可以驱动真实的 Arbotix 控制板,它还提供一个差速控制器,通过接受速度控制指令更新机器人的 joint 状态,从而帮助我们实现机器人在 rviz 中的运动。
这个差速控制器在 arbotix_python 程序包中,完整的 arbotix 程序包还包括多种控制器,分别对应 dynamixel 电机、多关节机械臂以及不同形状的夹持器
安装 Arbotix
$ sudo apt install ros-melodic-arbotix
创建新功能包,准备机器人 urdf、xacro
添加 arbotix 所需的配置文件
# 该文件是控制器配置,一个机器人模型可能有多个控制器,比如: 底盘、机械臂、夹持器(机械手) # 因此,根 name 是 controller controllers: { # 单控制器设置 base_controller: { # 类型: 差速控制器 type: diff_controller, # 参考坐标 base_frame_id: base_footprint, # 两个轮子之间的间距 base_width: 0.2, # 控制频率 Hz ticks_meter: 2000, # PID 控制参数,使机器人车轮快速达到预期速度 Kp: 12, Kd: 12, Ki: 0, Ko: 50, # 加速限制 m/s accel_limit: 1.0 } }
launch 文件中配置 arbotix 节点
<!-- demo07_control.launch --> <launch> <param name = "robot_description" command = "$(find xacro)/xacro $(find urdf01_rviz)/urdf/xacro/car.urdf.xacro"/> <node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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 = "arbotix_python" type = "arbotix_driver" name = "driver" output = "screen"> <rosparam command = "load" file = "$(find urdf01_rviz)/config/control.yaml" /> <param name = "sim" value = "true" /> </node> </launch> <!-- <node> 调用了 arbotix_python 功能包下的 arbotix_driver 节点 <rosparam> arbotix 驱动机器人运行时,需要获取机器人信息,可以通过 file 加载配置文件 <param> 在仿真环境下,需要配置 sim 为 true -->
启动 launch 文件并控制机器人模型运动
$ cd demo05_ws
$ source ./devel/setup.bash
$ roslaunch urdf01_rviz demo07_control.launch
配置 rviz
控制小车运动
此时调用 rostopic list 会发现一个熟悉的话题: /cmd_vel
也就说我们可以发布 cmd_vel 话题消息控制小车运动了,该实现策略有多种,可以另行编写节点,或者更简单些可以直接通过如下命令发布消息
$ rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 1, y: 0, z: 0}, angular: {x: 0, y: 0, z: 1}}'
创建功能包
在功能包下新建 urdf 和 launch 文件夹并分别建立下列文件
<!-- demo01_helloworld.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> <collision> <geometry> <box size = "0.5 0.3 0.1" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> </collision> <inertial> <origin xyz = "0 0 0" /> <mass value = "2" /> <inertia ixx = "1" ixy = "0" ixz = "0" iyy = "0" iyz = "1" izz = "1" /> </inertial> </link> <gazebo reference = "base_link"> <material>Gazebo/Red</material> </gazebo> </robot>
<!-- demo01_helloworld.launch --> <launch> <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 = "spawn_model" args = "-urdf -model car -param robot_description" /> <!-- 在 Gazebo 中加载一个机器人模型,该功能由 gazebo_ros 下的 spawn_model 提供: -urdf 加载的是 urdf 文件 -model car 模型名称是 car -param robot_description 从参数 robot_description 中载入模型 -x 模型载入的 x 坐标 -y 模型载入的 y 坐标 -z 模型载入的 z 坐标 --> </launch>
当 URDF 需要与 Gazebo 集成时,和 rviz 有明显区别:
- 必须使用 collision 标签,因为既然是仿真环境,那么必然涉及到碰撞检测,collision 提供碰撞检测的依据
- 必须使用 inertial 标签,此标签标注了当前机器人某个刚体部分的惯性矩阵,用于一些力学相关的仿真计算
- 颜色设置,也需要重新使用 gazebo 标签标注,因为之前的颜色设置为了方便调试包含透明度,仿真环境下没有此选项
$ cd demo05_ws
$ roslaunch urdf02_gazebo demo01_helloworld.launch
collision
inertial
惯性矩阵的设置需要结合 link 的质量与外形参数动态生成,标准的球体、圆柱与立方体的惯性矩阵公式如下(已经封装为 xacro 实现)
球体惯性矩阵
<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 reference = "link节点名称">
<material>Gazebo/Blue</material>
</gazebo>
material 标签中,设置的值区分大小写,颜色可以设置为 Red Blue Green Black
需求:将之前的机器人模型(xacro版)显示在 gazebo 中
实现流程
<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*(w*w + h*h)/12}" ixy = "0" ixz = "0" iyy="${m*(h*h + l*l)/12}" iyz= "0" izz="${m*(w*w + l*l)/12}" /> </inertial> </xacro:macro> </robot>
<!-- demo05_car_base.urdf.xacro --> <robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name="footprint_radius" value="0.001" /> <link name="base_footprint"> <visual> <geometry> <sphere radius = "${footprint_radius}" /> </geometry> </visual> </link> <xacro:property name="base_radius" value="0.1" /> <xacro:property name="base_length" value="0.08" /> <xacro:property name="base_mass" value="2" /> <xacro:property name="lidi" value="0.015" /> <xacro:property name="base_joint_z" 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 = "baselink_color"> <color rgba = "1.0 0.5 0.2 0.5" /> </material> </visual> <collision> <geometry> <cylinder radius = "${base_radius}" length = "${base_length}" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> </collision> <xacro:cylinder_inertial_matrix m = "${base_mass}" r = "${base_radius}" h = "${base_length}" /> </link> <gazebo reference = "base_link"> <material>Gazebo/Yellow</material> </gazebo> <joint name = "link2footprint" type = "fixed"> <parent link = "base_footprint" /> <child link = "base_link"/> <origin xyz = "0 0 ${base_joint_z}" rpy = "0 0 0" /> </joint> <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.1415927" /> <xacro:property name = "wheel_joint_z" value = "${-base_length / 2 - lidi + wheel_radius}" /> <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 0.0 0.3" /> </material> </visual> <collision> <geometry> <cylinder radius = "${wheel_radius}" length = "${wheel_length}" /> </geometry> <origin xyz = "0 0 0" rpy = "${PI / 2} 0 0" /> </collision> <xacro:cylinder_inertial_matrix m = "${wheel_mass}" r = "${wheel_radius}" h = "${wheel_length}" /> </link> <gazebo reference = "${wheel_name}_wheel"> <material>Gazebo/Red</material> </gazebo> <joint name = "${wheel_name}2link" type = "continuous"> <parent link = "base_link" /> <child link = "${wheel_name}_wheel" /> <origin xyz = "0 ${0.1 * flag} ${wheel_joint_z}" 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" /> <xacro:property name = "small_wheel_radius" value = "0.0075" /> <xacro:property name = "small_wheel_mass" value = "0.01" /> <xacro:property name = "small_joint_z" value = "${(base_length / 2 + lidi - small_wheel_radius) * -1}" /> <xacro:macro name = "small_wheel_func" params = "small_wheel_name flag"> <link name = "${small_wheel_name}_wheel"> <visual> <geometry> <sphere radius = "${small_wheel_radius}" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> <material name = "wheel_color"> <color rgba = "0.0 0.0 0.0 0.3" /> </material> </visual> <collision> <geometry> <sphere radius = "${small_wheel_radius}" /> </geometry> <origin xyz = "0 0 0" rpy = "0 0 0" /> </collision> <xacro:sphere_inertial_matrix m = "${small_wheel_mass}" r = "${small_wheel_radius}" /> </link> <gazebo reference = "${small_wheel_name}_wheel"> <material>Gazebo/Red</material> </gazebo> <joint name = "${small_wheel_name}2link" type = "continuous"> <parent link = "base_link" /> <child link = "${small_wheel_name}_wheel" /> <origin xyz = "${0.08 * flag} 0 ${small_joint_z}" rpy = "0 0 0" /> <axis xyz = "1 1 1" /> </joint> </xacro:macro> <xacro:small_wheel_func small_wheel_name = "front" flag = "1" /> <xacro:small_wheel_func small_wheel_name = "back" flag = "-1" /> </robot>
<!-- demo06_car_camera.urdf.xacro --> <robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name = "camera_length" value = "0.02" /> <xacro:property name = "camera_width" value = "0.05" /> <xacro:property name = "camera_height" value = "0.05" /> <xacro:property name = "camera_mass" value = "0.01" /> <xacro:property name = "joint_camera_x" value = "0.08" /> <xacro:property name = "joint_camera_y" value = "0" /> <xacro:property name = "joint_camera_z" value = "${base_length / 2 + camera_height / 2}" /> <link name = "camera"> <visual> <geometry> <box size = "${camera_length} ${camera_width} ${camera_height}" /> </geometry> <material name = "black"> <color rgba = "0 0 0 0.8" /> </material> </visual> <collision> <geometry> <box size = "${camera_length} ${camera_width} ${camera_height}" /> </geometry> </collision> <xacro:Box_inertial_matrix m = "${camera_mass}" l = "${camera_length}" w = "${camera_width}" h = "${camera_height}" /> </link> <gazebo reference = "camera"> <material>Gazebo/Blue</material> </gazebo> <joint name = "camera2base" type = "fixed"> <parent link = "base_link" /> <child link = "camera" /> <origin xyz = "${joint_camera_x} ${joint_camera_y} ${joint_camera_z}" rpy = "0 0 0" /> </joint> </robot>
<!-- demo07_car_laser.urdf.xacro --> <robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro"> <xacro:property name = "support_radius" value = "0.01" /> <xacro:property name = "support_length" value = "0.15" /> <xacro:property name = "support_mass" value = "0.1" /> <xacro:property name = "laser_radius" value = "0.03" /> <xacro:property name = "laser_length" value = "0.05" /> <xacro:property name = "laser_mass" value = "0.15" /> <xacro:property name = "joint_support_x" value = "0" /> <xacro:property name = "joint_support_y" value = "0" /> <xacro:property name = "joint_support_z" value = "${base_length / 2 + support_length / 2}" /> <xacro:property name = "joint_laser_x" value = "0" /> <xacro:property name = "joint_laser_y" value = "0" /> <xacro:property name = "joint_laser_z" value = "${support_length / 2 + laser_length / 2}" /> <link name = "support"> <visual> <geometry> <cylinder radius = "${support_radius}" length = "${support_length}" /> </geometry> <material name = "yellow"> <color rgba = "0.8 0.5 0.0 0.5" /> </material> </visual> <collision> <geometry> <cylinder radius = "${support_radius}" length = "${support_length}" /> </geometry> </collision> <xacro:cylinder_inertial_matrix m = "${support_mass}" r = "${support_radius}" h = "${support_length}" /> </link> <gazebo reference = "support"> <material>Gazebo/Gray</material> </gazebo> <joint name = "support2base" type = "fixed"> <parent link = "base_link" /> <child link = "support" /> <origin xyz = "${joint_support_x} ${joint_support_y} ${joint_support_z}" rpy = "0 0 0" /> </joint> <link name = "laser"> <visual> <geometry> <cylinder radius = "${laser_radius}" length = "${laser_length}" /> </geometry> <material name = "black"> <color rgba = "0 0 0 0.5" /> </material> </visual> <collision> <geometry> <cylinder radius = "${laser_radius}" length = "${laser_length}" /> </geometry> </collision> <xacro:cylinder_inertial_matrix m = "${laser_mass}" r = "${laser_radius}" h = "${laser_length}" /> </link> <gazebo reference = "laser"> <material>Gazebo/Black</material> </gazebo> <joint name = "laser2support" type = "fixed"> <parent link = "support" /> <child link = "laser" /> <origin xyz = "${joint_laser_x} ${joint_laser_y} ${joint_laser_z}" rpy = "0 0 0" /> </joint> </robot>
组合底盘、摄像头与雷达的 car.urdf.xacro 文件
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "head.xacro" />
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
</robot>
在 Gazebo 中执行:demo02_car.launch
<launch>
<param name = "robot_description" command = "$(find xacro)/xacro $(find urdf02_gazebo)/urdf/car.urdf.xacro" />
<include file = "$(find gazebo_ros)/launch/empty_world.launch" />
<node pkg = "gazebo_ros" type = "spawn_model" name = "spawn_model" args = "-urdf -model car -param robot_description" />
</launch>
Gazebo 中创建仿真实现方式有两种(也还可以直接下载使用官方或第三方提高的仿真环境插件)
$ roscore
$ rosrun gazebo_ros gazebo
<launch>
<param name = "robot_description" command = "$(find xacro)/xacro $(find urdf02_gazebo)/urdf/car.urdf.xacro" />
<!-- 启动 empty_world 后,再根据 arg 加载自定义的仿真环境 -->
<include file = "$(find gazebo_ros)/launch/empty_world.launch">
<arg name = "world_name" value = "$(find urdf02_gazebo)/worlds/box_house.world" />
<!-- 此为教程提供的自定义仿真环境 box_house.world -->
</include>
<node pkg = "gazebo_ros" type = "spawn_model" name = "spawn_model" args = "-urdf -model car -param robot_description" />
</launch>
启动 gazebo 打开构建面板,绘制仿真环境
保存构建的环境
保存为 world 文件
启动:同方式 1
下载官方模型库
$ git clone https://github.com/osrf/gazebo_models
将模型库复制进 gazebo
应用
关于 URDF(Xacro)、rviz 和 Gazebo 三者的关系,前面已有阐述:URDF 用于创建机器人模型、rviz 可以显示机器人感知到的环境信息,Gazebo 用于仿真,可以模拟外界环境,以及机器人的一些传感器
官方参考实现
gazebo 中已经可以正常显示机器人模型了,那么如何像在 rviz 中一样控制机器人运动呢?在此,需要涉及到 ros 中的组件:ros_control
场景:同一套 ROS 程序,如何部署在不同的机器人系统上,比如:开发阶段为了提高效率是在仿真平台上测试的,部署时又有不同的实体机器人平台,不同平台的实现是有差异的,如何保证 ROS 程序的可移植性?ROS 内置的解决方式是 ros_control
ros_control:是一组软件包,它包含了控制器接口,控制器管理器,传输和硬件接口。ros_control 是一套机器人控制的中间件,是一套规范,不同的机器人平台只要按照这套规范实现,那么就可以保证 与ROS 程序兼容,通过这套规范,实现了一种可插拔的架构设计,大大提高了程序设计的效率与灵活性
gazebo 已经实现了 ros_control 的相关接口,如果需要在 gazebo 中控制机器人运动,直接调用相关接口即可
为 joint 添加传动装置以及控制器(两轮差速配置)
<!-- 在 urdf 文件夹下新建 gazebo 文件夹 --> <!-- 然后新建 move.xacro 文件,内容如下 --> <robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro"> <xacro:macro name="joint_trans" params="joint_name"> <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="left2link" /> <xacro:joint_trans joint_name="right2link" /> <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>left2link</leftJoint> <!-- 左轮 --> <rightJoint>right2link</rightJoint> <!-- 右轮 --> <wheelSeparation>${base_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>
xacro 文件集成
<!-- car.urdf.xacro -->
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "head.xacro" />
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
<xacro:include filename = "gazebo/move.xacro" />
</robot>
启动 Gazebo 并控制机器人运动:demo03_env.launch
<launch>
<param name = "robot_description" command = "$(find xacro)/xacro $(find urdf02_gazebo)/urdf/car.urdf.xacro" />
<include file = "$(find gazebo_ros)/launch/empty_world.launch">
<arg name = "world_name" value = "$(find urdf02_gazebo)/worlds/box_house.world" />
</include>
<node pkg = "gazebo_ros" type = "spawn_model" name = "spawn_model" args = "-urdf -model car -param robot_description" />
</launch>
启动 launch 文件,使用 topic list 查看话题列表,会发现多了 /cmd_vel 然后发布 vmd_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}}'
或者直接使用下列命令实现键盘操纵
$ rosrun teleop_twist_keyboard teleop_twist_keyboard.py
在 Gazebo 的仿真环境中,机器人的里程计信息以及运动朝向等信息是无法获取的,可以通过 rviz 显示机器人的里程计信息以及运动朝向
- 里程计:机器人相对出发点坐标系的位姿状态 (X 坐标 Y 坐标 Z 坐标以及朝向)
启动 rviz:demo04_sensor.launch
<launch>
<node pkg = "rviz" type = "rviz" name = "rviz" args = "-d $(find urdf01_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"/>
</launch>
添加组件
新建 laser.xacro 文件,配置雷达传感器信息
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro"> <gazebo reference="laser"> <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 文件集成
<!-- car.urdf.xacro -->
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "head.xacro" />
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
<xacro:include filename = "gazebo/move.xacro" />
<xacro:include filename = "gazebo/laser.xacro" />
</robot>
启动仿真环境
$ source ./devel/setup.bash
$ roslaunch urdf02_gazebo demo03_env.launch
启动 rviz:demo04_sensor.launch 显示雷达数据
$ roslaunch urdf02_gazebo demo04_sensor.launch
新建 camera.xacro 文件,配置摄像头传感器信息
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro"> <gazebo reference="camera"> <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 文件集成
<!-- car.urdf.xacro -->
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "head.xacro" />
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
<xacro:include filename = "gazebo/move.xacro" />
<xacro:include filename = "gazebo/laser.xacro" />
<xacro:include filename = "gazebo/camera.xacro" />
</robot>
启动仿真环境
$ source ./devel/setup.bash
$ roslaunch urdf02_gazebo demo03_env.launch
启动 rviz:demo04_sensor.launch 显示摄像头数据
$ roslaunch urdf02_gazebo demo04_sensor.launch
新建 kinect.xacro 文件,配置 kinetic 传感器信息
<robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro"> <gazebo reference="support"> <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>support</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 文件集成
<!-- car.urdf.xacro -->
<robot name = "mycar" xmlns:xacro = "http://wiki.ros.org/xacro">
<xacro:include filename = "head.xacro" />
<xacro:include filename = "demo05_car_base.urdf.xacro" />
<xacro:include filename = "demo06_car_camera.urdf.xacro" />
<xacro:include filename = "demo07_car_laser.urdf.xacro" />
<xacro:include filename = "gazebo/move.xacro" />
<xacro:include filename = "gazebo/laser.xacro" />
<xacro:include filename = "gazebo/camera.xacro" />
<xacro:include filename = "gazebo/kinect.xacro" />
</robot>
启动仿真环境
$ source ./devel/setup.bash
$ roslaunch urdf02_gazebo demo03_env.launch
启动 rviz:demo04_sensor.launch 显示 Kinect 数据
$ roslaunch urdf02_gazebo demo04_sensor.launch
补充:kinect 点云数据显示
在 kinect 中也可以以点云的方式显示感知周围环境,在 rviz 中操作如下
问题:在rviz中显示时错位
原因:在 kinect 中图像数据与点云数据使用了两套坐标系统,且两套坐标系统位姿并不一致
解决方法
<!-- 将 support 改为 support_depth -->
<frameName>support_depth</frameName>
<node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 -1.57 0 -1.57 /support /support_depth" />
- 综上,如果你手上已经有机器人硬件平台,并且在上边可以完成需要的功能,用 rviz 应该就可以满足开发需求
- 如果你手上没有机器人硬件,或者想在仿真环境中做一些算法、应用的测试,Gazebo + rviz 应该是你需要的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。