假设我们现在要写一个控制“智能风扇”的 ROS 程序。这个风扇需要知道两个参数最大转速和风扇名字。第一步写一份 YAML 配置文件准备数据新建一个文件叫fan_config.yaml。里面的内容非常简单YAMLmax_speed: 3000 fan_name: LivingRoomFan这就是你风扇的“出厂说明书”。第二步写一个 Launch 文件把数据塞进私有空间新建一个文件叫start_fan.launch。它的作用是启动程序并把上面的说明书“塞”给程序。launch node namemy_fan_node pkgmy_pkg typefan_program outputscreen rosparam file$(find my_pkg)/config/fan_config.yaml commandload / /node /launch这一步做完后ROS 系统里就偷偷多出了两个专属变量/my_fan_node/max_speed和/my_fan_node/fan_name。第三步写 C 代码用 nh_private 把数据掏出来这就是你一直想学的部分。新建你的main.cpp照着下面这样写#include ros/ros.h #include string int main(int argc, char** argv) { // 1. 初始化 ROS 节点名字叫 my_fan_node ros::init(argc, argv, my_fan_node); // // ★ 核心 1打造一把私密空间的钥匙 // ros::NodeHandle nh_private(~); // 2. 准备两个空变量用来接住马上要取出来的数据 int speed_from_yaml 0; std::string name_from_yaml ; // // ★ 核心 2用钥匙开箱取物 // 语法nh_private.getParam(yaml里的变量名, 存入哪个C变量); // // 取出最大转速 if (nh_private.getParam(max_speed, speed_from_yaml)) { ROS_INFO(成功我读到的最大转速是: %d, speed_from_yaml); } else { ROS_WARN(没找到 max_speed 这个参数); } // 取出风扇名字 if (nh_private.getParam(fan_name, name_from_yaml)) { ROS_INFO(成功我读到的风扇名字是: %s, name_from_yaml.c_str()); } return 0; } 核心原理解析这段代码到底发生了什么为什么不写全名注意看getParam(max_speed, ...)。你并没有写/my_fan_node/max_speed你只写了max_speed。这就是~的厉害之处因为你是用nh_private调用的ROS 会自动帮你把节点名字拼在前面/my_fan_node/max_speed准确无误地去你的私密空间里找到了3000这个数字。如果在这个风扇项目中你把ros::NodeHandle nh_private(~);换成了普通的ros::NodeHandle nh;程序的运行结果会非常直接你会读不到任何数据程序会直接打印出警告“没找到 max_speed 这个参数”1. 为什么普通nh读不到找错房间了参数的实际存放位置 在你的start_fan.launch文件中rosparam ... /是写在node ...里面的。这意味着ROS 把max_speed这个参数锁进了my_fan_node的私有金库里。 它在 ROS 系统里的真实全名是/my_fan_node/max_speed。普通nh的寻找路径 如果你在 C 里写了ros::NodeHandle nh;然后调用nh.getParam(max_speed, speed_from_yaml);。 普通nh代表的是“公共大厅”。它会去 ROS 系统的最顶层全局目录下寻找这个参数。 它搜索的路径是/max_speed。结果显而易见普通nh在大厅里找/max_speed但参数实际上藏在/my_fan_node/max_speed房间里。找错了地方当然什么都读不到2. 如果非要用普通nh该怎么改如果你就是想用普通的nh把参数读出来你必须修改.launch文件把参数“搬到公共大厅”里去。你需要把rosparam从node的内部挪到它的外面launch rosparam file$(find my_pkg)/config/fan_config.yaml commandload / node namemy_fan_node pkgmy_pkg typefan_program outputscreen /node /launch当你这样写了之后参数就会被存为/max_speed。此时你的 C 代码里用普通的nh.getParam(max_speed, ...)就能成功读到3000了3. 既然普通nh也能搞定为什么全世界都在用nh_private(~)想象一下这个终极场景 夏天到了你买了两个风扇一个放在客厅LivingRoom一个放在卧室Bedroom。客厅比较大风扇最大转速需要配 3000卧室比较小风扇最大转速配 1500 就够了。这两个风扇运行的都是你写的这同一个 C 程序。灾难现场使用普通nh 如果把参数放在全局/max_speed两个风扇的 C 程序都会去读同一个地方。结果就是你要么让两个风扇都转 3000要么都转 1500它们之间无法区分它们打架了完美解决使用带~的私有nh 如果你在 C 里乖乖使用了ros::NodeHandle nh_private(~);在启动时你只需要写一个这样的 launch 文件launch node nameliving_room_fan pkgmy_pkg typefan_program rosparam file客厅的配置.yaml commandload / /node node namebedroom_fan pkgmy_pkg typefan_program rosparam file卧室的配置.yaml commandload / /node /launch你看完全相同的 C 代码客厅风扇的nh_private自动去读了/living_room_fan/max_speed拿到 3000。卧室风扇的nh_private自动去读了/bedroom_fan/max_speed拿到 1500。