** 一个节点的诞生**
在建立连接之前,首先要有节点。
节点就是一个独立的程序,它运行起来后就是一个普通的进程,与计算机中其它的进程并没有太大区别。
一个问题是:中为什么把一个独立的程序称为“节点”
这是因为ROS沿用了计算机中“节点”的概念。
在一个网络中,例如互联网,每一个上网的计算机就是一个节点。前面我们看到的客户端、服务器这样的称呼,也是从计算机网络中借用的。
下面来看一下节点是如何诞生的。我们在第一次使用ROS时,一般都会照着官方编写一个talker和一个listener节点,以熟悉ROS的使用方法。
我们以talker为例,它的部分代码如下。
#include "ros/ros.h"
int main(int argc, char **argv)
{
/* You must call one of the versions of ros::init() befe using any other part of the ROS system. */
ros::init(argc, argv, "talker");
ros::NodeHandle n;
main函数里首先调用了init()函数初始化一个节点,该函数的定义在init.cpp文件中。
当我们的程序运行到init()函数时,一个节点就呱呱坠地了。
而且在出生的同时我们还顺道给他起好了名字,也就是"talker"。
名字是随便起的,但是起名是必须的。
我们进入init()函数里看看它做了什么,代码如下,看上去还是挺复杂的。它初始化了一个叫g_global_queue的数据,它的类型是CallbkQueuePtr。
这是个相当重要的类,叫“回调队列”,后面还会见到它。init()函数还调用了network、master、this_node、file_log、pa这几个命名空间里的init初始化函数各自实现一些变量的初始化,这些变量都以g开头,例如g_host、g_uri,用来表明它们是全局变量。
其中,network::init完成节点主机名、IP地址等的初始化,master::init获取master的URI、主机号和号。
this_node::init定义节点的命名空间和节点的名字,没错,把我们给节点起的名字就存储在这里。file_log::init初始化日志文件的路径。
void init(const M_string& remapngs, const std::string& name, uint32_t opons)
{
if (!g_atexit_registered) {
g_atexit_registered = true;
atexit(atexitCallback);
}
if (!g_global_queue) {
g_global_queue.reset(new CallbackQueue);
}
if (!g_initialized) {
g_init_options = options;
g_ok = true;
ROSCONSOLE_AUTOINIT;
// Disable SIGPIPE
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#else
WSADATA wsaData;
Wtartup(MAKEWORD(2, 0), &wsaData);
#endif
check_ipv6_environment();
network::init(remappings);
master::init(remappings);
// names:: namespace is initialized by this_node
this_node::init(name, remappings, options);
file_log::init(remappings);
param::init(remappings);
g_initialized = true;
}
}
完成初始化以后,就进入下一步ros::NodeHandle n定义句柄。
我们再进入node_handle.cpp文件,发现构造函数NodeHandle::NodeHandle调用了自己的construct函数。然后,顺藤摸瓜找到construct函数,它里面又调用了ros::start()函数。
没错,我们又绕回到了init.cpp文件。
ros::start()函数主要实例化了几个重要的类,如下。
完成实例化后马上又调用了各自的start()函数,启动相应的动作。
这些都做完了以后就可以发布或订阅消息了。
一个节点的故事暂时就到这了。
TopicManager::instance()- >start();
ServeManager::instance()- >start();
ConnectionManager::instance()- >start();
PollManager::instance()- >start();
XMLRPCManager::instance()- >start();