《ROS1学习笔记8——自定义服务素材》

1、前言

在这一节我们要自定义服务通信接口,来实现服务通信。

这里以鱼香ROS老师给的例子解释一下。可能会更好理解:

总体的逻辑就是客服端发布指令让服务端给乌龟个速度,这部分是service ,服务端收到命令后给乌龟发布topic让乌龟动起来,这节就是service和topic都有
在这里插入图片描述
我们后面编写的程序只涉及到客户端与服务端之间的通信,并没有加入话题。

2、自定义消息接口

2.1、新建功能包

cd src
catkin_create_pkg demo_service roscpp rospy std_msgs geometry_msgs turtlesim

2.2、自定义消息接口

2.2.1、新建srv

在功能包目录下,新建srv文件夹,并在srv目录下新建Person.srv文件(使用驼峰命名法,文件首字母大写)

string name
uint8 age
uint8 sex
uint8 unkown = 0
uint8 male = 1
uint8 female =2
---
string result

—上面是请求消息,横线下面是响应消息
在这里插入图片描述

2.2.1、在package.xml添加依赖

添加下面两行配置代码:

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

message_genaation是编译依赖
message_runtime是运行依赖
在这里插入图片描述

2.2.3、修改CMakeLists

需要更改find_packagecatkin_package

将message_genaration添加进去。
在这里插入图片描述

将message_runtime添加进去

在这里插入图片描述

1、find_package(catkin REQUIRED COMPONENTS …)
核心作用:声明编译当前包时需要的依赖包

2、catkin_package(…)
核心作用:声明当前包被其他包依赖时,对方需要的信息(包括运行时依赖、头文件路径、库文件等)。其中 CATKIN_DEPENDS 明确指定了运行时依赖(当前包运行时需要的包,以及依赖当前包的其他包在编译 / 运行时也需要的包)。

通俗总结:

  • find_package 是 “我编译时需要什么”(给当前包的编译过程用)。
  • catkin_package 是 “别人用我时需要什么”(给依赖当前包的其他包用,同时也隐含了当前包运行时的需求)。

3、添加一个配置项,用于将自己新建的.msg文件编译成其他的文件

add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)

如下图位置所示,并且在上面也有相应的注释说明

在这里插入图片描述

generate_messages(DEPENDENCIES std_msgs)
触发消息生成过程:ROS 会根据 add_message_files 声明的 .msg 文件,自动生成对应语言(C++、Python 等)的代码(如头文件、类定义),供你的程序调用。

DEPENDENCIES std_msgs
表示当前自定义消息依赖于 std_msgs 包中的基础消息类型,如刚用到的uint8等

2.3、编译

回到工作空间目录下,进行编译

cd..
catkin_make

编译成功后,devel/include/[pkg_name]目录下会出现下列该头文件
后续在编写代码中直接引用Person.h即可。
在这里插入图片描述

3、编写程序

在src目录下新建客户端和服务端代码
在这里插入图片描述

3.1、客户端(client)

实现思路:

  • 初始化ROS节点
  • 创建一个Client实例
  • 发布服务请求数据
  • 等待server处理之后的应答结果
#include <ros/ros.h>
  #include "demo_service/Person.h"
  int main(int argc, char** argv)
  {
  //初始化节点
  ros::init(argc, argv, "person_client");
  //创建节点句柄
  ros::NodeHandle node;
  //发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
  //<demo_service::Person>数据类型
    ros::service::waitForService("/show_person");
    ros::ServiceClient person_client = node.serviceClient<demo_service::Person>("/show_person");
      //初始化demo_service::Person的请求报告
      demo_service::Person srv;
      srv.request.name = "Tom";
      srv.request.age = 20;
      srv.request.sex = demo_service::Person::Request::male;
      //请求服务调用
      ROS_INFO("Call service to show[name:%s , age:%d, sex:%d]",
      srv.request.name.c_str(), srv.request.age, srv.request.sex);
      person_client.call(srv);
      //显示服务调用结果
      ROS_INFO("show person result : %s", srv.response.result.c_str());
      return 0;
      }

3.2、服务端(server)

实现思路

  • 初始化ROS节点
  • 创建一个Server实例
  • 循环等待服务请求,进入回调函数
  • 在回调函数中完成服务功能的处理,并反馈应答数据
#include <ros/ros.h>
  #include "demo_service/Person.h"
  //service回调函数,输入参数req, 输出参数res
  bool personCallback(demo_service::Person::Request &req,
  demo_service::Person::Response &res)
  {
  //显示请求数据
  ROS_INFO("Person: name:%s age:%d sex:%d", req.name.c_str(), req.age, req.sex);
  //设置反馈数据
  res.result = "OK";
  return true;
  }
  int main(int argc, char** argv)
  {
  //ROS节点初始化
  ros::init(argc, argv, "person_server");
  //创建节点句柄
  ros::NodeHandle node;
  //创建一个名为/show_person的server,注册回调函数personCallback
  ros::ServiceServer person_service = node.advertiseService("/show_person", personCallback);
  //循环等待回调函数
  ROS_INFO("Ready to show person informtion.");
  ros::spin();
  return 0;
  }

3.3、配置CMakeLists

在CMakeLists中添加如下代码

add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_generate_messages_cpp)
add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_generate_messages_cpp)

在这里插入图片描述

4、编译运行

4.1、编译

catkin_make

编译成功后,devel/lib目录下出现可执行文件
在这里插入图片描述

4.2、运行

这里我们打开三个终端:

终端1:运行roscore

终端2:
1、改变环境变量

source devel/setup.bash

2、运行服务端

rosrun demo_service person_server

如图:此时,服务端已经成功运行起来了,并且在等待客户端发布命令
在这里插入图片描述

终端3:
1、改变环境变量

source devel/setup.bash

2、运行客服端

rosrun demo_service person_client

在这里插入图片描述
运行客户端之后,
客户端成功向服务端发送了消息
并且服务端接收到了消息,并向客户端有所反馈。

并且还有一点就是,客户端这边不会一直发送数据,只有运行一次相应程序才会发送一次数据,然后服务端相应接收到一次数据。

posted on 2025-11-27 20:04  ljbguanli  阅读(0)  评论(0)    收藏  举报