ROS入门21讲(5)
九、服务数据的定义与使用
1、服务模型
2、自定义服务数据
Person.srv
string name uint8 sex uint8 age uint8 unknown = 0 uint8 male = 1 uint8 female = 2 --- string result
如何自定义服务数据?
①定义srv文件
②在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
③在CMakeLists.txt添加编译选项
find_package(...... message_generation)
add_service_files(DILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(...... message_runtime)
④编译生成语言相关文件
3、创建服务器代码
如何实现一个服务器?
①初始化ROS节点
②创建Server实例
③循环等待服务请求,进入回调函数
④在回调函数中完成服务功能的处理,并反馈应答数据。
C++代码如下:

1 /** 2 * 该例程将执行/show_person服务,服务数据类型learning_service::Person 3 */ 4 5 #include <ros/ros.h> 6 #include "learning_service/Person.h" 7 8 // service回调函数,输入参数req,输出参数res 9 bool personCallback(learning_service::Person::Request &req, 10 learning_service::Person::Response &res) 11 { 12 // 显示请求数据 13 ROS_INFO("Person: name:%s age:%d sex:%d", req.name.c_str(), req.age, req.sex); 14 15 // 设置反馈数据 16 res.result = "OK"; 17 18 return true; 19 } 20 21 int main(int argc, char **argv) 22 { 23 // ROS节点初始化 24 ros::init(argc, argv, "person_server"); 25 26 // 创建节点句柄 27 ros::NodeHandle n; 28 29 // 创建一个名为/show_person的server,注册回调函数personCallback 30 ros::ServiceServer person_service = n.advertiseService("/show_person", personCallback); 31 32 // 循环等待回调函数 33 ROS_INFO("Ready to show person informtion."); 34 ros::spin(); 35 36 return 0; 37 }
python代码如下:

1 # 该例程将执行/show_person服务,服务数据类型learning_service::Person 2 3 import rospy 4 from learning_service.srv import Person, PersonResponse 5 6 def personCallback(req): 7 # 显示请求数据 8 rospy.loginfo("Person: name:%s age:%d sex:%d", req.name, req.age, req.sex) 9 10 # 反馈数据 11 return PersonResponse("OK") 12 13 def person_server(): 14 # ROS节点初始化 15 rospy.init_node('person_server') 16 17 # 创建一个名为/show_person的server,注册回调函数personCallback 18 s = rospy.Service('/show_person', Person, personCallback) 19 20 # 循环等待回调函数 21 print "Ready to show person informtion." 22 rospy.spin() 23 24 if __name__ == "__main__": 25 person_server()
4、创建客户端代码
①初始化ROS节点
②创建一个Client实例
③发布服务请求数据
④等待Server处理之后的应答结果
C++代码如下:

1 /** 2 * 该例程将请求/show_person服务,服务数据类型learning_service::Person 3 */ 4 5 #include <ros/ros.h> 6 #include "learning_service/Person.h" 7 8 int main(int argc, char** argv) 9 { 10 // 初始化ROS节点 11 ros::init(argc, argv, "person_client"); 12 13 // 创建节点句柄 14 ros::NodeHandle node; 15 16 // 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service 17 ros::service::waitForService("/show_person"); 18 ros::ServiceClient person_client = node.serviceClient<learning_service::Person>("/show_person"); 19 20 // 初始化learning_service::Person的请求数据 21 learning_service::Person srv; 22 srv.request.name = "Tom"; 23 srv.request.age = 20; 24 srv.request.sex = learning_service::Person::Request::male; 25 26 // 请求服务调用 27 ROS_INFO("Call service to show person[name:%s, age:%d, sex:%d]", 28 srv.request.name.c_str(), srv.request.age, srv.request.sex); 29 30 person_client.call(srv); 31 32 // 显示服务调用结果 33 ROS_INFO("Show person result : %s", srv.response.result.c_str()); 34 35 return 0; 36 };
python代码如下:

1 # 该例程将请求/show_person服务,服务数据类型learning_service::Person 2 3 import sys 4 import rospy 5 from learning_service.srv import Person, PersonRequest 6 7 def person_client(): 8 # ROS节点初始化 9 rospy.init_node('person_client') 10 11 # 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service 12 rospy.wait_for_service('/show_person') 13 try: 14 person_client = rospy.ServiceProxy('/show_person', Person) 15 16 # 请求服务调用,输入请求数据 17 response = person_client("Tom", 20, PersonRequest.male) 18 return response.result 19 except rospy.ServiceException, e: 20 print "Service call failed: %s"%e 21 22 if __name__ == "__main__": 23 #服务调用并显示调用结果 24 print "Show person result : %s" %(person_client())
5、配置服务器/客户端代码编译规则
如何配置CMakeLists.txt中的编译规则?
①设置需要配置的代码和生成的可执行文件
②设置链接库
③添加依赖项
CMakeLists.txt中需要添加:
add_executable(person_server src/person_server.cpp) target_link_libraries(person_server ${catkin_LIBRARIES}) add_dependencies(person_server ${PROJECT_NAME}_gencpp) add_executable(person_client src/person_client.cpp) target_link_libraries(person_client ${catkin_LIBRARIES}) add_dependencies(person_client ${PROJECT_NAME}_gencpp)
6、编译并且运行客户端和服务器
命令:
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun learning_topic person_server
$ rosrun learning_topic person_client
图示:
十、参数的使用与编程方法
1、参数模型
参数模型(全局字典):
2、创建功能包
命令:
$ cd ~/catkin_ws/src
$ catkin_create_pkg learning_parameter roscpp rospy std_srvs
3、参数命令行使用
YAML参数文件
rosparam
命令:
①rosparam list 作用:列出当前所有参数
②rosparam get param_key 作用:显示某个参数值
③rosparam set param_key param_value 作用:设置某个参数值
④rosparam dump file_name 作用:保存参数到文件
⑤rosparam load file_name 作用:从文件读取参数
⑥rosparam delete param_key 作用:删除参数
图示:
4、编程方法
如何获取/设置参数?
①初始化ROS节点
②get函数获取参数
③set函数设置参数
C++代码:

1 /** 2 * 该例程设置/读取海龟例程中的参数 3 */ 4 #include <string> 5 #include <ros/ros.h> 6 #include <std_srvs/Empty.h> 7 8 int main(int argc, char **argv) 9 { 10 int red, green, blue; 11 12 // ROS节点初始化 13 ros::init(argc, argv, "parameter_config"); 14 15 // 创建节点句柄 16 ros::NodeHandle node; 17 18 // 读取背景颜色参数 19 ros::param::get("/background_r", red); 20 ros::param::get("/background_g", green); 21 ros::param::get("/background_b", blue); 22 23 ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue); 24 25 // 设置背景颜色参数 26 ros::param::set("/background_r", 255); 27 ros::param::set("/background_g", 255); 28 ros::param::set("/background_b", 255); 29 30 ROS_INFO("Set Backgroud Color[255, 255, 255]"); 31 32 // 读取背景颜色参数 33 ros::param::get("/background_r", red); 34 ros::param::get("/background_g", green); 35 ros::param::get("/background_b", blue); 36 37 ROS_INFO("Re-get Backgroud Color[%d, %d, %d]", red, green, blue); 38 39 // 调用服务,刷新背景颜色 40 ros::service::waitForService("/clear"); 41 ros::ServiceClient clear_background = node.serviceClient<std_srvs::Empty>("/clear"); 42 std_srvs::Empty srv; 43 clear_background.call(srv); 44 45 sleep(1); 46 47 return 0; 48 }
python代码:

1 # 该例程设置/读取海龟例程中的参数 2 3 import sys 4 import rospy 5 from std_srvs.srv import Empty 6 7 def parameter_config(): 8 # ROS节点初始化 9 rospy.init_node('parameter_config', anonymous=True) 10 11 # 读取背景颜色参数 12 red = rospy.get_param('/background_r') 13 green = rospy.get_param('/background_g') 14 blue = rospy.get_param('/background_b') 15 16 rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue) 17 18 # 设置背景颜色参数 19 rospy.set_param("/background_r", 255); 20 rospy.set_param("/background_g", 255); 21 rospy.set_param("/background_b", 255); 22 23 rospy.loginfo("Set Backgroud Color[255, 255, 255]"); 24 25 # 读取背景颜色参数 26 red = rospy.get_param('/background_r') 27 green = rospy.get_param('/background_g') 28 blue = rospy.get_param('/background_b') 29 30 rospy.loginfo("Get Backgroud Color[%d, %d, %d]", red, green, blue) 31 32 # 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service 33 rospy.wait_for_service('/clear') 34 try: 35 clear_background = rospy.ServiceProxy('/clear', Empty) 36 37 # 请求服务调用,输入请求数据 38 response = clear_background() 39 return response 40 except rospy.ServiceException, e: 41 print "Service call failed: %s"%e 42 43 if __name__ == "__main__": 44 parameter_config()
5、配置代码编译规则
如何配置CMakeLists.txt中的编译规则?
①设置需要配置的代码和生成的可执行文件
②设置链接库
CMakeLists.txt中需要添加:
add_executable(parameter_config src/parameter_config.cpp)
target_link_libraries(parameter_config ${catkin_LIBRARIES})
6、编译并且运行发布者
命令:
$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_parameter parameter_config
图示: