NAOqi框架核心概念
NAOqi 框架核心概念
什么是 NAOqi 框架
NAOqi
是在机器人上运行
的软件和对机器人进行控制
的软件的总称。
NAOqi
框架( NAOqi Framework
)是用于对Aldebaran机器人进行编程的编程框架。
它满足了常见的机器人技术需求,包括:并行性、资源、同步、事件。
主要特征
该框架允许不同模块(运动,音频,视频)之间的同类通信,同类程序设计和同类信息共享。
NAOqi
框架是跨平台和跨语言的,并允许您创建分布式应用程序。
跨平台
您可以在Windows,Linux或Mac上使用NAOqi
框架进行开发。
-
使用Python:您将能够在计算机上或直接在机器人上轻松运行代码。
-
使用C++:由于它是一种编译语言,因此您需要针对目标操作系统编译代码。因此,如果要在机器人上运行
C++
代码,则需要使用交叉编译工具才能生成能够在机器人操作系统:NAOqi OS
上运行的代码。请遵循C++ SDK安装指南完成您的安装,以确保您已安装所有必需的工具。
跨语言
-
可以使用
C++
和Python
开发在机器人上运行的软件:在两种情况下,编程方法都完全相同。注意
初学者应该从Python开始。它更容易学习,并且应该满足他们的所有需求。
熟练使用C++的开发人员通常会使用以下开发方式:
-
Python
编写机器人行为 -
C++
编写模块
-
分布式应用
一个实时的功能程序不仅可以是一个可执行文件,还可以是分布在多个机器人上的多个进程或模块。无论您的选择是什么,调用方法始终是相同的。
他们可使用其IP地址和端口将一个可执行文件连接到另一个机器人,其他可执行文件中的所有API方法都可以使用与本地方法完全相同的方式来使用。
计算机使用代码指令r1MemoryProxy.insertData("danceLeader","yes")
来控制R1机器人调整为领舞者、使用代码指令r2MemoryProxy.insertData("danceLeader","yes")
来控制R2机器人调整为非领舞者。
R1机器人可以使用myMemoryProxy.insertData("CountDown",30)
来设置自身的CountDown
的值。
R2机器人可以使用r1MemoryProxy.getData("CountDown")
来获取R1机器人的CountDown
的值。
请注意,
NAOqi
会自动地在快速直接调用(LPC)和远程过程调用(RPC)之间进行选择。
它是如何工作的
内省(Introspection)
内省(Introspection)是机器人API、功能、监视和对受监视功能的操作的基础。机器人知道所有可用的API函数。卸载库将自动删除相应的API函数。可以使用BIND_METHOD
(在almodule.h
中定义)在API中添加模块中定义的功能。
如果您绑定一个函数(仅三行代码),您将自动受益于以下功能:
- 可以是C++和Python中的调用函数(请参见跨语言),
- 知道函数是否正在执行,
- 执行本地或远程的函数(从计算机或其他机器人执行)(请参阅分布式应用程序),
- 在函数上调用等待,停止,判断是否正在运行(
isRunning
)。
NAOqi 的运行过程
在机器人上运行的NAOqi
可执行文件是一个broker(该概念见下文,可理解暂时理解为中间商或者RPC框架中的注册中心)。启动时,它将加载一个名为autoload.ini
的首选项文件,该文件定义了NAOqi
应加载的库。每个库包含一个或多个使用broker发布其方法的methods(模块)。
broker提供查询服务,以便树中或整个网络中的任何模块都可以找到已发布的任何方法。
加载modules 形成一棵附加到modules 的方法树,以及附加到broker的modules 树。(Loading modules forms a tree of methods attached to modules, and modules attached to a broker.)
Broker
Broker 是提供以下内容的对象:
-
目录服务:允许您查找模块(modules)和方法(methods)。
-
网络访问:允许远程过程调用模块(modules)与其中的方法(methods)。
大多数时候,您无需考虑brokers。它们透明地(transparently)执行工作,使您可以编写与“本地模块”(在同一进程中)或“远程模块”(在另一进程或另一台机器上)的调用相同的代码。
Proxy
Proxy是一个对象,将充当其代表的模块(module)。
例如,如果创建ALMotion
模块的代理,您将获得一个包含所有ALMotion
方法的对象。
要创建模块的代理(从而调用模块的方法),您有两种选择:
- 只需使用模块的名称。在这种情况下,您正在运行的代码和要连接到的模块必须位于同一代理中。这称为本地调用。
- 使用模块的名称以及代理的IP和端口。在这种情况下,模块必须位于相应的代理中。
本地模块和远程模块之间的全部区别在下文的“本地模块”部分中说明。
若要学习如何扩展NAO API,必须学习如何创建新模块。您可以在“扩展NAO API-创建新模块”部分中阅读有关创建C++ NAOqi
模块的教程。
模块(Modules)
通常,每个模块都是库中的一个类。从 autoload.ini
加载库后,它将自动实例化为模块类。
在从ALModule
派生的类的构造函数中,可以绑定方法。这会将其名称和方法签名发布给broker,以便其他用户可以使用(个人理解为RPC框架中的注册)。
这个模块可以是远程也可以是本地的。
- 如果它是远程的,则将其编译为可执行文件,并且可以在机器人外面运行。远程模块更易于使用,并且可以从外部轻松调试,但在速度和内存使用方面效率较低。
- 如果是本地的,则将其编译为库,并且只能在机器人上使用。但是它们比远程模块更为高效。
每个模块包含各种方法。其中有一些方法是被绑定的,这意味着可以从模块外部(例如,在另一个模块内部,从可执行文件等)调用它们。如果模块是远程或本地的,则调用这些绑定函数的方式不会改变:模块将自动适应。
你可以从机器人网页上查看模块API。
本地模块
本地模块是在同一进程中启动的两个(或更多)模块。他们仅使用一个 broker 进行通话。
由于本地模块处于同一进程中,因此它们可以共享变量并调用彼此的方法,而无需序列化或联网。这允许它们之间最快的通讯。
如果您需要做一些闭环(close loop)操作(例如束缚(enslavement)),则必须使用本地模块。
远程模块
远程模块是使用网络进行通信的模块。远程模块需要broker与其他模块进行交互。broker负责所有网络部分。您必须知道远程模块通过网络使用SOAP(简单对象访问协议)可以工作。您不能使用远程模块进行快速访问(例如,直接进行内存访问)。
远程模块之间的连接
远程模块可以通过将其brokers 连接到其他模块的brokers 来与其他模块对话。
- broker与broker的连接将打开相互通信。两家broker的模块可以彼此对话。
- Proxy 到Broker 的连接打开了一种通信方式。Proxy 可以访问注册到Broker 的所有模块,但注册到Broker 的模块不能访问拥有Proxy 的模块。
Broker 到 Broker 的连接
您可以通过连接它们的Broker 来将两个模块连接在一起。
例如,您有两个模块B和C。连接它们的Broker 时,B可以访问C的功能,而C可以访问B的功能。
要以这种方式连接模块,您需要指定主代理的IP地址和端口号。(启动模块时使用--pip
, --pport
命令行选项)。然后,您可以通过在其上获取一个 proxy 来访问该模块:
AL::ALProxy proxy = AL::ALProxy(<modulename>);
由于模块的broker 已经使用 --pip
和--pport
连接,因此在创建proxy时无需指定IP地址和端口号。
Proxy到Broker 连接
您可以将模块连接到另一个模块,而无需指定 --pip
和--pport
。为此,您需要在模块内部创建一个proxy ,并将其连接到所需的代理IP地址和端口号。
例如,您有两个模块B和C。仅使用一个proxy将B连接到C时,B可以访问C函数,但C无法访问B函数。
// 一个 broker 需要name, IP, port来监听:
const std::string brokerName = "mybroker";
// NAOqi ip
const std::string pip = "127.0.0.1"; // local NAOqi
// NAOqi port
int pport = 9559;
// 创建你自己的 broker
boost::shared_ptr<AL::ALBroker> broker =
AL::ALBroker::createBroker(brokerName, "0.0.0.0", 54000, pip, pport);
AL::ALProxy proxy = AL::ALProxy(broker, <modulename>);
阻塞和非阻塞调用
NAOqi
提供了两种方法调用方法:
- 阻塞调用与常规方法调用一样,简单的调用也会被阻止,下一条指令将在上一次调用结束后执行。所有调用都可能引发异常,应将其封装在try-catch块中。调用可以具有返回值。
- 非阻塞调用通过使用proxy的post对象(post object ),可以在并行线程中创建任务。这样一来,您就可以同时进行其他工作(例如边聊天边走路)。每个post 调用都会生成一个任务ID。您可以使用此任务ID来检查任务是否正在运行,或者等到任务完成。
存储(Memory)
ALMemory是机器人数据存储器。所有模块都可以读取或写入数据,订阅事件,以便在引发事件时被调用。
请注意,ALMemory不是实时同步的工具。在DCM /时间或运动/同步或实时的变量上是限制订阅的。
ALMemory
ALMemory 是ALValues
的数组(有关更多详细信息,请参见:ALValue 库)。变量访问是线程安全的。我们使用读/写关键部分来避免在读取内存时出现不良表现。
ALMemory 包含三种类型的数据:
- 来自执行器和传感器的数据(Data from Actuators and Sensors),
- 事件(Event),
- 微事件(Micro-event)。
有关更多详细信息,请参见: ALMemory.
对事件做出反应
一些模块(module) 还公开了一些事件 (events)。
您必须使用必须是订阅者方法的回调从其他模块(module)订阅事件。
例如,您可以有一个名为 FaceReaction
(人脸反应)的模块,其中包含onFaceDetected
(检测到人脸时)方法。
您可以使用onFaceDetected
回调将FaceReaction
模块订阅到 ALFaceRecognition
模块的onFaceDetected
方法。
这将导致人脸检测算法运行,并且每次检测到人脸时,都会调用onFaceDetected
回调。
事件。
例如,您可以有一个名为 FaceReaction
(人脸反应)的模块,其中包含onFaceDetected
(检测到人脸时)方法。
您可以使用onFaceDetected
回调将FaceReaction
模块订阅到 ALFaceRecognition
模块的onFaceDetected
方法。
这将导致人脸检测算法运行,并且每次检测到人脸时,都会调用onFaceDetected
回调。
要了解如何在Python中完成此操作,请参见 制作Python模块-对事件进行反应部分。