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补齐
测试服务器端是否正常