ROS源代码阅读(3):ROS程序的初始化——this_node::init()
2017-09-18 23:03
851 查看
接着上一篇博文ROS程序的初始化——从ros:init()出发,我们接着来分析ROS程序的初始化问题。在此文中我们探讨的是节点环境的初始化——this_node::init()
this_node::init()函数的源代码在
其中,ThisNode是文件
this_node::init()函数实际上直接调用的是ThisNode类中的
从代码可以看出,该函数完成了以下几个功能:
获取ROS_NAMESPACE的环境变量名;
给变量name_赋值,并进行一些格式化处理。name_是类ThisNode的成员变量;
给变量namespace_赋值,并进行一些格式化处理。namespace_是类ThisNode的成员变量;
根据类ThisNode的定义,该类的成员变量就只有name_和namespace_两个变量。因此,该函数可以看做是根据输入参数,对ThisNode的对象进行初始化。
而根据ThisNode::instance()函数,该类在程序中只有唯一的一个对象。即调用this_node::init()的时候完成对该类唯一对象的初始化。
另外,上述函数调用了
names::validate(namespace_, error)(上述代码第57行)
names::init(remappings)(上述代码第66行)
ros::console::setFixedFilterToken(上述代码第86行)
三个函数。为了更好理解代码,我们下面对这三个函数做一简述。
其中调用了resolve()函数,该函数也定义在
从代码可以看出,该函数主要是对变量g_extra_fixed_tokens进行赋值。
该函数的具体作用如下:
1. 获取ROS_NAMESPACE的环境变量名;
2. 给变量name_赋值,并进行一些格式化处理。name_是类ThisNode的成员变量;
3. 给namespace_赋值,并进行一些格式化处理。namespace_是类ThisNode的成员变量;
4. 将remappings映射为g_remappings和g_unresolved_remappings两个变量;
是ros::init()函数的五个主要初始化操作中的第三个,后续我们将解析剩余的两个初始化操作file_log::init和param::init。然后,对ros::init()函数做一个综合的分析。
this_node::init()函数的源代码在
./src/ros_comm/roscpp/src/libros/this_node.cpp中,具体实现如下:
//./src/ros_comm/roscpp/src/libros/this_node.cppvoid init(const std::string& name, const M_string& remappings, uint32_t options)
{
ThisNode::instance().init(name, remappings, options);
}
其中,ThisNode是文件
./src/ros_comm/roscpp/src/libros/this_node.cpp中定义的一个类,该类的具体定义如下:
//./src/ros_comm/roscpp/src/libros/this_node.cppclass ThisNode
{
std::string name_;
std::string namespace_;
ThisNode() : name_("empty") {}//构造对象时将name_置为空
public:
static ThisNode& instance()
{
static ThisNode singleton;//整个ROS程序只有singleton一个拷贝,详见编程中的“单例模式”。
return singleton;
}
const std::string& getName() const
{
return name_;
}
const std::string& getNamespace() const
{
return namespace_;
}
void init(const std::string& name, const M_string& remappings, uint32_t options);
};
this_node::init()函数实际上直接调用的是ThisNode类中的
void init(const std::string& name, const M_string& remappings, uint32_t options);函数。该函数的定义如下:
//./src/ros_comm/roscpp/src/libros/this_node.cppvoid ThisNode::init(const std::string& name, const M_string& remappings, uint32_t options)
{
char *ns_env = NULL;
#ifdef _MSC_VER
_dupenv_s(&ns_env, NULL, "ROS_NAMESPACE");
#else
ns_env = getenv("ROS_NAMESPACE");//获取ROS_NAMESPACE的环境变量名
#endif
if (ns_env)//如果环境变量ns_env已被赋值
{
namespace_ = ns_env;//将ROS_NAMESPACE的环境变量名赋值给namespace_
//namespace_是类ThisNode的成员变量
#ifdef _MSC_VER
free(ns_env);
#endif
}
//检测通过参数传入的节点名不能为空
if (name.empty()) {
throw InvalidNameException("The node name must not be empty");
}
name_ = name; //将传入的节点名赋值给变量name_
//name_是类ThisNode的成员变量
bool disable_anon = false;
//在输入参数remappings查找键为"__name"的项
M_string::const_iterator it = remappings.find("__name");
if (it != remappings.end())//如果找到了
{
name_ = it->second;//将对应项的值赋值给name_
disable_anon = true;
}
//在输入参数remappings查找键为"__ns"的项
it = remappings.find("__ns");//如果找到了
if (it != remappings.end())
{
namespace_ = it->second;//将对应项的值赋值给变量namespace_
}
if (namespace_.empty())//如果namespace_为空
{
namespace_ = "/";
}
namespace_ = (namespace_ == "/")
? std::string("/")
: ("/" + namespace_)
;
std::string error;
//对照命名规则检查namespace_,看看是否合法。
if (!names::validate(namespace_, error))
{
std::stringstream ss;
ss << "Namespace [" << namespace_ << "] is invalid: " << error;
throw InvalidNameException(ss.str());
}
// names must be initialized here, because it requires the namespace to already be known so that it can properly resolve names.
// It must be done before we resolve g_name, because otherwise the name will not get remapped.
names::init(remappings);//将remappings映射为g_remappings和g_unresolved_remappings两个变量
//检查name_的合法性
if (name_.find("/") != std::string::npos)
{
throw InvalidNodeNameException(name_, "node names cannot contain /");
}
if (name_.find("~") != std::string::npos)
{
throw InvalidNodeNameException(name_, "node names cannot contain ~");
}
name_ = names::resolve(namespace_, name_);//进行格式化整理
if (options & init_options::AnonymousName && !disable_anon)
{
char buf[200];
snprintf(buf, sizeof(buf), "_%llu", (unsigned long long)WallTime::now().toNSec());
name_ += buf;
}
ros::console::setFixedFilterToken("node", name_);
}
从代码可以看出,该函数完成了以下几个功能:
获取ROS_NAMESPACE的环境变量名;
给变量name_赋值,并进行一些格式化处理。name_是类ThisNode的成员变量;
给变量namespace_赋值,并进行一些格式化处理。namespace_是类ThisNode的成员变量;
根据类ThisNode的定义,该类的成员变量就只有name_和namespace_两个变量。因此,该函数可以看做是根据输入参数,对ThisNode的对象进行初始化。
而根据ThisNode::instance()函数,该类在程序中只有唯一的一个对象。即调用this_node::init()的时候完成对该类唯一对象的初始化。
另外,上述函数调用了
names::validate(namespace_, error)(上述代码第57行)
names::init(remappings)(上述代码第66行)
ros::console::setFixedFilterToken(上述代码第86行)
三个函数。为了更好理解代码,我们下面对这三个函数做一简述。
插曲1:names::validate(namespace_, error)
上述代码调用了函数names::validate(namespace_, error),该函数定义在
./src/ros_comm/roscpp/src/libros/names.cpp中。具体实现如下。
bool validate(const std::string& name, std::string& error) { if (name.empty()) { return true; //如果name为空,则返回true } //检查首字符,首字符只能是~ / 或 alpha char c = name[0]; if (!isalpha(c) && c != '/' && c != '~') { std::stringstream ss; ss << "Character [" << c << "] is not valid as the first character in Graph Resource Name [" << name << "]. Valid characters are a-z, A-Z, / and in some cases ~."; error = ss.str(); return false; } //逐个检查name中的每个字符是否为合法字符 for (size_t i = 1; i < name.size(); ++i) { c = name[i]; if (!isValidCharInName(c)) { std::stringstream ss; ss << "Character [" << c << "] at element [" << i << "] is not valid in Graph Resource Name [" << name <<"]. Valid characters are a-z, A-Z, 0-9, / and _."; error = ss.str(); return false; } } return true; }
插曲2:names::init(remappings)
该函数定义在./src/ros_comm/roscpp/src/libros/names.cpp文件中,作用是将remappings映射为g_remappings和g_unresolved_remappings两个变量,其中g_remappings是按照一定规则整理过的remappings,而g_unresolved_remappings是初始传入的remappings参数
//./src/ros_comm/roscpp/src/libros/names.cppvoid init(const M_string& remappings)
{
//该函数的作用是将remappings映射为g_remappings和g_unresolved_remappings两个变量
M_string::const_iterator it = remappings.begin();
M_string::const_iterator end = remappings.end();
for (; it != end; ++it) //遍历M_string中的每个元素
{
const std::string& left = it->first; //left为键
const std::string& right = it->second; //right为值
//键不为空 且 键的第一个字符不为“_” 且 键不等于ThisNode对象的name_成员变量
if (!left.empty() && left[0] != '_' && left != this_node::getName())
{
std::string resolved_left = resolve(left, false);
std::string resolved_right = resolve(right, false);
g_remappings[resolved_left] = resolved_right;
g_unresolved_remappings[left] = right;
}
}
}
其中调用了resolve()函数,该函数也定义在
./src/ros_comm/roscpp/src/libros/names.cpp中,执行一些简答的格式化操作,在此不进行详述。
插曲3:ros::console::setFixedFilterToken
该文件的实现在./src/ros_comm/rosconsole/src/rosconsole/rosconsole.cpp文件中,具体代码如下:
void setFixedFilterToken(const std::string& key, const std::string& val) { g_extra_fixed_tokens[key] = val; }
从代码可以看出,该函数主要是对变量g_extra_fixed_tokens进行赋值。
总结
当初始化函数this_node::init()被ros::init()调用时,实际上调用了ROS程序中ThisNode类唯一的实例中的init(name, remappings, options)函数,作用是对该唯一的实例进行初始化。该函数的具体作用如下:
1. 获取ROS_NAMESPACE的环境变量名;
2. 给变量name_赋值,并进行一些格式化处理。name_是类ThisNode的成员变量;
3. 给namespace_赋值,并进行一些格式化处理。namespace_是类ThisNode的成员变量;
4. 将remappings映射为g_remappings和g_unresolved_remappings两个变量;
是ros::init()函数的五个主要初始化操作中的第三个,后续我们将解析剩余的两个初始化操作file_log::init和param::init。然后,对ros::init()函数做一个综合的分析。
相关文章推荐
- ROS源代码阅读(4):ROS程序的初始化——file_log::init()和param::init()
- ROS源代码阅读(5):ROS程序的初始化——对ros:init()的总结
- 解决Android端融云无法初始化(程序一运行就崩溃),定位在RongIM.init(this);
- linux文件系统初始化过程(6 完结)---执行init程序
- 用VS2008打开项目时出现了“初始化 Microsoft Visual SourceSafe 源代码管理提供程序时失败...”解决方式
- 关于vs2008的提示:“初始化 Microsoft Visual SourceSafe 源代码管理提供程序时失败。您无法使用此提供程序执行源代码管理操作”
- [置顶] nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数
- C程序库的Lazy Init 动态初始化
- AndroidStudio:x.Ext.init(this);初始化时this报红(错)(171130
- [Linux内核完全剖析]第七章 初始化程序(init)总结
- ros 初始化和关闭 (ros::init(); ros::shutdown())
- 为了方便把一些源代码放进pad的文件管理后不再显示.py无法阅读 写了一个小小程序将他们都变成以[py].txt结尾
- DirectFB源代码阅读(三)线程及信号初始化
- DOS下串口通信程序来传送文件的源代码 分类: DOS 2013-07-22 16:30 465人阅读 评论(0) 收藏
- Discuz!NT代码阅读笔记(2)--网站安装自动化--论坛程序安装及初始化过程
- Discuz!NT代码阅读笔记(2)--网站安装自动化--论坛程序安装及初始化过程
- 第八周 阅读程序 这里运用了this指针 Sample(*this.x+s.x)
- mips架构linux启动分析(六)(arch_mem_init(node内存)内存初始化)
- 初始化 Microsoft Visual SourceSafe 源代码管理提供程序时失败问题处理
- Android研究-Android系统初始化程序init和初始化配置文件init.rc分析[zz]