AuboStudio SDK 0.6.3

AuboStudio SDK

**当前 API 文档下载地址**：AuboStudio SDK API 文档.pdf

# 概述

AuboStudio SDK 提供了一整套完整的接口供开发插件使用，为用户提供更加丰富的功能。

# 目录

- 在示教器中集成插件的原理
- SDK 架构
- 使用示例
- 命名空间

# 在示教器中集成插件的原理

插件是一个软件包，作为 aubo_scope 的子进程运行。aubo_scope 将注册插件，并以各种方式与之交互，例如在 aubo_scope 启动的过程中以及基于用户与 aubo_scope 的交互过程中。

每个插件可以为 aubo_scope 贡献多个新功能，这种功能通常称为服务。这种服务一般有以下两类：

服务:

1. 提供安装节点服务。
2. 提供程序节点服务。

示例(夹爪`aubo_caps`):

1. 提供安装节点服务：例如配置夹爪的安装和连接。
2. 提供程序节点服务：例如一个程序节点可以打开夹爪，另一个程序节点可以关闭夹爪。

## 将插件集成到 <tt>aubo_scope</tt> 的原理：

**集成过程图如下**：

- 当 aubo_scope 启动时，它将查找所有已安装的 aubo_caps。
- 然后 aubo_scope 在每个 aubo_caps 调用激活器，激活器有两个重写的函数`start()`、`stop()`，在启动时首先调用 `start()` 利用 RegisterService 注册服务；而在 aubo_scope 停止时调用 `stop()` 函数。
- 注册后该 Service 提供了配置节点基本信息的函数、创建该节点的用户交互界面（`view`类）的函数以及创建每个节点的 Contribution 类的函数。
- 在 contribution 类中可以为该节点提供特殊功能的 Api 以及生成相应的 Script 代码。
- 通常 Service 中的设置可以认为是静态的设置，因为它们不可用于运动时，只在启动时调用。

## 在 <tt>aubo_scope</tt> 中集成程序节点的原理：

集成过程图如下：

具体实现：

ProgramNodeService

ProgramNodeService 接口必须实现以下函数：

**`getId()`**

> 参数：void
> 返回值类型：String
> 返回值内容：myNodeType
> 调用时机：服务注册后。
> 说明：`getId()` 函数返回此类节点的唯一 ID。当存在多个程序节点时，该函数用于标识哪些程序节点属于同一类程序节点。

**`getTitle()`**

> 参数：Locale 区域
> 返回值类型：String
> 返回值内容：程序节点的名称。
> 调用时机：服务注册后。
> 说明：它是一个静态名称，应该能够告诉用户该节点的用途。

**`getIcon()`**

> 参数：void
> 返回值类型：String
> 返回值内容：返回节点的图标地址。
> 调用时机：服务注册后。
> 说明：由于每一类的节点其图标都各不相同，在动态创建节点的过程中，需要为其匹配相对应的图标，因此我们需要在创建节点时拿到这类节点的图标链接地址。

**`configureContribution()`**

> 参数：ProgramContributionConfigurationPtr configuration
> 返回值类型：void
> 调用时机：服务注册后。
> 说明：

> - `ProgramContributionConfigurationPtr` 代表此类节点的配置；
> - `ProgramContributionConfigurationPtr` 对象可以通过调用相关联的函数来配置其值；
> - 例如设置程序节点是否可以有子节点、节点是否可以为用户插入还是仅仅在 aubo_caps 内部使用。

> configuration.setChildrenAllowed( false );
> configuration.setUserInsertable( false );

**`createView()`**

> 参数：ViewApiProviderPtr api_provider
> 返回值类型：ProgramNodeViewPtr
> 返回值内容：返回 view 类的新实例。
> 调用时机：仅一次，此类型的节点由用户第一次插入或者加载到程序中。
> 说明：

> - 仅在用户首次使用该类节点时才调用 createView。
> - 参数 ViewApiProviderPtr 对象可以获取 SystemAPI、UserInterfaceAPI。
> - 参数 ViewApiProviderPtr 通常会被转发到 view 类，例如需要在文本域中提供键盘，而键盘由 UserInterfaceAPI 提供。

**`createNode()`**

> 参数：

> - ProgramApiProviderPtr api_provider,
> - ProgramNodeViewPtr view，
> - DataModelPtr model,
> - ProgramCreationContextPtr context

> 返回值类型：ProgramNodeContributionPtr
> 返回值内容：

> - 此类节点 contribution 类的新实例;
> - MyProgramNodeContribution（apiProvider, view, model, context）。

> 调用时机：

> - 每当创建此类型的节点时;
> - 要么由用户插入新的节点，然后加载包含此类型节点的程序；
> - 要么由另一个 aubo_caps 插入该程序。

> 说明：

> - createNode 返回此类节点 contribution 类的新实例。虽然只有一个 view 实例，但是每次创建一个新节点时，都会创建一个 contribution 类的新实例；
> - 应该将参数转发给 contribution 类。ProgramApiProviderPtr 可以提供与程序节点相关的各类 API 的访问权限，contribution 对象可以使用 DataModelPtr 存储用户完成的节点的配置信息，如果新插入节点，则 DataModelPtr 将为空；如果加载了该节点，则 DataModelPtr 已经包含用户对该节点的配置信息，contribution 对象可以使用 ProgramCreationContextPtr 来检查自身的创建是否是新插入节点的结果，或者该节点是否已经被加载。

ProgramNodeView

ProgramNodeView 接口必须实现以下函数：

**`buildUi()`**

> 参数：

> - WidgetHandle parent,
> - ContributionProviderPtr <ProgramNodeContribution> contribution

> 返回值类型：void
> 调用时机：仅一次，当用户第一次插入或者加载这种类型节点到程序中。
> 说明：

> - widgetHandle 是 aubo_scope 中显示给用户的面板，在调用 buildUi 期间，我们将节点的界面嵌套在 aubo_scope 面板中；
> - 另一个参数是 ContributionProviderPtr。由于可以有多个 Contribution 实例，但是只有一个 view 实例，因此当用户与节点交互时 ContributionProviderPtr 将提供对 Contribution 的访问。调用 `contribution.get()` 将返回活动的 ProgramNodeContribution 实例。

ProgramNodeContribution

ProgramNodeContribution 接口必须实现以下函数：

**`openView()`**

> 参数：void
> 返回值类型：void
> 调用时机：每次用户进入特定的节点界面时。
> 说明：

> - 由于同一种类型的节点其用户界面 view 只有一个实例，但是这种类型的节点可能有多个，其 ProgramNodeContribution 可能也有多个实例，因此应该调用 `openView()` 函数来更新 view 以显示各个节点的特定设置；
> - 通常，此调用会读取 dataModel 中的设置，这些设置可用于动态更新 Ui 中的相关设置。在这个函数中也可以用来启动一个定时器，只要节点在焦点中，就可以实现动态的更新 Ui 中的值。

**`closeView()`**

> 参数：void
> 返回值类型：void
> 调用时机：用户每次离开此特定节点的用户界面时。
> 说明：对 `closeView()` 的调用会通知 Contribution 告知用户现在不再查看此节点。如果在 `openView()` 中启动了定时器或其他正在运行的任务，那么现在应该停止。

**`getTitle()`**

> 参数：void
> 返回值类型：String
> 返回值内容：返回程序树中所示的程序节点的名称。
> 调用时机：调用频繁，通常在更改 dataModel 时。
> 说明：

> - Contribution 中 getTitle() 和 Service 中的 `getTitle()` 的区别： Contribution 中 `getTitle()` 函数返回的时程序树中所示的程序节点的名称，是用来区分同一类型的不同节点的；Service 中的 `getTitle()` 函数返回的是可用节点列表中节点的基本名称，是一个静态名称，是用来区别哪些节点是同一类型的。由此也说明了程序树中的节点的名称，通常根据节点的配置而发生变化。
> - 通常，此调用将基于当前配置来更改节点的名称。它用于简化用户在程序树中的导航。例如，如果这是可设置特定夹持宽度的自适应手爪的程序节点，则在设置为 35mm 的夹持宽度时，它可能会返回 **“Gripper Move: 35 mm”**。这有助于用户找到要配置的适当节点。如果未设置夹持宽度，即未定义节点，则标题可能只是“Gripper Move”。

**`isDefined()`**

> 参数：void
> 返回值类型：bool
> 返回值内容：目前的节点配置能否生成脚本，如果缺少用于生成 Script 的数据，返回 false，反之返回 true。
> 调用时机：每当程序中任何地方发生任何的修改时。
> 说明：

> - 几乎在程序中的任何地方发生任何修改时，都会调用 `isDefined()`。这意味着即使此节点不在焦点上，`isDefined()` 也会被调用很多次，这就要求在回调中执行的代码必须非常精简，并且依赖于 dataModel 的值。
> - 此函数的作用不是发出是否已经连接外部硬件的信号，这应该在运行时来处理。`isDefined()` 仅用于提醒用户是否需要对此节点进行更多的配置。

**`generateScript()`**

> 参数：ScriptWriterPtr script_writer
> 返回值类型：void
> 调用时机：通常在启动或者保存程序时。
> 说明：

> - 程序节点和安装节点的目的是生成一些 LuaScript，这些脚本将在运行程序时被执行。而 **`generateScript()`** 函数就是为这些节点生成相应的脚本的，生成的脚本取决于 dataModel 中的配置或者创建节点时 service 中设置的静态配置。
> - 该脚本应使用 ScriptWriter 对象创建。

## 在 aubo_scope 中集成安装节点的原理：

集成过程图如下：

具体实现：

InstallationNodeService

InstallationNodeService 接口必须实现以下函数：

**`getTitle()`**

> 参数：Locale 区域
> 返回值类型：String
> 返回值内容：返回该安装节点的一个静态名称，能够提示用户该节点的用途。
> 说明：系统 Locale 作为参数，可用于返回本地化为系统语言的节点名称。

**`getIcon()`**

> 参数：void
> 返回值类型：String
> 返回值内容：返回节点的图标地址。
> 调用时机：服务注册后。
> 说明：由于每一类的节点其图标都各不相同，在动态创建节点的过程中，需要为其匹配相对应的图标，因此我们需要在创建节点时拿到这类节点的图标链接地址。

**`configureContribution()`**

> 参数：InstallationContributionConfigurationPtr configuration
> 返回值类型：void
> 调用时机：服务注册后。
> 说明：InstallationContributionConfigurationPtr 对象存储着这类节点的配置，它已实现供将来使用，目前不提供任何选项，它应该留为空白。

**`createView()`**

> 参数：ViewApiProviderPtr api_provider
> 返回值类型：InstallationNodeViewPtr
> 返回值内容：返回 view 类的新实例。
> 调用时机：仅一次，此类型的节点由用户第一次插入或者加载到程序中。
> 说明：

> - 仅在用户首次使用该类节点时才调用 createView。
> - 参数 ViewApiProviderPtr 对象可以获取 SystemAPI、UserInterfaceAPI。
> - 参数 ViewApiProviderPtr 通常会被转发到 view 类，例如需要在文本域中提供键盘，而键盘由 UserInterfaceAPI 提供。

**`createNode()`**

> 参数：

> - InstallationApiProviderPtr api_provider,
> - InstallationNodeViewPtr view，
> - DataModelPtr model,
> - InstallationCreationContextPtr context

> 返回值类型：InstallationNodeContributionPtr
> 返回值内容：

> - 此类节点 contribution 类的新实例;
> - MyInstallationNodeContribution（apiProvider, view, model, context）。

> 调用时机：

> - 每当创建此类型的节点时;
> - 要么由用户插入新的节点，然后加载包含此类型节点的程序；
> - 要么由另一个 aubo_caps 插入该程序。

> 说明：

> - createNode 返回此类节点 contribution 类的新实例。虽然只有一个 view 实例，但是每次创建一个新节点时，都会创建一个 contribution 类的新实例；
> - 应该将参数转发给 contribution 类。ProgramApiProviderPtr 可以提供与程序节点相关的各类API的访问权限、contribution 对象可以使用 DataModelPtr 存储用户完成的节点的配置信息，如果新插入节点，则 DataModelPtr 将为空；如果加载了该节点(例如作为安装文件的一部分)，则 DataModelPtr 已经包含用户对该节点的配置信息、contribution 对象可以使用 ProgramCreationContextPtr 来检查自身的创建是否是新插入节点的结果，或者该节点是否已经被加载。

InstallationNodeView

InstallationNodeView 接口必须实现以下函数：

**`buildUi()`**

> 参数：

> - WidgetHandle parent,
> - InstallationNodeContributionPtr contribution

> 返回值类型：void
> 调用时机：仅一次，当用户第一次插入或者加载这种类型节点到程序中。
> 说明：

> - widgetHandle 是 aubo_scope 中显示给用户的面板，在调用 buildUi 期间，我们将节点的界面嵌套在 aubo_scope 面板中；
> - 另一个参数是 InstallationNodeContributionPtr。由于可以有多个 Contribution 实例，但是只有一个 view 实例，因此当用户与节点交互时 ContributionProviderPtr 将提供对 Contribution 的访问。调用 `contribution.get()` 将返回活动的 ProgramNodeContribution 实例。

InstallationNodeContribution

InstallationNodeContribution 接口必须实现以下函数：

**`openView()`**

> 参数：void
> 返回值类型：void
> 调用时机：每次用户进入特定的节点界面时。
> 说明：

> - 由于同一种类型的节点其用户界面 view 只有一个实例，但是这种类型的节点可能有多个，其 InstallationNodeContribution 可能也有多个实例，因此应该调用 `openView()` 函数来更新 view 以显示各个节点的特定设置；
> - 通常，此调用会读取 dataModel 中的设置，这些设置可用于动态更新 Ui 中的相关设置。在这个函数中也可以用来启动一个定时器，只要节点在焦点中，就可以实现动态的更新 Ui 中的值。

**`closeView()`**

> 参数：void
> 返回值类型：void
> 调用时机：用户每次离开此特定节点的用户界面时。
> 说明：对 `closeView()` 的调用会通知 Contribution 告知用户现在不再查看此节点。如果在 `openView()` 中启动了定时器或其他正在运行的任务，那么现在应该停止。

**`generateScript()`**

> 参数：ScriptWriterPtr script_writer
> 返回值类型：void
> 调用时机：通常在启动或者保存程序时。
> 说明：程序节点和安装节点的目的是生成一些 Script ，这些脚本将在运行程序时被执行。而 **`generateScript()`** 函数就是为这些节点生成相应的 lua 脚本的，生成的脚本取决于 dataModel 中的配置或者创建节点时 service 中设置的静态配置。

# SDK 架构

AuboStudio SDK 为机器人安装的插件提供了一组功能。其“核心”就是 Contribution。Contribution 是可以添加到 aubo_scope 中的新服务，为用户提供更加丰富的功能。 有两种一般类型的 Contribution:

1. 安装节点：

> - 安装节点是机器人安装域的扩展；

> - 安装节点之间没有顺序；
> - 安装节点可以提供用户交互界面并添加功能以配置“环境设置”。

1. 程序节点：

> - 程序节点是机器人程序域的扩展；

> - 程序节点之间在程序树中按顺序排放，并以此决定了机器人在运行程序时被执行的顺序；
> - 程序节点可以为机器人的程序流程提供新的编程思想，并提供用户交互界面。

插件提供的扩展通用类型（安装节点，程序节点）两个用户界面可以访问 SDK 中的许多功能。而提供给这些节点的 API 通常称为域 API，这类 API 提供对机器人的域详细信息和逻辑的访问。

由于程序节点和安装节点是在机器人程序的上下文中获得的，该上下文具有特殊的 API 功能。这些功能仅在 Installation 域或 Program 域中才有意义，这两类 API 分别为安装 API、程序 API。

## 域 API

提供给一般节点类型的通用 API 称为域 API。但是，并非在任何给定时间，此 API 中的所有功能都对所有节点类型有意义。因此，将域 API 以合理的 API 子类型提供给使用 aubo_caps 的节点。

有三种基于域的 API:

1. 应用程序 API:

> 提供对与机器人或应用程序特定功能相关的 API 的访问。即机器人的 I/O，程序变量或坐标系（特征）。

1. 系统 API:

> 提供对包含有关机器人的系统信息的 API 的访问。即序列号，软件版本或系统语言。

1. 用户界面 API:

> 提供与 UI 中与用户进行交互时相关的 API 的访问。即创建键盘，或要求用户定义位置。

## 安装 API

1. 提供仅在 Program 域中才有意义的功能;
2. 安装 API 是对应用程序 API 的扩展，包括了可用于安装节点的特殊功能，例如创建 Tcp、创建 Feature 等。

## 程序 API

1. 提供仅在 Installation 域中才有意义的功能;
2. 程序 API 是对系统 API 和用户界面 API 的扩展，包括了可用于程序节点的功能，例如构建程序节点模板。

在特定于节点类型的 Provider 对象中提供了对安装 API 和程序 API 的访问。

## 层次结构

├── 域API
│ ├── system_api (系统信息)
│ ├── user_interface_api (用户界面)
│ ├── application_api (应用程序)
├── 安装API
│ ├── installation_api (安装)
└── 程序API
├── program_api (程序)

# 使用示例

## 开发 Service 类

目的: service 类提供了配置节点基本信息的函数、创建该节点的用户交互界面（view类）的函数以及创建每个节点的 Contribution 类的函数。

例如开发一个名为 hello 的程序节点：

# @code{c++}

helloProgramNodeService::helloProgramNodeService(){} helloProgramNodeService::~helloProgramNodeService(){}

std::string helloProgramNodeService::getId() { return "hello"; }

std::string helloProgramNodeService::getTitle() { return "hello"; }

std::string helloProgramNodeService::getIcon() { return "img:node-comment.png"; }

void helloProgramNodeService::configureContribution( ProgramContributionConfigurationPtr configuration) { }

ProgramNodeViewPtr helloProgramNodeService::createView( ViewApiProviderPtr api_provider) { return std::make_shared<helloProgramNodeView>(api_provider); }

ProgramNodeContributionPtr helloProgramNodeService::createNode( ProgramApiProviderPtr api_provider, ProgramNodeViewPtr view, DataModelPtr model, ProgramCreationContextPtr context) { return std::make_shared<helloProgramNodeContribution>( api_provider, std::dynamic_pointer_cast<helloProgramNodeView>(view), model); }

在激活器中注册服务：

当 service 类完成时，需要在激活器中注册此服务。激活器注册节点应该提供给 aubo_scope 的所有服务。当 aubo_scope 启动时，将调用激活器 `start()` 方法，并且应在 bundle context 中注册相关服务。

{c++}
#include "cppmicroservices/Bundle.h"
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleImport.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/BundleResource.h"
#include "cppmicroservices/BundleResourceStream.h"
#include "cppmicroservices/Constants.h"
#include "cppmicroservices/ServiceEvent.h"
#include "hello_program_node_service.h"
using namespace cppmicroservices;
/**
* This class implements a simple bundle that utilizes the CppMicroServices's
* event mechanism to listen for service events. Upon receiving a service event,
* it prints out the event's details.
*/
class Activator : public BundleActivator
{
private:
/**
* Implements BundleActivator::Start(). Prints a message and adds a member
* function to the bundle context as a service listener.
*
* @param context the framework context for the bundle.
*/
void Start(BundleContext context)
{
auto bundle = context.GetBundle();
auto headers = bundle.GetHeaders();
cppmicroservices::ServiceProperties props;
props["Name"] = std::string("MyFirstAuboCap");
props["VendorName"] = std::string("aubo-robotics");
props["Version"] = 0;
//注册节点
context.RegisterService<arcs::aubo_scope::ProgramNodeService>(
std::make_shared<helloProgramNodeService>(), props);
}
/**
* Implements BundleActivator::Stop(). Prints a message and removes the
* member function from the bundle context as a service listener.
*
* @param context the framework context for the bundle.
*/
void Stop(BundleContext /*context*/) {}
};
CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator)

## 开发 Contribution 类

目的: 为节点提供需要的特殊 API，以及生成 Script 脚本用以执行程序节点的功能，该代码基于 dataModel 中存储的配置信息。

例如开发一个名为 hello 的程序节点：

{c++}
helloProgramNodeContribution::helloProgramNodeContribution(
ProgramApiProviderPtr api_provider, helloProgramNodeViewPtr view,
DataModelPtr model)
: api_provider_(api_provider), view_(view), model_(model)
{
}
helloProgramNodeContribution::~helloProgramNodeContribution()
{
}
void helloProgramNodeContribution::openView()
{
}
void helloProgramNodeContribution::closeView()
{
}
std::string helloProgramNodeContribution::getTitle()
{
return "hello";
}
bool helloProgramNodeContribution::isDefined()
{
return true;
}
void helloProgramNodeContribution::generateScript(ScriptWriterPtr script_writer)
{
}

## 开发 View 类

目的：为节点提供用户交互界面。

例如开发一个名为 hello 的程序节点：

{c++}
helloProgramNodeView::helloProgramNodeView(ViewApiProviderPtr api_provider,
QWidget *parent)
: QWidget(parent), ui(new Ui::helloProgramNodeView), view_api_(api_provider)
{
}
helloProgramNodeView::~helloProgramNodeView()
{
delete ui;
}
void helloProgramNodeView::buildUi(
WidgetHandle parent,
ContributionProviderPtr<ProgramNodeContribution> contribution)
{
setParent((QWidget *)parent);
ui->setupUi(this);
}

# 命名空间

所有接口都定义在以下命名空间中：

namespace arcs {
namespace aubo_scope {
// 所有接口定义
}
}