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