对于ROS新手而言,可能会有疑问:学习机器人操作系统,实体机器人是必须的吗?答案是否定的,机器人一般价格不菲,为了降低机器人学习、调试成本,在ROS中提供了系统的机器人仿真实现,通过仿真,可以实现大部分需求,本章主要就是围绕“仿真”展开的,比如,本章会介绍:

  • 如何创建并显示机器人模型;
  • 如何搭建仿真环境;
  • 如何实现机器人模型与仿真环境的交互。
本章预期的学习目标如下:
  • 能够独立使用URDF创建机器人模型,并在Rviz和Gazebo中分别显示;
  • 能够使用Gazebo搭建仿真环境;
  • 能够使用机器人模型中的传感器(雷达、摄像头、编码器…)获取仿真环境数据。
案例演示:

1.创建并显示机器人模型

第六章 机器人系统仿真 - 图6第六章 机器人系统仿真 - 图7

2.仿真环境搭建第六章 机器人系统仿真 - 图8

3.控制机器人运动第六章 机器人系统仿真 - 图9第六章 机器人系统仿真 - 图10

4.雷达仿真

第六章 机器人系统仿真 - 图11

5.摄像头仿真第六章 机器人系统仿真 - 图12第六章 机器人系统仿真 - 图13

6.1概述

机器人操作系统学习、开发与测试过程中,会遇到诸多问题,比如:

场景1:机器人一般价格不菲,学习ROS要购买一台机器人吗?

场景2:机器人与之交互的外界环境具有多样性,如何实现复杂的环境设计?

场景3:测试时,直接将未经验证的程序部署到实体机器人运行,安全吗?

在诸如此类的场景中,ROS中的仿真就显得尤为重要了。

1.概念
机器人系统仿真:是通过计算机对实体机器人系统进行模拟的技术,在 ROS 中,仿真实现涉及的内容主要有三:对机器人建模(URDF)创建仿真环境(Gazebo)以及感知环境(Rviz)等系统性实现。

2.作用
2.1仿真优势:
仿真在机器人系统研发过程中占有举足轻重的地位,在研发与测试中较之于实体机器人实现,仿真有如下几点的显著优势:

1.低成本:当前机器人成本居高不下,动辄几十万,仿真可以大大降低成本,减小风险

2.高效:搭建的环境更为多样且灵活,可以提高测试效率以及测试覆盖率

3.高安全性:仿真环境下,无需考虑耗损问题

2.2仿真缺陷:
机器人在仿真环境与实际环境下的表现差异较大,换言之,仿真并不能完全做到模拟真实的物理世界,存在一些”失真”的情况,原因:

1.仿真器所使用的物理引擎目前还不能够完全精确模拟真实世界的物理情况

2.仿真器构建的是关节驱动器(电机&齿轮箱)、传感器与信号通信的绝对理想情况,目前不支持模拟实际硬件缺陷或者一些临界状态等情形

3.相关组件
3.1URDF
URDF是 Unified Robot Description Format 的首字母缩写,直译为**统一(标准化)机器人描述格式**,可以以一种 XML 的方式描述机器人的部分结构,比如底盘、摄像头、激光雷达、机械臂以及不同关节的自由度…..,该文件可以被 C++ 内置的解释器转换成可视化的机器人模型,是 ROS 中实现机器人仿真的重要组件

3.2rviz
RViz 是 ROS Visualization Tool 的首字母缩写,直译为ROS的三维可视化工具。它的主要目的是以三维方式显示ROS消息,可以将 数据进行可视化表达。例如:**可以显示机器人模型,可以无需编程就能表达激光测距仪(LRF)传感器中的传感 器到障碍物的距离RealSenseKinectXtion等三维距离传感器的点云数据(PCD, Point Cloud Data**),从相机获取的图像值等

以“ros- [ROS_DISTRO] -desktop-full”命令安装ROS时,RViz会默认被安装。

运行使用命令rviz或rosrun rviz rviz

如果rviz没有安装,请调用如下命令自行安装:

  1. sudo apt install ros-[ROS_DISTRO]-rviz

3.3 Gazebo
Gazebo是一款3D动态模拟器用于显示机器人模型并创建仿真环境,能够在复杂的室内和室外环境中准确有效地模拟机器人。与游戏引擎提供**高保真度**的视觉模拟类似,Gazebo提供高保真度的物理模拟,其提供一整套传感器模型,以及对用户和程序非常友好的交互方式。

以“ros- [ROS_DISTRO] -desktop-full”命令安装ROS时,gzebo会默认被安装。

运行使用命令gazebo或rosrun gazebo_ros gazebo

注意1:在 Ubuntu20.04 与 ROS Noetic 环境下,gazebo 启动异常以及解决

问题1:VMware: vmw_ioctl_command error Invalid argument(无效的参数)

解决:

  1. echo "export SVGA_VGPU10=0" >> ~/.bashrc
  2. source .bashrc

问题2:[Err] [REST.cc:205] Error in REST request

解决:

  1. sudo gedit ~/.ignition/fuel/config.yaml
  2. 然后将 url : https://api.ignitionfuel.org 使用 # 注释
  3. 再添加url: https://api.ignitionrobotics.org

问题3:启动时抛出异常:[gazebo-2] process has died [pid xxx, exit code 255, cmd…..

解决:

  1. killall gzserver 或者
  2. killall gzclient

注意2:如果 gazebo没有安装,请自行安装:

1.添加源:

  1. sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main"
  2. >
  3. /etc/apt/sources.list.d/gazebo-stable.list'
  1. wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -

2.安装:

  1. sudo apt update
  1. sudo apt install gazebo11
  2. sudo apt install libgazebo11-dev

另请参考:

https://wiki.ros.org/urdf

http://wiki.ros.org/rviz

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

课程说明:

机器人的系统仿真是一种集成实现,主要包含三部分:

URDF 用于创建机器人模型


Gzebo 用于搭建仿真环境


Rviz 图形化的显示机器人各种传感器感知到的环境信息

三者应用中,只是创建 URDF 意义不大,一般需要结合 Gazebo 或 Rviz 使用,在 Gazebo 或 Rviz 中可以将 URDF 文件解析为图形化的机器人模型,一般的使用组合为:

如果非仿真环境,那么使用 URDF 结合 Rviz 直接显示感知的真实环境信息

如果是仿真环境,那么需要使用** URDF 结合 Gazebo 搭建仿真环境,并结合 Rviz 显示**感知的虚拟环境信息

后续课程安排:

先介绍 URDF 与 Rviz 集成使用,在 Rviz 中只是显示机器人模型,主要用于学习 URDF 语法

再介绍 URDF 与 Gazebo 集成,主要学习 URDF 仿真相关语法以及仿真环境搭建

最后集成 URDF 与 Gazebo 与 Rviz,实现综合应用

素材链接:

https://github.com/zx595306686/sim_demo.git

6.2URDF集成Riz基本流程

前面介绍过,URDF 不能单独使用,需要结合 Rviz 或 Gazebo,URDF 只是一个文件,需要在 Rviz 或 Gazebo 中渲染成图形化的机器人模型,当前,首先演示URDF与Rviz的集成使用,因为URDF与Rviz的集成较之于URDF与Gazebo的集成更为简单,后期,基于Rviz的集成实现,我们再进一步介绍URDF语法。

需求描述:

在 Rviz 中显示一个盒状机器人

结果演示:第六章 机器人系统仿真 - 图14

实现流程:

  1. 准备:新建功能包,导入依赖
  2. 核心:编写 urdf 文件
  3. 核心:在 launch 文件集成 URDF 与 Rviz
  4. 在 Rviz 中显示机器人模型

1.创建功能包,导入依赖

创建一个新的功能包,名称自定义,导入依赖包:urdfxacro 在当前功能包下,再新建几个目录: urdf: 存储 urdf 文件的目录 meshes:机器人模型渲染文件(暂不使用) config: 配置文件 launch: 存储 launch 启动文件

2.编写 URDF 文件

新建一个子级文件夹:urdf(可选),文件夹中添加一个.urdf文件,复制如下内容:
  1. <robot name="mycar">
  2. <link name="base_link">
  3. <visual>
  4. <geometry>
  5. <box size="0.5 0.2 0.1" />
  6. </geometry>
  7. </visual>
  8. </link>
  9. </robot>

3.在 launch 文件中集成 URDF 与 Rviz

launch目录下,新建一个 launch 文件,该 launch 文件需要启动 Rviz,并导入 urdf 文件,Rviz 启动后可以自动载入解析urdf文件,并显示机器人模型,核心问题:如何导入 urdf 文件? 在 ROS 中,可以将 urdf 文件的路径设置到参数服务器,使用的参数名是:robot_description,示例代码如下:
  1. <launch>
  2. <!-- 设置参数 -->
  3. <param name="robot_description" textfile="$(find 包名)/urdf/urdf/urdf01_HelloWorld.urdf" />
  4. <!-- 启动 rviz -->
  5. <node pkg="rviz" type="rviz" name="rviz" />
  6. </launch>

4.在 Rviz 中显示机器人模型

rviz 启动后,会发现并没有盒装的机器人模型,这是因为默认情况下没有添加机器人显示组件,需要手动添加,添加方式如下:第六章 机器人系统仿真 - 图15第六章 机器人系统仿真 - 图16设置完毕后,可以正常显示了

5.优化 rviz 启动

重复启动launch文件时,Rviz 之前的组件配置信息不会自动保存,需要重复执行步骤4的操作,为了方便使用,可以使用如下方式优化: 首先,将当前配置保存进config目录第六章 机器人系统仿真 - 图17然后,launch文件中 Rviz 的启动配置添加参数:args,值设置为-d 配置文件路径
  1. <launch>
  2. <param name="robot_description" textfile="$(find 包名)/urdf/urdf/urdf01_HelloWorld.urdf" />
  3. <node pkg="rviz" type="rviz" name="rviz" args="-d $(find 报名)/config/rviz/show_mycar.rviz" />
  4. </launch>

再启动时,就可以包含之前的组件配置了,使用更方便快捷。

6.3URDF语法详解

URDF 文件是一个标准的 XML 文件,在 ROS 中预定义了一系列的标签用于描述机器人模型,机器人模型可能较为复杂,但是 ROS 的 URDF 中机器人的组成却是较为简单,可以主要简化为两部分:连杆(link标签) 与 关节(joint标签),接下来我们就通过案例了解一下 URDF 中的不同标签:

  • robot 根标签,类似于 launch文件中的launch标签
  • link 连杆标签
  • joint 关节标签
  • gazebo 集成gazebo需要使用的标签
关于gazebo标签,后期在使用 gazebo 仿真时,才需要使用到,用于配置仿真环境所需参数,比如: 机器人材料属性、gazebo插件等,但是该标签不是机器人模型必须的,只有在仿真时才需设置

另请参考:

6.3.1URDF语法详解01 robot

robot

urdf 中为了保证 xml 语法的完整性,使用了robot标签作为根标签,所有的 link 和 joint 以及其他标签都必须包含在 robot 标签内,在该标签内可以通过 name 属性设置机器人模型的名称

1.属性

name: 指定机器人模型的名称

2.子标签

其他标签都是子级标签

6.3.2URDF语法详解02_link

link

urdf 中的 link 标签用于描述机器人某个部件(也即刚体部分)的外观和物理属性,比如: 机器人底座、轮子、激光雷达、摄像头…每一个部件都对应一个 link, 在 link 标签内,可以设计该部件的形状、尺寸、颜色、惯性矩阵、碰撞参数等一系列属性第六章 机器人系统仿真 - 图18 #### 1.属性 + name —-> 为连杆命名

2.子标签

  • 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使用。

3.案例

需求:分别生成长方体、圆柱与球体的机器人部件

  1. <link name="base_link">
  2. <visual>
  3. <!-- 形状 -->
  4. <geometry>
  5. <!-- 长方体的长宽高 -->
  6. <!-- <box size="0.5 0.3 0.1" /> -->
  7. <!-- 圆柱,半径和长度 -->
  8. <!-- <cylinder radius="0.5" length="0.1" /> -->
  9. <!-- 球体,半径-->
  10. <!-- <sphere radius="0.3" /> -->
  11. </geometry>
  12. <!-- xyz坐标 rpy翻滚俯仰与偏航角度(3.14=180 1.57=90度) -->
  13. <origin xyz="0 0 0" rpy="0 0 0" />
  14. <!-- 颜色: r=red g=green b=blue a=alpha -->
  15. <material name="black">
  16. <color rgba="0.7 0.5 0 0.5" />
  17. </material>
  18. </visual>
  19. </link>

6.3.3URDF语法详解03 joint

joint

urdf 中的 joint 标签用于描述机器人关节的运动学和动力学属性,还可以指定关节运动的安全极限,机器人的两个部件(分别称之为 parent link 与 child link)以”关节”的形式相连接,不同的关节有不同的运动形式: 旋转、滑动、固定、旋转速度、旋转角度限制….,比如:安装在底座上的轮子可以360度旋转,而摄像头则可能是完全固定在底座上。 joint标签对应的数据在模型中是不可见的第六章 机器人系统仿真 - 图19 #### 1.属性 + name —-> 为关节命名 + type —-> 关节运动形式 - continuous: 旋转关节,可以绕单轴无限旋转 - revolute: 旋转关节,类似于 continues,但是有旋转角度限制 - prismatic: 滑动关节,沿某一轴线移动的关节,有位置极限 - planer: 平面关节,允许在平面正交方向上平移或旋转 - floating: 浮动关节,允许进行平移、旋转运动 - fixed: 固定关节,不允许运动的特殊关节

2.子标签

  • parent(必需的)parent link的名字是一个强制的属性: - link:父级连杆的名字,是这个link在机器人结构树中的名字。
  • child(必需的)child link的名字是一个强制的属性: - link:子级连杆的名字,是这个link在机器人结构树中的名字。
  • origin - 属性: xyz=各轴线上的偏移量 rpy=各轴线上的偏移弧度。
  • axis - 属性: xyz用于设置围绕哪个关节轴运动。

3.案例

需求:创建机器人模型,底盘为长方体,在长方体的前面添加一摄像头,摄像头可以沿着 Z 轴 360 度旋转。

URDF文件示例如下:

  1. <!--
  2. 需求: 创建机器人模型,底盘为长方体,
  3. 在长方体的前面添加一摄像头,
  4. 摄像头可以沿着 Z 360 度旋转
  5. -->
  6. <robot name="mycar">
  7. <!-- 底盘 -->
  8. <link name="base_link">
  9. <visual>
  10. <geometry>
  11. <box size="0.5 0.2 0.1" />
  12. </geometry>
  13. <origin xyz="0 0 0" rpy="0 0 0" />
  14. <material name="blue">
  15. <color rgba="0 0 1.0 0.5" />
  16. </material>
  17. </visual>
  18. </link>
  19. <!-- 摄像头 -->
  20. <link name="camera">
  21. <visual>
  22. <geometry>
  23. <box size="0.02 0.05 0.05" />
  24. </geometry>
  25. <origin xyz="0 0 0" rpy="0 0 0" />
  26. <material name="red">
  27. <color rgba="1 0 0 0.5" />
  28. </material>
  29. </visual>
  30. </link>
  31. <!-- 关节 -->
  32. <joint name="camera2baselink" type="continuous">
  33. <parent link="base_link"/>
  34. <child link="camera" />
  35. <!-- 需要计算两个 link 的物理中心之间的偏移量 -->
  36. <origin xyz="0.2 0 0.075" rpy="0 0 0" />
  37. <axis xyz="0 0 1" />
  38. </joint>
  39. </robot>

launch文件示例如下:

  1. <launch>
  2. <param name="robot_description" textfile="$(find urdf_rviz_demo)/urdf/urdf/urdf03_joint.urdf" />
  3. <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf_rviz_demo)/config/helloworld.rviz" />
  4. <!-- 添加关节状态发布节点 -->
  5. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
  6. <!-- 添加机器人状态发布节点 -->
  7. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
  8. <!-- 可选:用于控制关节运动的节点 -->
  9. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />
  10. </launch>
PS: 1.状态发布节点在此是必须的:
  1. <!-- 添加关节状态发布节点 -->
  2. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
  3. <!-- 添加机器人状态发布节点 -->
  4. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
2.关节运动控制节点(可选),会生成关节控制的UI,用于测试关节运动是否正常。
  1. <!-- 可选:用于控制关节运动的节点 -->
  2. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />

4.base_footprint优化urdf

前面实现的机器人模型是半沉到地下的,因为默认情况下: 底盘的中心点位于地图原点上,所以会导致这种情况产生,可以使用的优化策略,将初始 link 设置为一个尺寸极小的 link(比如半径为 0.001m 的球体,或边长为 0.001m 的立方体),然后再在初始 link 上添加底盘等刚体,这样实现,虽然仍然存在初始link半沉的现象,但是基本可以忽略了。这个初始 link 一般称之为 base_footprint
  1. <!--
  2. 使用 base_footprint 优化
  3. -->
  4. <robot name="mycar">
  5. <!-- 设置一个原点(机器人中心点的投影) -->
  6. <link name="base_footprint">
  7. <visual>
  8. <geometry>
  9. <sphere radius="0.001" />
  10. </geometry>
  11. </visual>
  12. </link>
  13. <!-- 添加底盘 -->
  14. <link name="base_link">
  15. <visual>
  16. <geometry>
  17. <box size="0.5 0.2 0.1" />
  18. </geometry>
  19. <origin xyz="0 0 0" rpy="0 0 0" />
  20. <material name="blue">
  21. <color rgba="0 0 1.0 0.5" />
  22. </material>
  23. </visual>
  24. </link>
  25. <!-- 底盘与原点连接的关节 -->
  26. <joint name="base_link2base_footprint" type="fixed">
  27. <parent link="base_footprint" />
  28. <child link="base_link" />
  29. <origin xyz="0 0 0.05" />
  30. </joint>
  31. <!-- 添加摄像头 -->
  32. <link name="camera">
  33. <visual>
  34. <geometry>
  35. <box size="0.02 0.05 0.05" />
  36. </geometry>
  37. <origin xyz="0 0 0" rpy="0 0 0" />
  38. <material name="red">
  39. <color rgba="1 0 0 0.5" />
  40. </material>
  41. </visual>
  42. </link>
  43. <!-- 关节 -->
  44. <joint name="camera2baselink" type="continuous">
  45. <parent link="base_link"/>
  46. <child link="camera" />
  47. <origin xyz="0.2 0 0.075" rpy="0 0 0" />
  48. <axis xyz="0 0 1" />
  49. </joint>
  50. </robot>

5.遇到问题以及解决

问题1:

命令行输出如下错误提示
  1. UnicodeEncodeError: 'ascii' codec can't encode characters in position 463-464: ordinal not in range(128)
  2. [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].
  3. 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-noetic-joint-state-publisher-gui

6.3.4URDF练习

6.3.4 URDF练习

需求描述:

创建一个四轮圆柱状机器人模型,机器人参数如下,底盘为圆柱状,半径 10cm,高 8cm,四轮由两个驱动轮和两个万向支撑轮组成,两个驱动轮半径为 3.25cm,轮胎宽度1.5cm,两个万向轮为球状,半径 0.75cm,底盘离地间距为 1.5cm(与万向轮直径一致)

结果演示:第六章 机器人系统仿真 - 图20实现流程:

创建机器人模型可以分步骤实现
  1. 新建 urdf 文件,并与 launch 文件集成
  2. 搭建底盘
  3. 在底盘上添加两个驱动轮
  4. 在底盘上添加两个万向轮

1.新建urdf以及launch文件

urdf 文件:基本实现
  1. <robot name="mycar">
  2. <!-- 设置 base_footprint -->
  3. <link name="base_footprint">
  4. <visual>
  5. <geometry>
  6. <sphere radius="0.001" />
  7. </geometry>
  8. </visual>
  9. </link>
  10. <!-- 添加底盘 -->
  11. <!-- 添加驱动轮 -->
  12. <!-- 添加万向轮(支撑轮) -->
  13. </robot>

launch 文件:

  1. <launch>
  2. <!-- urdf 文件内容设置进参数服务器 -->
  3. <param name="robot_description" textfile="$(find demo01_urdf_helloworld)/urdf/urdf/test.urdf" />
  4. <!-- 启动 rivz -->
  5. <node pkg="rviz" type="rviz" name="rviz_test" args="-d $(find demo01_urdf_helloworld)/config/helloworld.rviz" />
  6. <!-- 启动机器人状态和关节状态发布节点 -->
  7. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
  8. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
  9. <!-- 启动图形化的控制关节运动节点 -->
  10. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />
  11. </launch>

2.底盘搭建

  1. <!--
  2. 参数
  3. 形状:圆柱
  4. 半径:10 cm
  5. 高度:8 cm
  6. 离地:1.5 cm
  7. -->
  8. <link name="base_link">
  9. <visual>
  10. <geometry>
  11. <cylinder radius="0.1" length="0.08" />
  12. </geometry>
  13. <origin xyz="0 0 0" rpy="0 0 0" />
  14. <material name="yellow">
  15. <color rgba="0.8 0.3 0.1 0.5" />
  16. </material>
  17. </visual>
  18. </link>
  19. <joint name="base_link2base_footprint" type="fixed">
  20. <parent link="base_footprint" />
  21. <child link="base_link"/>
  22. <origin xyz="0 0 0.055" />
  23. </joint>

3.添加驱动轮

  1. <!-- 添加驱动轮 -->
  2. <!--
  3. 驱动轮是侧翻的圆柱
  4. 参数
  5. 半径: 3.25 cm
  6. 宽度: 1.5 cm
  7. 颜色: 黑色
  8. 关节设置:
  9. x = 0
  10. y = 底盘的半径 + 轮胎宽度 / 2
  11. z = 离地间距 + 底盘长度 / 2 - 轮胎半径 = 1.5 + 4 - 3.25 = 2.25(cm)
  12. axis = 0 1 0
  13. -->
  14. <link name="left_wheel">
  15. <visual>
  16. <geometry>
  17. <cylinder radius="0.0325" length="0.015" />
  18. </geometry>
  19. <origin xyz="0 0 0" rpy="1.5705 0 0" />
  20. <material name="black">
  21. <color rgba="0.0 0.0 0.0 1.0" />
  22. </material>
  23. </visual>
  24. </link>
  25. <joint name="left_wheel2base_link" type="continuous">
  26. <parent link="base_link" />
  27. <child link="left_wheel" />
  28. <origin xyz="0 0.1 -0.0225" />
  29. <axis xyz="0 1 0" />
  30. </joint>
  31. <link name="right_wheel">
  32. <visual>
  33. <geometry>
  34. <cylinder radius="0.0325" length="0.015" />
  35. </geometry>
  36. <origin xyz="0 0 0" rpy="1.5705 0 0" />
  37. <material name="black">
  38. <color rgba="0.0 0.0 0.0 1.0" />
  39. </material>
  40. </visual>
  41. </link>
  42. <joint name="right_wheel2base_link" type="continuous">
  43. <parent link="base_link" />
  44. <child link="right_wheel" />
  45. <origin xyz="0 -0.1 -0.0225" />
  46. <axis xyz="0 1 0" />
  47. </joint>

4.添加万向轮

  1. <!-- 添加万向轮(支撑轮) -->
  2. <!--
  3. 参数
  4. 形状: 球体
  5. 半径: 0.75 cm
  6. 颜色: 黑色
  7. 关节设置:
  8. x = 自定义(底盘半径 - 万向轮半径) = 0.1 - 0.0075 = 0.0925(cm)
  9. y = 0
  10. z = 底盘长度 / 2 + 离地间距 / 2 = 0.08 / 2 + 0.015 / 2 = 0.0475
  11. axis= 1 1 1
  12. -->
  13. <link name="front_wheel">
  14. <visual>
  15. <geometry>
  16. <sphere radius="0.0075" />
  17. </geometry>
  18. <origin xyz="0 0 0" rpy="0 0 0" />
  19. <material name="black">
  20. <color rgba="0.0 0.0 0.0 1.0" />
  21. </material>
  22. </visual>
  23. </link>
  24. <joint name="front_wheel2base_link" type="continuous">
  25. <parent link="base_link" />
  26. <child link="front_wheel" />
  27. <origin xyz="0.0925 0 -0.0475" />
  28. <axis xyz="1 1 1" />
  29. </joint>
  30. <link name="back_wheel">
  31. <visual>
  32. <geometry>
  33. <sphere radius="0.0075" />
  34. </geometry>
  35. <origin xyz="0 0 0" rpy="0 0 0" />
  36. <material name="black">
  37. <color rgba="0.0 0.0 0.0 1.0" />
  38. </material>
  39. </visual>
  40. </link>
  41. <joint name="back_wheel2base_link" type="continuous">
  42. <parent link="base_link" />
  43. <child link="back_wheel" />
  44. <origin xyz="-0.0925 0 -0.0475" />
  45. <axis xyz="1 1 1" />
  46. </joint>

思考:

  • 上述代码实现存在什么问题吗?比如复用性!

6.3.5URDF工具

在 ROS 中,提供了一些工具来方便 URDF 文件的编写,比如:

  • check_urdf命令可以检查复杂的 urdf 文件是否存在语法问题
  • urdf_to_graphiz命令可以查看 urdf 模型结构,显示不同 link 的层级关系
当然,要使用工具之前,首先需要安装,安装命令:sudo apt install liburdfdom-tools

1.check_urdf 语法检查

进入urdf文件所属目录,调用:check_urdf urdf文件,如果不抛出异常,说明文件合法,否则非法

第六章 机器人系统仿真 - 图21

第六章 机器人系统仿真 - 图22

2.urdf_to_graphiz 结构查看

进入urdf文件所属目录,调用:urdf_to_graphiz urdf文件,当前目录下会生成 pdf 文件

第六章 机器人系统仿真 - 图23

6.4URDF优化 acro

前面 URDF 文件构建机器人模型的过程中,存在若干问题。

问题1:在设计关节的位置时,需要按照一定的公式计算,公式是固定的,但是在 URDF 中依赖于人工计算,存在不便,容易计算失误,且当某些参数发生改变时,还需要重新计算。(变量计算) 问题2:URDF 中的部分内容是高度重复的,驱动轮与支撑轮的设计实现,不同轮子只是部分参数不同,形状、颜色、翻转量都是一致的,在实际应用中,构建复杂的机器人模型时,更是易于出现高度重复的设计,按照一般的编程涉及到重复代码应该考虑封装。(代码复用性) …… 如果在编程语言中,可以通过变量结合函数直接解决上述问题,在 ROS 中,已经给出了类似编程的优化方案,称之为:Xacro —- 概念 Xacro 是 XML Macros 的缩写,Xacro 是一种 XML 宏语言,是可编程的 XML。

原理

Xacro 可以声明变量,可以通过数学运算求解,使用流程控制控制执行顺序,还可以通过类似函数的实现,封装固定的逻辑,将逻辑中需要的可变的数据以参数的方式暴露出去,从而提高代码复用率以及程序的安全性。

作用

较之于纯粹的 URDF 实现,可以编写更安全、精简、易读性更强的机器人模型文件,且可以提高编写效率。

另请参考:

6.4.1 Acro快速体验

目的:简单了解 xacro 的基本语法。

需求描述:

使用xacro优化上一节案例中驱动轮实现,需要使用变量封装底盘的半径、高度,使用数学公式动态计算底盘的关节点坐标,使用 Xacro 宏封装轮子重复的代码并调用宏创建两个轮子(注意: 在此,演示 Xacro 的基本使用,不必要生成合法的 URDF )。

准备:

创建功能包,导入 urdf 与 xacro。

1.Xacro文件编写

编写 Xacro 文件,以变量的方式封装属性(常量半径、高度、车轮半径…),以函数的方式封装重复实现(车轮的添加)。
  1. <robot name="mycar" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <!--
  3. 上节案例存在的缺陷:
  4. 1、代码复用问题:——> Xacro宏(函数)
  5. 2、参数设计:——> Xacro变量
  6. -->
  7. <!-- 属性封装 -->
  8. <xacro:property name="wheel_radius" value="0.0325" />
  9. <xacro:property name="wheel_length" value="0.0015" />
  10. <xacro:property name="PI" value="3.1415927" />
  11. <xacro:property name="base_link_length" value="0.08" /> #车体高度
  12. <xacro:property name="lidi_space" value="0.015" /> #离地间距
  13. <!-- -->
  14. <xacro:macro name="wheel_func" params="wheel_name flag" >
  15. <link name="${wheel_name}_wheel">
  16. <visual>
  17. <geometry>
  18. <cylinder radius="${wheel_radius}" length="${wheel_length}" />
  19. </geometry>
  20. <origin xyz="0 0 0" rpy="${PI / 2} 0 0" />
  21. <material name="wheel_color">
  22. <color rgba="0 0 0 0.3" />
  23. </material>
  24. </visual>
  25. </link>
  26. <!-- 3-2.joint -->
  27. <joint name="${wheel_name}2link" type="continuous">
  28. <parent link="base_link" />
  29. <child link="${wheel_name}_wheel" />
  30. <!--
  31. x 无偏移
  32. y 车体半径
  33. z z= 车体高度 / 2 + 离地间距 - 车轮半径
  34. -->
  35. <origin xyz="0 ${0.1 * flag} ${(base_link_length / 2 + lidi_space - wheel_radius) * -1}" rpy="0 0 0" />
  36. <axis xyz="0 1 0" />
  37. </joint>
  38. </xacro:macro>
  39. <xacro:wheel_func wheel_name="left" flag="1" />
  40. <xacro:wheel_func wheel_name="right" flag="-1" />
  41. </robot>

2.Xacro文件转换成 urdf 文件

命令行进入 xacro文件 所属目录,执行:rosrun xacro xacro xxx.xacro > xxx.urdf, 会将 xacro 文件解析为 urdf 文件,内容如下:
  1. <?xml version="1.0" ?>
  2. <!-- =================================================================================== -->
  3. <!-- | This document was autogenerated by xacro from test.xacro | -->
  4. <!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
  5. <!-- =================================================================================== -->
  6. <robot name="mycar">
  7. <link name="left_wheel">
  8. <visual>
  9. <geometry>
  10. <cylinder length="0.0015" radius="0.0325"/>
  11. </geometry>
  12. <origin rpy="1.57079635 0 0" xyz="0 0 0"/>
  13. <material name="wheel_color">
  14. <color rgba="0 0 0 0.3"/>
  15. </material>
  16. </visual>
  17. </link>
  18. <!-- 3-2.joint -->
  19. <joint name="left2link" type="continuous">
  20. <parent link="base_link"/>
  21. <child link="left_wheel"/>
  22. <!--
  23. x 无偏移
  24. y 车体半径
  25. z z= 车体高度 / 2 + 离地间距 - 车轮半径
  26. -->
  27. <origin rpy="0 0 0" xyz="0 0.1 -0.0225"/>
  28. <axis xyz="0 1 0"/>
  29. </joint>
  30. <link name="right_wheel">
  31. <visual>
  32. <geometry>
  33. <cylinder length="0.0015" radius="0.0325"/>
  34. </geometry>
  35. <origin rpy="1.57079635 0 0" xyz="0 0 0"/>
  36. <material name="wheel_color">
  37. <color rgba="0 0 0 0.3"/>
  38. </material>
  39. </visual>
  40. </link>
  41. <!-- 3-2.joint -->
  42. <joint name="right2link" type="continuous">
  43. <parent link="base_link"/>
  44. <child link="right_wheel"/>
  45. <!--
  46. x 无偏移
  47. y 车体半径
  48. z z= 车体高度 / 2 + 离地间距 - 车轮半径
  49. -->
  50. <origin rpy="0 0 0" xyz="0 -0.1 -0.0225"/>
  51. <axis xyz="0 1 0"/>
  52. </joint>
  53. </robot>

注意: 该案例编写生成的是非法的 URDF 文件,目的在于演示 Xacro 的极简使用以及优点。

6.4.2 Acro语法详解

6.4.2 Xacro_语法详解

xacro 提供了可编程接口,类似于计算机语言,包括变量声明调用、函数声明与调用等语法实现。在使用 xacro 生成 urdf 时,根标签**robot中必须包含命名空间声明:xmlns:xacro=”http://wiki.ros.org/xacro ** 1.属性与算数运算 用于封装 URDF 中的一些字段,比如: PAI 值,小车的尺寸,轮子半径 ….

属性**定义**

  1. <xacro:property name="xxxx" value="yyyy" />
  2. <xacro:property name="PI" value="3.1415937" /> #举例
  3. <xacro:property name="radius" value="0.03" /> #举例

属性**调用**

  1. ${属性名称}
  2. <Myuseproperty123 name="${PI}" />
  3. <Myuseproperty456 name="${radius}" />

算数**运算**

  1. ${数学表达式}
  2. <Myuseproperty789 result="${PI / 2}" />

2.宏

类似于函数实现,提高代码复用率,优化代码结构,提高安全性

宏定义

  1. <xacro:macro name="宏名称" params="参数列表(多参数之间使用空格分隔)">
  2. .....
  3. 参数调用格式: ${参数名}
  4. </xacro:macro>

宏调用

  1. <xacro:宏名称 参数1=xxx 参数2=xxx/>

3.文件包含

机器人由多部件组成,不同部件可能封装为单独的 xacro 文件,最后再将不同的文件集成,组合为完整机器人,可以使用文件包含实现

文件包含

  1. <robot name="xxx" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <xacro:include filename="my_base.xacro" />
  3. <xacro:include filename="my_camera.xacro" />
  4. <xacro:include filename="my_laser.xacro" />
  5. ....
  6. </robot>

6.4.3 Acro完整使用流程

需求描述:

使用 Xacro 优化 URDF 版的小车底盘模型实现

结果演示:

第六章 机器人系统仿真 - 图24

1.编写 Xacro 文件v

  1. <!--
  2. 使用 xacro 优化 URDF 版的小车底盘实现:
  3. 实现思路:
  4. 1.将一些常量、变量封装为 xacro:property
  5. 比如:PI 值、小车底盘半径、离地间距、车轮半径、宽度 ....
  6. 2.使用 封装驱动轮以及支撑轮实现,调用相关宏生成驱动轮与支撑轮
  7. -->
  8. <!-- 根标签,必须声明 xmlns:xacro -->
  9. <robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
  10. <!-- 封装变量、常量 -->
  11. <xacro:property name="PI" value="3.141"/>
  12. <!-- 宏:黑色设置 -->
  13. <material name="black">
  14. <color rgba="0.0 0.0 0.0 1.0" />
  15. </material>
  16. <!-- 底盘属性 -->
  17. <xacro:property name="base_footprint_radius" value="0.001" /> <!-- base_footprint 半径 -->
  18. <xacro:property name="base_link_radius" value="0.1" /> <!-- base_link 半径 -->
  19. <xacro:property name="base_link_length" value="0.08" /> <!-- base_link -->
  20. <xacro:property name="earth_space" value="0.015" /> <!-- 离地间距 -->
  21. <!-- 底盘 -->
  22. <link name="base_footprint">
  23. <visual>
  24. <geometry>
  25. <sphere radius="${base_footprint_radius}" />
  26. </geometry>
  27. </visual>
  28. </link>
  29. <link name="base_link">
  30. <visual>
  31. <geometry>
  32. <cylinder radius="${base_link_radius}" length="${base_link_length}" />
  33. </geometry>
  34. <origin xyz="0 0 0" rpy="0 0 0" />
  35. <material name="yellow">
  36. <color rgba="0.5 0.3 0.0 0.5" />
  37. </material>
  38. </visual>
  39. </link>
  40. <joint name="base_link2base_footprint" type="fixed">
  41. <parent link="base_footprint" />
  42. <child link="base_link" />
  43. <origin xyz="0 0 ${earth_space + base_link_length / 2 }" />
  44. </joint>
  45. <!-- 驱动轮 -->
  46. <!-- 驱动轮属性 -->
  47. <xacro:property name="wheel_radius" value="0.0325" /><!-- 半径 -->
  48. <xacro:property name="wheel_length" value="0.015" /><!-- 宽度 -->
  49. <!-- 驱动轮宏实现 -->
  50. <xacro:macro name="add_wheels" params="name flag">
  51. <link name="${name}_wheel">
  52. <visual>
  53. <geometry>
  54. <cylinder radius="${wheel_radius}" length="${wheel_length}" />
  55. </geometry>
  56. <origin xyz="0.0 0.0 0.0" rpy="${PI / 2} 0.0 0.0" />
  57. <material name="black" />
  58. </visual>
  59. </link>
  60. <joint name="${name}_wheel2base_link" type="continuous">
  61. <parent link="base_link" />
  62. <child link="${name}_wheel" />
  63. <origin xyz="0 ${flag * base_link_radius} ${-(earth_space + base_link_length / 2 - wheel_radius) }" />
  64. <axis xyz="0 1 0" />
  65. </joint>
  66. </xacro:macro>
  67. <xacro:add_wheels name="left" flag="1" />
  68. <xacro:add_wheels name="right" flag="-1" />
  69. <!-- 支撑轮 -->
  70. <!-- 支撑轮属性 -->
  71. <xacro:property name="support_wheel_radius" value="0.0075" /> <!-- 支撑轮半径 -->
  72. <!-- 支撑轮宏 -->
  73. <xacro:macro name="add_support_wheel" params="name flag" >
  74. <link name="${name}_wheel">
  75. <visual>
  76. <geometry>
  77. <sphere radius="${support_wheel_radius}" />
  78. </geometry>
  79. <origin xyz="0 0 0" rpy="0 0 0" />
  80. <material name="black" />
  81. </visual>
  82. </link>
  83. <joint name="${name}_wheel2base_link" type="continuous">
  84. <parent link="base_link" />
  85. <child link="${name}_wheel" />
  86. <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + earth_space / 2)}" />
  87. <axis xyz="1 1 1" />
  88. </joint>
  89. </xacro:macro>
  90. <xacro:add_support_wheel name="front" flag="1" />
  91. <xacro:add_support_wheel name="back" flag="-1" />
  92. </robot>

2.集成launch文件

方式1**:**先将 xacro 文件转换出 urdf 文件,然后集成

先将 xacro 文件解析成 urdf 文件:rosrun xacro xacro xxx.xacro > xxx.urdf然后再按照之前的集成方式直接整合 launch 文件,内容示例:
  1. <launch>
  2. <param name="robot_description" textfile="$(find demo01_urdf_helloworld)/urdf/xacro/my_base.urdf" />
  3. <node pkg="rviz" type="rviz" name="rviz" args="-d $(find demo01_urdf_helloworld)/config/helloworld.rviz" />
  4. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" output="screen" />
  5. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen" />
  6. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen" />
  7. </launch>

方式2:在 launch 文件中直接加载 xacro(建议使用)

launch 内容示例:
  1. <launch>
  2. <param name="robot_description" command="$(find xacro)/xacro $(find demo01_urdf_helloworld)/urdf/xacro/my_base.urdf.xacro" />
  3. <node pkg="rviz" type="rviz" name="rviz" args="-d $(find demo01_urdf_helloworld)/config/helloworld.rviz" />
  4. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" output="screen" />
  5. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen" />
  6. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen" />
  7. </launch>

核心代码:

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

加载**robot_description时使用command属性**,属性值就是调用 xacro 功能包的 xacro 程序直接解析 xacro 文件。

6.4.4 Acro实操

需求描述:

在前面小车底盘基础之上,添加摄像头和雷达传感器。

结果演示:

第六章 机器人系统仿真 - 图25

实现分析:

机器人模型由多部件组成,可以将不同组件设置进单独文件,最终通过文件包含实现组件的拼装。

实现流程:

  1. 1. **<font style="color:rgb(51, 51, 51);">首先编写摄像头和雷达的 xacro 文件</font>**
  2. 2. **<font style="color:rgb(51, 51, 51);">然后再编写一个组合文件,组合底盘、摄像头与雷达</font>**
  3. 3. **<font style="color:rgb(51, 51, 51);">最后,通过 launch 文件启动 Rviz 并显示模型</font>**

1.摄像头和雷达 Xacro 文件实现

摄像头 xacro 文件:

  1. <!-- 摄像头相关的 xacro 文件 -->
  2. <robot name="my_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <!-- 摄像头属性 -->
  4. <xacro:property name="camera_length" value="0.01" /> <!-- 摄像头长度(x) -->
  5. <xacro:property name="camera_width" value="0.025" /> <!-- 摄像头宽度(y) -->
  6. <xacro:property name="camera_height" value="0.025" /> <!-- 摄像头高度(z) -->
  7. <xacro:property name="camera_x" value="0.08" /> <!-- 摄像头安装的x坐标 -->
  8. <xacro:property name="camera_y" value="0.0" /> <!-- 摄像头安装的y坐标 -->
  9. <xacro:property name="camera_z" value="${base_link_length / 2 + camera_height / 2}" /> <!-- 摄像头安装的z坐标:底盘高度 / 2 + 摄像头高度 / 2 -->
  10. <!-- 摄像头关节以及link -->
  11. <link name="camera">
  12. <visual>
  13. <geometry>
  14. <box size="${camera_length} ${camera_width} ${camera_height}" />
  15. </geometry>
  16. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  17. <material name="black" />
  18. </visual>
  19. </link>
  20. <joint name="camera2base_link" type="fixed"> #type是固定的fixed的
  21. <parent link="base_link" />
  22. <child link="camera" />
  23. <origin xyz="${camera_x} ${camera_y} ${camera_z}" />
  24. </joint>
  25. </robot>

雷达 xacro 文件:

  1. <!--
  2. 小车底盘添加雷达
  3. -->
  4. <robot name="my_laser" xmlns:xacro="http://wiki.ros.org/xacro">
  5. <!-- 雷达支架 -->
  6. <xacro:property name="support_length" value="0.15" /> <!-- 支架长度 -->
  7. <xacro:property name="support_radius" value="0.01" /> <!-- 支架半径 -->
  8. <xacro:property name="support_x" value="0.0" /> <!-- 支架安装的x坐标 -->
  9. <xacro:property name="support_y" value="0.0" /> <!-- 支架安装的y坐标 -->
  10. <xacro:property name="support_z" value="${base_link_length / 2 + support_length / 2}" /> <!-- 支架安装的z坐标:底盘高度 / 2 + 支架高度 / 2 -->
  11. <link name="support">
  12. <visual>
  13. <geometry>
  14. <cylinder radius="${support_radius}" length="${support_length}" />
  15. </geometry>
  16. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  17. <material name="red">
  18. <color rgba="0.8 0.2 0.0 0.8" />
  19. </material>
  20. </visual>
  21. </link>
  22. <joint name="support2base_link" type="fixed">
  23. <parent link="base_link" />
  24. <child link="support" />
  25. <origin xyz="${support_x} ${support_y} ${support_z}" />
  26. </joint>
  27. <!-- 雷达属性 -->
  28. <xacro:property name="laser_length" value="0.05" /> <!-- 雷达长度 -->
  29. <xacro:property name="laser_radius" value="0.03" /> <!-- 雷达半径 -->
  30. <xacro:property name="laser_x" value="0.0" /> <!-- 雷达安装的x坐标 -->
  31. <xacro:property name="laser_y" value="0.0" /> <!-- 雷达安装的y坐标 -->
  32. <xacro:property name="laser_z" value="${support_length / 2 + laser_length / 2}" /> <!-- 雷达安装的z坐标:支架高度 / 2 + 雷达高度 / 2 -->
  33. <!-- 雷达关节以及link -->
  34. <link name="laser">
  35. <visual>
  36. <geometry>
  37. <cylinder radius="${laser_radius}" length="${laser_length}" />
  38. </geometry>
  39. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  40. <material name="black" />
  41. </visual>
  42. </link>
  43. <joint name="laser2support" type="fixed">
  44. <parent link="support" />
  45. <child link="laser" />
  46. <origin xyz="${laser_x} ${laser_y} ${laser_z}" />
  47. </joint>
  48. </robot>

2.组合底盘摄像头与雷达的 xacro 文件

  1. <!-- 组合小车底盘与摄像头与雷达 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_base.urdf.xacro" />
  4. <xacro:include filename="my_camera.urdf.xacro" />
  5. <xacro:include filename="my_laser.urdf.xacro" />
  6. </robot>

3.launch 文件

  1. <launch>
  2. <param name="robot_description" command="$(find xacro)/xacro $(find demo01_urdf_helloworld)/urdf/xacro/my_base_camera_laser.urdf.xacro" />
  3. <node pkg="rviz" type="rviz" name="rviz" args="-d $(find demo01_urdf_helloworld)/config/helloworld.rviz" />
  4. <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" output="screen" />
  5. <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen" />
  6. <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen" />
  7. </launch>

6.5Rwz中控制机器人模型运动

通过 URDF 结合 rviz 可以创建并显示机器人模型,不过,当前实现的只是静态模型,如何控制模型的运动呢?在此,可以调用 Arbotix 实现此功能。


简介

Arbotix:Arbotix 是一款控制电机、舵机的控制板,并提供相应的 ros 功能包,这个功能包的功能不仅可以驱动真实的 Arbotix 控制板,它还提供一个差速控制器,通过接受速度控制指令更新机器人的 joint 状态,从而帮助我们实现机器人在 rviz 中的运动。

这个差速控制器在 arbotix_python 程序包中,完整的 arbotix 程序包还包括多种控制器,分别对应 dynamixel 电机、多关节机械臂以及不同形状的夹持器。

6.5.1 Arbotixl使用流程

接下来,通过一个案例演示 arbotix 的使用。

需求描述:

控制机器人模型在 rviz 中做圆周运动

结果演示:

第六章 机器人系统仿真 - 图26

实现流程:

  1. 1. **<font style="color:rgb(51, 51, 51);">安装 Arbotix</font>**
  2. 2. **<font style="color:rgb(51, 51, 51);">创建新功能包,准备机器人 urdfxacro 文件</font>**
  3. 3. **<font style="color:rgb(51, 51, 51);">添加 Arbotix 配置文件</font>**
  4. 4. **<font style="color:rgb(51, 51, 51);">编写 launch 文件配置 Arbotix</font>**
  5. 5. **<font style="color:rgb(51, 51, 51);">启动 launch 文件并控制机器人模型运动</font>**

1.安装 Arbotix

方式1:命令行调用

  1. sudo apt-get install ros-<<VersionName()>>-arbotix
将 <> 替换成当前 ROS 版本名称,如果提示功能包无法定位,请采用方式2。

方式2:源码安装

先从 github 下载源码,然后调用 catkin_make 编译
  1. git clone https://github.com/vanadiumlabs/arbotix_ros.git

2.创建新功能包,准备机器人 urdf、xacro

urdf 和 xacro 调用上一讲实现即可

3.添加 arbotix 所需的配置文件

添加 arbotix 所需配置文件

  1. # 该文件是控制器配置,一个机器人模型可能有多个控制器,比如: 底盘、机械臂、夹持器(机械手)....
  2. # 因此,根 name 是 controller
  3. controllers: {
  4. # 单控制器设置
  5. base_controller: {
  6. #类型: 差速控制器
  7. type: diff_controller,
  8. #参考坐标
  9. base_frame_id: base_footprint,
  10. #两个轮子之间的间距
  11. base_width: 0.2,
  12. #控制频率
  13. ticks_meter: 2000,
  14. #PID控制参数,使机器人车轮快速达到预期速度
  15. Kp: 12,
  16. Kd: 12,
  17. Ki: 0,
  18. Ko: 50,
  19. #加速限制
  20. accel_limit: 1.0
  21. }
  22. }

另请参考: http://wiki.ros.org/arbotix_python/diff_controller

4.launch 文件中配置 arbotix 节点

launch 示例代码

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

代码解释:

调用了 arbotix_python 功能包下的 arbotix_driver 节点 arbotix 驱动机器人运行时,需要获取机器人信息,可以通过 file 加载配置文件 在仿真环境下,需要配置 sim 为 true

5.启动 launch 文件并控制机器人模型运动

启动launch:roslaunch xxxx ….launch

配置 rviz:

第六章 机器人系统仿真 - 图27

控制小车运动:

此时调用 rostopic list 会发现一个熟悉的话题: /cmd_vel 第六章 机器人系统仿真 - 图28 也就说我们可以发布 cmd_vel 话题消息控制小陈运动了,该实现策略有多种,可以另行编写节点,或者更简单些可以直接通过如下命令发布消息:

  1. 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}}'

现在,小车就可以运动起来了。

6.6URDF集成 Gazebo

URDF 需要集成进 Rviz 或 Gazebo 才能显示可视化的机器人模型,前面已经介绍了URDF 与 Rviz 的集成,本节主要介绍:

  • URDF 与 Gazebo 的基本集成流程;
  • 如果要在 Gazebo 中显示机器人模型,URDF 需要做的一些额外配置;
  • 关于Gazebo仿真环境的搭建。

6.6.1URDF与 Gazebo基本


URDF 与 Gazebo 集成流程与 Rviz 实现类似,主要步骤如下:

  1. 1. **<font style="color:rgb(51, 51, 51);">创建功能包,导入依赖项</font>**
  2. 2. **<font style="color:rgb(51, 51, 51);">编写 URDF Xacro 文件</font>**
  3. 3. **<font style="color:rgb(51, 51, 51);">启动 Gazebo 并显示机器人模型</font>**

1.创建功能包

创建新功能包,导入依赖包: urdfxacrogazebo_ros、gazebo_ros_controlgazebo_plugins ### 2.编写URDF文件(加另外两个标签) python <!-- 创建一个机器人模型(盒状即可),显示在 Gazebo 中 --> <!-- --> <robot name="mycar"> <link name="base_link"> <visual> <geometry> <box size="0.5 0.2 0.1" /> </geometry> <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" /> <material name="yellow"> <color rgba="0.5 0.3 0.0 1" /> </material> </visual> <!--新加碰撞参数--> <!--如果是标准几何体,直接复制上面参数--> <collision> <geometry> <box size="0.5 0.2 0.1" /> </geometry> <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" /> </collision> <!--新加惯性矩阵--> <inertial> <!--重心偏移--> <origin xyz="0 0 0" /> <!--质量--> <mass value="6" /> <!--不同维度的惯性值,需要计算。--> <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" /> </inertial> </link> <gazebo reference="base_link"> <!--Gazebo有自己的颜色设置--> <material>Gazebo/Black</material> </gazebo> </robot> 注意, 当 URDF 需要与 Gazebo 集成时,和 Rviz 有明显区别: 1.必须使用 collision 标签,因为既然是仿真环境,那么必然涉及到碰撞检测,collision 提供碰撞检测的依据。 2.必须使用 inertial 标签,此标签标注了当前机器人某个刚体部分的惯性矩阵,用于一些力学相关的仿真计算。 3.颜色设置,也需要重新使用 gazebo 标签标注,因为之前的颜色设置为了方便调试包含透明度,仿真环境下没有此选项。

3.启动Gazebo并显示模型

launch 文件实现:
  1. <launch>
  2. <!--第一步 Urdf 文件的内容加载到参数服务器 -->
  3. <param name="robot_description" textfile="$(find demo02_urdf_gazebo)/urdf/urdf01_helloworld.urdf" />
  4. <!-- 第二步 启动 gazebo -->
  5. <include file="$(find gazebo_ros)/launch/empty_world.launch" />
  6. <!-- 第三步 gazebo 中显示机器人模型 -->
  7. <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description" />
  8. </launch>

代码解释:

  1. <include file="$(find gazebo_ros)/launch/empty_world.launch" />
  2. <!-- 启动 Gazebo 的仿真环境,当前环境为空环境 -->
  1. <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description" />
  2. <!--
  3. Gazebo 中加载一个机器人模型,该功能由 gazebo_ros 下的 spawn_model 提供:
  4. -urdf 加载的是 urdf 文件
  5. -model mycar 模型名称是 mycar
  6. -param robot_description 从参数 robot_description 中载入模型
  7. -x 模型载入的 x 坐标
  8. -y 模型载入的 y 坐标
  9. -z 模型载入的 z 坐标
  10. -->

6.6.2URDF集成 Gazebo相关设置

较之于 rviz,gazebo在集成 URDF 时,需要做些许修改,比如:必须添加 collision 碰撞属性相关参数、必须添加 inertial 惯性矩阵相关参数,另外,如果直接移植 Rviz 中机器人的颜色设置是没有显示的,颜色设置也必须做相应的变更。

1.collision(区别第一点)

如果机器人link是标准的几何体形状,和link的 visual 属性设置一致即可。

2.inertial(区别第二点)

惯性矩阵的设置需要结合link的质量与外形参数动态生成,标准的球体、圆柱与立方体的惯性矩阵公式如下(已经封装为 xacro 实现):

球体惯性矩阵

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

圆柱惯性矩阵

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

立方体惯性矩阵

  1. <xacro:macro name="Box_inertial_matrix" params="m l w h">
  2. <inertial>
  3. <mass value="${m}" />
  4. <inertia ixx="${m*(h*h + l*l)/12}" ixy = "0" ixz = "0"
  5. iyy="${m*(w*w + l*l)/12}" iyz= "0"
  6. izz="${m*(w*w + h*h)/12}" />
  7. </inertial>
  8. </xacro:macro>

需要注意的是,原则上,除了 base_footprint 外,机器人的每个刚体部分都需要设置惯性矩阵,且惯性矩阵必须经计算得出,如果随意定义刚体部分的惯性矩阵,那么可能会导致机器人在 Gazebo 中出现抖动,移动等现象。

3.颜色设置(区别第三点)

在 gazebo 中显示 link 的颜色,必须要使用指定的标签:
  1. <gazebo reference="link节点名称">
  2. <material>Gazebo/Blue</material>
  3. </gazebo>

PS:material 标签中,设置的值区分大小写,颜色可以设置为 Red Blue Green Black …..

6.6.3URDF集成 Gazebo实操

需求描述:

将之前的机器人模型(xacro版)显示在 gazebo 中

结果演示:第六章 机器人系统仿真 - 图29实现流程:

  1. 1. **<font style="color:rgb(51, 51, 51);">需要编写封装惯性矩阵算法的 xacro 文件</font>**
  2. 2. **<font style="color:rgb(51, 51, 51);">为机器人模型中的每一个 link 添加 collision inertial 标签,并且重置颜色属性</font>**
  3. 3. **<font style="color:rgb(51, 51, 51);">在 launch 文件中启动 gazebo 并添加机器人模型</font>**

1.编写封装惯性矩阵算法的 xacro 文件

  1. <robot name="base" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <!-- Macro for inertia matrix -->
  3. <xacro:macro name="sphere_inertial_matrix" params="m r">
  4. <inertial>
  5. <mass value="${m}" />
  6. <inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
  7. iyy="${2*m*r*r/5}" iyz="0"
  8. izz="${2*m*r*r/5}" />
  9. </inertial>
  10. </xacro:macro>
  11. <xacro:macro name="cylinder_inertial_matrix" params="m r h">
  12. <inertial>
  13. <mass value="${m}" />
  14. <inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
  15. iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
  16. izz="${m*r*r/2}" />
  17. </inertial>
  18. </xacro:macro>
  19. <xacro:macro name="Box_inertial_matrix" params="m l w h">
  20. <inertial>
  21. <mass value="${m}" />
  22. <inertia ixx="${m*(h*h + l*l)/12}" ixy = "0" ixz = "0"
  23. iyy="${m*(w*w + l*l)/12}" iyz= "0"
  24. izz="${m*(w*w + h*h)/12}" />
  25. </inertial>
  26. </xacro:macro>
  27. </robot>

2.复制相关 xacro 文件,并设置 collision inertial 以及 color 等参数

A.底盘 Xacro 文件

  1. <!--
  2. 使用 xacro 优化 URDF 版的小车底盘实现:
  3. 实现思路:
  4. 1.将一些常量、变量封装为 xacro:property
  5. 比如:PI 值、小车底盘半径、离地间距、车轮半径、宽度 ....
  6. 2.使用 封装驱动轮以及支撑轮实现,调用相关宏生成驱动轮与支撑轮
  7. -->
  8. <!-- 根标签,必须声明 xmlns:xacro -->
  9. <robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
  10. <!-- 封装变量、常量 -->
  11. <!-- PI 值设置精度需要高一些,否则后续车轮翻转量计算时,可能会出现肉眼不能察觉的车轮倾斜,从而导致模型抖动 -->
  12. <xacro:property name="PI" value="3.1415926"/>
  13. <!-- 宏:黑色设置 -->
  14. <material name="black">
  15. <color rgba="0.0 0.0 0.0 1.0" />
  16. </material>
  17. <!-- 底盘属性 -->
  18. <xacro:property name="base_footprint_radius" value="0.001" /> <!-- base_footprint 半径 -->
  19. <xacro:property name="base_link_radius" value="0.1" /> <!-- base_link 半径 -->
  20. <xacro:property name="base_link_length" value="0.08" /> <!-- base_link -->
  21. <xacro:property name="earth_space" value="0.015" /> <!-- 离地间距 -->
  22. <xacro:property name="base_link_m" value="0.5" /> <!-- 质量 -->
  23. <!-- 底盘 -->
  24. <link name="base_footprint">
  25. <visual>
  26. <geometry>
  27. <sphere radius="${base_footprint_radius}" />
  28. </geometry>
  29. </visual>
  30. </link>
  31. <link name="base_link">
  32. <visual>
  33. <geometry>
  34. <cylinder radius="${base_link_radius}" length="${base_link_length}" />
  35. </geometry>
  36. <origin xyz="0 0 0" rpy="0 0 0" />
  37. <material name="yellow">
  38. <color rgba="0.5 0.3 0.0 0.5" />
  39. </material>
  40. </visual>
  41. <collision>
  42. <geometry>
  43. <cylinder radius="${base_link_radius}" length="${base_link_length}" />
  44. </geometry>
  45. <origin xyz="0 0 0" rpy="0 0 0" />
  46. </collision>
  47. <xacro:cylinder_inertial_matrix m="${base_link_m}" r="${base_link_radius}" h="${base_link_length}" />
  48. </link>
  49. <joint name="base_link2base_footprint" type="fixed">
  50. <parent link="base_footprint" />
  51. <child link="base_link" />
  52. <origin xyz="0 0 ${earth_space + base_link_length / 2 }" />
  53. </joint>
  54. <gazebo reference="base_link">
  55. <material>Gazebo/Yellow</material>
  56. </gazebo>
  57. <!-- 驱动轮 -->
  58. <!-- 驱动轮属性 -->
  59. <xacro:property name="wheel_radius" value="0.0325" /><!-- 半径 -->
  60. <xacro:property name="wheel_length" value="0.015" /><!-- 宽度 -->
  61. <xacro:property name="wheel_m" value="0.05" /> <!-- 质量 -->
  62. <!-- 驱动轮宏实现 -->
  63. <xacro:macro name="add_wheels" params="name flag">
  64. <link name="${name}_wheel">
  65. <visual>
  66. <geometry>
  67. <cylinder radius="${wheel_radius}" length="${wheel_length}" />
  68. </geometry>
  69. <origin xyz="0.0 0.0 0.0" rpy="${PI / 2} 0.0 0.0" />
  70. <material name="black" />
  71. </visual>
  72. <collision>
  73. <geometry>
  74. <cylinder radius="${wheel_radius}" length="${wheel_length}" />
  75. </geometry>
  76. <origin xyz="0.0 0.0 0.0" rpy="${PI / 2} 0.0 0.0" />
  77. </collision>
  78. <xacro:cylinder_inertial_matrix m="${wheel_m}" r="${wheel_radius}" h="${wheel_length}" />
  79. </link>
  80. <joint name="${name}_wheel2base_link" type="continuous">
  81. <parent link="base_link" />
  82. <child link="${name}_wheel" />
  83. <origin xyz="0 ${flag * base_link_radius} ${-(earth_space + base_link_length / 2 - wheel_radius) }" />
  84. <axis xyz="0 1 0" />
  85. </joint>
  86. <gazebo reference="${name}_wheel">
  87. <material>Gazebo/Red</material>
  88. </gazebo>
  89. </xacro:macro>
  90. <xacro:add_wheels name="left" flag="1" />
  91. <xacro:add_wheels name="right" flag="-1" />
  92. <!-- 支撑轮 -->
  93. <!-- 支撑轮属性 -->
  94. <xacro:property name="support_wheel_radius" value="0.0075" /> <!-- 支撑轮半径 -->
  95. <xacro:property name="support_wheel_m" value="0.03" /> <!-- 质量 -->
  96. <!-- 支撑轮宏 -->
  97. <xacro:macro name="add_support_wheel" params="name flag" >
  98. <link name="${name}_wheel">
  99. <visual>
  100. <geometry>
  101. <sphere radius="${support_wheel_radius}" />
  102. </geometry>
  103. <origin xyz="0 0 0" rpy="0 0 0" />
  104. <material name="black" />
  105. </visual>
  106. <collision>
  107. <geometry>
  108. <sphere radius="${support_wheel_radius}" />
  109. </geometry>
  110. <origin xyz="0 0 0" rpy="0 0 0" />
  111. </collision>
  112. <xacro:sphere_inertial_matrix m="${support_wheel_m}" r="${support_wheel_radius}" />
  113. </link>
  114. <joint name="${name}_wheel2base_link" type="continuous">
  115. <parent link="base_link" />
  116. <child link="${name}_wheel" />
  117. <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + earth_space / 2)}" />
  118. <axis xyz="1 1 1" />
  119. </joint>
  120. <gazebo reference="${name}_wheel">
  121. <material>Gazebo/Red</material>
  122. </gazebo>
  123. </xacro:macro>
  124. <xacro:add_support_wheel name="front" flag="1" />
  125. <xacro:add_support_wheel name="back" flag="-1" />
  126. </robot>
注意: 如果机器人模型在 Gazebo 中产生了抖动,滑动,缓慢位移 …. 诸如此类情况,请查看
  1. 1. <font style="color:rgb(51, 51, 51);">惯性矩阵是否设置了,且设置是否正确合理</font>
  2. 2. <font style="color:rgb(51, 51, 51);">车轮翻转需要依赖于 PI 值,如果 PI 值精度偏低,也可能导致上述情况产生</font>

B.摄像头 Xacro 文件

  1. <!-- 摄像头相关的 xacro 文件 -->
  2. <robot name="my_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <!-- 摄像头属性 -->
  4. <xacro:property name="camera_length" value="0.01" /> <!-- 摄像头长度(x) -->
  5. <xacro:property name="camera_width" value="0.025" /> <!-- 摄像头宽度(y) -->
  6. <xacro:property name="camera_height" value="0.025" /> <!-- 摄像头高度(z) -->
  7. <xacro:property name="camera_x" value="0.08" /> <!-- 摄像头安装的x坐标 -->
  8. <xacro:property name="camera_y" value="0.0" /> <!-- 摄像头安装的y坐标 -->
  9. <xacro:property name="camera_z" value="${base_link_length / 2 + camera_height / 2}" /> <!-- 摄像头安装的z坐标:底盘高度 / 2 + 摄像头高度 / 2 -->
  10. <xacro:property name="camera_m" value="0.01" /> <!-- 摄像头质量 -->
  11. <!-- 摄像头关节以及link -->
  12. <link name="camera">
  13. <visual>
  14. <geometry>
  15. <box size="${camera_length} ${camera_width} ${camera_height}" />
  16. </geometry>
  17. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  18. <material name="black" />
  19. </visual>
  20. <collision>
  21. <geometry>
  22. <box size="${camera_length} ${camera_width} ${camera_height}" />
  23. </geometry>
  24. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  25. </collision>
  26. <xacro:Box_inertial_matrix m="${camera_m}" l="${camera_length}" w="${camera_width}" h="${camera_height}" />
  27. </link>
  28. <joint name="camera2base_link" type="fixed">
  29. <parent link="base_link" />
  30. <child link="camera" />
  31. <origin xyz="${camera_x} ${camera_y} ${camera_z}" />
  32. </joint>
  33. <gazebo reference="camera">
  34. <material>Gazebo/Blue</material>
  35. </gazebo>
  36. </robot>

C.雷达 Xacro 文件

  1. <!--
  2. 小车底盘添加雷达
  3. -->
  4. <robot name="my_laser" xmlns:xacro="http://wiki.ros.org/xacro">
  5. <!-- 雷达支架 -->
  6. <xacro:property name="support_length" value="0.15" /> <!-- 支架长度 -->
  7. <xacro:property name="support_radius" value="0.01" /> <!-- 支架半径 -->
  8. <xacro:property name="support_x" value="0.0" /> <!-- 支架安装的x坐标 -->
  9. <xacro:property name="support_y" value="0.0" /> <!-- 支架安装的y坐标 -->
  10. <xacro:property name="support_z" value="${base_link_length / 2 + support_length / 2}" /> <!-- 支架安装的z坐标:底盘高度 / 2 + 支架高度 / 2 -->
  11. <xacro:property name="support_m" value="0.02" /> <!-- 支架质量 -->
  12. <link name="support">
  13. <visual>
  14. <geometry>
  15. <cylinder radius="${support_radius}" length="${support_length}" />
  16. </geometry>
  17. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  18. <material name="red">
  19. <color rgba="0.8 0.2 0.0 0.8" />
  20. </material>
  21. </visual>
  22. <collision>
  23. <geometry>
  24. <cylinder radius="${support_radius}" length="${support_length}" />
  25. </geometry>
  26. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  27. </collision>
  28. <xacro:cylinder_inertial_matrix m="${support_m}" r="${support_radius}" h="${support_length}" />
  29. </link>
  30. <joint name="support2base_link" type="fixed">
  31. <parent link="base_link" />
  32. <child link="support" />
  33. <origin xyz="${support_x} ${support_y} ${support_z}" />
  34. </joint>
  35. <gazebo reference="support">
  36. <material>Gazebo/White</material>
  37. </gazebo>
  38. <!-- 雷达属性 -->
  39. <xacro:property name="laser_length" value="0.05" /> <!-- 雷达长度 -->
  40. <xacro:property name="laser_radius" value="0.03" /> <!-- 雷达半径 -->
  41. <xacro:property name="laser_x" value="0.0" /> <!-- 雷达安装的x坐标 -->
  42. <xacro:property name="laser_y" value="0.0" /> <!-- 雷达安装的y坐标 -->
  43. <xacro:property name="laser_z" value="${support_length / 2 + laser_length / 2}" /> <!-- 雷达安装的z坐标:支架高度 / 2 + 雷达高度 / 2 -->
  44. <xacro:property name="laser_m" value="0.1" /> <!-- 雷达质量 -->
  45. <!-- 雷达关节以及link -->
  46. <link name="laser">
  47. <visual>
  48. <geometry>
  49. <cylinder radius="${laser_radius}" length="${laser_length}" />
  50. </geometry>
  51. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  52. <material name="black" />
  53. </visual>
  54. <collision>
  55. <geometry>
  56. <cylinder radius="${laser_radius}" length="${laser_length}" />
  57. </geometry>
  58. <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  59. </collision>
  60. <xacro:cylinder_inertial_matrix m="${laser_m}" r="${laser_radius}" h="${laser_length}" />
  61. </link>
  62. <joint name="laser2support" type="fixed">
  63. <parent link="support" />
  64. <child link="laser" />
  65. <origin xyz="${laser_x} ${laser_y} ${laser_z}" />
  66. </joint>
  67. <gazebo reference="laser">
  68. <material>Gazebo/Black</material>
  69. </gazebo>
  70. </robot>

D.组合底盘、摄像头与雷达的 Xacro 文件

  1. <!-- 组合小车底盘与摄像头 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_head.urdf.xacro" />
  4. <xacro:include filename="my_base.urdf.xacro" />
  5. <xacro:include filename="my_camera.urdf.xacro" />
  6. <xacro:include filename="my_laser.urdf.xacro" />
  7. </robot>

3.在 gazebo 中执行

launch 文件:
  1. <launch>
  2. <!-- Urdf 文件的内容加载到参数服务器 -->
  3. <param name="robot_description" command="$(find xacro)/xacro $(find demo02_urdf_gazebo)/urdf/xacro/my_base_camera_laser.urdf.xacro" />
  4. <!-- 启动 gazebo -->
  5. <include file="$(find gazebo_ros)/launch/empty_world.launch" />
  6. <!-- gazebo 中显示机器人模型 -->
  7. <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description" />
  8. </launch>

6.6.4 Gazebo仿真环境搭建

到目前为止,我们已经可以将机器人模型显示在 Gazebo 之中了,但是当前默认情况下,在 Gazebo 中机器人模型是在 empty world 中,并没有类似于房间、家具、道路、树木… 之类的仿真物,如何在 Gazebo 中创建仿真环境呢?

Gazebo 中创建仿真实现方式有两种:

  1. - **<u><font style="color:#F5222D;background-color:#FADB14;">方式1: 直接添加内置组件创建仿真环境</font></u>**
  2. - **<u><font style="color:#F5222D;background-color:#FADB14;">方式2: 手动绘制仿真环境(更为灵活)</font></u>**

也还可以直接下载使用官方或第三方提供的仿真环境插件。

1.添加内置组件创建仿真环境

1.1启动 Gazebo 并添加组件第六章 机器人系统仿真 - 图30
1.2保存仿真环境
添加完毕后,选择 file —-> Save World as 选择保存路径(功能包下: worlds 目录),文件名自定义,后缀名设置为 .world第六章 机器人系统仿真 - 图31 ##### 1.3 启动 python <launch> <!-- 将 Urdf 文件的内容加载到参数服务器 --> <param name="robot_description" command="$(find xacro)/xacro $(find demo02_urdf_gazebo)/urdf/xacro/my_base_camera_laser.urdf.xacro" /> <!-- 启动 gazebo --> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <!--新加arg标签 --> <arg name="world_name" value="$(find demo02_urdf_gazebo)/worlds/hello.world" /> </include> <!-- 在 gazebo 中显示机器人模型 --> <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description" /> </launch> # 核心代码: 启动 empty_world 后,再根据arg加载自定义的仿真环境 python <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="world_name" value="$(find demo02_urdf_gazebo)/worlds/hello.world" /> </include> ### 2.自定义仿真环境 ##### 2.1 启动 gazebo 打开构建面板,绘制仿真环境 第六章 机器人系统仿真 - 图32第六章 机器人系统仿真 - 图33 ##### 2.2 保存构建的环境 点击: 左上角 file —-> Save (保存路径功能包下的: models) 然后 file —-> Exit Building Editor
2.3 保存为 world 文件
可以像方式1一样再添加一些插件,然后保存为 world 文件(保存路径功能包下的: worlds)

第六章 机器人系统仿真 - 图34

2.4 启动
同方式1

3.使用官方提供的插件

当前 Gazebo 提供的仿真道具有限,还可以下载官方支持,可以提供更为丰富的仿真实现,具体实现如下:
3.1 下载官方模型库
  1. git clone https://github.com/osrf/gazebo_models
之前是:hg clone https://bitbucket.org/osrf/gazebo_models但是已经不可用 注意: 此过程可能比较耗时
3.2 将模型库复制进 gazebo
将得到的gazebo_models文件夹内容复制到 /usr/share/gazebo-*/models
3.3 应用
重启 Gazebo,选择左侧菜单栏的 insert 可以选择并插入相关道具了

6.7URDF、 Gazebo与Rviz综合

关于URDF(Xacro)、Rviz 和 Gazebo 三者的关系,前面已有阐述: **URDF 用于创建机器人模型、Rviz 可以显示机器人感知到的环境信息,Gazebo 用于仿真,可以模拟外界环境,以及机器人的一些传感器,如何在 Gazebo 中运行这些传感器,并显示这些传感器的数据(机器人的视角)**呢?本节主要介绍的重点就是将三者结合:通过 Gazebo 模拟机器人的传感器,然后在 Rviz 中显示这些传感器感知到的数据。主要内容包括:

  • 运动控制以及里程计信息显示
  • 雷达信息仿真以及显示
  • 摄像头信息仿真以及显示
  • kinect 信息仿真以及显示

另请参考:

6.7.1机器人运动控制以及里

gazebo 中已经可以正常显示机器人模型了,那么如何像在 rviz 中一样控制机器人运动呢?在此,需要涉及到ros中的组件: ros_control。

1.ros_control 简介

场景:同一套 ROS 程序,如何部署在不同的机器人系统上,比如:开发阶段为了提高效率是在仿真平台上测试的,部署时又有不同的实体机器人平台,不同平台的实现是有差异的,如何保证 ROS 程序的可移植性?ROS 内置的解决方式是 ros_control

ros_control:是一组软件包,它包含了控制器接口,控制器管理器,传输和硬件接口。ros_control 是一套机器人控制的中间件,是一套规范,不同的机器人平台只要按照这套规范实现,那么就可以保证 与ROS 程序兼容,通过这套规范,实现了一种可插拔的架构设计,大大提高了程序设计的效率与灵活性。

gazebo 已经实现了 ros_control 的相关接口,如果需要在 gazebo 中控制机器人运动,直接调用相关接口即可

2.运动控制实现流程(Gazebo)

承上,运动控制基本流程:
  1. 已经创建完毕的机器人模型,**编写一个单独的 xacro 文件**,为机器人模型添加传动装置以及控制器
  2. 将此文件集成进整个模型的xacro文件
  3. 启动 Gazebo 并发布 /cmd_vel 消息控制机器人运动
2.1 为 joint 添加传动装置以及控制器
两轮差速配置
  1. <robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <!-- 传动实现:用于连接控制器与关节 -->
  3. <xacro:macro name="joint_trans" params="joint_name">
  4. <!-- Transmission is important to link the joints and the controller -->
  5. <transmission name="${joint_name}_trans">
  6. <type>transmission_interface/SimpleTransmission</type>
  7. <joint name="${joint_name}">
  8. <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  9. </joint>
  10. <actuator name="${joint_name}_motor">
  11. <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  12. <mechanicalReduction>1</mechanicalReduction>
  13. </actuator>
  14. </transmission>
  15. </xacro:macro>
  16. <!-- 每一个驱动轮都需要配置传动装置 -->
  17. <xacro:joint_trans joint_name="left_wheel2base_link" />
  18. <xacro:joint_trans joint_name="right_wheel2base_link" />
  19. <!-- 控制器 -->
  20. <gazebo>
  21. <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
  22. <rosDebugLevel>Debug</rosDebugLevel>
  23. <publishWheelTF>true</publishWheelTF>
  24. <robotNamespace>/</robotNamespace>
  25. <publishTf>1</publishTf>
  26. <publishWheelJointState>true</publishWheelJointState>
  27. <alwaysOn>true</alwaysOn>
  28. <updateRate>100.0</updateRate>
  29. <legacyMode>true</legacyMode>
  30. <leftJoint>left_wheel2base_link</leftJoint> <!-- 左轮 -->
  31. <rightJoint>right_wheel2base_link</rightJoint> <!-- 右轮 -->
  32. <wheelSeparation>${base_link_radius * 2}</wheelSeparation> <!-- 车轮间距 -->
  33. <wheelDiameter>${wheel_radius * 2}</wheelDiameter> <!-- 车轮直径 -->
  34. <broadcastTF>1</broadcastTF>
  35. <wheelTorque>30</wheelTorque>
  36. <wheelAcceleration>1.8</wheelAcceleration>
  37. <commandTopic>cmd_vel</commandTopic> <!-- 运动控制话题 -->
  38. <odometryFrame>odom</odometryFrame>
  39. <odometryTopic>odom</odometryTopic> <!-- 里程计话题 -->
  40. <robotBaseFrame>base_footprint</robotBaseFrame> <!-- 根坐标系 -->
  41. </plugin>
  42. </gazebo>
  43. </robot>
2.2 xacro文件集成
最后还需要将上述 xacro 文件集成进总的机器人模型文件,代码示例如下:
  1. <!-- 组合小车底盘与摄像头 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_head.urdf.xacro" />
  4. <xacro:include filename="my_base.urdf.xacro" />
  5. <xacro:include filename="my_camera.urdf.xacro" />
  6. <xacro:include filename="my_laser.urdf.xacro" />
  7. <xacro:include filename="move.urdf.xacro" />
  8. </robot>
当前核心: 包含 控制器以及传动配置的 xacro 文件
  1. <xacro:include filename="move.urdf.xacro" />
2.3 启动 gazebo并控制机器人运动
launch文件:
  1. <launch>
  2. <!-- Urdf 文件的内容加载到参数服务器 -->
  3. <param name="robot_description" command="$(find xacro)/xacro $(find demo02_urdf_gazebo)/urdf/xacro/my_base_camera_laser.urdf.xacro" />
  4. <!-- 启动 gazebo -->
  5. <include file="$(find gazebo_ros)/launch/empty_world.launch">
  6. <arg name="world_name" value="$(find demo02_urdf_gazebo)/worlds/hello.world" />
  7. </include>
  8. <!-- gazebo 中显示机器人模型 -->
  9. <node pkg="gazebo_ros" type="spawn_model" name="model" args="-urdf -model mycar -param robot_description" />
  10. </launch>
启动 launch 文件,使用 topic list 查看话题列表,会发现多了 /cmd_vel 然后发布 vmd_vel 消息控制即可 使用命令控制(或者可以编写单独的节点控制)
  1. 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}}'
接下来我们会发现: 小车在 Gazebo 中已经正常运行起来了

第六章 机器人系统仿真 - 图35

3.Rviz查看里程计信息

在 Gazebo 的仿真环境中,机器人的里程计信息以及运动朝向等信息是无法获取的,可以通过 Rviz 显示机器人的里程计信息以及运动朝向

里程计:** **机器人相对出发点坐标系的位姿状态(X 坐标 Y 坐标 Z坐标以及朝向)。

3.1启动 Rviz
launch 文件
  1. <launch>
  2. <!-- 启动 rviz -->
  3. <node pkg="rviz" type="rviz" name="rviz" />
  4. <!-- 关节以及机器人状态发布节点 -->
  5. <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
  6. <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
  7. </launch>
3.2 添加组件
执行 launch 文件后,在 Rviz 中添加图示组件:第六章 机器人系统仿真 - 图36 ## 6.7.2雷达信息仿真以及显示 通过 Gazebo 模拟激光雷达传感器,并在 Rviz 中显示激光数据。 实现流程: 雷达仿真基本流程:
  1. 已经创建完毕的机器人模型,编写一个单独的 xacro 文件,为机器人模型添加雷达配置;
  2. 将此文件集成进xacro文件;
  3. 启动 Gazebo,使用 Rviz 显示雷达信息。

1.Gazebo 仿真雷达

1.1 新建 Xacro 文件,配置雷达传感器信息
  1. <robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <!-- 雷达 -->
  3. <gazebo reference="laser">
  4. <sensor type="ray" name="rplidar">
  5. <pose>0 0 0 0 0 0</pose>
  6. <visualize>true</visualize>
  7. <update_rate>5.5</update_rate>
  8. <ray>
  9. <scan>
  10. <horizontal>
  11. <samples>360</samples>
  12. <resolution>1</resolution>
  13. <min_angle>-3</min_angle>
  14. <max_angle>3</max_angle>
  15. </horizontal>
  16. </scan>
  17. <range>
  18. <min>0.10</min>
  19. <max>30.0</max>
  20. <resolution>0.01</resolution>
  21. </range>
  22. <noise>
  23. <type>gaussian</type>
  24. <mean>0.0</mean>
  25. <stddev>0.01</stddev>
  26. </noise>
  27. </ray>
  28. <plugin name="gazebo_rplidar" filename="libgazebo_ros_laser.so">
  29. <topicName>/scan</topicName>
  30. <frameName>laser</frameName>
  31. </plugin>
  32. </sensor>
  33. </gazebo>
  34. </robot>
1.2 xacro 文件集成
将步骤1的 Xacro 文件集成进总的机器人模型文件,代码示例如下:
  1. <!-- 组合小车底盘与传感器 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_head.urdf.xacro" />
  4. <xacro:include filename="my_base.urdf.xacro" />
  5. <xacro:include filename="my_camera.urdf.xacro" />
  6. <xacro:include filename="my_laser.urdf.xacro" />
  7. <xacro:include filename="move.urdf.xacro" />
  8. <!-- 雷达仿真的 xacro 文件 -->
  9. <xacro:include filename="my_sensors_laser.urdf.xacro" />
  10. </robot>
1.3启动仿真环境
编写launch文件,启动gazebo,此处略…

2.Rviz 显示雷达数据

先启动 rviz,添加雷达信息显示插件第六章 机器人系统仿真 - 图37 ## 6.7.3摄像头信息仿真以及显示 通过 Gazebo 模拟摄像头传感器,并在 Rviz 中显示摄像头数据。 实现流程: 摄像头仿真基本流程:
  1. 1. <font style="color:rgb(51, 51, 51);">已经创建完毕的机器人模型,编写一个单独的 xacro 文件,为机器人模型添加摄像头配置;</font>
  2. 2. <font style="color:rgb(51, 51, 51);">将此文件集成进xacro文件;</font>
  3. 3. <font style="color:rgb(51, 51, 51);">启动 Gazebo,使用 Rviz 显示摄像头信息。</font>

1.Gazebo 仿真摄像头

1.1 新建 Xacro 文件,配置摄像头传感器信息
  1. <robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <!-- 被引用的link -->
  3. <gazebo reference="camera">
  4. <!-- 类型设置为 camara -->
  5. <sensor type="camera" name="camera_node">
  6. <update_rate>30.0</update_rate> <!-- 更新频率 -->
  7. <!-- 摄像头基本信息设置 -->
  8. <camera name="head">
  9. <horizontal_fov>1.3962634</horizontal_fov>
  10. <image>
  11. <width>1280</width>
  12. <height>720</height>
  13. <format>R8G8B8</format>
  14. </image>
  15. <clip>
  16. <near>0.02</near>
  17. <far>300</far>
  18. </clip>
  19. <noise>
  20. <type>gaussian</type>
  21. <mean>0.0</mean>
  22. <stddev>0.007</stddev>
  23. </noise>
  24. </camera>
  25. <!-- 核心插件 -->
  26. <plugin name="gazebo_camera" filename="libgazebo_ros_camera.so">
  27. <alwaysOn>true</alwaysOn>
  28. <updateRate>0.0</updateRate>
  29. <cameraName>/camera</cameraName>
  30. <imageTopicName>image_raw</imageTopicName>
  31. <cameraInfoTopicName>camera_info</cameraInfoTopicName>
  32. <frameName>camera</frameName>
  33. <hackBaseline>0.07</hackBaseline>
  34. <distortionK1>0.0</distortionK1>
  35. <distortionK2>0.0</distortionK2>
  36. <distortionK3>0.0</distortionK3>
  37. <distortionT1>0.0</distortionT1>
  38. <distortionT2>0.0</distortionT2>
  39. </plugin>
  40. </sensor>
  41. </gazebo>
  42. </robot>
1.2 xacro 文件集成
将步骤1的 Xacro 文件集成进总的机器人模型文件,代码示例如下:
  1. <!-- 组合小车底盘与传感器 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_head.urdf.xacro" />
  4. <xacro:include filename="my_base.urdf.xacro" />
  5. <xacro:include filename="my_camera.urdf.xacro" />
  6. <xacro:include filename="my_laser.urdf.xacro" />
  7. <xacro:include filename="move.urdf.xacro" />
  8. <!-- 摄像头仿真的 xacro 文件 -->
  9. <xacro:include filename="my_sensors_camara.urdf.xacro" />
  10. </robot>
1.3启动仿真环境
编写launch文件,启动gazebo,此处略…

2.Rviz 显示摄像头数据

执行 gazebo 并启动 Rviz,在 Rviz 中添加摄像头组件。

第六章 机器人系统仿真 - 图38第六章 机器人系统仿真 - 图39

6.7.4 kinect信息仿真以及显示

通过 Gazebo 模拟kinect摄像头,并在 Rviz 中显示kinect摄像头数据。

实现流程:

kinect摄像头仿真基本流程:
  1. 1. <font style="color:rgb(51, 51, 51);">已经创建完毕的机器人模型,编写一个单独的 xacro 文件,为机器人模型添加kinect摄像头配置;</font>
  2. 2. <font style="color:rgb(51, 51, 51);">将此文件集成进xacro文件;</font>
  3. 3. <font style="color:rgb(51, 51, 51);">启动 Gazebo,使用 Rviz 显示kinect摄像头信息。</font>

1.Gazebo仿真Kinect

1.1 新建 Xacro 文件,配置 kinetic传感器信息
  1. <robot name="my_sensors" xmlns:xacro="http://wiki.ros.org/xacro">
  2. <gazebo reference="kinect link名称">
  3. <sensor type="depth" name="camera">
  4. <always_on>true</always_on>
  5. <update_rate>20.0</update_rate>
  6. <camera>
  7. <horizontal_fov>${60.0*PI/180.0}</horizontal_fov>
  8. <image>
  9. <format>R8G8B8</format>
  10. <width>640</width>
  11. <height>480</height>
  12. </image>
  13. <clip>
  14. <near>0.05</near>
  15. <far>8.0</far>
  16. </clip>
  17. </camera>
  18. <plugin name="kinect_camera_controller" filename="libgazebo_ros_openni_kinect.so">
  19. <cameraName>camera</cameraName>
  20. <alwaysOn>true</alwaysOn>
  21. <updateRate>10</updateRate>
  22. <imageTopicName>rgb/image_raw</imageTopicName>
  23. <depthImageTopicName>depth/image_raw</depthImageTopicName>
  24. <pointCloudTopicName>depth/points</pointCloudTopicName>
  25. <cameraInfoTopicName>rgb/camera_info</cameraInfoTopicName>
  26. <depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
  27. <frameName>kinect link名称</frameName>
  28. <baseline>0.1</baseline>
  29. <distortion_k1>0.0</distortion_k1>
  30. <distortion_k2>0.0</distortion_k2>
  31. <distortion_k3>0.0</distortion_k3>
  32. <distortion_t1>0.0</distortion_t1>
  33. <distortion_t2>0.0</distortion_t2>
  34. <pointCloudCutoff>0.4</pointCloudCutoff>
  35. </plugin>
  36. </sensor>
  37. </gazebo>
  38. </robot>
1.2 xacro 文件集成
将步骤1的 Xacro 文件集成进总的机器人模型文件,代码示例如下:
  1. <!-- 组合小车底盘与传感器 -->
  2. <robot name="my_car_camera" xmlns:xacro="http://wiki.ros.org/xacro">
  3. <xacro:include filename="my_head.urdf.xacro" />
  4. <xacro:include filename="my_base.urdf.xacro" />
  5. <xacro:include filename="my_camera.urdf.xacro" />
  6. <xacro:include filename="my_laser.urdf.xacro" />
  7. <xacro:include filename="move.urdf.xacro" />
  8. <!-- kinect仿真的 xacro 文件 -->
  9. <xacro:include filename="my_sensors_kinect.urdf.xacro" />
  10. </robot>
1.3启动仿真环境
编写launch文件,启动gazebo,此处略…

2 Rviz 显示 Kinect 数据

启动 rviz,添加摄像头组件查看数据

第六章 机器人系统仿真 - 图40第六章 机器人系统仿真 - 图41


补充:kinect 点云数据显示

在kinect中也可以以点云的方式显示感知周围环境,在 rviz 中操作如下:

第六章 机器人系统仿真 - 图42

问题:在rviz中显示时错位。

原因:在kinect中图像数据与点云数据使用了两套坐标系统,且两套坐标系统位姿并不一致。

解决:

1.在插件中为kinect设置坐标系,修改配置文件的标签内容:
  1. <frameName>support_depth</frameName>
2.发布新设置的坐标系到kinect连杆的坐标变换关系,在启动rviz的launch中,添加:
  1. <node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 -1.57 0 -1.57 /support /support_depth" />
3.启动rviz,重新显示。

第六章 机器人系统仿真 - 图43

6.8本章小结

本章主要介绍了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。