ROS learning (5) - topic message and service

Message communication between nodes is divided into several forms:

  • Topic: one-way message sending/receiving method
  • Service (service): Two-way message request/response method
  • Action (action): two-way message goal (goal)/result (result)/feedback (feedback) method
  • Parameter server (parameter sharing mode)

type the difference
topic asynchronous unidirectional In the case of continuous one-way sending/receiving data
Serve Synchronize two-way ` Situations that require an immediate response to a request
action asynchronous two-way   

When it takes too long between request and response, so it is difficult to use the service,

Or when you need to return a value halfway

The process of node communication

1. Run the master node

Among the message communication between nodes, the master node that manages connection information is a necessary element that must be run first to use ROS
. The ROS master node is run using the roscore command and the server is run using XMLRPC.

For the connection between nodes, the master node will register the name, topic, message type, URI address and port of the node,
and notify other nodes of this information when there is a request.

 2. Run the publisher node

Publisher nodes are run using the rosrun or roslaunch commands. The publisher node registers the publisher node
name, topic name, message type, URI address and port with the master node. Master and nodes communicate using XMLRPC
.

  3. Run the subscriber node

Subscriber nodes are run using the rosrun or roslaunch command. A subscriber node registers its subscriber node name, topic name, message type, URI address, and port with the master node at runtime. Master and nodes
communicate using XMLRPC.

4. Notify the publisher of the information


The master node sends information such as the publisher's name, topic name, message type, URI address, and port that the subscriber wants to access to the subscriber node . Master and nodes communicate using XMLRPC.

 5. The connection request of the subscriber node

The subscriber node requests a direct connection to the publisher node based on the publisher information received from the master node. In this case, the information to be sent includes the subscriber node name, topic name, and message type. Publisher nodes and subscriber
nodes communicate using XMLRPC.

6. The connection response of the publisher node

The publisher node sends the URI address and port of the TCP server to the subscriber node as a connection response. Publisher
nodes and subscriber nodes communicate using XMLRPC.

 7. TCPROS connection


The subscriber node uses TCPROS to create a client corresponding to the publisher node, and directly connects with the publisher node . Communication between nodes uses a TCP/IP method called TCPROS.

  8. Send a message

Publisher nodes send messages to subscriber nodes. Inter-node communication uses a TCP/IP method called TCPROS
.

The following is an example of an implementer (Publisher) publishing a topic and a receiver (Subscriber) receiving a topic

1. Publisher

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

int main(int argc, char *argv[])
{
    // 1.设置编码
    setlocale(LC_ALL,"");

    //2.初始化 ROS 节点:命名(唯一)
    // 参数 1 和参数 2 后期为节点传值会使用
    // 参数 3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
    ros::init(argc, argv, "publisher");

    //3.实例化 ROS 句柄
    ros::NodeHandle nh;  //该类封装了 ROS 中的一些常用功能

    //4.实例化 发布者 对象
    //泛型: 发布的消息类型
    //参数 1: 要发布到的话题
    //参数 2: 队列中最大保存的消息数,超出此阈值时,先进的先销毁(时间早的先销毁)
    ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);

    //5.组织被发布的数据,并编写逻辑发布数据
    //数据(动态组织)
    std_msgs::String msg;
    std::string msg_front = "Hello,你好啊!";  // 消息前缀
    int count = 0;  //消息计数器

    //逻辑(一秒 10 次)
    ros::Rate r(1);

    //节点不死;
    while(ros::ok())
    {
        //使用 stringstream 拼接字符串与编号
        std::stringstream ss;
        ss<<msg_front<<count;
        msg.data = ss.str();
        //发布消息
        pub.publish(msg);
        //加入调试,打印发送的消息
        ROS_INFO("发送的消息:%s",msg.data.c_str());

        //根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率;
        r.sleep();
        count++;//循环结束前,让 count 自增
        ros::spinOnce();
    }
    return 0;
}

2. Receiver

// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h"

void doMsg(const std_msgs::String::ConstPtr& msg_p){
    ROS_INFO("我订阅:%s",msg_p->data.c_str());
    // ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    //2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"subscriber");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;
    //4.实例化 订阅者 对象
    ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
    //5.处理订阅的消息(回调函数)

    //6.设置循环调用回调函数

    ros::spin(); //循环读取接收的数据,并调用回调函数处理
    return 0;
}

3. CMakeLists file writing (you can refer to ROS learning (3) - CMakeLists file writing )

cmake_minimum_required(VERSION 3.0.2)
project(hello)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES hello
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
)

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
add_executable(publish_man src/publish_man.cpp)
add_executable(subscrib_man src/subscrib_man.cpp)

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

4. Write the launch file (those who don’t know how can refer to ROS learning (4)—launch file writing )

<launch>
    <node pkg="hello" type="publish_man" name="pub" output="screen" />
    <node pkg = "hello" type = "subscrib_man" name = "sub" output = "screen" />
</launch>

 5. Run the launch file in the terminal:

source ./devel/setup.bash
roslaunch <功能包名> <launch文件名.launch>

The result of the operation is as follows:

 Implemented the process of publishing and receiving messages.

A few points to note:

1. The format of the main function auto-completion is

int main(int argc, char const *argv[]){}

We need to delete the const inside.

2. The first data is lost

The reason is that when the first piece of data is sent, the publisher has not yet registered in roscore.

The solution is, after registration, add dormant ros::Duration(3.0).sleep(); to delay the sending of the first piece of data.

3. There is an error ros/ros.h No such file or directory

Check CMakeLists for duplicates and delete them.

Guess you like

Origin blog.csdn.net/bulletstart/article/details/130795717