Communication mechanism of ROS

Topic communication

Principle of topic communication

Topic communication has three roles:

  • ROS Master (Manager)
  • Talker (publisher)
  • Listener (subscriber)
    The Master is responsible for linking publishers and subscribers to publish and subscribe links through the same topic. After the link, the publisher and subscriber can continuously publish and subscribe communication data without the continuous link of the Master (the Master is started through roscore)

0.Talker registration

After Talker is started, it will register its own information in the ROS Master through RPC, including the topic name of the published message. The ROS Master will add the node registration information to the registry.

1.Listener registration

After the Listener is started, it will also register its own information in the ROS Master through RPC, including the topic name of the message to be subscribed. The ROS Master will add the node registration information to the registry.

2.ROS Master realizes information matching

The ROS Master will match Talker and Listener according to the information in the registry, and send the RPC address information of Talker to the Listener through RPC.

3.Listener sends a request to Talker

The Listener sends a connection request to the Talker through RPC according to the received RPC address, and transmits the subscribed topic name, message type and communication protocol (TCP/UDP).

4.Talker confirmation request

After receiving the Listener's request, Talker also confirms the connection information to the Listener through RPC and sends its own TCP address information.

5. Connection between listener and Talker

The Listener uses TCP to establish a network connection with Talker according to the message returned in step 4.

6.Talker sends message to Listener

After the connection is established, Talker starts publishing messages to the Listener.

Note:

  • Start the Master (roscore) before starting the listener and tailer

  • In the above implementation process, the RPC Protocol is used in the first five steps, and the TCP protocol is used in the last two steps

  • There is no sequence requirement for the startup of Talker and Listener

  • Both Talker and Listener can have multiple

  • After the Talker and Listener are connected, the ROS Master is no longer required. That is, even if the ROS Master is closed, Talker communicates with Listern as usual.

C + + code to realize topic communication

Publisher (file name: Hello_pub)

#include "ros/ros.h"
#include "std_msgs/String.h" / / system built-in text messages
#include <sstream>

int main(int argc, char  *argv[])
{   
    //Set the code to prevent Chinese random code
    setlocale(LC_ALL,"");

    //2. Initialize ROS node: name (unique)
    // Parameter 1 and parameter 2 will be used for node value transfer later
    // Parameter 3 is the node name and an identifier. It needs to be unique in the ROS network topology after operation
    ros::init(argc,argv,"talker");
    //3. Instantiate ROS handle
    ros::NodeHandle nh;//This class encapsulates some common functions in ROS

    //4. Instantiate publisher object
    //Generic: published message type
    //Parameter 1: topic to publish to
    //Parameter 2: the maximum number of messages saved in the queue. When this threshold is exceeded, the first one will be destroyed first (the earlier one will be destroyed first)
    ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);

    //5. Organize the published data and write logic to publish the data
    //Data (dynamic organization)
    std_msgs::String msg;
    // msg.data = "Hello!!!";
    std::string msg_front = "Hello Hello!"; //Message prefix
    int count = 0; //Message counter

    //Logic (once a second)
    ros::Rate r(1);

    //It is always true without forced exit
    while (ros::ok())
    {
        //Splicing strings and numbers using stringstream
        std::stringstream ss;
        //Store data in ss
        ss << msg_front << count;
        //Take out the text content, assign string type data to msg variable, and the msg variable data is stored under the data attribute
        msg.data = ss.str();
        //Publish msg message
        pub.publish(msg);
        
        //Add debugging, print the sent message,% s format and output char array data through c_str() is converted into char class data
        ROS_INFO("Messages sent:%s",msg.data.c_str());

        //According to the transmission frequency specified above, automatic sleep time = 1 / frequency;
        r.sleep();
        count++;//Before the end of the loop, let the count increase automatically
        //No application
        ros::spinOnce();
    }
    return 0;
}

Subscriber (file name: Hello_sub)

#include "ros/ros.h"
#include "std_msgs/String.h"

void doMsg(const std_msgs::String::ConstPtr& msg_p){
    ROS_INFO("I heard:%s",msg_p->data.c_str());
}
int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    //2. Initialize ROS node: name (unique)
    ros::init(argc,argv,"listener");
    //3. Instantiate ROS handle
    ros::NodeHandle nh;

    //4. Instantiate the subscriber object, suspend running and continue running downward until the active callback of the command is met, and then start to enter the doMsg function
    //When calling the callback function, the accepted subscription data will be passed to the callback function as a parameter,
    //"chatter" is the name of the topic to be accepted. The Master will match and link the topics in the ros runtime through this name.
    ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
    //5. Process subscribed messages (callback function)

    ros::spin();//Loop to read the received data and call the callback function for processing

    return 0;
}

configuration file

The CMakeLists.txt file under the function package is not under the workspace.

# Hello_pub.cpp maps a name called hello in the configuration file_ Pub, which can be customized, but the file name without suffix is generally selected
add_executable(Hello_pub
  src/Hello_pub.cpp
)
add_executable(Hello_sub
  src/Hello_sub.cpp
)

# Hello_pub is to fill in the file mapping name and locate Hello_pub.cpp file
target_link_libraries(Hello_pub
  ${catkin_LIBRARIES}
)
target_link_libraries(Hello_sub
  ${catkin_LIBRARIES}
)

function

Compiled file

catkin_make

Start Master

roscore

Refresh environment variables

source ./devel/setup.bash 
# Run Hello_pub file
rosrun Function pack name Hello_pub

# Run Hello_sub file
rosrun Function pack name Hello_sub

Custom data transfer

Through STD in ROS_ Msgs encapsulates some native data types, such as String, Int32, Int64, Char, Bool, Empty... However, these data generally contain only one data field. The single structure means functional limitations. When transmitting some complex data, it cannot be transmitted well. Then we need to create custom data classes for data packaging and transmission.

The supported data types when packaging file data are
msgs is just a simple text file. Each line has field type and field name. The field types you can use are:

  • int8, int16, int32, int64 (or unsigned type: uint *)

  • float32, float64

  • string

  • time, duration

  • other msg files

  • variable-length array[] and fixed-length array[C]

Create an msg file to store custom data packages

Add the file Person.msg in the new MSG directory

string name
uint16 age
float64 height

Then, Person.msg is a user-defined data package. There are three attributes in it, which are composed of native data

Custom file configuration

Add to package.xml:

 <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

CMakeLists.txt file add:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

add_message_files(
  FILES
  Person.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

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

About C + + code

Publisher

Guide Package:

#include "package name / msg file name. h"
For example:
#include "demo02_talker_listener/Person.h"

Instantiate transmission package, assign and transmit:

//The package type is package name:: file name
demo02_talker_listener::Person p;
p.name = "sunwukong";
p.age = 2000;
p.height = 1.45;

//Instantiate the transmission channel to determine the data transmission type and topic name
ros::Publisher pub = nh.advertise<demo02_talker_listener::Person>("chattern",1000);
//Send step message
pub.publish(p);

subscriber

Guide Package:

#include "package name / msg file name. h"
For example:
#include "demo02_talker_listener/Person.h"

receive data

//Define acceptance type and topic name
ros::Subscriber sub = nh.subscribe<demo02_talker_listener::Person>("chatter_person",10,doPerson);

Callback function

void doPerson(const demo02_talker_listener::Person::ConstPtr& p){
	char[] name=p->name.c_str();
	int age=p->age;
	double height=p->height;
}

Service communication

Service communication principle

, the model involves three roles:

  • ROS master (Manager)
  • Server (server)
  • Client

The ROS Master is responsible for keeping the information registered by the Server and Client, matching the Server and Client with the same topic, and helping the Server establish a connection with the Client. After the connection is established, the Client sends the request information and the Server returns the response information.
0.Server registration

After the Server starts, it will register its own information in the ROS Master through RPC, including the name of the provided service. The ROS Master will add the node registration information to the registry.

1.Client registration

After the Client starts, it will also register its own information in the ROS Master through RPC, including the name of the service to be requested. The ROS Master will add the node registration information to the registry.

2.ROS Master realizes information matching

The ROS Master will match the Server and Client according to the information in the registry, and send the TCP address information of the Server to the Client through RPC.

3.Client send request

According to the information responded in step 2, the Client establishes a network connection with the Server using TCP and sends the request data.

4.Server sends response

The Server receives and parses the requested data, generates response results, and returns them to the Client.

C + + implementation of service communication

Custom transfer data

The available data types in the srv file are consistent with the msg file, and the defined srv implementation process is similar to the custom msg implementation process:

  • Creating srv files in a fixed format
  • Edit profile
  • Compile and generate intermediate files

Create the test.srv file in the SRV folder

int32 num1
int32 num2
---
int32 sum

Data entered by int32 num1 and int32 num2 clients
int32 sum is the returned data from the server to the client
Intermediate - split
to configure
package.xml:

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

CMakeLists.txt:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

add_service_files(
  FILES
  test.srv # Custom files
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

So test.srv can be used

Server side coding (Add_Server.cpp)

#include "ros/ros.h"
#include "first_ros/test.h" / / service communication custom packet first_ ROS is a function pack

// bool returns whether the flag is processed successfully
bool doReq(first_ros::test::Request& req,//Accept data on test file
          first_ros::test::Response& resp){//Accept data in test file
    //Take out the data input by the client
    int num1 = req.num1;
    int num2 = req.num2;
    ROS_INFO("The request data received by the server is:num1 = %d, num2 = %d",num1, num2);

    //If there is no exception, add and assign the result to the sum variable under resp
    resp.sum = num1 + num2;
    //The return value bool tells the server whether it successfully accepts the data and submits it to the client, and automatically submits the data to the client
    return true;
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2. Initialize ROS node
    ros::init(argc,argv,"Add_Server");
    // 3. Create ROS handle
    ros::NodeHandle nh;
    // 4. Create a service object and determine the service topic name
    ros::ServiceServer server = nh.advertiseService("Add",doReq);
    ROS_INFO("Service started....");
    // 5. The callback function processes the request and generates a response
    // 6. Because there are multiple requests, you need to call ros::spin(), which has been running since then
    // ros::ServiceServer server = nh.advertiseService("Add",doReq); Waiting to run
    ros::spin();
    return 0;
}

Client code writing (file: Add_Client.cpp)

#include "ros/ros.h"
//1.  Import package
#include "first_ros/test.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");

    // 2. Initialize ROS node
    ros::init(argc,argv,"Add_Client");
    // 3. Create ROS handle
    ros::NodeHandle nh;
    // 4. Create a client object and accept the message with the topic of Add
    ros::ServiceClient client = nh.serviceClient<first_ros::test>("Add");

    //After the service is started successfully, you can run the client before starting the server
    //Mode 1
    ros::service::waitForService("Add");
    //Mode 2
    // client.waitForExistence();

    // 5. Organization request data
    first_ros::test ai;
    std::cout<<"Please enter two integers"<<std::endl;
    std::cin>>ai.request.num1>>ai.request.num2;
    // 6. Send the request, return the bool value and mark whether it is successful, which is the return value of the service callback function
    bool flag = client.call(ai);
    // 7. Process response
    if (flag)
    {
        ROS_INFO("Request normal processing,Response results:%d",ai.response.sum);
    }
    else
    {
        ROS_ERROR("Request processing failed....");
        return 1;
    }
    return 0;
}

to configure

add_executable(Add_Server src/Add_Server.cpp)
add_executable(Add_Client src/Add_Client.cpp)


add_dependencies(AddInts_Server ${PROJECT_NAME}_gencpp)
add_dependencies(AddInts_Client ${PROJECT_NAME}_gencpp)


target_link_libraries(Add_Server
  ${catkin_LIBRARIES}
)
target_link_libraries(Add_Client
  ${catkin_LIBRARIES}
)

function

function

Compiled file

catkin_make

Start Master

roscore

Refresh environment variables (if the running file is not found, refresh the variables)

source ./devel/setup.bash 

function

# Run Add_Server.cpp file
rosrun first_ros Add_Server

# Run Add_Client,cpp file
rosrun first_ros Add_Client

Parameter service

principle

The implementation of parameter server is the simplest. The model is shown in the figure below. The model involves three roles:

  • ROS Master (Manager)
  • Talker (parameter setter)
  • Listener (parameter caller)

ROS Master saves parameters as a public container, Talker can set parameters in the container, and Listener can obtain parameters.

The whole process is realized by the following steps:
1.Talker setting parameters

Talker sends parameters (including parameter name and parameter value) to the parameter server through RPC, and ROS Master saves the parameters in the parameter list.

2.Listener get parameters

The Listener sends a parameter lookup request to the parameter server through RPC, which contains the parameter name to be searched.

3.ROS Master sends parameter values to Listener

The ROS Master finds the parameter value according to the parameter name requested in step 2, and sends the query result to the Listener through RPC.

C + + code implementation parameter setting

#include "ros/ros.h"
int main(int argc, char *argv[])
{
    ros::init(argc,argv,"set_update_param");
    //NodeHandle--------------------------------------------------------
    ros::NodeHandle nh;

	//Settings can also be modified
    nh.setParam("nh_int",10); //integer
    nh.setParam("nh_double",3.14); //float 
    nh.setParam("nh_bool",true); //bool
    nh.setParam("nh_string","hello NodeHandle"); //character string
    nh.setParam("nh_vector",stus); // vector
    nh.setParam("nh_map",friends); // map


/*
	param(Key, default) 
            If yes, the corresponding result is returned; otherwise, the default value is returned

    getParam(Key, variable to store the result)
            Exists, returns true, and assigns the value to parameter 2
            If the key does not exist, the return value is false and parameter 2 is not assigned

    getParamCached Key, variable for storing results) -- improve variable acquisition efficiency
            Exists, returns true, and assigns the value to parameter 2
            If the key does not exist, the return value is false and parameter 2 is not assigned

    getParamNames(std::vector<std::string>)
            Get all the keys and store them in the parameter vector 

    hasParam((key)
            Whether a key is included. If it exists, return true; otherwise, return false

    searchParam(Parameter 1, parameter 2)
            Search key, parameter 1 is the searched key, and parameter 2 stores the variables of the search results


	deleteParam("Key ")
        If the parameter is deleted according to the key, it returns true if the deletion is successful; otherwise (the parameter does not exist), it returns false
*/
	return 0;
}

Common commands in operation

rosnode

rosnode ping Node name  //Test connection status to node
rosnode list    //List active nodes
rosnode info  Node name  //Print node information
rosnode machine    //Lists the nodes on the specified device
rosnode kill   Node name  //Kill a node
rosnode cleanup    //Clear unconnected nodes

rostopic

rostopic bw   		  //Displays the bandwidth used by the topic
rostopic delay 		//Show topic delay with header
rostopic echo  Topic name  // Print message to screen
rostopic find  data type //Find topics by type
rostopic hz   Topic name  //Displays how often a topic is published
rostopic info Topic name  //Display topic related information
rostopic list  		 //Show all active topics
rostopic pub  Topic name  //Publish data to topics
rostopic type Topic name  //Print subject type

rosmsg

rosmsg list
rosmsg package Package name //List all msg under a package
rosmsg show Message name //Show message description

rosservice

rosservice list    List all active services
rosservice args service name //Print service parameters
rosservice info service name  // Print information about the service
rosservice call Service name.... tab Key extraction //Call the service object to publish the message

rosparam

Get and set the master parameter in ROS.

rosparam set    Set parameters
rosparam get    Get parameters
rosparam load    Load parameters from external files
rosparam dump    Write out parameters to an external file
rosparam delete    Delete parameter
rosparam list    List all parameters

Keywords: Linux ROS udp TCP/IP

Added by rpieszak on Tue, 21 Sep 2021 23:46:13 +0300