
参数(Parameter)是ROS2中用于动态配置节点行为的键值对(Key-Value),支持运行时修改,无需重新编译代码。其核心特点包括:
动态性:可在节点运行时查询、修改,实时生效。类型安全:支持整数、浮点数、布尔值、字符串、数组等类型。节点私有性:默认归属于某个节点,通过命名空间隔离。持久性:可配置为持久化存储,节点重启后保留参数值。参数广泛应用于机器人系统的动态配置,如调整PID控制器参数、设置传感器采样频率、配置路径规划阈值等。
参数操作依赖ROS2 C++核心库
rclcpp和参数接口库
rclcpp_components,创建功能包:
ros2 pkg create cpp_parameter_demo --build-type ament_cmake --dependencies rclcpp rclcpp_components
在节点构造函数中,通过
declare_parameter方法声明参数(指定名称、默认值和类型):
#include "rclcpp/rclcpp.hpp"
class ParamDemoNode : public rclcpp::Node {
public:
ParamDemoNode() : Node("param_demo_node") {
// 声明参数:名称、默认值(自动推断类型)
this->declare_parameter("max_speed", 0.5); // 浮点型(m/s)
this->declare_parameter("use_safety_mode", true); // 布尔型
this->declare_parameter("robot_name", "turtlebot3"); // 字符串
this->declare_parameter("target_positions", std::vector<double>{1.0, 2.0, 3.0}); // 浮点数组
RCLCPP_INFO(this->get_logger(), "参数节点初始化完成");
}
通过
get_parameter方法获取参数当前值,支持显式类型转换:
private:
void print_parameters() {
// 方法1:通过get_parameter获取Parameter对象
rclcpp::Parameter max_speed_param = this->get_parameter("max_speed");
double max_speed = max_speed_param.as_double(); // 显式转换类型
// 方法2:直接获取值(推荐,简洁)
bool use_safety = this->get_parameter("use_safety_mode").as_bool();
std::string robot_name = this->get_parameter("robot_name").as_string();
std::vector<double> targets = this->get_parameter("target_positions").as_double_array();
// 打印参数值
RCLCPP_INFO(this->get_logger(), "当前参数:");
RCLCPP_INFO(this->get_logger(), "max_speed: %.2f m/s", max_speed);
RCLCPP_INFO(this->get_logger(), "use_safety_mode: %s", use_safety ? "true" : "false");
RCLCPP_INFO(this->get_logger(), "robot_name: %s", robot_name.c_str());
RCLCPP_INFO(this->get_logger(), "target_positions: [%.1f, %.1f, %.1f]",
targets[0], targets[1], targets[2]);
}
通过
set_parameter或
set_parameters方法在代码中修改参数:
void update_parameters() {
// 单个参数修改
this->set_parameter(rclcpp::Parameter("max_speed", 0.8));
// 批量修改参数
std::vector<rclcpp::Parameter> new_params;
new_params.emplace_back("use_safety_mode", false);
new_params.emplace_back("robot_name", "my_robot");
this->set_parameters(new_params);
RCLCPP_INFO(this->get_logger(), "参数已主动更新");
print_parameters(); // 打印更新后的值
}
当参数被外部修改时,通过回调函数验证并响应(书中第4章重点内容):
public:
ParamDemoNode() : Node("param_demo_node") {
// ... 省略参数声明 ...
// 设置参数变化回调
param_callback_handle_ = this->add_on_set_parameters_callback(
std::bind(&ParamDemoNode::on_parameter_change, this, std::placeholders::_1)
);
}
private:
// 参数变化回调函数(返回修改结果)
rcl_interfaces::msg::SetParametersResult on_parameter_change(
const std::vector<rclcpp::Parameter> ¶ms) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true; // 默认修改成功
for (const auto ¶m : params) {
// 验证max_speed参数(必须非负)
if (param.get_name() == "max_speed") {
if (param.as_double() < 0) {
result.successful = false;
result.reason = "max_speed不能为负数";
RCLCPP_ERROR(this->get_logger(), "参数修改失败: %s", result.reason.c_str());
return result; // 一旦失败,终止所有修改(原子性)
}
RCLCPP_INFO(this->get_logger(), "max_speed更新为: %.2f", param.as_double());
}
// 处理use_safety_mode参数
if (param.get_name() == "use_safety_mode") {
RCLCPP_INFO(this->get_logger(), "use_safety_mode更新为: %s",
param.as_bool() ? "true" : "false");
}
}
return result;
}
// 回调句柄(需保持生命周期)
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr param_callback_handle_;
添加节点编译规则:
add_executable(param_node src/param_node.cpp)
ament_target_dependencies(param_node
rclcpp
rclcpp_components
)
install(TARGETS
param_node
DESTINATION lib/${PROJECT_NAME}
)
colcon build --packages-select cpp_parameter_demo
source install/setup.bash
ros2 run cpp_parameter_demo param_node
通过
ros2 param工具直接操作参数:
| 命令 | 功能 | 示例 |
|---|---|---|
ros2 param list | 列出节点参数 |
ros2 param list /param_demo_node |
ros2 param get | 获取参数值 |
ros2 param get /param_demo_node max_speed |
ros2 param set | 修改参数值 |
ros2 param set /param_demo_node max_speed 0.6 |
ros2 param dump | 导出参数到文件 |
ros2 param dump /param_demo_node > params.yaml |
ros2 param load | 从文件加载参数 |
ros2 param load /param_demo_node params.yaml |
通过YAML文件批量配置参数,启动时加载:
params.yaml)
/param_demo_node: # 节点名称(需与实际节点名一致)
ros__parameters:
max_speed: 0.7
use_safety_mode: true
robot_name: "demo_robot"
target_positions: [4.0, 5.0, 6.0]
ros2 run cpp_parameter_demo param_node --ros-args --params-file ./params.yaml
声明参数时可添加描述、只读属性和验证规则:
// 带元数据的参数声明
this->declare_parameter(
"sample_rate", // 名称
10.0, // 默认值
rclcpp::ParameterDescriptor() // 元数据
.set_description("传感器采样频率(Hz)") // 描述
.set_read_only(false) // 是否只读
.set_range(rclcpp::ParameterRange::from_double(1.0, 100.0)) // 范围约束
);
通过
ros2 param dump导出参数后,下次启动时加载可实现持久化:
# 导出参数
ros2 param dump /param_demo_node > ~/.ros/param_demo_params.yaml
# 启动时加载(持久化生效)
ros2 run cpp_parameter_demo param_node --ros-args --params-file ~/.ros/param_demo_params.yaml
ROS2中每个节点默认提供参数服务接口,跨节点修改参数本质是:通过
SetParameters服务向目标节点发送修改请求。相关服务信息:
/目标节点名/set_parameters服务类型:
rcl_interfaces/srv/SetParameters通信模式:客户端-服务端模式,支持同步/异步调用
param_demo_node(提供参数服务,被修改方)。控制节点:
param_controller_node(创建客户端,发起修改请求)。
#include "rclcpp/rclcpp.hpp"
#include "rcl_interfaces/srv/set_parameters.hpp"
#include "rcl_interfaces/msg/parameter.hpp"
#include "rcl_interfaces/msg/parameter_value.hpp"
class ParamControllerNode : public rclcpp::Node {
public:
ParamControllerNode() : Node("param_controller_node") {
// 目标节点名称
std::string target_node = "param_demo_node";
// 创建SetParameters服务客户端
client_ = this->create_client<rcl_interfaces::srv::SetParameters>(
"/" + target_node + "/set_parameters"
);
// 等待服务可用(超时5秒)
while (!client_->wait_for_service(std::chrono::seconds(5))) {
if (!rclcpp::ok()) {
RCLCPP_ERROR(this->get_logger(), "客户端被中断");
return;
}
RCLCPP_INFO(this->get_logger(), "等待目标节点参数服务...");
}
RCLCPP_INFO(this->get_logger(), "参数控制节点启动完成");
// 定时发送修改请求(每8秒一次)
timer_ = this->create_wall_timer(
std::chrono::seconds(8),
std::bind(&ParamControllerNode::send_param_request, this)
);
}
private:
// 发送参数修改请求
void send_param_request() {
// 创建请求消息
auto request = std::make_shared<rcl_interfaces::srv::SetParameters::Request>();
// 添加要修改的参数(支持多个)
rcl_interfaces::msg::Parameter max_speed_param;
max_speed_param.name = "max_speed";
max_speed_param.value.type = rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE;
max_speed_param.value.double_value = 0.9; // 新值
request->parameters.push_back(max_speed_param);
rcl_interfaces::msg::Parameter safety_param;
safety_param.name = "use_safety_mode";
safety_param.value.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
safety_param.value.bool_value = true; // 新值
request->parameters.push_back(safety_param);
// 异步发送请求(非阻塞)
auto result_future = client_->async_send_request(
request,
std::bind(&ParamControllerNode::response_callback, this, std::placeholders::_1)
);
}
// 处理服务响应
void response_callback(rclcpp::Client<rcl_interfaces::srv::SetParameters>::SharedFuture future) {
auto response = future.get();
if (response->results[0].successful) {
RCLCPP_INFO(this->get_logger(), "参数修改成功");
} else {
RCLCPP_ERROR(this->get_logger(), "参数修改失败: %s", response->results[0].reason.c_str());
}
}
// 成员变量
rclcpp::Client<rcl_interfaces::srv::SetParameters>::SharedPtr client_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char * argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ParamControllerNode>());
rclcpp::shutdown();
return 0;
}
目标节点无需额外配置,只需确保参数已声明且回调正常工作(同前文“参数回调”部分)。
在
CMakeLists.txt中添加控制节点编译规则:
add_executable(param_controller src/param_controller.cpp)
ament_target_dependencies(param_controller
rclcpp
rcl_interfaces
)
install(TARGETS
param_node
param_controller
DESTINATION lib/${PROJECT_NAME}
)
运行节点验证:
# 终端1:启动目标节点
ros2 run cpp_parameter_demo param_node
# 终端2:启动控制节点
ros2 run cpp_parameter_demo param_controller
通过
GetParameters服务查询目标节点参数:
#include "rcl_interfaces/srv/get_parameters.hpp"
void get_remote_parameters() {
auto client = this->create_client<rcl_interfaces::srv::GetParameters>(
"/param_demo_node/get_parameters"
);
auto request = std::make_shared<rcl_interfaces::srv::GetParameters::Request>();
request->names = {"max_speed", "use_safety_mode"}; // 要查询的参数名
auto future = client->async_send_request(request);
future.wait(); // 同步等待结果
auto response = future.get();
RCLCPP_INFO(this->get_logger(), "查询到max_speed: %.2f",
response->values[0].double_value);
RCLCPP_INFO(this->get_logger(), "查询到use_safety_mode: %s",
response->values[1].bool_value ? "true" : "false");
}
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 参数获取失败(返回默认值) | 未声明参数;参数名称拼写错误 | 确保
declare_parameter在
get_parameter之前调用;检查名称拼写 |
| 回调函数不触发 | 未保存回调句柄;参数修改方式错误 | 用成员变量保存
OnSetParametersCallbackHandle;通过服务或
ros2 param set修改参数 |
| 跨节点修改提示“服务不可用” | 目标节点未启动;服务名称错误(含命名空间) | 确认目标节点已启动;用
ros2 service list检查服务名称 |
| 参数修改被拒绝 | 目标节点回调返回
successful=false | 检查目标节点参数约束(如范围、类型);修改符合规则的参数值 |
| 批量修改部分生效 | 误解原子性:批量修改要么全成功,要么全失败 | 确保所有参数通过验证;避免在回调中部分处理参数 |
| YAML文件加载失败 | 格式错误(如缩进、类型不匹配) | 检查YAML语法;确保参数类型与声明一致(如字符串加引号) |
C++设置ROS2参数的核心流程包括:
声明参数:在节点构造函数中用
declare_parameter定义参数及默认值。获取参数:通过
get_parameter获取值,用于业务逻辑。监听变化:用
add_on_set_parameters_callback实现参数修改后的验证与响应。外部交互:通过命令行、YAML文件或跨节点服务修改参数。
跨节点修改参数基于
SetParameters服务实现,控制节点通过客户端发送请求,目标节点通过回调验证修改。这一机制在多节点协作场景(如远程调参、自适应控制)中至关重要。结合参数约束、持久化等特性,可构建灵活、健壮的机器人系统。