
面试被问ROS2的参数系统是怎么工作的你怎么在不重启节点的情况下修改参数我说用ros2 param set命令行。面试官说那在代码里怎么声明参数参数变了怎么通知节点参数文件怎么用一连串问题下来我发现自己对参数系统的了解太浅了。今天把ROS2参数服务彻底讲清楚。参数是什么参数Parameter是附加在Node上的配置值。每个Node可以声明任意数量的参数每个参数有名字、类型和值。常见的参数比如控制频率、PID参数、传感器阈值、通信超时时间。这些东西在开发阶段经常需要调整如果每次改个数值都要重新编译效率太低了。ROS2的参数系统设计得比较灵活可以在代码里声明默认值可以在launch文件里覆盖可以在命令行里修改还可以从YAML文件批量加载。声明和使用参数在Node的构造函数里声明参数class ControllerNode(Node): def __init__(self): super().__init__(controller) # 声明参数带默认值 self.declare_parameter(control_rate, 100.0) self.declare_parameter(kp, 1.5) self.declare_parameter(ki, 0.01) self.declare_parameter(kd, 0.2) self.declare_parameter(max_speed, 1.0) # 获取参数值 self.control_rate self.get_parameter(control_rate).value self.kp self.get_parameter(kp).value # 创建定时器 self.timer self.create_timer( 1.0 / self.control_rate, self.control_loop)declare_parameter的第一个参数是名字第二个是默认值。类型由默认值自动推断——100.0是floatTrue是boolhello是string。你也可以不传默认值这样参数就没有初始值必须在使用前通过外部方式设置。如果没设置就访问会抛异常。运行时修改参数这是参数系统最强大的地方。不用重启节点直接在线修改命令行方式ros2 param set /controller kp 2.0 ros2 param set /controller max_speed 0.5YAML文件方式/controller: ros__parameters: kp: 2.0 ki: 0.02 kd: 0.3 max_speed: 0.8加载命令ros2 param load /controller params.yaml修改之后节点需要重新获取参数值才能生效。上面的命令行修改后如果你还在用self.kp这个变量它的值不会自动更新。你需要注册一个参数回调self.add_on_set_parameters_callback( self.parameters_callback) def parameters_callback(self, params): result SetParametersResult() result.successful True for param in params: if param.name kp: self.kp param.value self.get_logger().info(fkp更新为: {self.kp}) elif param.name max_speed: if param.value 0 or param.value 3.0: result.successful False result.reason 速度超出安全范围 return result self.max_speed param.value return result这个回调函数有两个作用一是把新值同步到成员变量二是可以做参数校验。比如max_speed超过3.0就拒绝设置返回失败。这在安全要求高的机器人项目中非常重要。参数回调和校验参数回调的校验能力经常被忽略但它真的很实用。举个例子你的机器人有个参数是最大线速度。如果有人在运行时不小心设成了10m/s机器人可能会失控。通过参数回调你可以限制这个值的范围超出就拒绝。再比如某些参数修改后需要重新计算派生值。PID参数改了之后可能需要重新初始化积分项。这些逻辑都可以放在参数回调里。def parameters_callback(self, params): for param in params: if param.name pid: if len(param.value) ! 3: return SetParametersResult( successfulFalse, reasonPID需要三个值) self.kp, self.ki, self.kd param.value self.integral 0.0 # 重置积分项 return SetParametersResult(successfulTrue)在Launch文件中使用参数实际项目中参数通常在launch文件里设置from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( packagemy_robot, executablecontroller, namecontroller, parameters[{ control_rate: 100.0, kp: 1.5, ki: 0.01, kd: 0.2, max_speed: 1.0 }] ) ])也可以从YAML文件加载Node( packagemy_robot, executablecontroller, parameters[os.path.join( get_package_share_directory(my_robot), config, controller.yaml)] )这种方式的好处是参数和代码分离。不同场景用不同的参数文件不用改代码就能切换配置。查看和导出参数ros2 param list /controller——列出节点的所有参数。ros2 param get /controller kp——获取某个参数的当前值。ros2 param dump /controller——导出当前所有参数值格式是YAML。这个命令在调试时特别有用你把参数调到满意了dump下来保存成文件以后就能复现这个配置。面试中怎么聊面试官问参数你可以说ROS2的参数系统支持声明默认值、运行时修改、参数校验和YAML文件加载。通过declare_parameter声明参数add_on_set_parameters_callback注册回调来同步值和做校验。Launch文件可以覆盖默认参数支持字典和YAML文件两种方式。ros2 param dump可以导出当前配置方便复现和版本管理。参数管理的工程实践实际项目中参数管理比想象中复杂。当系统有几十个节点、每个节点有十几个参数时手动管理就不现实了。解决方案是用YAML文件集中管理参数在launch文件中加载。ROS2还提供了参数事件通知机制可以监听参数变化并做出响应。一个实用的技巧是把参数分为调试参数和生产参数分别维护不同的配置文件。给你的建议把你项目里的硬编码数值超时时间、阈值、增益系数全部改成参数。第一次改可能觉得麻烦但等你需要在不重启的情况下调参数的时候你会感谢自己。参数文件放到config/目录下按功能模块分文件controller.yaml、sensor.yaml、navigation.yaml。在launch文件里加载对应的配置文件。这套结构一旦搭好后续调参效率会高很多。上一篇第116篇 ROS2 Action通信——长时任务与三阶段反馈机制下一篇预告第118篇 ROS2动态重配置——运行时改变系统行为