参考:
https://blog.csdn.net/qq_28087491/article/details/119053810
https://www.jianshu.com/p/63a959bfbb96
https://blog.csdn.net/ngsford/article/details/113177116
ROS核心概念
节点管理器(ROS master):
节点注册与管理
提供参数服务器,节点使用此服务器存储和检索运行时的参数
跟踪和记录话题/服务通信,辅助节点相互查找、建立连接
没有它,节点将无法找到彼此,也无法交换信息或调用服务器
打开管理器命令:roscore
节点(node):执行单元,即进程,不同节点可用不同语言
运行节点命令:rosrun
创建ROS工作空间
mkdir -p 指定文件夹/工作空间名称/src //递归创建文件夹
cd 指定文件夹/工作空间名称/src //进入src文件夹
catkin_init_workspace //初始化工作空间
ROS文件系统
注意:功能包创建后其文件名是可以更改的,但功能包名称不变,在package.xml中可查看名称
因此功能包名称不一定与所在文件名相同
功能包(package):src文件夹下的一个文件夹,且只有包含以下两个文件的文件夹才是功能包
CMakeLists.txt :包含功能包的编译信息
package.xml : 包含功能包的基本信息和依赖信息
注:功能包中有多少个main函数,就有多少个节点(最终生成的可执行文件数)
功能包创建:
cd 指定文件夹/工作空间名称/src //进入src文件夹
catkin_create_pkg 功能包名称 功能包依赖1 功能包依赖2... //创建,cpp功能包依赖一般有roscpp,std_msgs
如:catkin_create_pkg test roscpp std_msgs
//执行完命令后将会生成功能包文件,里面包括:include,src文件夹和CMakeLists.txt,package.xml文件
编写节点代码
在功能包内创建节点代码的头文件和源文件并进行编写(与编写普通代码类似)
main的函数编写(下面为最基本的举例)
#include <ros/ros.h>
using namespace std;
int main(int argc, char **argv)
{
//节点初始化,设置节点名称为“test1”
ros::init(argc, argv, "test1");
//创建句柄 - 管理节点资源
ros::NodeHandle n;
cout<<"hello test1 node"<<endl;
//阻塞并等待话题
ros::spin();
return 0;
}
CMakeLists.txt修改(注意是功能包里面的),在合适位置添加以下内容:
add_executable(test1 src/main.cpp) //有几个可执行文件,就相当于有几个节点
target_link_libraries(test1 ${catkin_LIBRARIES})
编译和配置环境变量
//编译 - 即使没有功能包,也能进行编译
cd 指定文件夹/工作空间名称
catkin_make
//生成的可执行文件在devel/lib文件夹中可以找到
//设置环境变量
cd 指定文件夹/工作空间名称
source devel/setup.bash
为避免每次打开终端都要配置环境变量,可参考:https://blog.csdn.net/qq_37769337/article/details/129127138
运行节点
//首先打开一个终端,开启节点管理器
roscore
//再打开一个终端,打开节点
//若未按照https://blog.csdn.net/qq_37769337/article/details/129127138进行.bashrc的相关配置,则首先需要配置环境变量,否则无法找到功能包
cd 指定文件夹/工作空间名称
source devel/setup.bash
rosrun test test1
launch启动文件
作用: 通过xml语法实现多节点配置与启动(若未启动ROS Master,将自动启动ROS Master)
解决:工程规模大,需要同时启动多个节点的工程,提高效率
xml文件格式(在功能包内创建xml文件并编写内容):(以下用vins-mono举例)
<launch>
<!-- arg为launch文件内部的变量,仅限launch文件使用 -->
<arg name="config_path" default = "$(find feature_tracker)/euroc_config.yaml" />
<arg name="vins_path" default = "$(find feature_tracker)/../config/../" />
<!-- name为节点名称 -->
<!-- pkg为节点对应功能包名称 -->
<!-- type为生成的可执行文件名称 -->
<!-- output为话题信息打印位置:screen打印到终端,log打印到log文件中 -->
<node name="feature_tracker" pkg="feature_tracker" type="feature_tracker" output="screen">
<!-- param是设置ROS系统运行时的参数,存储在参数服务器中 -->
<param name="config_file" type="string" value="$(arg config_path)" />
<param name="vins_folder" type="string" value="$(arg vins_path)" />
</node>
</launch>
default与value两者的唯一区别在于命令行参数
roslaunch pkg-name launch-file-name arg-name:=”set-value”可以覆盖默认值default,但是不能覆盖参数值value;在launch文件中出现$(arg arg-name)的地方,运行时roslaunch会将它替换成参数值。并且可以在include元素标签内使用arg来设置所包含的launch文件中的参数值
关于roslaunch + main参数传递参考:
https://blog.csdn.net/u013834525/article/details/88744327
启动launch文件
roslaunch launch文件所在功能包名 launch文件名
一个launch文件启动多个launch文件(include标签)
include标签用于将另一个xml格式的launch文件导入到当前文件
file="$(find 包名)/xxx/xxx.launch"
在launch文件中复用其他launch文件可以减少代码编写的工作量,提高文件的简洁性。使用包含元素include在launch文件中可包含其他launch文件中所有的节点和参数
新创建一个launch文件,内容如下:
<launch>
<include file="$(find 包名)/xxx/xxx.launch"> //路径为你要启动的launch文件路径
</include>
<include file="$(find 包名)/xxx/xxx.launch">
<arg name="arg_name" value="set-value"/>
</include>
</launch>
编写完成后只需启动当前launch文件便可同时启动其中包含的所有launch文件
launch文件启动bag录制和播放
//播放
<launch>
<node pkg="rosbag" type="play" name="player" output="screen" args="--clock /home/xx/xxx/xxx/xxx.bag"/>
<!-- 注意这里bag文件的路径必须为绝对路径-->
</launch>
//录制
<launch>
<node pkg="rosbag" type="record" name="bag_record" args="topic-name1 topic-name1 -o /home/xx/xxx/xxx/xxx.bag"/>
<!-- 注意这里bag文件的路径必须为绝对路径-->
</launch>
代码运行后的信息查看
查看节点 :rosnode list
查看节点关系图 :rqt_graph
查看参数服务器中的参数 :rosparam list
查看话题 :rostopic list
查看某个话题 :rostopic list /话题名称
可视化工具:
1.rqt
2.Rviz
话题运行与记录
rosbag record -a -O 输出名称 //话题记录 -a为记录话题的所有数据
rosbag play bag包路径 //话题播放
通讯方式 - 话题通讯(Topic)
传输的消息类型称为话题
过程
Talker 注册:Talker 启动,通过 1234 端口使用 RPC 向 ROS Master 注册发布者的信息,包含所发布消息的话题名;ROS master 会将节点的注册信息加入注册列表中。、
Listener 注册:Listener 启动,同样通过 RPC 像 ROS Master 注册订阅者的信息,包含需要订阅的话题名。
ROS Master 进行信息匹配:Master 根据 Listener 的订阅信息从注册列表中进行查找,如果没有找到匹配的发布者,则等待发布者的加入;如果找到匹配的发布者信息,则通过 RPC 向 Listener 发布 Talker 的 RPC 地址信息。
Listener 发送连接请求:Listener 接收到 Master 发回的 Talker 地址信息,尝试通过 RPC 向 Talker 发送连接请求,传输订阅的话题名、消息类型以及通信协议(TCP/UDP)。
Talker 确认连接请求:Talker 接收到 listener 发送的连接请求后,继续通过 RPC 向 Listener 确认链接信息,其中包含自身的 TCP 地址信息。、
Listener 尝试与 Talker 建立网络连接:Listener 接收到确认信息后,使用 TCP 尝试与 Talker 建立网络连接。
Talker 向 Listener 发布数据:成功建立连接后,Talker 开始向 Listener 发送话题消息数据。
从上面的分析中可以发现,前五个步骤使用的通信协议都是 RPC,最后发布数据的过程才使用到 TCP。ROS Master 在节点建立连接的过程中起到了重要作用,但是并不参与节点之间最终的数据传输。
节点建立连接后,可以关掉ROS Master,节点之间的数据传输并不会受到影响,但是其他节点也无法加入这两个节点之间的网络