笔记

简介

ros的主要通讯方式

Topic, Message, Publisher 与 Subscriber的关系

小结

  • 话题Topic是节点间进行持续通讯的一种形式。
  • 话题通讯的两个节点通过话题的名称建立起话题通讯连接。
  • 话题中通讯的数据,叫做消息Message。
  • 消息Message通常会按照一定的频率持续不断地发送,以保证消息数据的实时性。
  • 消息的发送方叫做话题的发布者Publisher。
  • 消息的接收方叫做话题的订阅者Subscriber。
  • 一个ROS节点网络中,可以同时存在多个话题。
  • 一个话题可以有多个发布者,也可以有多个订阅者。
  • 一个节点可以对多个话题进行订阅,也可以发布多个话题。
  • 不同的传感器消息通常会拥有各自独立话题名称,每个话题只有一个发布者。
  • 机器人速度指令话题通常会有多个发布者,但是同一个时间只能有一个发言人。

基本的消息类型

std_msgs

一些复杂的数据类型可以类比为c++中的结构体,本质是由基本的数据类型组合而成。

Publisher的实现

代码实现

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

int main(int argc, char *argv[])//去除const
{
    ros::init(argc,argv,"chao_node");//初始化
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<std_msgs::String>("TpName",10);
    //定义一个发送消息的工具pub,advertise<填入消息类型>(“话题名称”,消息的缓存长度)
    while(ros::ok())
    {
        printf("好好好好好!\n");
        std_msgs::String msg;
        msg.data = "哈哈哈哈";
        //生成消息包
        pub.publish(msg);
    }
    return 0;
}
  • 运行节点

rostopic list可以查看当前话题
rostopic echo /话题名称可以查看话题内容(message)
由于中文显示为Unicode,使用
echo -e "unicode代码"
可以查看中文消息

控制消息发送频率

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

int main(int argc, char *argv[])//去除const
{
    ros::init(argc,argv,"chao_node");//初始化
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<std_msgs::String>("TpName",10);
    //定义一个发送消息的工具pub,advertise<填入消息类型>(“话题名称”,消息的缓存长度)
    
    ros::Rate loop_rate(10);//参数单位为“次/秒”
    
    while(ros::ok())
    {
        printf("好好好好好!\n");
        std_msgs::String msg;
        msg.data = "哈哈哈哈";
        //生成消息包
        pub.publish(msg);
        loop_rate.sleep();//进行阻塞
    }
    return 0;
}

使用rostopic hz命令 即可查看发送频率 如图Rate:10

输入图片说明

小结

输入图片说明

  • 常用指令
    rostopic list
    列出当前系统中所有活跃着的话题
    rostopic echo 主题名称
    显示制定话题中发送的消息包内容
    rostopic hz 主题名称
    统计指定话题中消息包发送频率

Subscriber的实现

创建订阅者节点

  • 创建一个新包,名为"atr_pkg"
  • 创建一个新节点,名为"ma_node"
#include <ros/ros.h>
#include <std_msgs/String.h>

void chao_callback(std_msgs::String msg)
{
    printf(msg.data.c_str());//printf参数为char*,需要将string转化为字符数组(c_str())
    printf("\n");
}// 定义一个回调函数

int main(int argc, char *argv[])
{
    ros::init(argc,argv,"ma_node");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("TpName",10,chao_callback);//(话题名称,缓存长度,回调函数)
    while (ros::ok())
    {
        ros::spinOnce();
    }
    return 0;
}

运行测试

  • 分别运行chao_node与ma_node

调整与优化

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

void chao_callback(std_msgs::String msg)
{
    ROS_INFO(msg.data.c_str());//可以显示时间
}
int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"zh_CN.UTF-8");//设置locale为中文
    ros::init(argc,argv,"ma_node");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("TpName",10,chao_callback);
    while (ros::ok())
    {
        ros::spinOnce();
    }
    return 0;
}
  • 通过rqt_graph直观展示当前节点关系
注意:ROS话题不单独属于Publisher或者Subscriber,话题由ROS系统统一管理。只要节点向NodeHandle提出话题发布或者订阅需求,话题就会被创建

小结

使用launch文件启动节点

launch文件是一种遵循xml语法的描述文件,批量启动ROS节点是它的功能之一。
<标记名称 属性名1="属性值"...>内容</标记名称>

launch文件放在哪都可以

例:

<launch>

    <node pkg="ssr_pkg" type="chao_node" name="chao_node"/>
    //包名 节点 节点名
    <node pkg="atr_pkg" type="ma_node" name="ma_node" output="screen"/>
    //输出于屏幕
</launch>

运行launch文件
roslaunch atr_pkg qidong.launch
使用新的终端程序运行节点,添加属性
launch-prefix="gnome-terminal -e"
即可

小结

我的理解

这是小乌龟的rqt_graph,展示了/teleop_turtle节点与/turtlesim节点之间的通讯关系。两个节点之间的共同话题为/turtle1/cmd_vel
其中/teleop_turte节点将会检测键盘的输入,并将其以信息通过/turtle1/cmd_vel话题发送给/turtlesim,turtlesim将会改变运动轨迹,最终呈现键盘控制小乌龟运动的效果。

附加:使用launch文件启动小乌龟以及键盘控制程序

由于打开单个节点过于繁琐,需要分别执行如下命令
roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
此处在turtleism包中创建launch文件,为避免与原作者文件混淆,此处命名带上了自己的名字

代码实现如下

<launch>
    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="urtle_teleop_key"/>
</launch>

运行launch文件
roslaunch turtlesim turtlesim_key_Elaina.launch
实现效果

评论

This is just a placeholder img.