ROS 学习记录(二)——ROS 的通信机制
文章目录
话题通信
模型
ROS 话题通信中涉及三个角色:
- ROS Master(管理者)
- Talker(发布者)
- Listener(订阅者)
话题通信由以下步骤实现:
- Talker 注册
- Listener 注册
- ROS Master 匹配已注册的 Talker 和 Listener
- Listener 向 Talker 发送请求
- Talker 确认请求
- Listener 与 Talker 建立连接
- Talker 向 Lkstener 发送消息
注意
- 通信步骤的前五步使用 RPC 协议,后两步使用 TCP 协议。
- Talker 和 Listener 启动顺序无要求。
- 一个 Talker 可以与多个 Listener 建立连接,反之亦然。
- Talker 与 Listener 建立连接后,不再需要 ROS Master。此时即使关闭 ROS Master 也不会影响通信。
C++ 实现话题通信
创建一个新的包 communication_package
,通信部分的脚本都在这个包中测试。
1catkin_create_pkg communication_package roscpp rospy std_msgs
在 communication_package/src/
下创建 topic_talker_cpp.cpp
作为 C++ 实现的 Talker:
1#include "ros/ros.h"
2#include "std_msgs/String.h"
3#include <sstream>
4
5int main(int args, char **argv)
6{
7 setlocale(LC_ALL, "");
8 ros::init(args, argv, "topic_talker_cpp"); // 初始化节点,节点名称为 topic_talker_cpp,这也是节点的唯一标识符
9 ros::NodeHandle n; // 创建节点句柄
10 ros::Publisher chatter_pub = n.advertise<std_msgs::String>("topic_chatter_cpp", 10); // 创建发布者,话题名称为 topic_chatter_cpp,最多保存 10 条消息
11
12 std_msgs::String msg; // 创建消息对象
13 std::string msg_front = "Hello from C++ talker!";
14
15 int count = 0;
16 ros::Rate loop_rate(1); // 设置循环频率为 1Hz
17
18 while (ros::ok())
19 {
20 std::stringstream ss;
21 ss << msg_front << " " << count;
22 msg.data = ss.str();
23
24 chatter_pub.publish(msg); // 发布消息
25 ROS_INFO("C++ Talker: %s", msg.data.c_str()); // 打印发布的消息内容
26 loop_rate.sleep(); // 控制循环频率
27 count++;
28 ros::spinOnce(); // 刷新 ROS 事件队列
29 }
30
31 return 0;
32}
创建 topic_listener_cpp.cpp
作为 C++ 实现的 Listener:
1#include "ros/ros.h"
2#include "std_msgs/String.h"
3
4void callback(const std_msgs::String::ConstPtr &msg_ptr) // 用 ConstPtr 指针接收消息,msg_ptr 是指向消息的指针
5{
6 ROS_INFO("C++ Listener: %s", msg_ptr->data.c_str()); // 打印消息内容;msg_ptr->data.c_str() 等价于 (*msg_ptr).data.c_str()
7}
8
9int main(int args, char **argv)
10{
11 setlocale(LC_ALL, "");
12 ros::init(args, argv, "topic_listener_cpp");
13 ros::NodeHandle n;
14 ros::Subscriber chatter_sub = n.subscribe("topic_chatter_cpp", 10, callback); // 订阅话题,话题名为 "topic_chatter_py",消息队列长度为 10
15
16 ros::spin(); // 阻塞,等待回调函数 callback 执行完毕
17 return 0;
18}
在 CMakeLists.txt
中添加编译目标:
1add_executable(topic_talker_cpp_node src/topic_talker_cpp.cpp)
2add_executable(topic_listener_cpp_node src/topic_listener_cpp.cpp)
3
4target_link_libraries(topic_talker_cpp_node
5 ${catkin_LIBRARIES}
6)
7target_link_libraries(topic_listener_cpp_node
8 ${catkin_LIBRARIES}
9)
配置 topic_communication.launch
文件:
1<launch>
2 <!-- C++ nodes -->
3 <node pkg="communication_package" type="topic_talker_cpp_node" name="topic_talker_cpp"
4 output="screen" />
5 <node pkg="communication_package" type="topic_listener_cpp_node" name="topic_listener_cpp"
6 output="screen" />
7</launch>
roslauunch communication_package topic_communication.launch
启动节点。
Python 实现话题通信
创建 scripts/topic_talker_py.py
:
1import rospy
2from std_msgs.msg import String
3
4
5def main():
6 rospy.init_node("topic_talker_py") # 初始化节点
7 chatter_pub = rospy.Publisher(
8 "topic_chatter_py", String, queue_size=10
9 ) # 创建发布者对象
10
11 msg = String() # 创建消息对象
12 msg_front = "Hello from Python talker!"
13
14 count = 0
15 loop_rate = rospy.Rate(1) # 设置循环频率为 1Hz
16
17 while not rospy.is_shutdown():
18 msg.data = msg_front + " " + str(count)
19
20 chatter_pub.publish(msg) # 发布消息
21 rospy.loginfo("Python Talker: " + msg.data)
22 loop_rate.sleep() # 控制循环频率
23 count += 1
24
25
26if __name__ == "__main__":
27 main()
创建 scripts/topic_listener_py.py
:
1import rospy
2from std_msgs.msg import String
3
4
5def callback(msg):
6 rospy.loginfo("Python Listener: " + msg.data)
7
8
9def main():
10 rospy.init_node("topic_listener_py") # 初始化节点
11 sub = rospy.Subscriber(
12 "topic_chatter_py", String, callback=callback, queue_size=10
13 ) # 创建订阅者对象并注册回调函数
14 rospy.spin() # 保持节点运行,直到节点关闭
15
16
17if __name__ == "__main__":
18 main()
编辑 CMakeLists.txt
:
1catkin_install_python(PROGRAMS
2 scripts/topic_listener_py.py
3 scripts/topic_talker_py.py
4 DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
5)
配置 topic_communication.launch
:
1<launch>
2 <!-- C++ nodes -->
3 <node pkg="communication_package" type="topic_talker_cpp_node" name="topic_talker_cpp"
4 output="screen" />
5 <node pkg="communication_package" type="topic_listener_cpp_node" name="topic_listener_cpp"
6 output="screen" />
7
8 <!-- Python nodes -->
9 <node pkg="communication_package" type="topic_talker_py.py" name="topic_talker_py"
10 output="screen" />
11 <node pkg="communication_package" type="topic_listener_py.py" name="topic_listener_py"
12 output="screen" />
13</launch>
自定义消息类型
ROS 给出的消息类型一般都比较简单,所以有时我们需要自定义消息类型。假设我们想创建一个 Person
类型,这个类型包含字符串 name
、整型 age
和布尔型 gender
。
在包下创建 msg/Person.msg
文件:
1cd communication_package
2mkdir msg
3touch msg/Person.msg
编辑 msg/Person.msg
文件:
1string name
2int32 age
3bool gender
在 package.xml
中添加编译依赖和执行依赖:
1<build_depend>message_generation</build_depend>
2<exec_depend>message_runtime</exec_depend>
在 CMakeLists.txt
中添加编译目标:
1find_package(catkin REQUIRED COMPONENTS
2 roscpp
3 rospy
4 std_msgs
5 message_generation # 添加 message_generation 依赖
6)
7
8add_message_files(
9 FILES
10 Person.msg # 添加 Person.msg 自定义消息
11)
12
13generate_messages( # 生成自定义消息类型
14 DEPENDENCIES
15 std_msgs
16)
17
18catkin_package(
19# INCLUDE_DIRS include
20# LIBRARIES communication_package
21 CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # 添加执行时依赖
22# DEPENDS system_lib
23)
此时可以先按 Ctrl
+Shift
+B
编译消息文件,编译完成后,在 ros-project/devel/lib/communication_package/
目录下会出现 Person.h
文件,在 devel/lib/python3/dist-packages/communication_package/msg/
目录下会出现 _Person.py
文件,这两个就是编译后的自定义消息所在文件,后续写代码时可以直接使用。
C++ 调用自定义消息类型
发布方代码:
1#include "ros/ros.h"
2#include "communication_package/Person.h"
3
4int main(int argc, char **argv)
5{
6 setlocale(LC_ALL, "");
7 ros::init(argc, argv, "person_talker_cpp");
8 ros::NodeHandle n;
9 ros::Publisher person_pub = n.advertise<communication_package::Person>("person_chatter_cpp", 10);
10
11 communication_package::Person person;
12 person.name = "John Doe";
13 person.age = 13;
14 person.gender = true;
15
16 ros::Rate loop_rate(1);
17 ros::Duration(3.0).sleep(); // 等待订阅者连接,否则订阅者有可能无法收到发出的第一条消息
18 while (ros::ok())
19 {
20 person_pub.publish(person);
21 person.age++;
22 loop_rate.sleep();
23 ros::spinOnce();
24 }
25
26 return 0;
27}
订阅方代码:
1#include "ros/ros.h"
2#include "communication_package/Person.h"
3
4void callback(const communication_package::Person::ConstPtr &msg_ptr)
5{
6 ROS_INFO("Name: %s, Age: %d, Gender: %s from C++", msg_ptr->name.c_str(), msg_ptr->age, msg_ptr->gender ? "Male" : "Female");
7}
8
9int main(int argc, char **argv)
10{
11 setlocale(LC_ALL, "");
12 ros::init(argc, argv, "person_listener_cpp");
13 ros::NodeHandle n;
14 ros::Subscriber person_sub = n.subscribe("person_chatter_cpp", 10, callback);
15 ros::spin();
16 return 0;
17}
配置 CMakeLists.txt
1add_executable(person_talker_node src/person_talker_cpp.cpp)
2add_executable(person_listener_node src/person_listener_cpp.cpp)
3
4add_dependencies(person_talker_node ${PROJECT_NAME}_generate_messages_cpp)
5add_dependencies(person_listener_node ${PROJECT_NAME}_generate_messages_cpp)
6
7target_link_libraries(person_talker_node
8 ${catkin_LIBRARIES}
9)
10target_link_libraries(person_listener_node
11 ${catkin_LIBRARIES}
12)
顺序不能变!
配置 person_communication.launch
:
1<launch>
2 <!-- C++ nodes -->
3 <node pkg="communication_package" type="person_talker_node" name="person_talker_cpp"
4 output="screen" />
5 <node pkg="communication_package" type="person_listener_node" name="person_listener_cpp"
6 output="screen" />
7</launch>
使用 roslaunch communication_package topic_communication.launch
运行节点。
Python 调用自定义消息类型
发布方代码:
1import rospy
2from communication_package.msg import Person
3
4
5def main():
6 rospy.init_node("person_talker_py")
7 person_pub = rospy.Publisher("person_chatter_py", Person, queue_size=10)
8
9 person = Person()
10 person.name = "Jane Doe"
11 person.age = 13
12 person.gender = False
13
14 loop_rate = rospy.Rate(1)
15 rospy.sleep(rospy.Duration(3, 0)) # 等待订阅者连接
16 while not rospy.is_shutdown():
17 person_pub.publish(person)
18 person.age += 1
19 loop_rate.sleep()
20
21
22if __name__ == "__main__":
23 main()
订阅方代码:
1import rospy
2from communication_package.msg import Person
3
4
5def callback(msg):
6 rospy.loginfo(
7 "Name: %s, Age: %d, Gender: %s from Python",
8 msg.name,
9 msg.age,
10 "Male" if msg.gender else "Female",
11 )
12
13
14def main():
15 rospy.init_node("person_listener_py")
16 person_sub = rospy.Subscriber("person_chatter_py", Person, callback, queue_size=10)
17 rospy.spin()
18
19
20if __name__ == "__main__":
21 main()
配置 CMakeLists.txt
:
1catkin_install_python(PROGRAMS
2 scripts/person_listener_py.py
3 scripts/person_talker_py.py
4 DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
5)
配置 person_communication.launch
:
1<launch>
2 <!-- C++ nodes -->
3 <node pkg="communication_package" type="person_talker_node" name="person_talker_cpp"
4 output="screen" />
5 <node pkg="communication_package" type="person_listener_node" name="person_listener_cpp"
6 output="screen" />
7
8 <!-- Python nodes -->
9 <node pkg="communication_package" type="person_talker_py.py" name="person_talker_py"
10 output="screen" />
11 <node pkg="communication_package" type="person_listener_py.py" name="person_listener_py"
12 output="screen" />
13</launch>
使用 roslaunch communication_package person_communication.launch
运行节点。
服务通信
模型
ROS 服务通信中同样涉及三个角色:
- ROS Master(管理者)
- Server(服务端)
- Client(客户端)
服务通信由以下步骤实现:
- Server 注册
- Client 注册
- ROS Master 匹配已注册的 Server 和 Client
- Client 向 Server 发送请求
- Server 向 Client 发送响应
注意
- 客户端请求被处理时,需要确保服务端已经注册。
- 一个服务端可以匹配多个客户端,反之亦然。
自定义服务类型
在包目录下创建 srv
目录并且创建 Division.srv
:
1cd communication_package
2mkdir srv
3touch srv/Division.srv
编辑 srv/Division.srv
文件:
1float64 numerator
2float64 denominator
3---
4float64 result
自定义服务中,---
前是客户端请求的消息类型,---
后是服务端响应的消息类型。
在 package.xml
中添加编译依赖和执行依赖:
1<build_depend>message_generation</build_depend>
2<exec_depend>message_runtime</exec_depend>
在 CMakeLists.txt
中添加编译目标:
1find_package(catkin REQUIRED COMPONENTS
2 roscpp
3 rospy
4 std_msgs
5 message_generation
6)
7
8add_service_files(
9 FILES
10 Division.srv # 添加 Division.srv 服务类型
11)
12
13generate_messages( # 生成自定义消息类型
14 DEPENDENCIES
15 std_msgs
16)
现在编译服务类型。编译完成后,在 devel/include/communication_package/
目录下会出现 Division.h
DivisionRequest.h
DivisionResponse.h
三个文件,在 devel/lib/python3/dist-packages/communication_package/srv/
目录下会出现 _Division.py
文件。
C++ 实现服务通信
服务端代码:
1#include "ros/ros.h"
2#include "communication_package/Division.h"
3
4bool do_request(communication_package::Division::Request &req, communication_package::Division::Response &res)
5{
6 double numerator = req.numerator, denominator = req.denominator;
7 ROS_INFO("Received numerator: %f, denominator: %f", numerator, denominator);
8
9 if (denominator == 0.0) // 业务逻辑
10 {
11 ROS_ERROR("Denominator cannot be zero");
12 return false;
13 }
14
15 double result = numerator / denominator;
16 res.result = result;
17 ROS_INFO("Sending result: %f", result);
18 return true;
19}
20
21int main(int argc, char **argv)
22{
23 setlocale(LC_ALL, "");
24 ros::init(argc, argv, "division_server_cpp");
25 ros::NodeHandle n;
26 ros::ServiceServer server = n.advertiseService("division_service_cpp", do_request); // 创建服务器对象
27 ROS_INFO("Starting division service from C++");
28 ros::spin();
29 return 0;
30}
客户端代码:
1#include "ros/ros.h"
2#include "communication_package/Division.h"
3
4int main(int argc, char **argv)
5{
6 setlocale(LC_ALL, "");
7 ros::init(argc, argv, "division_client_cpp");
8 ros::NodeHandle n;
9 ros::ServiceClient client = n.serviceClient<communication_package::Division>("division_service_cpp");
10 client.waitForExistence(); // 等待服务端启动
11
12 communication_package::Division div_srv; // 创建服务对象,包含请求和响应
13 ros::Rate loop_rate(1); // 设置循环频率
14
15 for (int i = 3; i >= 0; i--)
16 {
17 div_srv.request.numerator = 10.0; // 设置请求参数
18 div_srv.request.denominator = double(i);
19
20 bool flag = client.call(div_srv); // 调用服务
21 if (flag)
22 {
23 ROS_INFO("Result: %f", div_srv.response.result);
24 }
25 else
26 {
27 ROS_ERROR("Failed to call service");
28 }
29 loop_rate.sleep(); // 控制循环频率
30 }
31}
CmakeLists.txt
和 service_communication.launch
文件与之前相同。
Python 实现服务通信
服务端代码:
1import rospy
2from communication_package.srv import Division, DivisionRequest, DivisionResponse
3
4
5def do_request(req): # 与 C++ 中不同,这里的回调函数的参数是请求对象,返回值是响应对象
6 rospy.loginfo(
7 "Received numerator: %f, denominator: %f", req.numerator, req.denominator
8 )
9
10 if req.denominator == 0:
11 rospy.logerr("Denominator cannot be zero")
12 return DivisionResponse(result=float("nan"))
13
14 result = req.numerator / req.denominator
15 res = DivisionResponse(result=result)
16 rospy.loginfo("Sending result: %f", result)
17 return res
18
19
20def main():
21 rospy.init_node("division_server_py")
22 server = rospy.Service("division_service_py", Division, handler=do_request)
23 rospy.spin()
24
25
26if __name__ == "__main__":
27 main()
客户端代码:
1import rospy
2from communication_package.srv import Division, DivisionRequest, DivisionResponse
3
4
5def main():
6 rospy.init_node("division_client_py")
7 client = rospy.ServiceProxy("division_service_py", Division) # 创建客户端
8 client.wait_for_service() # 等待服务端启动
9
10 req = DivisionRequest() # 创建请求对象
11 loop_rate = rospy.Rate(1)
12
13 for i in range(4)[::-1]:
14 req.numerator = 10.0
15 req.denominator = i
16
17 res = client.call(req) # 调用服务端
18 if res.result != res.result: # 判断返回值是否为 nan
19 rospy.logerr("Failed to call service")
20 else:
21 rospy.loginfo("Result: %f", res.result)
22 loop_rate.sleep()
23
24
25if __name__ == "__main__":
26 main()
跨语言支持
不难发现,C++ 服务端的回调函数返回布尔值,而 Python 服务端的回调函数返回响应对象。C++ 服务端的返回值只是为了确认服务是否执行成功,而并非真正的响应。在 Python 的服务端中,如果服务调用成功,则会自动返回一个 True
。为了实现跨语言支持,我们在服务文件的响应部分添加 success
字段用于表示请求是否成功。略微修改服务端代码,确保不同语言的客户端都能正常调用服务。
C++ 客户端:
1#include "ros/ros.h"
2#include "communication_package/Division.h"
3
4bool do_request(communication_package::Division::Request &req, communication_package::Division::Response &res)
5{
6 double numerator = req.numerator, denominator = req.denominator;
7 ROS_INFO("Received numerator: %f, denominator: %f", numerator, denominator);
8
9 if (denominator == 0.0)
10 {
11 ROS_ERROR("Denominator cannot be zero");
12 res.success = false; // 响应中添加 success 字段
13 }
14 else
15 {
16 double result = numerator / denominator;
17 res.success = true;
18 res.result = result;
19 ROS_INFO("Sending result: %f", result);
20 }
21
22 return true; // 返回值为 true 代表服务调用成功
23}
24
25int main(int argc, char **argv)
26{
27 setlocale(LC_ALL, "");
28 ros::init(argc, argv, "division_server_cpp");
29 ros::NodeHandle n;
30 ros::ServiceServer server = n.advertiseService("division_service_cpp", do_request);
31 ROS_INFO("Starting division service from C++");
32 ros::spin();
33 return 0;
34}
Python 客户端:
1import rospy
2from communication_package.srv import Division, DivisionRequest, DivisionResponse
3
4
5def main():
6 rospy.init_node("division_client_py")
7 client = rospy.ServiceProxy("division_service_cpp", Division) # 连接 C++ 服务端
8 client.wait_for_service()
9
10 req = DivisionRequest()
11 loop_rate = rospy.Rate(1)
12
13 for i in range(4)[::-1]:
14 req.numerator = 10.0
15 req.denominator = i
16
17 res = client.call(req)
18 if res.success: # 判断 success 字段
19 rospy.loginfo("Result: %f", res.result)
20 else:
21 rospy.logerr("Failed to call service")
22 loop_rate.sleep()
23
24
25if __name__ == "__main__":
26 main()
Python 服务端:
1import rospy
2from communication_package.srv import Division, DivisionRequest, DivisionResponse
3
4
5def do_request(req):
6 rospy.loginfo(
7 "Received numerator: %f, denominator: %f", req.numerator, req.denominator
8 )
9
10 if req.denominator == 0:
11 rospy.logerr("Denominator cannot be zero")
12 return DivisionResponse(success=False)
13
14 result = req.numerator / req.denominator
15 res = DivisionResponse(success=True, result=result)
16 rospy.loginfo("Sending result: %f", result)
17 return res
18
19
20def main():
21 rospy.init_node("division_server_py")
22 server = rospy.Service("division_service_py", Division, handler=do_request)
23 rospy.spin()
24
25
26if __name__ == "__main__":
27 main()
C++ 客户端:
1#include "ros/ros.h"
2#include "communication_package/Division.h"
3
4int main(int argc, char **argv)
5{
6 setlocale(LC_ALL, "");
7 ros::init(argc, argv, "division_client_cpp");
8 ros::NodeHandle n;
9 ros::ServiceClient client = n.serviceClient<communication_package::Division>("division_service_py");
10 client.waitForExistence();
11
12 communication_package::Division div_srv;
13 ros::Rate loop_rate(1);
14
15 for (int i = 3; i >= 0; i--)
16 {
17 div_srv.request.numerator = 10.0;
18 div_srv.request.denominator = double(i);
19
20 if (client.call(div_srv) && div_srv.response.success) // 同时满足服务调用成功且服务端返回 success 字段为 true
21 {
22 ROS_INFO("Result: %f", div_srv.response.result);
23 }
24 else
25 {
26 ROS_ERROR("Failed to call service");
27 }
28 loop_rate.sleep();
29 }
30}
参数服务器
模型
ROS 参数服务器中涉及三个角色:
- ROS Master(管理者)
- Talker(参数设置者)
- Listener(参数调用者)
话题通信由以下步骤实现:
- Talker 设置参数
- Listener 获取参数
- ROS Master 向 Listener 发送参数值
C++ 实现参数服务器
写入参数:
1#include "ros/ros.h"
2
3int main(int argc, char **argv)
4{
5 setlocale(LC_ALL, "");
6 ros::init(argc, argv, "paramset_cpp");
7 ros::NodeHandle n;
8
9 // 写入参数
10 n.setParam("name", "John Doe");
11 n.setParam("age", 13);
12 n.setParam("gender", "Male");
13
14 ros::Duration(3.0).sleep();
15
16 // 删除参数
17 n.deleteParam("name");
18 n.deleteParam("age");
19 n.deleteParam("gender");
20
21 return 0;
22}
读取参数:
1#include "ros/ros.h"
2#include <string>
3
4using namespace std;
5
6int main(int argc, char **argv)
7{
8 setlocale(LC_ALL, "");
9 ros::init(argc, argv, "paramget_cpp");
10 ros::NodeHandle n;
11
12 ros::Duration(1.0).sleep();
13 string name, gender;
14 int age;
15 // 读取参数
16 n.getParam("name", name);
17 n.getParam("age", age);
18 n.getParam("gender", gender);
19 ROS_INFO("Name: %s, Age: %d, Gender: %s", name.c_str(), age, gender.c_str());
20
21 ros::Duration(3.0).sleep();
22 if (n.getParam("name", name) && n.getParam("age", age) && n.getParam("gender", gender))
23 {
24 ROS_INFO("Name: %s, Age: %d, Gender: %s", name.c_str(), age, gender.c_str());
25 }
26 else
27 {
28 ROS_ERROR("Failed to get parameters");
29 }
30 return 0;
31}
Python 实现参数服务器
写入参数:
1import rospy
2
3
4def main():
5 rospy.init_node("paramset_py")
6 rospy.set_param("name", "Jane Doe")
7 rospy.set_param("age", 13)
8 rospy.set_param("gender", "Female")
9
10 rospy.sleep(rospy.Duration(3))
11
12 rospy.delete_param("name")
13 rospy.delete_param("age")
14 rospy.delete_param("gender")
15
16
17if __name__ == "__main__":
18 main()
读取参数:
1import rospy
2
3
4def main():
5 rospy.init_node("paramget_py")
6
7 rospy.sleep(rospy.Duration(1))
8 name = rospy.get_param("name")
9 age = rospy.get_param("age")
10 gender = rospy.get_param("gender")
11
12 rospy.loginfo("Name: %s, Age: %d, Gender: %s", name, age, gender)
13
14 rospy.sleep(rospy.Duration(3))
15 # 如果参数不存在,则返回默认值,此处设置为 None
16 name = rospy.get_param("name", None)
17 age = rospy.get_param("age", None)
18 gender = rospy.get_param("gender", None)
19 if name and age and gender:
20 rospy.loginfo("Name: %s, Age: %d, Gender: %s", name, age, gender)
21 else:
22 rospy.logerr("Failed to get parameters")
23
24
25if __name__ == "__main__":
26 main()
launch 文件配置参数
除了在节点中动态设置参数,在 launch 文件中也可以静态配置参数,例如使用下面的 launch 文件配置参数:
1<launch>
2 <!-- C++ nodes -->
3 <!-- <node pkg="communication_package" type="paramset_node" name="paramset_cpp"
4 output="screen" /> -->
5 <node pkg="communication_package" type="paramget_node" name="paramget_cpp"
6 output="screen" />
7
8 <!-- Python nodes -->
9 <!-- <node pkg="communication_package" type="paramset_py.py" name="paramset_py"
10 output="screen" /> -->
11 <node pkg="communication_package" type="paramget_py.py" name="paramget_py"
12 output="screen" />
13
14 <param name="name" type="string" value="jackgdn" />
15 <param name="age" type="int" value="20" />
16 <param name="gender" type="string" value="Male" />
17
18</launch>
如果参数很多,可以将参数放在一个参数文件中,例如 ros-project/src/communication_package/config/Person.yaml
:
1name: "jackgdn"
2age: 20
3gender: "Male"
然后修改 param_server.launch
文件:
1<launch>
2 <!-- C++ nodes -->
3 <!-- <node pkg="communication_package" type="paramset_node" name="paramset_cpp"
4 output="screen" /> -->
5 <node pkg="communication_package" type="paramget_node" name="paramget_cpp"
6 output="screen" />
7
8 <!-- Python nodes -->
9 <!-- <node pkg="communication_package" type="paramset_py.py" name="paramset_py"
10 output="screen" /> -->
11 <node pkg="communication_package" type="paramget_py.py" name="paramget_py"
12 output="screen" />
13
14 <!-- <param name="name" type="string" value="jackgdn" />
15 <param name="age" type="int" value="20" />
16 <param name="gender" type="string" value="Male" /> -->
17
18 <rosparam file="$(find communication_package)/config/Person.yaml" command="load" />
19
20</launch>
这样,参数就能被加载到参数服务器中。