ROS service communication mechanism

Service communication is also an extremely common communication mode in ROS. Service communication is based on the request response mode and is a response mechanism. That is: a node A sends a request to another node B, and B receives the processing request and generates a response result and returns it to A.

srv file

Service communication requires the use of srv files. The types of request data and response data are defined in the srv file.

1. Define srv file

Specific implementation: Create a new srv directory under the function package and add the .srv file.

The contents of the .srv file are as follows:

# 客户端请求时发送的数据
int8 num
---
# 服务端响应时发送的数据
int32 result

2. Edit configuration file

Add compilation dependencies and execution dependencies in package.xml

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

CMakeLists.txt edit srv related configuration

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs
add_service_files(
  FILES
  AddInts.srv
)
generate_messages(
  DEPENDENCIES
  std_msgs
)

3. Compile

View the compiled intermediate file:

C++ needs to call the intermediate file (.../workspace/devel/include/package name/xxx.h)

4. vscode configuration

Configure the c_cpp_properies.json file and copy the path of the intermediate file to "incluedePath"

{
    
    
    "configurations": [
        {
    
    
            "browse": {
    
    
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": true
            },
            "includePath": [
                "/opt/ros/noetic/include/**",
                "/usr/include/**",
                "/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径 
            ],
            "name": "ROS",
            "intelliSenseMode": "gcc-x64",
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ],
    "version": 4
}

1. Service communication implementation of ROS basic data types

1. Service communication implementation of ROS shaped data

Case: The client sends an integer data, and the server implements the quadratic operation of the integer data.

Server side implementation

#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"

bool doReq(int_server_client::int_server_client::Request& req,
            int_server_client::int_server_client::Response& res)
{
    res.result = pow(req.num,2);
    // ROS_INFO("接受到的数据为:%d",req.num);
    // ROS_INFO("处理后的数据为:%d",res.result);
    return true;
} 


int main(int argc, char *argv[])
{
    /* code */
    //解决乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"server");
    //句柄
    ros::NodeHandle nh;
    //创建server对象
    ros::ServiceServer server;
    server = nh.advertiseService("intServer",doReq);
    ros::spin();


    return 0;
}

Client implementation

#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"server");
    //句柄
    ros::NodeHandle nh;
    //创建client对象
    ros::ServiceClient client;
    client = nh.serviceClient<int_server_client::int_server_client>("intServer");
    //等待服务端启动
    client.waitForExistence();
    //组织数据
    int_server_client::int_server_client ai;
    ai.request.num = 10;

    //发送请求
    bool flag = client.call(ai);
    if (flag == 1)
    {
        ROS_INFO("处理后的数据为%d",ai.response.result);
    }
    else
    {
        ROS_INFO("请求失败!");
    }


    ros::spin();


    return 0;
}

launch file

<launch>
    <node pkg="int_server_client" type="int_server" name="intServer" output="screen"/>
    <node pkg="int_server_client" type="int_client" name="intClint" output="screen"/>
</launch>

2. Implementation of service communication of ROS shaped data using dynamic parameter transmission for parameter transmission

The server-side implementation is the same as the previous section. The difference is the client-side implementation. The client-side implementation needs to obtain the parameters input by the terminal and then pass them to the server for calculation and response.

Client implementation

#include "ros/ros.h"
#include "std_msgs/Int8.h"
#include "int_server_client/int_server_client.h"

int main(int argc, char *argv[])
{
    /* code */
    //  argc 是指命令行输入参数的个数(以空白符分隔),默认包含一个程序名
    if (argc != 2)
    {
        ROS_ERROR("请提交一个整数");
        return 1;
    }
    //ROS_INFO("%s",argv[1]);

    //解决乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"server");
    //句柄
    ros::NodeHandle nh;
    //创建client对象
    ros::ServiceClient client;
    client = nh.serviceClient<int_server_client::int_server_client>("intServer");
    //等待服务端启动
    client.waitForExistence();
    //组织数据
    int_server_client::int_server_client ai;
    
    //atoi()将字符串转换为整形
    ai.request.num = atoi(argv[1]);

    //发送请求
    bool flag = client.call(ai);
    if (flag == 1)
    {
        ROS_INFO("处理后的数据为%d",ai.response.result);
    }
    else
    {
        ROS_INFO("请求失败!");
    }


    ros::spin();


    return 0;
}

run

Different from the previous section, this section requires running the server and client separately in the terminal, because the client needs to obtain the parameters passed in the terminal

The command is as follows:

rosrun 功能包名 节点名 参数

Note: You need to start the roscore command first

3. Service communication implementation of ros string type data

Server side implementation

#include "ros/ros.h"
#include "string_server_client/string_srv.h"


bool doReq(string_server_client::string_srvRequest& req,
            string_server_client::string_srvResponse& res)
{
    ROS_INFO("名字:%s",req.name.c_str());
    ROS_INFO("年龄:%s",req.age.c_str());
    ROS_INFO("地址:%s",req.address.c_str());
    std::stringstream ss;
    ss<< req.name.c_str()<<"来自"<<req.address.c_str()<<"今年"<<req.age.c_str()<<"岁";    
    res.msg = ss.str();
}

int main(int argc, char *argv[])
{
    /* code */
    //乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"server");
    //句柄
    ros::NodeHandle nh;
    //创建服务端对象
    ros::ServiceServer server;
    server = nh.advertiseService("stringServerClient",doReq);
    ros::spin();

    return 0;
}

Client implementation

#include "ros/ros.h"
#include "string_server_client/string_srv.h"


int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //判断参数数量是否正确
    if (argc!=4)
    {
        ROS_INFO("参数数量不正确,请重新输入");
        return 1;
    }
 
    //初始化ros节点
    ros::init(argc,argv,"server");
    //句柄
    ros::NodeHandle nh;
    //客户端对象
    ros::ServiceClient client;
    client = nh.serviceClient<string_server_client::string_srv>("stringServerClient");
    string_server_client::string_srv clientData;
    clientData.request.name = argv[1];
    clientData.request.age = argv[2];
    clientData.request.address = argv[3];
    //等待服务启动
    client.waitForExistence();
    bool flag = client.call(clientData);
    if (flag==1)
    {
        ROS_INFO("响应的数据为:");
        ROS_INFO("%s",clientData.response.msg.c_str());
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_49216787/article/details/132678297