-
Notifications
You must be signed in to change notification settings - Fork 0
Feature
MeshEngine 定义了一系列 Feature,用以控制飞机执行各种飞行相关的行为。在 MeshEngine 2.0 中,我们进一步加强了 Feature 的执行权限,开发者不能随心所欲,随时随地对 feature 进行调用,而必须遵守一定的规则。而站在用户的角度,这里的规则指的是:所有 Feature 只会在 Handler 页面被执行。
除了 Featrue 以外,同时还提供了
目前提供了如下 Feature,调用方式见后面 Feature 的生命周期控制 部分:
除了 Feature,MeshEngine 还定义了一系列 Action. 某种意义上 Action 与 Feature “相反”:Feature 控制飞机飞行相关的行为,而 Action 控制飞机飞行以外的行为,例如拍照,录像,云台调整等等。不同的 Feature 可能定义不同的 Action 触发点,比如在 Waypoint Feature 中定义了如下 Action 触发点:
- resumeAction: Waypoint Feature 恢复执行时,将会触发的 Action;
- finishAction: 到达某 Waypoint 时将会触发的 Action;
所有 Action 的执行相对与 Feature 都是异步的(如果需要同步,则应该使用 CustomFeature ,详见下方 2.7 的相关讨论)。目前 MeshEngine 中定义了如下 Action:
控制 Feature 执行的生命周期的核心在于,在 Feature 开始执行之后,将 Feature 的 Pause/Stop/Resume 管理从 Package 中独立开来,保证 Swift 对 Feature 的管理拥有最高权限,从而保证用户对飞机拥有最高控制权,凌驾于 Package 之上,确保操作的安全性。
FeatureControl 控件:
| Start/Resume | Pause/Stop |
|---|---|
![]() |
![]() |
为了简明起见,这里将 Start/Resume 的按钮命名为 Active 按钮,将 Pause/Stop 按钮命名为 Abort 按钮。
在 Package 的开发中,执行 Feature 的方法如下:
mesh.featureExecutor.executeFeatures(array, uuid)
其中 array 的元素为一个 JSON 字典,指定了某个 Feature 执行所需的各种参数。
而 uuid 的生成细节可参阅后面 Start 部分内容。
当用户点击 Active 按钮执行 Start 操作,Swift 会触发事件 featureWillStart,并且带上一个新生成的 uuid 作为执行 feature 的「通行证」,这个 uuid 在用户离开 Handler 页面之后便会失效,从而确保 Feature 只能在恰当的时空执行。
事件 featureWillStart 被触发时附带的数据格式:
{
"uuid": "xxxxxx"
}
之后 Package 便可以使用此 uuid 来调用 executeFeature 方法。
当 Feature 被成功执行后,Swift 将会触发 featureDidStart 事件,Package 可根据此来做界面上的更新。
而如果开始执行这个 Feature 的时候发生了错误,则会触发 featureStartFail 事件,并带上对应的错误信息:
{
"error": "xxxx"
}
| 事件 | 描述 | 数据 |
|---|---|---|
featureWillStart |
用户点击 Start 按钮时触发,用于向 Package 传递 uuid | {"uuid": xxx, "toDeviceId": xxx} |
featureDidStart |
Feature 成功开始执行后被触发 | {"toDeviceId": xxx} |
featureStartFail |
Feature 开始执行出错时被触发 | {"error": xxx, "toDeviceId": xxx} |
当用户点击了 FeatureControl 的 Abort 按钮,会触发 Pause/Stop 操作,由 Swift 执行,详细如下:

| 事件 | 描述 | 数据 |
|---|---|---|
featureDidPause |
Feature 被成功 Pause 之后触发 | {"toDeviceId": xxx} |
featurePauseFail |
Pause Feature 出错后被触发 | {"error": xxx, "toDeviceId": xxx} |
| 事件 | 描述 | 数据 |
|---|---|---|
featureDidStop |
Feature 被成功 Stop 之后触发 | See detail below |
featureStopFail |
Stop Feature 出错后被触发 | See detail below |
在触发 featureDidStop 以及 featureStopFail 时,Swift 会向 Package 回传数据:
{
"currentFeatureIndex": 0,
"error": "Some error if existed",
"data": {},
"toDeviceId": xxx
}
其中 data 字段的内容是根据 currentFeatureIndex 所指向的 feature 种类而定,对于不同 Feature,data 字段对应的内容如下:
{
"currentFeatureIndex": 0,
"error": "xxx",
"data": {
"lastWaypointIndex": 0
}
}
lastWaypointIndex 表示最近一次到达的航点的索引,没有则为 -1(飞往第一个点的过程中被 Stop)。
{
"currentFeatureIndex": 0,
"error": "xxx",
"data": {
"currentStepIndex": 0,
"lastWaypointIndex": x // Woudl be returned if current step is waypoint step
}
}
currentStepIndex 表示 CustomFeature 被 Stop 时正在执行的 Step 的索引。
当用用户点击 Active 按钮,Swift 按照以下逻辑进行判断处理:

| 事件 | 描述 | 数据 |
|---|---|---|
featureDidResume |
Feature 被成功 Resume 之后触发 | {"toDeviceId": xxx} |
featureResumeFail |
Resume Feature 出错后被触发 | {"toDeviceId": xxx, "error": xxx } |
| 事件 | 描述 | 数据 |
|---|---|---|
featureDidFinish |
Feature 顺利执行完毕后被触发 | See detail below |
featureExecuteFail |
Feature 由于自身执行出错而被中止 | See detail below |
在触发 featureDidFinish 以及 featureExecuteFail 时附带向 Package 回传数据,数据格式与 Stop 相关事件被触发时的回传数据一致。
| 事件 | 描述 | 数据 |
|---|---|---|
featureExecutionProgress |
事件的触发条件见下方详细描述 | See detail below |
由于 CustomFeature 以及 WaypointFeature 是以序列的方式定义的,他们都由一系列的元素组成:
- CustomFeature 接受一系列 Step,每个 Step 指定其需要完成的工作,CustomFeature 执行的时候按顺序依次执行每个 Step;
- WaypointFeature 接受一系列的 Waypoint,每个 Waypoint 指定一个 GPS 坐标,WaypointFeature 被执行时,飞机按顺序依次飞往每个指定的坐标;
对于这类序列形式的 Feature,Swift 通过 featureExecutionProgress 向 Package 回传其执行状态,在触发 featureExecutionProgress 的同时附带向 Package 回传数据。数据格式与 Stop 相关事件被触发时的回传数据类似。触发时机为:
- WaypointFeature: 飞机开始飞向下一个目标点时;
lastWaypointIndex代表上一个到达的航点索引;
- CustomFeature: 飞机开始执行下一个 Step 时;
currentStepIndex代表当前开始执行的 Step 的索引;
在前面 1.2 处关于 Action 的描述中提到:所有 Action 的执行相对与 Feature 都是异步的,由此引申出 Feature 与 Action 之间的生命周期关系:
- Feature 被 Abort (即:暂停/停止)时,相关 Action 会被停止;
- Action 执行/停止出错时不会干扰 Feature 的生命周期;
对于最后一点,制定此规则的原因是:
- 飞行相关的操作被终止后恢复的成本比较高;
- Action 执行出错可手动操作 ActionControl 来解决;
关于 Feature 与 Action 之间的生命周期关系,下面举一个例子帮助理解。如是一个 Waypoint Feature:

根据以上所述 Feature 与 Action 之间的生命周期关系,会有如下结论:
- 飞机到达
wp3时将会触发拍照,同时飞向wp4; - 如果
wp3处的拍照触发失败,飞机仍然会飞向wp4; - 如果
wp3处触发的是无限间隔拍照,当飞机到达wp5时此 Action 将被停止,因为 Feature 已经 Finish 了; - 如果
wp3处触发的是无限间隔拍照,当飞机到达wp4时用户触发暂停,此时 Action 会被停止; - 如果用户在
wp4处通过 ActionControl 停止了拍照,飞机照常飞行; - 如果飞机在
wp4处由于 SD Card 已满而以外停止拍照,飞机照常飞行;
**总而言之:**Feature 控制 Action 的生命周期,而 Action 不会影响 Feature 的生命周期。
上面讨论是基于 Pilot 环境。至于 Copilot 参与协作的情况下,相当于在上面的基础上再批一层 WebSocket 事件转发的外衣。此处的职责划分如下:

如上图所示,Feature 的配置过程中的信息交互由 Package 负责,包括 Feature 的 execute,也是由 Copilot 端的 Package 转发到 Pilot 端的 Package 环境,再由 Pilot 端的 Package 调用相应的 API。
而 Feature Control 相关的交互事件,以及 Feature 生命周期事件,由 Swift 进行转发处理。
因此 Copilot 端的 Package 仍然能从其 Swift 端接收到 featureExecutionProgress 事件,进行界面上的更新。

