ROS源代码阅读(3):ROS程序的初始化——this_node::init()
来源:互联网 发布:junit数据库自动回滚 编辑:程序博客网 时间:2024/06/08 13:23
接着上一篇博文ROS程序的初始化——从ros:init()出发,我们接着来分析ROS程序的初始化问题。在此文中我们探讨的是节点环境的初始化——this_node::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源代码阅读(3):ROS程序的初始化——this_node::init()
- ROS源代码阅读(5):ROS程序的初始化——对ros:init()的总结
- ROS源代码阅读(2):ROS程序的初始化——从ros:init()出发
- ROS源代码阅读(4):ROS程序的初始化——file_log::init()和param::init()
- ros 初始化和关闭 (ros::init(); ros::shutdown())
- ROS源代码阅读(1):找切入点
- ROS常见问题2——用KDevelop编译ROS程序
- ros 编译ROS程序前要做的事
- 我的ROS学习之路——ROS安装
- 我的ROS学习之路—ros相关命令
- ros::init源码分析(未完待续。)
- ROS-Industrial 之 ABB_Driver ——ROS Server(1/3)
- ROS-Industrial 之 ABB_Driver ——ROS Server(2/3)
- ROS探索总结(一)——ROS简介
- ROS探索总结(二)——ROS总体框架
- ROS探索总结(三)——ROS新手教程
- ROS探索总结(一)——ROS简介
- ROS探索总结(二)——ROS总体框架
- 闲谈寻票软件
- mysql常用权限管理
- 简单说明什么是递归,什么情况下会使用递归,并写一个简单的递归程序。
- MySQL高可用架构
- 解决APP进程被杀掉之后,导致fragment失效或者错乱的办法
- ROS源代码阅读(3):ROS程序的初始化——this_node::init()
- 线性表
- 算法题-关于麻将是不是炸和?
- 安装包解析出现问题
- android 数据库SQLite用法
- 列表改变时监听,解决下标越界
- 画笔 QPen
- php向mysql数据库中插入数据(单条和多条)
- Vmware下设置Ubuntu桥接上网