ROS(Robot Operating System,机器人操作系统)是一个面向机器人开发的开源软件框架与工具集。它为机器人系统的构建、运行和协作提供了标准化的基础环境。本篇文章将从ROS的机制原理入手,告诉你ROS能做什么。
推荐课程
ROS入门视频,个人认为是b站上最详细的讲解视频。从原理到实操,只需较低的学习成本即可快速入门。强烈建议使用虚拟机跟着课程敲一遍代码,只需一遍就可以自己编写程序让小车动起来。
安装ROS
使用鱼香ROS提供的一键安装命令,具体的使用请自行搜索
wget http://fishros.com/install -O fishros && . fishros
ROS架构
WorkSpace --- 自定义的工作空间
|--- build:编译空间,用于存放CMake和catkin的缓存信息、配置信息和其他中间文件。
|--- devel:开发空间,用于存放编译后生成的目标文件,包括头文件、动态&静态链接库、可执行文件等。
|--- src: 源码
|-- package:功能包(ROS基本单元)包含多个节点、库与配置文件,包名所有字母小写,只能由字母、数字与下划线组成
|-- CMakeLists.txt 配置编译规则,比如源文件、依赖项、目标文件
|-- package.xml 包信息
|-- scripts 存储python文件
|-- src 存储C++源文件
|-- include 头文件
|-- msg 消息通信格式文件
|-- srv 服务通信格式文件
|-- action 动作格式文件
|-- launch 可一次性运行多个节点
|-- config 配置信息
|-- CMakeLists.txt: 编译的基本配置
工作空间
ROS工作空间是最外层文件夹,每个工作空间都是独立的存在。一个小车上可以有不同的工作空间,比如不同队伍使用同一台小车就可以各自维护自己的工作空间。在官方源码中,工作空间名字为ucar_ws。
如何创建一个ROS工作空间:
mkdir -p my_ws/src
cd my_ws
catkin_make
catkin_make命令执行之后,会在工作空间目录下产生build和devel文件夹,这两个文件夹中存放的缓存和编译后的目标文件都是依赖于src中文件产生的。任何时候,你都可以彻底删除build和devel文件夹,并通过catkin_make重新生成。建议在存储代码或者使用git推送时将build和devel删除,只维护src,这样可以大大减小仓库大小。
功能包
功能包-package是一个或者若干个功能的集合。一个功能包中可以包含若干个节点。在目录上看,功能包是一个个文件夹,位于src目录下。在官方源码中,ucar_controller就是一个功能包,关于底盘的一切都由它管理。你可以创建自己的功能包,并在其中添加节点来实现功能。
功能包的创建
-
进入
src目录cd ~/catkin_ws/src -
创建功能包,这里功能包名字为benz,后面的std_msgs rospy roscpp是所需的依赖。
catkin_create_pkg benz_pkg std_msgs rospy roscppstd_msgs包含了各种基本的消息类型,在后续使用节点订阅和接收话题时会使用;rospy和roscpp是关于python和c++的接口,加入这两个依赖你才可以用python或者c++来开发。
节点
节点是ROS中的可执行程序,通俗来讲每一个节点实现一个功能。当然你也可以将多个功能写到一个节点中,但是这样会增加代码维护的难度。
ROS的节点可以用C++或者Python编写,各有各的好处,C++处理更快,但是每次修改都需要编译来重新生成可执行文件;Python修改后直接生效,因为其本质是脚本。在处理速度无明显差异的情况下推荐使用Python。
创建一个节点
-
在功能包下创建一个scripts目录,专门用于存放python脚本;而功能包中的src存放cpp文件。在scripts中创建一个新python文件benz.py。
-
在文件开头标明解释器,重要!
#!/usr/bin/env python3 import rospy # 使用python开发需要导入rospy if __name__ == "__main__": rospy.init_node("benz") # 初始化一个ros节点这样就创建了一个python的ROS节点,只是初始化而已,并没有功能。
-
如果创建的是python节点,那么需要对该文件赋予权限。
cd ~/catkin_ws/src/benz_pkg/scripts在终端中打开scripts后,使用如下命令赋予可执行权限
chmod +x benz.py然后执行
ls你可以看到benz.py变成绿色,说明这个节点可以执行了。
-
启动节点,在ucar_ws工作空间的目录下执行。
rosrun benz_pkg benz.py
话题通信
ROS有三种通信机制,分别是话题通信、服务通信和动作通信。其中话题通信时最常见的,其他不多做介绍。
话题通信原理
采用发布/订阅的模型,来实现节点之间的消息传递。允许一个或多个节点发布消息,同时一个或多个节点订阅这些消息。
发布/订阅模型概述
- 发布者(Publisher): 发布者节点负责将消息发送到某个话题上。发布者并不关心谁订阅了它发布的消息,也不需要知道有多少订阅者。
- 订阅者(Subscriber): 订阅者节点从某个话题上接收消息。它只关心从该话题接收到的消息,不需要知道谁在发布消息。
ROS 系统内部负责管理话题的注册、发布者和订阅者的匹配,并在它们之间传递消息。
话题的基本概念
- 话题名称: 每个话题有唯一的名称,节点通过话题名称进行消息传递。比如雷达话题是/scan,摄像头图像话题是/img等
- 消息类型: 每个话题都必须定义其传递的消息类型。消息类型可以是 ROS 提供的标准消息(如
std_msgs/String),也可以是自定义消息。 - 队列大小: 订阅者和发布者都可以定义队列大小,用于控制消息缓存。如果队列满了,新的消息会替换掉旧的消息。
关于话题的应用,比如视觉识别中,我们可以创建一个节点专门打开摄像头获取图像,然后将每一帧图像发布到话题/img;另外一个节点订阅该话题就可以获取到每一帧图像,然后对图像进行处理。这样做的好处是,分解耦合,只需要一个节点来打开摄像头,其他很多节点都可以订阅,用来执行不同的功能。
话题通信实操
创建发布者
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
if __name__ == "__main__":
rospy.init_node("benz")
# 创建一个话题的发布者,话题名称为talk,类型为字符串
pub = rospy.Publisher("talk",String,queue_size=1000)
# 创建发送的文字
msg = String()
msg.data = "hello word"
# 设置发送频率
rate = rospy.Rate(10)
# 在循环中发布,只要ros节点没有关闭
while not rospy.is_shutdown():
pub.publish(msg)
rate.sleep()
创建订阅者
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
# 每收到一次消息就会进入一次回调函数
def call_back(msg):
rospy.loginfo(msg.data)
if __name__ == "__main__":
rospy.init_node("sub_python")
# 创建订阅者,订阅talk话题,类型为String,并且指定回调函数
sub = rospy.Subscriber("talk",String,call_back)
# 这一句保证节点持续运行,直到ctrl+c关闭
rospy.spin()
launch文件
在功能包的launch目录下,你会看到有launch文件。顾名思义这是一个可以同时启动多个节点的文件。启动单个节点可以使用rosrun命令,但是如果你想启动多个节点,一个一个启动就很麻烦。所以你可以在一个launch文件中包含进多个节点,一键启动。
以下是launch文件的一般格式及其常用标签:
<launch>
<!-- arg参数,可在launch中任意位置通过$(arg hello)调用其值 -->
<arg name="hello" default = "0.55" />
<param name="param" value="$(arg xxx)" />
<!-- 定义参数服务器中的参数 -->
<param name="param_name" value="param_value" />
<!-- 启动ROS节点 -->
<node pkg="package_name" type="executable_name" name="node_name" output="screen" >
<!-- 向节点传递参数,会自动添加命名空间前缀,相当于私有参数 -->
<param name="param_name" value="param_value" />
<!-- 重映射话题 -->
<remap from="/original_topic" to="/new_topic" />
<!-- 环境变量 -->
<env name="ENV_VAR" value="env_value" />
<!-- node内传递参数文件(私有) -->
<rosparam file="$(find hello_vscode)/config/config_file.yaml" command="load"/>
</node>
<!-- 包含其他launch文件 -->
<include file="$(find hello_vscode)/launch/other_launch_file.launch" />
</launch>
<!-- node外传递参数文件(公有) -->
<rosparam file="$(find hello_vscode)/config/config_file.yaml" command="load"/>
常用标签说明:
-
<launch>: 每个launch文件的根标签。 -
<node>: 启动节点。常用属性包括:-
pkg: 节点所在的ROS包名。 -
name: 节点的名称。 -
type: 可执行文件的名称。add_executable(${PROJECT_NAME}_node src/hello_vscode.cpp)hello_vscode.cpp==生成的可执行文件的名称为==hello_vscode_node -
output: 输出的目标,通常为screen或log,screen表示将输出打印到终端。 -
respawn:如果节点崩溃或意外退出,是否自动重启节点。
-
-
<param>: 定义ROS参数,可以在参数服务器name(参数名)和value(参数值)。 -
<remap>: 重新映射话题名称,from表示原话题,to表示重映射后的话题。 -
<env>: 设置环境变量,name为环境变量名称,value为环境变量值。 -
<rosparam>: 加载YAML格式的参数文件,file指向参数文件的路径,command常用为load,用于加载文件;dump用于导出文件。 -
<include>: 包含其他launch文件,通常用于将多个launch文件组合。
常用命令
-
rosnode list:列出当前运行的所有节点。rosnode info <node_name>:查看某个节点的详细信息,包括发布和订阅的主题、服务等。rosnode ping <node_name>:测试与某个节点的连接性。rosnode kill <node_name>:关闭指定的节点。rosnode machine <machine_name>:查看某台机器上运行的节点。rostopic list:列出当前所有的 ROS 话题。rostopic echo <topic_name>:打印发布到该话题的数据。rostopic pub <topic_name> <msg_type> <msg_data>:发布消息到指定话题(手动发布)。rostopic hz <topic_name>:检查话题的发布频率。rostopic info <topic_name>:显示某个话题的详细信息(包括发布者和订阅者)。rosservice list:列出当前可用的服务。rosservice call <service_name> <args>:调用一个服务并传递参数。rosservice info <service_name>:查看某个服务的详细信息(包括请求和响应消息类型)。rosservice type <service_name>:查看服务的类型。rosservice find <service_type>:查找使用某种类型的服务。rosmsg list:列出所有可用的 ROS 消息类型。rosmsg show <msg_type>:显示某个消息类型的结构定义。rosmsg package <package_name>:列出某个包中定义的所有消息类型。rossrv list:列出所有可用的 ROS 服务类型。rossrv show <srv_type>:显示某个服务类型的结构定义。rossrv package <package_name>:列出某个包中定义的所有服务类型。rosparam list:列出所有当前存在的参数。rosparam get <param_name>:获取某个参数的值。rosparam set <param_name> <value>:设置某个参数的值。rosparam delete <param_name>:删除某个参数。rosparam load <file>:从 YAML 文件中加载参数到参数服务器。rosparam dump <file>:将参数服务器上的参数导出到文件。 -
设置环境变量:
在工作空间下输入命令:
nano ~/.bashrc在末尾增加
source /home/prac_ws/devel/setup.bash此后在该工作空间下打开终端会自动刷新环境变量。
-
==功能相同但传入参数不同时,可以传不同的参启动该节点多次,但是要使用不同的name,可以提高代码复用性。==
-
没有传参时,
argc = 1,argv[0]始终是可执行文件的名称。 -
参数实时调节器:
rosrun rqt_reconfigure rqt_reconfigure
以上就是一些关于ROS的预备知识,更多详细内容请自行查阅或者借助AI工具。千里之行,始于足下。只有强大的基础才能支持你走的更远。
更多关于全国大学生智能汽车的分享,请访问个人主页。
期待你的评论与交流!