编写一个最小的ROS发布器和订阅器

最近在复习ROS的一些基础知识,所以写了本博客,有错误望指正

ROS概念基础

节点(node)间的通信是ROS的核心。节点是一种使用ROS的中间件进行通信的ROS程序。一个节点只有当与其他节点通信并最终与传感器和执行器进行连接时,它才是有用的。
节点之间的通信涉及了message、topic、roscore、publisher、subscriber等。而本文我们旨在编写最小最简单的发布器和订阅器。

编写ROS节点

  1. 建立一个目录(ROS工作区)
    ROS工作区中放置ROS代码。这个工作区必须要有名为src的子目录,在这里放置源代码(程序包)。而想要操作系统知道ROS工作区的位置(一般要通过编辑起动脚本.bashrc来完成)
    如果你已经安装了ROS,并且有了一个ROS工作区(我命名为catkin_ws,后面的叙述中也沿用这一工作区的名称)。除此之外你也有了src子目录,操作系统也知道工作区的路径(通过查询环境变量可知)

    1. 创建ROS程序包
      开始编写新的ROS代码时,首要工作是创建一个packge(程序包)。
      packeage是ROS中的一个概念,它将众多必要的部分集合在一起,以简化ROS代码的构建,并于其他ROS代码组合在一起。
      我们用catkin_create_pkg命令来创建程序包
      该程序应该放在catkin_ws工作区中的src目录下,命名该程序包为my_minimal_nodes
cd catkin_ws/src
catkin_create_pkg my_minimal_nodes roscpp std_msgs

注意:ROS系统中的程序包的名字不可以重复
roscpp和std_msgs是两个依赖项
当我们移至新创建的程序包目录下时,~/catkin_ws/src/my_minimal_nodes,我们可以看到它已经被package.xml、CMakelists以及子目录src和include填充。
package.xml文件:构建系统将根据其拥有的package.xml文件来重新组织ROS程序包,一个兼容的packeage.xml文件具有一个特定的结构,可以命名程序包,并列出它的依赖项

编写一个最小的ROS发布器

在一个终端窗口中,利用cd命令进入创建的my_minimal_nodes程序包里的src目录中,打开编辑器创建一个minimal_publisher.cpp的文件,并输入以下代码(当然你直接在文件夹中创建也是可以的)

#include<ros/ros.h> 
 //引入ROS的核心头文件,对于任何利用C++编写的ROS源代码,这都应该放在第一行
#include<std_msgs/Float64.h>
//引入描述对象的std_msgs::Float64的头文件,它是我们会用到的消息类型

int main(int argc,char **argv){
ros::init(argc,argv,"minimal_publisher");
ros::NodeHandle n;  //初始化通信对象
ros::Publisher my_publisher_object = n.advertise<std_msgs::Float64>("topic1",1);
//实例化发布器对象,发布到topic1的话题

ros::Rate naptime(1);
std_msgs::Float64 input_float;
input_float.data = 0.0;
    while(ros::ok()){
        input_float.data = input_float.data+0.001;
        my_publisher_object.publish(input_float); //发布
        naptime.sleep();
        }
}

编译ROS 节点

在编译之前,我们还需要让catkin_make知道minimal_publisher.cpp的存在
需要编辑文件CMakeList.txt。这个文件虽然很长,但绝大部分是注释

## Declare a cpp executable
add_executable(my_minimal_publisher src/minimal_publisher.cpp)


##Specify libraries to link a library or executable target against
target_link_libraries(my_minimal_publisher ${catkin_LIBRARIES})

在CMakeList.txt文件中添加上述代码
上述内容中add_executable的第一个参数是为可执行文件选定的名字,第二个参数是对包目录而言在哪找到源代码

通常使用catkin_make命令编译ROS节点,该命令须在特定目录下执行,我的是catkin_ws工作区下

catkin_make

如果你不想编译整个工作空间,ros还允许编译特定功能包,如果需要可以自己百度这条命令
建立一个catkin包后,可执行文件放在根据源代码包命名的catkin_ws/devel/lib中的文件夹中

编写一个ROS的最小订阅器

首先也是建立minimal_subscriber.cpp文件
然后输入以下代码

#include<ros/ros.h>
#include<std_msgs/Float64.h>

void myCallback(const std_msgs::Float64& message_holder)
{
    ROS_INFO("received value is: %f",message_holder.data);
    //这里的回调函数的作用只是输出数据
}
//当新数据发布到关联话题时,回到函数会被唤醒,同时已发布的数据灰出现在参数message_holder中
int main(int argc,char **argv)
{
    ros::init(argc,argv,"minimal_subscriber");
    ros::NodeHandle n;
    ros::Subscriber my_subscriber_object = n.subscribe("topic1",1,myCallback);
    //基本上与发布器相同,关联到话题topic1,回调函数是myCallback
//如果回调函数无法跟上发布数据的频率,数据就要排队,本例中消息队列设为1
    ros::spin();
    return 0;
}

编写完之后也要修改CMakeLists文件

## Declare a cpp executable
add_executable(my_minimal_subscriber src/minimal_subscriber.cpp)

##Specify libraries to link a library or executable target against
target_link_libraries(my_minimal_subscriber ${catkin_LIBRARIES})

然后也是进行编译

运行

编译完成后
输入

roscore
rosrun my_minimal_nodes my_minimal_publisher
rosrun my_minimal_nodes my_minimal_subscriber

上面的代码每一句都需要开一个终端
运行成功后会看到终端在输出

[ INFO] [1618111430.398091772]: received value is: 0.008000
[ INFO] [1618111431.397634861]: received value is: 0.009000
[ INFO] [1618111432.397692972]: received value is: 0.010000
[ INFO] [1618111433.397781803]: received value is: 0.011000
[ INFO] [1618111434.397900474]: received value is: 0.012000

同时我们也可以在终端运行

rqt_graph

来查看运行系统的图形显示
ps:其实可以不用每次修改CMakeLists文件,也不用每次rosrun(catkin_simple, 编写launch文件)
这就是以后的事情啦