一、环境搭建
在ubuntu安装好ROS后(可以尝试鱼香ROS的方法,终端输入wget http://fishros.com/install -O fishros && . fishros),本人用的是noetic版本,使用的代码编译工具是vscode,并在其中安装了ROS插件,同时安装了超级终端工具,方便ROS的调试。推荐安装教程
二、节点与包
我们在使用ROS时,实际是在使用ROS的一些节点(node),例如建图节点、导航节点、控制底盘节点、控制雷达节点等,ROS机器人所实现的功能,实际是这些节点堆在一起的运行结果。虽然ROS的基础单元时节点(node),但实际上我们所使用的节点都被封装在软件包(package)里了,我们一般都把项目所需的软件包(package)下载下来,进而使用软件包(package)里的节点(node)。所以,可以理解包为节点的容器,节点不能脱离包而存在。
三、实现一个节点
加入我们要实现一个超声波节点,即超声波_node,因为节点不能脱离包而存在,所以我们需要给节点找一个上级组织,命名为ssr_pkg。
在目录下新建一个catkin_ws文件夹,并在里面再建立一个src文件夹,并在终端执行catkin_init_workspace,之后会生成cmakelist文件,再回到上一级目录执行catkin_make进行编译,会生成build,devel文件夹
再执行catkin_make install,生成install文件夹
再进入src文件夹,执行catkin_create_pkg test_pkg roscpp rospy std_msgs,生成文件夹以及相关依赖。意思是catkin_create_pkg <包名> <依赖项列表>
在返回工程文件夹(catkin文件夹下),执行catkin_make,完成编译
接着我们进入到src文件夹下,在终端输入
code .
在vscode下打开了项目源码
接着需要完成环境参数的配置,在桌面的.bashrc文件添加如下代码
source 路径/catkin_ws/devel/setup.bash
接着修改ssr_pkg文件下的CMakeLists.txt文件,完成配置,在代码最后添加如下代码
add_executable(chao_node src/chao_node.cpp) #添加可执行文件
target_link_libraries(chao_node #链接所需要的库
${catkin_LIBRARIES}
)
四、使用话题通讯方式完成不同包之间节点通讯
1.介绍
(1)话题Topic是节点间进行持续通讯的一种形式;
(2)话题通讯的两个节点通过话题的名称建立起话题通讯连接;
(3)话题中通讯的数据,叫做消息Message;
(4)消息Message通常会按照一定的频率持续不断的发送,以保证消息数据的实时性;
(5)消息的发送方叫做话题的发布者Publisher;
(6)消息的接收方叫做话题的订阅者Subscriber.
2.同时也可以多个话题(Topic)多个发布者(Publisher),发布相应的消息(Message),通常Message为传感器观测到的数据,对应为多个话题(Topic),订阅者(Subscriber)根据需要订阅需要的话题(Topic)
当然也可以一个话题(Topic)多个发布者(Publisher),例如机器人的底盘节点(底盘_node)需要订阅速度指令_topic,话题里有导航节点和跟踪节点发布的消息。
3.总结
(1).一个ROS节点网络中,可以同时存在多个话题
(2).一个话题可以有多个发布者,也可以有多个订阅者
(3).一个节点可以对多个话题进行订阅,也可以发布多个话题
(4).不同的传感器信息通常会拥有各自独立话题名称,每个话题只有一个发布者
(5).机器人速度指令话题通常会有多个发布者,但是同一时间只能有一个发言人,否则会造成抖动
五、Publisher发布者的C++实现
来完成如下的通讯实现
在src下的chao_node下编写代码如下
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])
{
/* code */
ros::init(argc, argv, "chao_node"); //节点初始化,节点名称
ros::NodeHandle nh; //创建节点管理对象nh
ros::Publisher pub = nh.advertise<std_msgs::String>("kuai_shang_che_kai_hei_qun", 10);//创建话题和缓存长度,pub为消息发布对象
ros::Rate loop_rate(10); //延时,1s10次
while(ros::ok())
{
std_msgs::String msg; //创建消息对象msg
msg.data = "国服马超,带飞"; //给消息Message赋值
pub.publish(msg); //发布消息
loop_rate.sleep();
}
return 0;
}
编译后运行,首先执行roscore,启动ROS;再分出一个终端,执行chao_node.cpp文件,输入代码rosrun ssr_pkg chao_node;执行后发布者便可以把消息发布出来,执行代码rostopic list可以查看当前运行着的topic;
接着执行代码rostopic echo /话题名称,便可以显示发布者发布的消息,
由于编码的缘故,显示与实际输出不一致,再次执行如下代码便可正常显示
执行代码rostopic hz /话题名称,便可以显示消息发布的频率
总结:
(1).确定话题名称和消息类型
(2).在代码文件中include消息类型对应的头文件
(3).在main函数中通过NodeHandle大管家发布一个话题并得到消息发布对象
(4).生成要发送的消息包并进行发布数据的赋值
(5).调用消息发送对象的publish()函数将消息包发送到话题中
/
接着复制一个节点,命名为yao_node;代码如下
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])
{
/* code */
ros::init(argc, argv, "yao_node");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("gie_gie_dai_wo", 10);
ros::Rate loop_rate(10);
while(ros::ok())
{
//printf("明天见\n");
std_msgs::String msg;
msg.data = "求上车+++";
pub.publish(msg);
loop_rate.sleep();
}
return 0;
}
同时修改CMakeists文件
测试通过
六、Subscriber订阅者的C++实现
在catkin_ws的src文件下,使用代码catkin_create_pkg atr_pkg roscpp rospy std_msgs创建新的软件包,进入vscode,在对应的src文件下新建ma_node.cpp文件,输入代码
#include <ros/ros.h>
#include <std_msgs/String.h>
void chao_callback(std_msgs::String msg) //回调函数
{
ROS_INFO(msg.data.c_str()); //带时间戳显示输出
}
void yao_callback(std_msgs::String msg)
{
ROS_WARN(msg.data.c_str()); //显示颜色不同
}
int main(int argc, char *argv[])
{
/* code */
setlocale(LC_ALL, ""); //使输出正常显示
ros::init(argc, argv, "ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("kuai_shang_che_kai_hei_qun",10,chao_callback);
ros::Subscriber sub_2 = nh.subscribe("gie_gie_dai_wo",10,yao_callback);
while (ros::ok())
{
ros::spinOnce(); //让回调函数能够响应接收到的消息包
}
return 0;
}
通讯图解为
同时还需配置CMaketists文件
测试通过
执行代码rqt_graph,可以图示通信网络
总结:
(1).确定话题名称和消息类型
(2).在代码文件中include <ros.h>和消息类型对应的头文件
(3).在main函数中通过NodeHandler大管家订阅一个话题并设置消息接收回调函数
(4).定义回调函数,对接受到的消息包进行处理
(5).main函数中需要执行ros::spinOnce(),让回调函数能够相应接收到的消息包
七.使用launch文件启动节点
在atr_pkg文件夹下新建launch文件夹,并在里面新建kaihei.launch文件,按照既定规则编写代码
<launch>
<node pkg = "ssr_pkg" type = "yao_node" name = "yao_node"/>
<node pkg = "ssr_pkg" type = "chao_node" name = "chao_node" launch-prefix = "gnome-terminal -e"/>
<node pkg = "atr_pkg" type = "ma_node" name = "ma_node" output = "screen"/>
</launch>
总结:
(1).使用launch文件,可以通过roslaunch指令一次启动多个节点
(2).在launch文件中,为节点添加output="screen"属性,可以让节点信息输出在终端中(ROS_WARN属性不受影响)
(3).在launch文件中,为节点添加launch-prefix="gnome-terminal -e"属性,可以让节点单独运行在一个独立终端中