需求: 服务通信中,客户端提交两个整数至服务端,服务端求和并响应结果到客户端,请创建服务器与客户端通信的数据载体。
流程:
srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:
- 按照固定格式创建 srv 文件
- 编辑配置文件
- 编译生成可以被 Python 或 C++ 调用的中间文件。
实现:
创建功能包:
右键src文件夹->Create Catin Package,在弹框中输入包名称:server_client,回车,然后在输入依赖:roscpp rospy std_msgs,创建功能包。
自定义msg文件:
进入功能包目录下,新建srv目录,添加文件 addints.srv并添加自定义类型数据,在addints.srv中输入内容:
addints.srv中输入内容:
#客户端请求时发送的两个数字
int32 num1
int32 num2
---
#服务器响应发送的数据
int32 age
编辑配置文件:
在package.xml中添加编译依赖与执行依赖:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
<!--
exce_depend 以前对应的是 run_depend 现在非法
-->
CMakeLists.txt编辑 srv 相关配置:
# 需要加入 message_generation,必须有 std_msgs
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
## 配置 msg 源文件
add_message_files(
FILES
addints.srv
)
# 生成消息时依赖于 std_msgs
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
)
编译生成文件:
ctrl+shift+B
编译后的中间文件查看:
C++ 需要调用的中间文件(.../工作空间/devel/include/包名/xxx.h)
Python 需要调用的中间文件(.../工作空间/devel/lib/python3/dist-packages/包名/msg)
C++实现服务通信模型源码:
服务端实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 服务 对象
5.回调函数处理请求并产生响应
6.由于请求有多个,需要调用 ros::spin()
#include “ros/ros.h”
#include “server_client/addints.h”
bool doReq(server_client::addints::Request& req,
server_client::addints::Response& resp)
{
Int num1 = req.num1;
Int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);
//逻辑处理
if (num1 < 0 || num2 < 0)
{
ROS_ERROR("提交的数据异常:数据不可以为负数");
return false;
}
//如果没有异常,那么相加并将结果赋值给 resp
resp.sum = num1 + num2;
return true;
}
//1 包含头文件
int main(int argc,char *argv[])
{
setlocale(LC_ALL,“”);
//2 初始化ros节点
ros::init(argc,argv,”addints_server”);
//3 创建ros句柄
ros::NodeHandle nh;
//4 创建服务对象
ros::ServiceServer server = nh.advertiseService(“addints”,doReq);
ROS_INFO(“服务已经启动…”);
//5 回调函数处理请求并产生响应
//6 由于请求有多个,需要调用ros::spin()
ros::spin();
return 0;
}
客户端实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 客户端 对象
5.请求服务,接收响应
// 1.包含头文件
#include “ros/ros.h”
#include “server_client/addints.h”
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
if(argc != 3)
{
ROS_ERROR("请提交两个整数");
return 1;
}
//2 初始化ros节点
ros::init(argc,argv,”addints_client”);
//3 创建ros句柄
ros::NodeHandle nh;
//4 客户端对象
ros::ServiceClient client = nh.serviceClient<server_client::addInts>("addInts");
//等待服务器启动成功
Ros::service::waitForService(“addints”);
//5 构建数据
server_client::addints ai;
ai.request.num1 = atoi(argv[1]);
ai.request.num2 = atoi(argv[2]);
//6 发送请求,返回bool数值,标记是否成功
Bool flag = client.call(ai);
//7 处理响应
if (flag)
{
ROS_INFO("请求正常处理,响应结果:%d",ai.response.sum);
}
else
{
ROS_ERROR("请求处理失败....");
return 1;
}
return 0;
}
配置Cmakelists.txt:
add_executable(server src/server.cpp)
add_executable(client src/client.cpp)
add_dependencies(server ${PROJECT_NAME}_gencpp)
add_dependencies(client ${PROJECT_NAME}_gencpp)
target_link_libraries(server
${catkin_LIBRARIES}
)
target_link_libraries(client
${catkin_LIBRARIES}
)
执行:
需要先启动服务:rosrun 包名 服务
然后再调用客户端 :rosrun 包名 客户端 参数1 参数2
Python实现:
服务端实现流程:
- 导包
- 初始化ROS节点
- 创建服务对象
- 回调函数处理请求产生响应
- Spin函数
#! /usr/bin/env python
import rospy
from server_client.srv import *
#回调函数
Def doReq(req):
# 解析提交的数据
num1 = req.num1
num2 = req.num2
sum = num1 + num2
# 创建响应对象,赋值并返回
resp = addintsResponse(sum)
return resp
If __name__ == “__main__”:
# 2.初始化 ROS 节点
rospy.nodeinit(“server_p”)
# 3.创建服务对象
server = rospy.Service(“addints_p”,addints,doReq)
# 4.回调函数处理请求并产生响应
# 5.spin 函数
rospy.spin()
客户端实现
1.导包
2.初始化 ROS 节点
3.创建请求对象
4.发送请求
5.接收并处理响应
#! /usr/bin/env python
import rospy
from server_client.srv import *
import sys
if __name__ == "__main__":
if len(sys.argv) != 3:
rospy.logerr("请正确提交参数")
sys.exit(1)
# 2.初始化 ROS 节点
rospy.nodeinit(“client_p”)
# 3.创建请求对象
client = rospy.ServiceProxy(“addints_p”,addints)
# 请求前,等待服务已经就绪
client.wait_for_service()
# 4.发送请求,接收并处理响应
req = addintsRequest()
req.num1 = int(sys.argv[1])
req.num2 = int(sys.argv[2])
resp = client.call(req)
rospy.loginfo("响应结果:%d",resp.sum)
修改文件权限:
chmod +x ./*.py
配置CMakeLists.txt:
catkin_install_python(PROGRAMS
scripts/server_p.py
scripts/client_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
执行:
需要先启动服务:rosrun 包名 服务
然后再调用客户端 :rosrun 包名 客户端 参数1 参数2