编程实现ROS话题通信——手撕 turtlesim 节点

一、实验任务

任务要求如下:使用 C++ 编程实现1个ROS节点,订阅 turtlesim 例程中 turtle_teleop_key 节点发出的消息,并将此消息进行一定的转换后(自行定义,如将数值按适当比例缩小、运动方向变换等),再发布给 turtlesim_node 节点,并将接收的和转换后发布的消息内容实时输出打印到终端,运行时的计算图应如下图所示。

编程实现ROS话题通信——手撕 turtlesim 节点_第1张图片

二、实验原理

本人通过学习 talker 和 chatter 的代码,进行相应的修改。

在终端输入

catkin_create_pkgs rospy roscpp std_msgs #创建一个功能包

然后在功能包内的src文件夹下创建一个节点tranform_node,编写transform_node的cpp文件。

首先订阅turtle_teleop_key节点发布的cmd_vel的话题,编写回调函数,在回调函数中,对小海龟的坐标进行一个处理,我将小海龟的x轴和y轴进行了一个调换。在回调函数中,需要定义一下发布的消息类型transform,和cmd_vel保持一致,都是两组,分别是linear和anagular中的float x,float y和float z。

然后编写一个发布者,将transform消息发布出去,定义一个叫做cmd_vel_cov的话题,将这个话题中的transform消息发布出去。

通过ROS重映射,将turtlesim_node节点订阅的话题修改为cmd_vel_cov,就能实现任务的要求了

其中ROS重映射的知识可以参考这个链接:wiki.ros.org/Remapping Arguments

三、实验过程

如果不进行重映射,那么transform和turtlesim_node都是订阅的cmd_vel的话题,没有人订阅transform发布的cmd_vel_cov话题。

终端输入指令如下:

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
rosrun tranform_node transform_node
rqt_graph

编程实现ROS话题通信——手撕 turtlesim 节点_第2张图片

rqt_graph如下所示:

编程实现ROS话题通信——手撕 turtlesim 节点_第3张图片

根据ros重映射的知识,在终端输入:

rosrun turtlesim turtlesim_node /turtle1/cmd_vel:=/cmd_vel_cov

将turtlesim_node节点的订阅话题从cmd_vel改为cmd_vel_cov,这样就能让turtlesim_node节点订阅我设计的tranform节点发布的话题了,最终实现,turtle_teleop发布cmd_vel话题,tranform订阅cmd_vel话题,修改数据后再发布一个cmd_vel_cov的话题,turtlesim_node订阅cmd_vel_cov话题。

终端输入完整的指令如下:

roscore
rosrun turtlesim turtlesim_node /turtle1/cmd_vel:=/cmd_vel_cov
rosrun turtlesim turtle_teleop_key
rosrun tranform_node transform_node
rqt_graph

编程实现ROS话题通信——手撕 turtlesim 节点_第4张图片

rqt_graph如下所示:

编程实现ROS话题通信——手撕 turtlesim 节点_第5张图片

按照任务要求的截图如下:

编程实现ROS话题通信——手撕 turtlesim 节点_第6张图片

四、代码实现

本人编写的 cpp 代码如下:

#include"ros/ros.h"//引用ros的头文件
#include"geometry_msgs/Twist.h"//引用小海龟的消息类型

ros::Publisher transform_pub;//定义一个话题的发布者transform_pub

void TransformCallback(const geometry_msgs::Twist msg)//定义一个回调函数,用于海龟/turtle1/cmd_vel话题的订阅
{
    geometry_msgs::Twist transform;//定义一个消息类型,用于处理cmd_vel的转换
    //数据处理:将海龟cmd_vel中数据(线速度和角速度)的x,y,z坐标进行旋转,将x轴变成y轴,y轴变成x轴
    transform.linear.x = msg.linear.y;
    transform.linear.y = msg.linear.x;
    transform.linear.z = msg.linear.z;
    transform.angular.x = msg.angular.y;
    transform.angular.y = msg.angular.x;
    transform.angular.z = msg.angular.z;
    //将处理后的数据发布出去
    transform_pub.publish(transform);
    //通过ROS_INFO和ROS_WARN在终端中输出海龟的运动信息
    ROS_INFO("坐标变换后,小海龟x轴线速度为%f,y轴线速度为%f,z轴线速度为%f,",transform.linear.x,transform.linear.y,transform.linear.z);
    ROS_WARN("坐标变换后,小海龟x轴角速度为%f,y轴角速度为%f,z轴角速度为%f,",transform.angular.x,transform.angular.y,transform.angular.z);

}


int main(int argc, char **argv)
{
    setlocale(LC_ALL,"");//中文字符不乱码
    ros::init(argc, argv, "transform_node");//初始化transform_node节点
    
    ros::NodeHandle n;//定义节点管理者

    transform_pub = n.advertise("/cmd_vel_cov",10);//发布一个叫做/cmd_vel_cov的话题

    ros::Subscriber turtle_sub = n.subscribe("/turtle1/cmd_vel", 10, TransformCallback);//通过回调函数订阅/turtle1/cmd_vel

    ros::spin();//进行循环
    return 0;
}

    

在之前创建包时系统自动创建的 CmakeLists.txt 文件末尾添加如下代码即可编译:

#添加可执行程序
add_executable(transform_node src/transform_node.cpp)
#链接库文件
target_link_libraries(transform_node ${catkin_LIBRARIES} )

此外,还可以结合 launch文件 进行节点的集成化运行。















【对于launch文件的说明】

launch文件将之前实验实现的订阅与发布集成的节点transform_node,与ROS系统自带的turtlesim_node和turtlesim_teleop_key节点,合并写在一个launch启动文件中,最终实现在终端只运行roslaunch  [包名]   [launch文件名],对于本人编写的代码, roslaunch transform_node turtlesim.launch即可将全部功能实现,启动了所有节点(包括主节点),实现了话题通讯。

下面是运行launch文件的截图:

编程实现ROS话题通信——手撕 turtlesim 节点_第7张图片

编程实现ROS话题通信——手撕 turtlesim 节点_第8张图片

总结

 我们主要学习了ROS的通信机制,本人以话题通讯为例,结合小海龟的示例程序进行详细的讲解,并自行编写发布者订阅者的代码,还通过编写launch文件实现节点同步运行,最终实现了一个小海龟速度的转换节点。

你可能感兴趣的:(机器人快速入门,机器人,自动驾驶,人工智能,ROS)