服务
首先,创建一个新的功能包:service_pkg
catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim
依旧是在包下的src文件夹下写c++文件,script文件夹下写python文件
服务的数据类型是:srv
查看系统中的服务数据类型:
rossrv list
注意:一定要先启动roscore
本次使用的数据类型:turtlesim/Spawn
查看数据类型:
rossrv info turtlesim/Spawn
1 服务端(service)
1.1 c++
创建cpp文件:server_cpp.cpp
该文件意思:创建一个服务:cpp_server,该服务作用是,每调用一次服务,就打印一次“your are right!!!”
#include <ros/ros.h>
#include <turtlesim/Spawn.h>
int count=0;
bool b = false;
//回调函数(回调函数返回值是bool) 这里规定了“服务”的srv类型:turtlesim::Spawn
bool CallBack(turtlesim::Spawn::Request &req,
turtlesim::Spawn::Response &res)
{
b = !b;
count++;
ROS_INFO("your are right!!!! ---%d", count);
//调用服务时,response的值会打印到屏幕
res.name = req.name;
return true;
}
int main(int argc, char **argv){
ros::init(argc,argv,"server_cpp");
ros::NodeHandle n;
//创建一个 服务:cpp_server 服务的数据类型由回调函数决定
ros::ServiceServer ser = n.advertiseService("cpp_server", CallBack);
ROS_INFO("---------1-------");
//循环查看回调函数
ros::spin();
ROS_INFO("---------2-------");
return 0;
}
c++文件需要生成可执行文件
在CMakeList文件中添加:
add_executable(client_cpp src/client_cpp.cpp)
target_link_libraries(client_cpp ${catkin_LIBRARIES})
运行:
在一个终端中输入:
rosrun service_pkg server_cpp
另一个终端输入:
# 指令意思:向服务(cpp_server)发出请求
rosservice call /cpp_server 双击tab键
可以修改x、y等里的内容,修改好后并回车
1.2 python
创建文件:server_py.py
作用:创建一个名为/py_server的服务,该服务每调用一次,就打印一次“your are right!!!”
#!/usr/bin/env python
import rospy
from turtlesim.srv import Spawn, SpawnResponse
count =0
def Callback(req):
global count # 定义全局变量
count += 1
rospy.loginfo(f"you are right!!! ---{count}")
# 将 请求的名字 传给 响应
res_name = req.name
# Spawn的response中只有一个参数,则SpawnResponse只有一个参数
return SpawnResponse(res_name)
def server_py():
rospy.init_node("server_py")
# 创建一个服务:/py_server 数据类型是Spawn
s = rospy.Service('/py_server', Spawn, Callback)
rospy.loginfo("....ready....")
rospy.spin()
if __name__ == "__main__":
server_py()
注意:python虽然不需要配置,但需要将文件改为可执行文件
rosrun service_pkg server_py.py
rosservice call /py_server 双击tab键
# 向/py_server发出请求,双击tab之后出现的内容是request的内容;
# 最后回车
2 客户端(client)
2.1 c++
创建文件:client_cpp.cpp
作用:创建一个连接服务cpp_server的客户端
#include <ros/ros.h>
#include <turtlesim/Spawn.h>
int main(int agrc,char** agrv){
ros::init(agrc,agrv,"client_cpp");
ros::NodeHandle n;
ROS_INFO("wait");
//等待名为cpp_server的服务
ros::service::waitForService("/cpp_server");
ROS_INFO("finish");
//创建服务客户端cli,连接服务cpp_server
ros::ServiceClient cli = n.serviceClient<turtlesim::Spawn>("/cpp_server");
turtlesim ::Spawn srv;
srv.request.x = 3;
srv.request.y = 5;
srv.request.name = "server";
ROS_INFO("request: x:%.0f,y:%.0f,name:%s",srv.request.x,srv.request.y,srv.request.name.c_str());
//向服务发出请求
cli.call(srv);
ROS_INFO("name:%s", srv.response.name.c_str());
return 0;
}
注意:不要忘记配置cpp文件
运行:
rosrun service_pkg client_cpp
rosrun service_pkg server_cpp
2.2 python
创建文件:client_py.py
#!/usr/bin/env python
import rospy
from turtlesim.srv import Spawn
def func():
rospy.init_node("client_py")
rospy.loginfo("....wait....")
# 查找服务py_server
rospy.wait_for_service('/py_server')
rospy.loginfo("....finish....")
try:
# 创建客户端,链接服务py_server 服务的数据类型:Spawn
cli = rospy.ServiceProxy("/py_server",Spawn)
# 向服务发送请求 请求的数据
res = cli(2,2,0,'name1')
rospy.loginfo("....end....")
except rospy.ServiceException as e:
print(f"error:{e}")
if __name__ == '__main__':
func()
运行:
rosrun service_pkg client_py.py
rosrun service_pkg server_py.py
包中最后的文件结构:
3 易错点
1.运行程序时,没有运行roscore
2.c++文件没有进行配置(CMakeList文件)
3.python文件,没有改成可执行文件:在文件上右击——属性——权限