跳转至

参数服务器

参数服务器(Parameter Server) 是 ROS 提供的一个共享数据存储机制,用于存储参数,实现不同节点之间的数据共享。例如:

  • 机器人的配置(如轮子半径、最大速度)
  • 节点的运行参数(如控制频率、阈值)

它是全局的,每个节点都可以 读取、设置、删除 参数,就像访问一个“全局字典”。

理论模型

参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:

  • ROS Master (管理者)
  • Talker (参数设置者)
  • Listener (参数调用者)

ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。

image

整个流程由以下步骤实现:

1.Talker 设置参数

Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值),ROS Master 将参数保存到参数列表中。

2.Listener 获取参数

Listener 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。

3.ROS Master 向 Listener 发送参数值

ROS Master 根据步骤2请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 Listener。


参数可使用数据类型:

  • 32-bit integers
  • booleans
  • strings
  • doubles
  • iso8601 dates
  • lists
  • base64-encoded binary data
  • 字典

注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据

常用操作

获取参数

函数:rospy.get_param(name, default=None)

作用:获取指定名称的参数值,如果该参数不存在,返回默认值。每次调用都会实时访问参数服务器,获取最新值。

speed = rospy.get_param("robot_speed", 1.0)

终端命令:

rosparam get param_name

函数:rospy.get_param_names()

作用:返回当前参数服务器上所有参数的完整列表(带路径)。

all_params = rospy.get_param_names()
print(all_params)

终端命令:

rosparam list

函数:rospy.get_param_cached(name)

作用:获取指定参数的值(缓存版本),第一次调用时访问参数服务器,之后的调用直接从本地缓存读取不会再次访问 Master,因此更快。

speed = rospy.get_param_cached("robot_speed")

终端命令:

rosparam get param_name

设置/修改参数

函数:rospy.set_param(name, value)

作用:设置或修改一个参数(会自动创建或更新)。

rospy.set_param("robot_name", "P0w3rBot")

终端命令:

rosparam set <param_name> <value>

删除参数

函数:rospy.delete_param(name)

作用:删除参数,如果不存在则抛出异常。

rospy.delete_param("robot_name")

终端命令:

rosparam delete param_name

检查参数

函数:rospy.has_param(name)

作用:判断指定参数是否存在。

if rospy.has_param("robot_speed"):
    print("参数存在")

终端命令:

rosparam get param_name   # 若不存在会报错

搜索参数

函数:rospy.search_param(key)

作用:在参数命名空间中向上查找指定参数名称,返回完整路径。

param_path = rospy.search_param("robot_speed")
# 可能返回:'/namespace1/robot_speed'

终端命令:

rosparam list | grep <relative_name>

演示

param_test.py:

#!/usr/bin/env python

import rospy

# 设置参数到ROS参数服务器
def create_param():
    rospy.set_param("robot_name", "RoboStar")                      # 设置字符串参数
    rospy.set_param("robot_speed", 1.5)                            # 设置浮点型参数
    rospy.set_param("robot_config", {"wheels": 4, "arm": True})   # 设置字典型参数
    rospy.loginfo("参数已设置...")                                # 控制台打印提示信息

# 获取参数并打印
def read_param():
    name = rospy.get_param("robot_name")                         # 获取字符串参数
    speed = rospy.get_param("robot_speed")                       # 获取浮点型参数
    config = rospy.get_param("robot_config")                     # 获取字典参数
    missing = rospy.get_param("not_exist_param", "默认值default") # 获取不存在的参数,设置默认值
    rospy.loginfo("获取参数:name=%s, speed=%.2f, config=%s, missing=%s", 
                  name, speed, config, missing)

    # 遍历 robot_config 字典参数
    rospy.loginfo("robot_config 配置如下:")
    for key, value in config.items():
        rospy.loginfo("%s: %s", key, value)

    # 使用缓存机制获取参数(第一次访问时缓存)
    speed_cached = rospy.get_param_cached("robot_speed")
    rospy.loginfo("缓存方式获取参数 robot_speed: %.2f", speed_cached)

# 更新参数,并展示缓存机制行为
def update_param():
    old_speed = rospy.get_param_cached("robot_speed")  # 注意:此时缓存的是旧值1.5
    rospy.set_param("robot_speed", 2.5)                # 更新参数为新值2.5
    new_speed = rospy.get_param("robot_speed")         # 直接获取最新值
    rospy.loginfo("更新后的robot_speed:%.2f, 缓存中的robot_speed:%.2f", new_speed, old_speed)

# 检查参数是否存在、查找完整参数名、列出所有参数
def find_param():
    if rospy.has_param("robot_name"):                                # 检查参数是否存在
        rospy.loginfo("参数 'robot_name' 存在")
    if not rospy.has_param("not_real_param"):                        # 检查一个不存在的参数
        rospy.loginfo("参数 'not_real_param' 不存在")

    full_key = rospy.search_param("robot_speed")                     # 查找 robot_speed 的完整命名空间路径
    rospy.loginfo("查找到参数 robot_speed 的完整路径: %s", full_key)

    all_params = rospy.get_param_names()                             # 获取所有参数名称
    rospy.loginfo("当前所有参数名: \n%s", "\n".join(all_params))

# 删除参数并验证删除结果
def del_param():
    rospy.delete_param("robot_name")                                 # 删除参数
    rospy.loginfo("删除参数 'robot_name'")
    if not rospy.has_param("robot_name"):                            # 验证参数已被删除
        rospy.loginfo("确认 'robot_name' 已删除")

# 主函数入口
if __name__ == "__main__":
    rospy.init_node("param_node")  # 初始化 ROS 节点,节点名为 param_node
    create_param()                 # 设置参数
    rospy.loginfo("-"*90)
    read_param()                   # 读取参数
    rospy.loginfo("-"*90)
    update_param()                 # 修改参数
    rospy.loginfo("-"*90)
    find_param()                   # 参数查询
    rospy.loginfo("-"*90)
    del_param()                    # 删除参数

image