一个程序运行时,通常需要获取配置一些和运行环境相关的参数,如一个摄像头。那么除了在编译时就让程序自动获取对应参数,或是硬编码参数以外,就需要在运行时获取对应的参数。通常,公认的参数获取方法包括:

  • 通过图形或者是命令行界面和用户直接发起交互
  • 使用命令行参数,比如ls -l中的-l或是cmake --build build中的--build build
  • 从环境变量获取参数,比如使用wget时会参考https_proxy变量
  • 从配置文件获取参数,比如 .bashrc/.profile 等

选择使用哪种参数获取方式取决于软件的使用场景,比如 systemd 不由用户主动启动,而启动的环境也由系统指定,因此只能从配置文件中获取参数。而需要用户输入密码的程序为了安全,一般不会存储密码,需要通过用户交互获取参数。而没有特殊要求的程序通常会结合多种来源的参数,比如 CMake 除了读取编写的 CMakeLists.txt 以外,还会从命令行中读取各种参数(一般是-DXX=YY),并且还会综合环境变量中包括PATH/CC/OpenCV_DIR等各种各样变量的内容进行综合判断。

rosrun

而在 ROS 中,由于大部分程序并不由用户直接启动,而是以 .launch 文件的形式组织,因此参数获取同样是关键的问题。作为生态的一部分,ROS1 中直接规定了以 rosrun 形式运行的 ROS 节点的参数应是以下形式

  • from:=to话题映射,将节点代码中的from话题定义到外界的to话题。一个常见的情况 image_transport 只会订阅in话题并发布out话题,使用rosrun image_transport republish raw in:=camera/image out:=camera/image_repub的形式在运行时定义为外界的话题。使用话题映射时,节点的代码无需做特殊处理,直接使用from话题即可。
  • _param:=value:定义节点的私有参数,也就是只对该节点有效,不是全局生效的参数。通过这个方法定义的参数和后面 roslaunch 中的<param>标签是同样的,在程序中新建ros::NodeHandle("~"),再使用ros::NodeHandle::param方法读取。注意~表示当前节点,如果读取全局参数使用ros::NodeHandle的默认构造函数即可

当然,作为一个完整的程序,ROS 节点同样可以使用包括环境变量、配置文件在内的其他的方法获取参数,并不需要来自 rosrun 的支持。比如环境变量ROSCONSOLE_FORMAT可以用来很方便地修改节点的日志内容。

roslaunch

既然名叫节点,那么 ROS 的常见用法理应是同时运行多个节点,用于组成一个完整的图。ROS 为此任务提供了专门的工具 roslaunch。roslaunch 并不是一个用户提供的程序,因此 roslaunch 中只能使用固定的几种方法获取参数:

  • 首先自然是 .launch 文件,以 XML 格式编写,其中根元素是<launch>标签,其中包含若干个<node>用于运行rosrun,或是<include>重用其他的 .launch 文件。使用<arg>标签声明变量1注意,roslaunch 并不使用 rosparam 机制,<arg>参数只能在本文件中以$(arg var)的形式使用
  • 从其他来源获取的参数,通过参数替换的方法使用。如果需要读取环境变量,可以使用$(env ENV)/$(optenv ENV),而读取变量使用$(arg var)。另外,$(find pkg)用于查找包的路径,也非常常用。
  • 在命令行,可以使用roslaunch package file.launch arg:=value的形式赋值上述已经通过<arg>声明的变量。注意,roslaunch 变量赋值的形式和rosrun类似,但含义截然不同。例如,roslaunch 命令无法建立话题映射。

在一个<include>或是<arg>元素内部,还可以嵌套<param><remap><arg> 等元素,用于传递参数、话题映射、变量等。

dynamic_reconfigure

dynamic_reconfigure 是一套和上述的 rosparam 类似,但更复杂也更多样的参数设置系统,需要首先编写 .cfg 文件并生成接口,支持在更改参数时调用回调而避免轮询,并且提供图形界面(rqt_reconfigure)和参数范围校验。

dynamic_reconfigure 在建立节点时,会取节点的参数的初值进行一次配置,但随后不再和 rosparam 中的参数进行同步。这次配置同样遵守 dynamic_reconfigure 中取值范围等的要求。这样可以避免在 .launch 文件中直接调用 dynamic_reconfigure。

注:

  1. 为了区分,本文把<arg>声明的叫做变量