前言
最近在学习ROS2,希望通过写一些文章对这段时间的学习进行回顾和总结,文章内容只是我的一点浅薄的见解有不准确不对的地方请见谅。我的文章写作还在摸索阶段,本身也处于学习入门阶段,如果文章中有哪里写的不对、写的不好的欢迎指正。
给大家推荐一个教学ROS2的UP主(鱼香ROS机器人),我就是通过他的视频来学习ROS2的,教学很详细,他的视频地址(《ROS 2机器人开发从入门到实践》1.1 ROS部落的自我介绍_哔哩哔哩_bilibili)。
一、ROS2的简单介绍
ROS2是专门为机器人开发设计的开源中间件框架,解决了ROS1的诸多局限性,并且保留了模块化和工具链的优势。
(一).RO2的特点
1.通讯机制改进:
(1)将DDS(Data Distribution service)作为底层通讯协议,相对于ROS1的自定义TCP/UDP其具备更灵活的实时性、可靠性以及跨平台通讯。
(2)支持服务质量(QoS)配置如:数据可靠性、历史记录、通讯优先级,适应复杂的通讯网络。
2.实时性与嵌入式支持:
(1)新增对实时操作系统(RTOS)兼容性,适合工业机器人、自动驾驶等对实时性要求高的场景。
(2)支持微型控制器(MCU),可以在资源受限的硬件上运行。
3.跨平台和分布式架构
(1)支持Windows、Linux、macOS和嵌入式系统。
(2)原生支持多机器人协作(通过DDS域共享或者隔离),简化分布式系统开发。
4.生命周期管理
(1)节点明确了生命周期的状态(配置、激活、清理),避免资源泄露,提高系统稳定性。
(二).ROS2的核心概念
1.Node(节点)
机器人的工作细胞,它是独立的功能单元(如传感器驱动、导航算法等),通过话题/服务/动作进行通讯,它的特点是:执行具体的任务进程,可以分布在不同的主机运行,可以用不同的编程语言,可以独立运行可执行文件,通过节点名称进行管理。(需要注意的是通常在使用中并非是一个硬件对应一个节点,为了方便维护和升级,复杂功能的节点通常使用多个节点,比如说硬件功能分层,驱动节点和控制节点,可以分别更新驱动程序和控制程序)
2.通讯机制
(1)Topic(话题):使用发布/订阅模型,多对多的通讯模式:发布和订阅者都不唯一,异步通讯:发布者不管接收者什么时候收到消息,使用.msg文件定义消息的结构。
(2)Service(服务):使用客户端/服务器通讯模型,一对多模式:一个服务器对应多个客户端,同步通讯:客户端发送请求,服务器收到请求后做出回应,使用.srv文件定义消息的结构。
(3)Action(动作):通过三个服务和一个话题组成,三个服务包括:客户端发送目标;客户端请求取消任务;服务器返回执行的结果,一个话题是指:服务器实时反馈状态。Action适用于长时间的任务如导航、机械臂抓取物体等。特点:支持长时间任务管理,提供实时反馈机制,支持中途取消任务。
(三).部分软件工具介绍
1.rviz2
rviz2全称——ROS Visualization 2,ROS官方的可视化工具,用于实时显示机器人的:模型、传感器数据、坐标系(TF)、路径、地图、点云等。
应用场景:
- 调试传感器的数据(相机雷达等)
- 验证坐标系(TF)是否正确
- 显示机器人的路径、运动轨迹等
2.gazebo
gazebo是一款强大的机器人仿真软件,可以模拟机器人在复杂物理环境中的运行情况,可以逼真的还原真实世界的物理特性(重力,摩擦,碰撞等),可以通过配置传感器的参数仿真传感器数据生成并且支持多机器人协同仿真。
主要功能:
物理引擎 | 支持多种物理引擎(如 ODE、Bullet、SimBody),精确模拟物体运动、碰撞、摩擦等力学行为。 |
传感器模拟 | 生成激光雷达(Lidar)、摄像头(RGB/深度)、IMU、GPS 等传感器的逼真数据输出。 |
环境建模 | 通过 3D 模型构建复杂仿真环境(如室内场景、地形、障碍物等),支持 SDF 和 URDF 格式。 |
多机器人协同仿真 | 同时模拟多个机器人之间的交互,适用于集群机器人或协作任务研究。 |
实时交互与控制 | 通过 ROS 2/ROS 接口与外部程序通信,实时控制机器人或修改环境参数。 |
可视化与调试工具 | 提供 3D 可视化界面、数据图表、日志记录等 |
(四)ROS2下载安装
以我学习使用的版本为例子(我安装时并没有很顺利,笔记本下载时很慢,而且我用的还是镜像源,下了两天才百分之二十几,后面找了台式下载的就比较顺利了不知道为什么,这是我后来整理的下载流程,由于没有重新测试过,可能会有问题,下载地址建议使用镜像地址,一个不行可以换别的镜像试试多试几次,我的安装过程全是文字叙述内容可能也不够详细,这里推荐去看UP鱼香ROS机器人的安装ROS2的详细教程:《ROS 2机器人开发从入门到实践》1.2.4 在Ubuntu中安装ROS2_哔哩哔哩_bilibili)
- 使用的虚拟机版本——ubuntu 22.04
- ROS2版本——ROS2-humble
1.ROS2 Humble 要求 Ubuntu 22.04(其他系统需通过源码或Docker安装):
lsb_release -a
# 确认输出中包含 "Ubuntu 22.04"
2.设置语言和软件库
# 确保系统支持UTF-8语言环境
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8
3.添加ROS 2的APT源
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl gnupg
4.添加ROS 2 GPG密钥
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
5.编辑源文件(替换为清华镜像地址)
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/ros2.list
6. 更新软件包索引
sudo apt update
7. 安装完整版ROS 2(包含桌面工具和示例)
sudo apt install ros-humble-desktop
8. 安装开发工具
sudo apt install python3-colcon-common-extensions python3-rosdep python3-argcomplete
9. 激活ROS 2环境
source /opt/ros/humble/setup.bash
二、机器人建模
在分享机器人建模开始之前,我给大家推荐一下我使用的编程软件以及扩展,我使用的编程软件是Visual Studio Code,支持多种编程语言并且轻量化,还有很多功能强大的扩展能提高编程的效率。
安装vs code之后可以先安装Chinese扩展,可以汉化软件,方便快速上手,先点击图中左下角的扩展,然后在搜索框搜索Chinese安装后重启软件即可。
可以使用的扩展有点多直接上图片吧
(一)、机器人的描述文件
首先介绍一下.urdf文件,urdf(unified robot description format)翻译过来就是机器人统一描述格式。.urdf文件采用标准的XML格式,其中主要包含了机器人名字以及各个连杆(link)以及关节(joint)的描述,这里解释一下连杆和关节的意思,假设有一个机械臂,类比人类的手臂,大臂和小臂就是连杆,肘关节就是joint关节,这只是一个片面的比喻,实际上的连杆和关节不仅限于此,比如说一个两轮机器人,那么在.urdf文件中它两个轮子是连杆,连接轮子和机器人身体的地方是关节;关节有多种分类,比如:固定不可以活动的、可以滑动的、可以持续旋转的、旋转有角度限制的。
1.机器人的连杆描述
这是一个机器人连杆最基础的描述,只包含了visual(可见的)参数设置:
<link name="imu_up_link">
<!-- 部件的外观描述 -->
<visual>
<!-- 沿着自己几何中心的偏移旋转量 -->
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
<!-- 长宽高为0.02的正方体 -->
<geometry>
<box size="0.02 0.02 0.02"/>
</geometry>
<material name="white">
<!-- 材质颜色 -->
<color rgba="0.0 0.0 0.0 0.5"/>
</material>
</visual>
</link>
这段代码的含义
<link name>定义了一个叫做imu_up_link的连杆,<link>表示开始定义一个连杆,</link>表示这个连杆的定义结束了,它们是对应的,其他的标签visual、geometry、material也是类似的。
<origin>连杆并没有沿着几何中心发生偏移或者旋转
<geometry>形状是一个边长为0.02米的正方体<box>
<color>的参数rgba中rgb表示红绿蓝三原色,a表示材料的透明度,四个参数的取值都为0到1,透明度1表示不透明,0表示全透明
对于初学者想要记住这么多的参数比较困难,死记硬背也没有这个必要,其实只需做到看到一个.urdf文件可以知道其中的参数的含义即可,不需要背记下来。
安装上面推荐的扩展图片里URDF之后,编写机器人的.urdf文件会方便很多,输入link之后它就会自动弹出补全提示(如下图),选择linkFull可以快速补全link包含的所有参数,然后就可以在默认的参数上根据实际需要进行修改。
补全的代码如下:
<link name="link_name">
<inertial>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<mass value="0.0"/>
<inertia ixx="0.0" ixy="0.0" ixz="0.0" iyy="0.0" iyz="0.0" izz="0.0"/>
</inertial>
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<box size="0.0 0.0 0.0"/>
</geometry>
<material name="">
<color rgba="1.0 0.0 0.0 1.0"/>
<texture filename=""/>
</material>
</visual>
<collision>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<box size="0.0 0.0 0.0"/>
</geometry>
</collision>
</link>
其中<intertial>标签中:<origin>定义了惯性参数坐标系,用于表示质心位置和惯性主轴方向,<mass>参数是连杆的质量单位千克、<intertia>参数表示惯性矩阵下的元素。
<collision>标签中:<origin>描述了碰撞体积坐标系相对于其所属连杆坐标系的偏移和旋转,<geometry>描述了碰撞体积的形状大小。
2.机器人关节的描述
机器人关节的分类
类型名(英文) | 中文名 | 自由度 | 运动轴 | 限位(Limit) | 典型应用场景 | 示例 |
---|---|---|---|---|---|---|
fixed | 固定关节 | 0(无运动) | 无 | 无需 | 刚性连接结构 | 传感器与基座连接 |
revolute | 旋转关节 | 1(绕轴旋转) | 单轴(如 0 0 1 ) | 必填(角度范围) | 机械臂关节、门铰链 | 机械臂旋转关节 |
continuous | 连续旋转关节 | 1(无限旋转) | 单轴 | 无需角度限制 | 车轮、无限旋转部件 | 机器人驱动轮 |
prismatic | 平移关节 | 1(沿轴平移) | 单轴(如 1 0 0 ) | 必填(位移范围) | 线性导轨、伸缩臂 | 3D打印机Z轴 |
floating | 浮动关节 | 6(3平移+3旋转) | 无约束 | 无需 | 自由运动物体 | 无人机、漂浮机器人 |
planar | 平面关节 | 3(平面平移+绕轴旋转) | 法线轴(如 0 0 1 ) | 可选 | 平面移动机器人、绘图仪 | AGV底盘 |
这段代码描述了有角度限制的转动关节
<joint name="joint_name" type="revolute">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<parent link="parent_link"/>
<child link="child_link"/>
<axis xyz="0.0 0.0 0.0"/>
<limit lower="0.0" upper="0.0" effort="0.0" velocity="0.0"/>
</joint>
这段代码中name标签定义了关节的名字;type标签定义了关节的类型;
<origin>标签定义了关节相对于父连杆的坐标系的偏移和旋转;
<parent >标签定义了关节的付连杆;<child>标签定义了关节的子连杆;
<axis>标签定义关节沿着关节坐标系的哪一个轴旋转,沿着z轴旋转的描述是xyz="0.0 0.0 1"。
<limit>标签下lower表示关节角度的下限单位是弧度如:-1.57,upper表示关节角的上限如:1.57,effort表示最大力矩,velocity表示最大速度。
(二)、.xacro——XML的宏定义(XMLMacros)
复杂的机器人包含着许多的连杆和关节,这样一来如果使用同一个.urdf文件描述一个机器人,这会导致.urdf文件内容很繁多,在调试代码时想要找出其中某一个关节或者连杆的描述代码是比较麻烦的,并且代码给其他开发者看也很难捋清楚描述文件中连杆、关节的关系。
为了解决这一问题,开发者在编写机器人描述文件时,会使用xacro(XML的macros)宏定义,通过xacro可以对机器人不同部位分成许多个描述文件并进行封装,使用时只需导入所需的宏定义并且调用即可。此外通过宏定义包含可以实现代码的复用,比如四轮机器人的描述文件,其中四个轮子除了位姿不同以外其他属性都应当相同,那么只需要将位姿设为参数,在调用四次轮子的宏并传入每个轮子相对应的位姿即可,避免了重复写相同的代码。
在开始编写代码前先在终端的根目录下输入 mkdir robot 创建一个名为robot的文件夹,然后输入cd robot 跳转到文件夹下,在使用 mkdir robot_ws 创建一个叫robot_ws的文件夹,ws表示work space工作空间,之后的操作几乎都在robot_ws下进行,在使用cd 跳转到robot_ws文件夹下创建一个src文件夹用于存放源代码;接下来创建一个名叫robot_sim的功能包在终端中输入:
ros2 pkg create robot_sim --build-type ament_camke
--build-type ament_camke构建系统使用标准的ament_cmake构建,主要用于c++的项目
功能包创建完成之后输入 cd .. 返回工作空间,终端中输入 code ./ 命令,在vs code中打开工作空间,在功能包中创建一个文件夹叫urdf并在文件夹下创建一个叫robot1文件夹,在robot1下创建叫baselink.urdf.xacro的文件,文件中编写代码:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="base_xacro" params="length radius">
<link name="base_link">
<visual>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<cylinder radius="${radius}" length="${length}"/>
</geometry>
<material>
<color rgba="0.0 0.5 0.5 0.5"/>
</material>
</visual>
</link>
</xacro:macro>
</robot>
<?xml version="1.0"?>声明了XML文档的版本是1.0,需注意这一句代码时XML的标准开头XML必须包含并且必须在第一行顶格否则会报错。robot标签定义了一个机器人。robot标签下xmlns:xacro="http://www.ros.org/wiki/xacro"定义了xacro的命名空间,表明文档中可以使用xacro宏定义。
<xacro:macro name="base_xacro" params="length radius">声明了一个宏用于封装可以重复利用的代码,宏的名字叫base_xacro,其中声明了两个参数:length\radius。
在robot1文件下再创建一个文件robot.urdf.xacro,在这个文件中调用baselink.urdf.xacro文件,机器人其他的部位也需要在该文件内调用,代码如下:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="robot1">
<xacro:include filename="$(find robot_sim)/urdf/robot1/baselink.urdf.xacro"/>
<xacro:base_xacro length="0.12" radius="0.10"/>
</robot>
<xacro:include filename="$(find robot_sim_review)/urdf/baselink.urdf.xacro"/>:xacro:include当前文件内包含或者插入另一个文件的内容。$(find robot_sim_review)使用ROS的命令找到一个名字叫robot_sim_review的功能包,并且拼接/urdf/baselink.urdf.xacro的相对路径找到具体的文件。
<xacro:base_xacro length="0.12" radius="0.1">调用了一个叫base_xacro的宏,给参数length传入了0.15,radius传入了0.1。
(三)、将机器人模型加载到rviz2中显示
1.安装所需的工具xacro
要把机器人模型加载到rviz2中,如果描述机器人时没有使用xacro宏语言,只有一个.urdf文件描述机器人的话,可以直接在终端中输入rviz2,点击左下角的add按钮找到Robot_Model选项点击添加,再点击Description Source选择file,再选择Description File找到对应的机器人描述文件加载即可。
如果使用了xacro宏,需要先使用ROS提供的xacro工具对描述文件进行转换,安装xacro工具在终端中输入:sudo apt install ros-$ROS_DISTRO-xacro。安装完成后可以尝试对编写的robot.urdf.xacro文件进行转换看是否能够成功,如果没有成功可能是代码的某个地方出现了错误,下面就是我转换的结果:
wenaiping@wenaiping-virtual-machine:~/reviw/simulation_ws$ xacro /home/wenaiping/reviw/simulation_ws/src/robot_sim/urdf/robot1/robot1.urdf.xacro
<?xml version="1.0" ?>
<!-- =================================================================================== -->
<!-- | This document was autogenerated by xacro from /home/wenaiping/reviw/simulation_ws/src/robot_sim/urdf/robot1.urdf.xacro | -->
<!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
<!-- =================================================================================== -->
<robot name="robot1">
<link name="base_link">
<visual>
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
<geometry>
<cylinder length="0.12" radius="0.1"/>
</geometry>
<material>
<color rgba="0.0 0.5 0.5 0.5"/>
</material>
</visual>
</link>
</robot>
2.安装功能包
还需要安装两个标准功能包:joint_state_publisher和robot_state_publisher
joint_state_publisher包有一个joint_state_publisher节点,这个节点的功能:
· 可以发布机器人所有不固定的关节的状态(位置、速度、力等);
· 没有硬件的情况下提供虚拟的关节状态;
· 通过rviz2手动调节机器人的姿态,验证URDF文件的正确性。
同样的robot_state_publisher包中也有一个robot_state_publisher节点,它的功能是:
· 将 URDF/Xacro 文件加载到 ROS 参数服务器(参数名为 /robot_description
)。Rviz2 通过订阅参数服务器直接读取该 URDF 模型;
· 将URDF中的机器人连杆坐标系生成Transform Tree;通过接收joint_state_publisher发布的关节状态,计算机器人连杆的状态;为导航、运动规划、点云等提供准确的坐标系关系。
安装joint_state_publisher:
在终端中输入 sudo apt install ros-$ROS_DISTRO-joint-state-publisher
安装robot_state_publisher:
在终端中输入 sudo apt install ros-$ROS_DISTRO-robot-state-publisher
3.编写lauch文件
经过前面的学习我们了解到,要将模型加载到rviz2中我们需要启动joint_state_publisher、robot_state_publisher节点,并且robot_state_publisher节点需要URDF文件的内容作为参数,同时我们还需要启动rviz2。而使用launch文件就可以让我们在终端输入一条命令就能启动这些节点;launch文件用于批量启动和管理节点,launch的核心语法是python。
launch的功能有:
- 配置节点参数
- 设置环境变量
- 定义节点启动的顺序和依赖
- 处理命名空间、重映射
- 支持条件触发和事件驱动
launch文件的内容如下:
import launch
import launch_ros
import os
from ament_index_python import get_package_share_directory
import launch_ros.parameter_descriptions
def generate_launch_description():
#获取文件路径
package_path=get_package_share_directory('robot_sim')
default_urdf_path=os.path.join(package_path,'urdf/robot1','robot1.urdf.xacro')
#为了方便修改将路径设置为参数
action_declare_arg_model_path=launch.actions.DeclareLaunchArgument(
name="model",default_value=str(default_urdf_path),description='机器人模型描述文件的路径'
)
#通过路径获取文件的内容并且提供给robot_state
get_xacro_result=launch.substitutions.Command(
['xacro ', launch.substitutions.LaunchConfiguration('model')]
)
parameter_value=launch_ros.parameter_descriptions.ParameterValue(
get_xacro_result,value_type=str)
print(parameter_value)
robot_state_publisher=launch_ros.actions.Node(
package='robot_state_publisher',
executable='robot_state_publisher',
parameters=[{'robot_description':parameter_value}],
)
joint_state_publisher=launch_ros.actions.Node(
package="joint_state_publisher",
executable="joint_state_publisher",
)
rviz2=launch_ros.actions.Node(
package='rviz2',
executable='rviz2',
)
return launch.LaunchDescription([
robot_state_publisher,
joint_state_publisher,
rviz2,
]
)
- 代码中import launch导入了ROS2 launch系统的核心功能,LaunchDescription、Actions的所有基类、事件处理器(EventHandler)、条件判断(IfCondition
/UnlessCondition
);
- import launch_ros 导入了ROS专用的launch的功能扩展,重要子模块:Node启动节点、 parameter_description参数描述、节点组合支持。
- import os 引入了路径操作,常用于路径拼接、环境配置、检查路径是否存在。
- from ament_index_python import get_package_share_directory 获取ROS2功能包的共享目录路径
- import launch_ros.parameter_descriptions 提供参数描述的专用工具类
- def generate_launch_description ():
return launch.LaunchDescription()为硬性要求,launch文件必须以generate_launch_description的函数作为入口,并且必须返回LaunchDescription,LaunchDescription函数功能——封装节点(Node)\动作(Action)\事件处理(EventHandler)组,形成可执行的描述。
package_path=get_package_share_directory('robot_sim')
获取share目录下一个名叫robot_sim的包的路径
default_urdf_path=os.path.join(package_path,'urdf/robot1','robot1.urdf.xacro')
拼接路径share/robot_sim/urdf/robot1/robot1.urdf.xacro
action_declare_arg_model_path=launch.actions.DeclareLaunchArgument(
name="model",default_value=str(default_urdf_path),description='机器人模型描述文件的路径')
拼接好的路径声明为动态参数(launch启动后参数可以动态修改),名字叫model,类型为str,对参数的描述为:机器人模型描述文件的路径。
get_xacro_result=launch.substitutions.Command(
['xacro ', launch.substitutions.LaunchConfiguration('model')]
)
使用xacro工具将路径下的.xacro文件进行解析,获取解析的内容
parameter_value=launch_ros.parameter_descriptions.ParameterValue(
get_xacro_result,value_type=str)
print(parameter_value)
将获取到的内容封装成参数
robot_state_publisher=launch_ros.actions.Node(
package='robot_state_publisher',
executable='robot_state_publisher',
parameters=[{'robot_description':parameter_value}],
)
配置节点参数,功能包的名称叫robot_state_publisher(上一小节下载的官方标准功能包),可执行文件名叫robot_state_publisher,将parameter_value传给参数robot_description,robot_description
是标准参数名,用于传递机器人模型数据
return launch.LaunchDescription([
robot_state_publisher,
joint_state_publisher,
rviz2,])
返回节点组的可执行的描述
编写完成launch文件并保存之后,需要在功能包中找到CmakeList文件并打开,在文件中的ament_packgae()和endif()之间加入
install(DIRECTORY urdf launch
DESTINATION share/${PROJECT_NAME}
)
表示将urdf、launch文件夹拷贝到install/robot_sim/share/robot_sim目录下
4.启动launch文件,将模型加载到rviz2
完成以上步骤之后,就可以构建功能包了(这里需要确保终端中使用 xacro 机器人模型.xacro文件的路径,使用示例如: xacro /home/wenaiping/review/simulation_ws/src/robot_sim/urdf/robot1/robot1.urdf.xacro ,注意xacro之后要输入空格,如果可以正确解析.xacro文件内容即机器人描述文件没有错误,不然构建时会报错),打开终端跳转到工作空间下,输入colcon build 命令进行构建,构建完成会生成三个文件:buil(存放编译过程中的临时文件,Cmake缓存、中间文件等) log(存放日志信息以及编译过程中的错误信息) install(存放可执行文件、库和资源等)。在构建代码时可能会报错,查看错误信息,仔细检查代码,注意修改完代码需要保存后再重新进行编译,不能解决的问题可以复制错误信息在浏览器搜索。
成功构建之后,输入 source install/setup.base 配置运行环境,现在我们就可以运行我们的launch文件了,终端中输入 ros2 launch robot_sim robot_sim.launch.py,此时也有可能会报错,排查代码错误是一件枯燥乏味的事,需要有足够的耐心和细心,但是当你排查完错误代码跑起来的时候,你会收获成功的喜悦。
如果你成功运行了luanch并且打开了rviz2那么点击左下角的Add(图一),选择RobotModel(图二),在Description Source选择Topic话题,Description Topic选择 /robot_description(图三),你将会的到一个绿色的圆柱体(图四)。至此你已经成功的将一个自己通过外观参数定义的机器人的基连杆(base_link)加载到rviz2可视化软件中了。
5.继续完善机器人
接下来你可以创建并编写机器人的其他部位的描述文件,并在robot1.urdf.xacro文件中加入并调用,重新编译后,通过launch文件启动节点将其加载到rviz2中。这里需要注意的是,需要计算好每一个关节相对于baselink几何中心(圆柱体高的一半的圆心位置)的偏移或者旋转,并且rviz2中的呈现的效果达到自己的预期。
展示一下我建的机器人模型,(有点丑哈哈,是不是和心目中的机器人差距有点大)我学习鱼香ROS老师的视频时建的就是这样一个两轮机器人,我这里也是建了两轮机器人,为了方便后面复习使用两轮差速控制机器人移动。
解释一下图中的机器人结构,最顶上黑色的圆盘是雷达(对应图四中laser.urdf.xacro),黄色的圆杆是连接杆,正前方黑色长方体是相机(对应图四中camera.urdf.xacro),机器人身体内的黑色正方体是惯性传感器(对应图四中imu.urdf.xacro),两个蓝色的轮子是驱动轮(对应图四中wheel.urdf.xacro),黑色的小球模拟支持用的万向轮(对应图四中caster.urdf.xacro)。图三中的坐标系表示机器人关节的位姿,通过添加TF可以看到,红色是x轴,绿色是y轴,蓝色是z轴。需要注意两个驱动轮关节的旋转轴应该是y轴,x轴指向机器人前进的方向,z轴垂直向上。
描述机器人的代码如下:
laser.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="laser_xacro">
<link name="laser_pole_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<cylinder radius="0.01" length="0.1"/>
</geometry>
<material name="">
<color rgba="0.5 0.5 0.0 0.5"/>
</material>
</visual>
</link>
<joint name="laser_pole_joint" type="fixed">
<origin xyz="0.0 0.0 0.11" rpy="0.0 0.0 0.0"/>
<parent link="base_link"/>
<child link="laser_pole_link"/>
</joint>
<link name="laser_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<cylinder radius="0.03" length="0.02"/>
</geometry>
<material name="">
<color rgba="0.0 0.0 0.0 1.0"/>
</material>
</visual>
</link>
<joint name="laser_joint" type="fixed">
<origin xyz="0.0 0.0 0.05" rpy="0.0 0.0 0.0"/>
<parent link="laser_pole_link"/>
<child link="laser_link"/>
</joint>
</xacro:macro>
</robot>
camera.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="camera_xacro" params="xyz">
<link name="camera_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<box size="0.03 0.1 0.03"/>
</geometry>
<material name="">
<color rgba="0.0 0.0 0.0 1.0"/>
</material>
</visual>
</link>
<joint name="camera_joint" type="fixed">
<origin xyz="${xyz}" rpy="0.0 0.0 0.0"/>
<parent link="base_link"/>
<child link="camera_link"/>
</joint>
</xacro:macro>
</robot>
imu.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="imu_xacro" params="xyz">
<link name="imu_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<box size="0.05 0.05 0.05"/>
</geometry>
<material name="">
<color rgba="0.0 0.0 0.0 1.0"/>
</material>
</visual>
</link>
<joint name="imu_joint" type="fixed">
<origin xyz="${xyz}" rpy="0.0 0.0 0.0"/>
<parent link="base_link"/>
<child link="imu_link"/>
</joint>
</xacro:macro>
</robot>
wheel.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="wheel_xacro" params="name xyz">
<link name="${name}_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="1.57 0.0 0.0"/>
<geometry>
<cylinder radius="0.03" length="0.03"/>
</geometry>
<material name="">
<color rgba="0.0 0.0 0.66 1.0"/>
</material>
</visual>
</link>
<joint name="${name}_joint" type="continuous">
<origin xyz="${xyz}" rpy="0.0 0.0 0.0"/>
<parent link="base_link"/>
<child link="${name}_link"/>
<axis xyz="0.0 1.0 0.0"/>
</joint>
</xacro:macro>
</robot>
caster.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="caster_xacro" params="name xyz">
<link name="${name}_link">
<visual name="">
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<sphere radius="0.015"/>
</geometry>
<material name="">
<color rgba="0.0 0.0 0.0 1.0"/>
</material>
</visual>
</link>
<joint name="${name}_joint" type="fixed">
<origin xyz="${xyz}" rpy="0.0 0.0 0.0"/>
<parent link="base_link"/>
<child link="${name}_link"/>
</joint>
</xacro:macro>
</robot>
baselink.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="base_xacro" params="length radius">
<link name="base_link">
<visual>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
<geometry>
<cylinder radius="${radius}" length="${length}"/>
</geometry>
<material name="">
<color rgba="0.0 0.5 0.5 0.5"/>
</material>
</visual>
</link>
</xacro:macro>
</robot>
robot1.urdf.xacro:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="robot1">
<xacro:include filename="$(find robot_sim)/urdf/robot1/baselink.urdf.xacro"/>
<xacro:include filename="$(find robot_sim)/urdf/robot1/sensor/laser.urdf.xacro"/>
<xacro:include filename="$(find robot_sim)/urdf/robot1/sensor/camera.urdf.xacro"/>
<xacro:include filename="$(find robot_sim)/urdf/robot1/sensor/imu.urdf.xacro"/>
<xacro:include filename="$(find robot_sim)/urdf/robot1/actuator/wheel.urdf.xacro"/>
<xacro:include filename="$(find robot_sim)/urdf/robot1/actuator/caster.urdf.xacro"/>
<xacro:base_xacro length="0.12" radius="0.10"/>
<xacro:laser_xacro/>
<xacro:camera_xacro xyz="0.11 0.0 0.08"/>
<xacro:imu_xacro xyz="0.0 0.0 0.0"/>
<xacro:wheel_xacro name="left_wheel" xyz="0.0 0.112 -0.06"/>
<xacro:wheel_xacro name="right_wheel" xyz="0.0 -0.112 -0.06"/>
<xacro:caster_xacro name="ahead_caster" xyz="0.08 0.0 -0.072"/>
<xacro:caster_xacro name="back_caster" xyz="-0.08 0.0 -0.072"/>
</robot>
需要注意代码中关节位置使用了参数定义,统一在robot1.urdf.xacro文件内调用时设置关节位置,方便调试时修改关节位置;另外驱动轮和支撑轮代码都被调用了两次(复用),为了避免连杆名字和关节名字重复,连杆和关节名也使用了参数。代码内的描述机器人各个部位的颜色、位置和尺寸都可根据自己的想法做调整,这里的代码仅供参考,学习还是要多上手实践,代码一定要多敲才能熟悉。
总结
完成上述的操作之后,你就已经使用ROS2完成了对一个两轮机器人进行建模,并且将模型加载到rviz2可视化工具内了。完成这些需要进行机器人描述文件编写,launch文件的编写,代码的错误排查等一系列的操作,过程中可能会碰到很多问题和困难,但是在不断解决问题克服困难的过程中你也在不断的进步。对于初学者而言,光看文字叙述想要深入了解学习ROS2可能会比较困难,可以配合查找视频资料,有的时候听别人的讲解你可能一下就理解了自己没有想明白的问题。
之后我还会写关于两轮机器人的仿真的文章,其中包括配置机器人的惯性矩阵、碰撞体积,使用两轮差速控制器控制机器人移动、slam_toolbox绘制地图以及navigation2导航等。(写的不好希望见谅,我会继续努力的哈哈)