ROS2——参数的使用
上回说到, Organization
给每个人免费送2个汉堡, 有一天Organization
正在营业中, 汉堡突然供不应求了, 领导决定临时改变规则, 之后的每个人只能领取一个汉堡. 但是此时节点已经在运行中, 该如何改变这个值呢? 这就需要用到参数parameters
参数简介
参数是节点的配置参数值。你可以认为参数是节点配置的一部分。参数为整数,浮点数,布尔值,字符串和列表。在ROS2中,每个节点都有自己的参数。所有参数都是可动态重新配置的,并且是基于ROS2服务构建的。
在这个案例中, 每个人领取的汉堡数量就可以是Organization
节点的一个参数.
下面, 我们将修改这段服务程序, 通过修改参数来改变人均汉堡数
修改服务程序
新建Organization_with_parameter.cpp
文件
代码由Organization.cpp
修改而来, 不同的地方均使用// CHANGE:
标注出了, 请读者自行与上节代码进行对比.
#include "rclcpp/rclcpp.hpp"
#include "service_interfaces/srv/calculate.hpp"
using std::placeholders::_1;
using std::placeholders::_2;
class Organization : public rclcpp::Node
{
public:
Organization() : Node("Organization"), NumOfAll(100)
{
RCLCPP_INFO(this->get_logger(), "大家好, 我们是热心组织, 我们只给poorer发汉堡.");
callback_group_organization = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
Organization_Server = this->create_service<service_interfaces::srv::Calculate>("Calculate",
std::bind(&Organization::organization_callback,this,_1,_2),
rmw_qos_profile_services_default,
callback_group_organization);
// CHANGE: 声明参数
this->declare_parameter<int>("NumOfEachPerson", NumOfEachPerson);
}
private:
size_t NumOfAll;
// CHANGE: 声明每个人分得的汉堡数, 默认为2
int NumOfEachPerson = 2;
rclcpp::CallbackGroup::SharedPtr callback_group_organization;
rclcpp::Service<service_interfaces::srv::Calculate>::SharedPtr Organization_Server;
void organization_callback(const service_interfaces::srv::Calculate::Request::SharedPtr request,
const service_interfaces::srv::Calculate::Response::SharedPtr response)
{
if(request->status == "Poorer")
{
RCLCPP_INFO(this->get_logger(), "收到一个来自%s的请求,他家有%d个人.", request->status.c_str(), request->num_of_people);
// CHANGE: 更新参数
this->get_parameter("NumOfEachPerson", NumOfEachPerson);
// CHANGE: 计算应给汉堡数量,由参数给定
unsigned int NumOfRequired = request->num_of_people * NumOfEachPerson;
if(NumOfRequired > NumOfAll)
{
RCLCPP_INFO(this->get_logger(), "当前汉堡库里只剩%d个汉堡啦! 已经不够分了, 请明日再来.", NumOfRequired);
response->success = false;
}
else
{
NumOfAll -= NumOfRequired;
response->num_of_hamburger = NumOfRequired;
response->success = true;
RCLCPP_INFO(this->get_logger(), "成功送出%d个汉堡~ 还剩余%d个汉堡", NumOfRequired, NumOfAll);
}
}
else
{
response->success = false;
response->num_of_hamburger = 0;
RCLCPP_INFO(this->get_logger(), "收到一个非法请求,这人是个%s, 不满足送汉堡资格.", request->status.c_str());
}
}
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<Organization>();
rclcpp::executors::MultiThreadedExecutor exector;
exector.add_node(node);
exector.spin();
rclcpp::shutdown();
return 0;
}
Cmakelist.txt
添加:
add_executable(Organization_with_parameters_node src/Organization_with_parameters.cpp)
ament_target_dependencies(Organization_with_parameters_node rclcpp service_interfaces)
添加:Organization_with_parameters_node
install(TARGETS
...
Organization_with_parameters_node
DESTINATION lib/${PROJECT_NAME}
)
package.xml
不用修改
编译
--packages-select
指定编译customer_and_kfc
功能包
colcon build --packages-select poor_and_organization
刷新环境
source ~/.bashrc
运行
新建一个终端窗口, 运行带参数的Organization服务端节点
ros2 run poor_and_organization Organization_with_parameters_node
再另新建一个终端, 运行Poor客户端节点
一开始每人领取两个汉堡, 直接运行客户端:
ros2 run poor_and_organization Poor_node Poorer 5
Organization服务端: 成功发出10个汉堡
![Parameters-Organization1](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-Organization1.png)
Poor客户端: 成功领取10个汉堡
![Parameters-change-Poor1](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-change-Poor1.png)
此时需要修改参数, 另起一个终端, 运行:
ros2 param set /Organization NumOfEachPerson 1
提示如下即为成功
![Parameters-change](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-change.png)
再次运行客户端
ros2 run poor_and_organization Poor_node Poorer 50
Poor客户端: 50个人领取了50个汉堡
![Parameters-change-Poor2](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-change-Poor2.png)
Organization服务端: 成功发出50个汉堡
![Parameters-Organization2](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-Organization2.png)
由此可见, 参数成功被修改了, 但此时的参数不会被保留, 参数所在的节点重启后即恢复至初始值. 那如果一个节点的参数特别多, 修改完之后想将当前的参数保存下来供下次调用应该怎么操作呢? 请继续阅读.
参数常用命令
使用 ros2 param
查看参数列表
ros2 param list
![Parameters-ros2-param-list](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-ros2-param-list.png)
也可具体到某个节点
ros2 param list /Organization
查看参数描述
ros2 param describe /Organization NumOfEachPerson
![Parameters-ros2-param-describe-Organization-NumOfEachPerson](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-ros2-param-describe-Organization-NumOfEachPerson.png)
获取参数值
ros2 param get <node_name> <parameter_name>
ros2 param get /Organization NumOfEachPerson
![Parameters-ros2-param-get-Organization-NumOfEachPerson-2](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-ros2-param-get-Organization-NumOfEachPerson-2.png)
设置参数值
ros2 param set <node_name> <parameter_name> <value>
ros2 param set /Organization NumOfEachPerson 1
再次获取参数值, 发生了改变:
![Parameters-ros2-param-get-Organization-NumOfEachPerson-1](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-ros2-param-get-Organization-NumOfEachPerson-1.png)
保存参数
ros2 param dump <node_name>
ros2 param dump /Organization
在当前终端的根目录下, 可以看到增加了一个Organization.yaml
文件, 打开此文件
/Organization:
ros__parameters:
NumOfEachPerson: 1
use_sim_time: false
有了这个参数文件, 就可以通过这个文件设置节点的参数
加载参数
节点启动后加载参数
ros2 param load <node_name> <parameter_file>
ros2 param load /Organization ./Organization.yaml
返回如下表示加载成功:
![Parameters-ros2-param-load-Organization-Organization-yaml](https://fan-ziqi.oss-cn-beijing.aliyuncs.com/img/Parameters-ros2-param-load-Organization-Organization-yaml.png)
节点启动前加载参数
ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>
ros2 run poor_and_organization Organization_with_parameters_node --ros-args --params-file ./Organization.yaml
请读者尝试自行获取一下当前的NumOfEachPerson
值作为练习.