# 4.5.1 自定义服务接口 帅鱼又来了,上一节小鱼给大家介绍了什么是服务,并且给大家举了李三向李四借钱吃麻辣烫,张三向王二买二手书的例子。作为ROS镇的创造者的我们,肯定要满足村民们的需求。 所以本节小鱼将带你一起,创造一个借钱服务接口和一个买书服务接口。 ## 1.服务接口介绍 在4.5到4.6章节中,小鱼介绍了接口和话题接口的概念。那服务接口和话题接口有什么不同呢? 那就要看,话题和服务有什么不同之处了。之前小鱼曾提起过: - 话题是**发布订阅模型**。主要是单向传输数据,只能由发布者发布,接收者接收(同一话题,发布者接收者都可以有多个) - 服务是**客户端服务端(请求响应)模型**。由客户端发送请求,服务端处理请求,然后返回处理结果(同一服务,客户端可以由多个,服务端只能有一个) 由以上差别我们可以知道,话题通信是单向的,自定义话题只需要定义**传过去的数据类型**就行,而服务是双向的,所以要定义**一去一回两种数据类型**。 我们来看一下服务的消息接口长什么样子? 服务接口格式:`xxx.srv` ``` int64 a int64 b --- int64 sum ``` 与话题不同的是,srv文件比msg文件中间多出了三个`---`这三个杠杠就是分界线,上方的是客户端发送请求的数据结构定义,下方的是服务端响应结果的数据结构定义。 是不是也很好理解,那如何创建我们自己的服务接口呢?可以参考下面的步骤: - 新建`srv`文件夹,并在文件夹下新建`xxx.srv` - 在`xxx.srv`下编写服务接口内容并保存 - 在`CmakeLists.txt`添加依赖和srv文件目录 - 在`package.xml`中添加`xxx.srv`所需的依赖 - 编译功能包即可生成`python`与c++头文件 当然在做上面的步骤之前,我们还需要做一件很重要的事情。就是根据业务需求,确定好请求的数据结构和返回的数据结构。 ## 2.创建借钱服务接口 我们依然是在`village_interfaces`下创建服务接口。 ### 2.1 确认数据结构 开始之前,我们先根据李四的需求来确定数据结构。 上一节中李四对借钱的要求如下: 1. 借钱一定要打欠条,收到欠条才能给钱 2. 每次借钱不能超过自己全部资金的`10%`且一定是整数,也就是说李四假如现在有100块钱,那么最多借出去`100x10%=10`块钱 总结一下就是,李三发送借钱请求的时候一定要有欠条,我们想一下,欠条中应该至少包含两条信息 - 借钱者名字,字符串类型、可以用`string`表示 - 金额,整形,可以用`uint32`表示 那请求的数据结构我们就可以确定下来了,接着确定返回的数据的格式。 既然是借钱,那李四就有可能拒绝,会有借钱失败的情况,所以返回数据应该有这两条信息: - 是否出借:只有成功和失败两种情况,布尔类型(`bool`)可表示 - 出借金额:无符号整形,可以用`uint32`表示,借钱失败时为0 ### 2.2 创建`srv`文件夹及`BorrowMoney.srv`消息文件 打开VsCode,然后打开`town_ws`,在`village_interfaces`下新建srv文件夹。 > 同样大家可以使用鼠标右击新建,不用输入命令行😜 ```shell cd src/village_interfaces mkdir srv && cd srv touch BorrowMoney.srv ``` 创建完成后的目录结构 ![image-20210811162010736](4.8自定义服务接口/imgs/image-20210811162010736.png) ### 2.3 编写文件内容 既然确定了内容,编写文件就很简单了 ``` string name uint32 money --- bool success uint32 money ``` ### 2.4修改`CMakeLists.txt` 因为在4.6中我们已经添加过依赖`DEPENDENCIES`和`msg`文件了,所以这里我们直接添加一个`srv`即可。 ```cmake find_package(rosidl_default_generators REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} #---msg--- "msg/Novel.msg" #---srv--- "srv/BorrowMoney.srv" DEPENDENCIES sensor_msgs ) ``` 需要关注的是这一行`"srv/BorrowMoney.srv"`,添加了对应的文件位置。 ### 2.5修改`package.xml` 在4.6节我们已经添加过了,这里就不用添加了,如果没有加的同学可以再加一次。 ```xml sensor_msgs rosidl_default_generators rosidl_default_runtime rosidl_interface_packages ``` ### 2.6编译 在vscode中,使用`Ctrl+Shift+~`打开一个新的终端,在`town_ws`目录下输入: ```shell colcon build --packages-select village_interfaces ``` ![image-20210811163033796](4.8自定义服务接口/imgs/image-20210811163033796.png) ### 2.7测试 这次测试我们依然使用`ros2 interface`指令进行测试。 之前已经测试过了话题了,这里小鱼就只放一下测试指令和测试结果。 ``` source install/setup.bash ros2 interface package village_interfaces ros2 interface show village_interfaces/srv/BorrowMoney ros2 interface proto village_interfaces/srv/BorrowMoney ``` > 注意,`ros2 interface proto` 该指令目前只显示出请求部分话题数据 ![image-20210816145858746](4.8自定义服务接口/imgs/image-20210816145858746.png) ## 3.创建买书服务接口 ### 3.1 确认数据结构 和创建借钱服务一样,我们先确定王二卖书的数据结构。 上一节中王二对卖书的要求如下: 1. 必须一手交钱,一手交货,爱买不买😎 2. 每次给多少钱卖多少章,每章一块钱,如果手里的存货不足,就继续等待 总结一下,王二提供书的时候,一定要先给钱才行,所以张三只需要给钱就行,服务的请求数据结构如下: - 买书的钱,无符号整形,`uint32` 那王二返回什么呢?因为王二对应的数量艳娘传奇,所以王二的返回就是n章小说。 一章节的小说我们可以采用`string`来,那n章节的小说该怎么办?办法就是用`string`数组来容纳多个章节。 - 所以王二的返回是一个`string`类型的数组,表示多个章节的书 ### 3.2 创建`srv`文件夹及`SellNovel.srv`消息文件 上面我们已经创建了`srv`,这里直接创建`SellNovel.srv` ``` cd src/village_interfaces cd srv touch SellNovel.srv ``` 创建完成后的目录结构 ![image-20210812173303503](4.8自定义服务接口/imgs/image-20210812173303503.png) ### 3.3 编写文件内容 用无符号整形表示`money`大家已经很清楚如何做了,那如何表示小说数组呢?其实只需在类型的后面加上`[]`中括号。 完整内容如下: ``` uint32 money --- string[] novels ``` 请求时给钱,返回即为多章小说。 ### 3.4修改`CMakeLists.txt` 在上面的基础上,再添加上一行`"srv/SellNovel.srv"`代码即可: ``` rosidl_generate_interfaces(${PROJECT_NAME} #---msg--- "msg/Novel.msg" #---srv--- "srv/BorrowMoney.srv" "srv/SellNovel.srv" DEPENDENCIES sensor_msgs ) ``` ### 3.5修改`package.xml` 同样的,因为我们已经修改过了,这里就不需要修改了。 ### 3.6编译 在vscode中,使用`Ctrl+Shift+~`打开一个新的终端,在`town_ws`目录下输入: ```shell colcon build --packages-select village_interfaces ``` ![image-20210811163033796](4.8自定义服务接口/imgs/image-20210811163033796.png) ### 3.7测试 这次测试我们依然使用`ros2 interface`指令进行测试。 之前已经测试过了话题了,这里小鱼就只放一下测试指令和测试结果。 ``` source install/setup.bash ros2 interface package village_interfaces ros2 interface show village_interfaces/srv/SellNovel ros2 interface proto village_interfaces/srv/SellNovel ``` > 注意,`ros2 interface proto`该指令目前只显示出请求部分话题数据 ![image-20210816150038830](4.8自定义服务接口/imgs/image-20210816150038830.png) ## 4.总结 本节小鱼带大家创建了用于借钱和买书的服务接口,下一节我们就开始编写代码,完成借钱服务。