ROS实践笔记6

服务通信实现

srv文件

服务通信是基于请求和响应,因此服务通信的消息载体需要包含“请求”和“响应”两个部分,默认的数据结构不能满足,所以需要自定义数据载体srv文件。
srv文件可用的数据类型与msg文件一致,且实现流程与msg文件类似。
实现流程:
    1. 在功能包目录下创建srv文件夹,并创建xxx.srv文件文件
    2. 修改package.xml文件
    3. 修改CMakeLists.txt文件
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
)
# 改为
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
## Generate services in the 'srv' folder
# add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# )
# 改为
## Generate services in the 'srv' folder
 add_service_files(
   FILES
   information.srv
 )
# generate_messages(
#   DEPENDENCIES
#   std_msgs
# )
# 注释放开
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES hellovscode
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
)
# 改为
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES plumbing_server_client
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

编译后生成的文件路径与msg文件类似
将生成的文件配置进msg生成文件相同的位置

c++

Server的实现

服务端实现:解析客户端提交的数据。运算后产生响应:
    1. 包含头文件
    2. 初始化ROS节点
    3. 创建节点句柄
    4. 创建服务对象
    5. 处理请求并产生响应
    6. spin()

编写完成后在CMakeList.txt文件中需要额外配置:

 add_dependencies(server ${PROJECT_NAME}_gencpp)

服务端代码

# include"ros/ros.h"
# include"plumbing_server_client/information.h"


bool doNums(plumbing_server_client::information::Request &request,
plumbing_server_client::information::Response &response)
{
    response.sum=request.num1+request.num2;
    return response.sum==request.num1+request.num2;
}

int main(int argc, char  *argv[])
{
    ros::init(argc,argv,"Server_c");
    ros::NodeHandle nh;
    ros::ServiceServer server=nh.advertiseService("Server",doNums);
    ros::spin();
    return 0;
}

Client的实现

客户端实现:提交数据并处理响应结果
    1. 包含头文件
    2. 初始化ROS节点
    3. 创建节点句柄
    4. 创建一个客户端对象
    5. 提交请求并处理响应

客户端代码:

# include"ros/ros.h"
# include"plumbing_server_client/information.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"Client_c");
    ros::NodeHandle nh;
    ros::ServiceClient client=nh.serviceClient<plumbing_server_client::information>("Service");
    plumbing_server_client::information t;
    /*

    //通过命令输入参数
    //rosrun plumbing_server_client client_c num1 num2
    //用数字代替num1和num2
    //argv[0]可能是文件名,argc代表输入的参数个数
    t.request.num1=atoi(argv[1]);
    t.request.num2=atoi(argv[2]);

    */
    std::cin>>t.request.num1>>t.request.num2;
    //判断服务端状态,如果服务端未启动则挂起
    //client.waitForExistence(); //函数1
    ros::service::waitForService("Service");//函数2

    if(client.call(t))
        //std::cout<<t.response.sum<<std::endl;
        ROS_INFO("响应结果=%d\n",t.response.sum);
    else
        ROS_INFO("处理失败!!!");
    
    return 0;
}

python

服务端代码如下

#! /usr/bin/env python

import rospy
from plumbing_server_client.srv import information,informationRequest,informationResponse
#from plumbing_server_client.srv import *
#参数封装了请求数据
#返回值是响应数据
def doNum(request):
    response=informationResponse()
    response.sum=request.num1+request.num2
    return response

if __name__=="__main__":
    rospy.init_node("Server_p")
    server=rospy.Service("Service",information,doNum)
    rospy.spin()

客户端代码实现

#! /usr/bin/env python

import rospy
import sys # 用于传参
#from plumbing_server_client.srv import information,informationRequest,informationResponse
from plumbing_server_client.srv import *

if __name__=="__main__":
    if len(sys.argv) !=3:
        rospy.logerr("传参错误!")
        sys.exit(1)
    rospy.init_node("Client_p")
    client=rospy.ServiceProxy("Service",information)
    num1=int(sys.argv[1])
    num2=int(sys.argv[2])
    #客户端等待服务端函数
    #client.wait_for_service() #函数1
    rospy.wait_for_service("Service") #函数2
    response = client.call(num1,num2)
    rospy.loginfo("响应的数据为 %d",response.sum)

可以通过命令

rosservice call Sevice
# server是节点名
# 输入完成后再输入一个空格后Tab补齐

测试服务器端是否正常

posted @ 2022-02-13 23:12  一心如旧  阅读(95)  评论(0)    收藏  举报