深入探究ros::init() - maohaihua/ros_study GitHub Wiki

深入探究ros::init() MirskingBlog-飞扬博客 2015-01-26 3951 阅读 C++

ROS是Willow Garage公司与Stanford University合作推出的开源机器人操作系统(Robot Operation System), Willow Garage也在此系统之上推出了Personal Robot 2(PR2), PR2由于出色的抓取在家庭服务机器人里可谓相当吊! 重要的是ROS已经被大多数科研机构接受并在其上进行研究和开发. 感觉Willow Garage在下一盘很大的棋, 有点安卓系统在手机上的赶脚...

用ROS也有大半年了, 但有个问题一直困扰我, 就是ROS每个Node在建立时第一步要做的就是 ros::init() 一个node, 但是在C++的API里边, ros一定要加入argc和argv两个参数. 但是这两个参数又从来没用过,而且在运行的时候ROS一般又不用 XX [Options] 这种方式, 那参数到底是谁传进去的, 传进去到底做了什么呢?

今天仔细翻了一下API, 算是把这个问题大概理解清楚了. 函数原型

void ros::init(int& argc, char** argv, const std::string& name, unit32_t options=0);

void ros::init(const M_string& remappings, const std::string& name, unit32_t options=0); void ros::init(const VP_string& remappings_args, const std::string& name, unit32_t options=0);

谁传入参数? 传入参数做什么?

先说第一个, 官方说argc, argv是用来解析来自命令行remapping arguments, 而所谓remapping arguments就是在调用 rosrun package_name node_name param_name:=param_value 中的 param:=param_value 部分. OK, 解决了第一个问题: 这些参数是从命令行的remapping arguments中传入的.

那么传入参数是有一定格式的, ROS wiki在 这里 对Remappig Arguments做了详细解释. 在看这个之前, 我们先来回顾一个Resources Names这个概念. Resource Names Graph Resource Names

图资源命名提供了ROS计算图中资源的分层命名结构, 这些计算图包括 Nodes/Parameters/Topics/Services等.

ROS中图资源命名包括四种格式: base/relative/global/private, 大概是这个样子:

base
relative/name
/global/name
~private/name

也就是说直接名字开头的不以/开头的表示base names, 这种方式是最常用的, 因为可以方便的remapping到其他namespace.

而以/开头的表示global names, 这种方式不推荐用, 因为这样写出来的代码不太方便移植.

以~开头的则是private names, 这个目前没用到过, 不太理解. Package Resource Names

Package命名就是比如 std_msgs/String 这种, std_msgs 就是一个package name. 这里就不详细说了. 传入参数做什么?

回顾完资源命名方法, 就可以来说传入参数到底是干什么的了. param_name:=param_value 传入的参数, 就是为了remap resource name, 其格式如下: Node Namespace Remapping Argument Matching Names Final Resolved Name / foo:=bar foo, /foo /bar /baz foo:=bar foo, /baz/foo /baz/bar / /foo:=bar foo, /foo /bar /baz /foo:=bar /foo /baz/bar /baz /foo:=/a/b/c/bar /foo /a/b/c/bar

用两句话概括就是: 不具名的命名空间中, 匹配的是param_name和/param_name, Resolve是直接加/替换; 具名命名空间中, 匹配的是/namespace/param_name, Resolve分两种: 1) 替换内容中无命名空间, 则加Node namespace替换, 2)替换内容中有命名空间, 则直接替换.

最后回过头看下函数原型: 一三函数分别将argv 和 VP_String类型的参数转化为M_String, 从而调用第二个函数, 最终用这些参数初始化了master和network.

其中M_String是typedef的 map<string, string> , 而VP_String则是 vector<pair<string, string>> .