在 DJI SDK 中 Mission 的执行是由各自对应的 operator 管理的,WaypointMission 的生命周期由 DJIWaypointMissionOperator
管理。
基本流程
检查任务
在上一篇文章中介绍了 mission 和 waypoint 可以进行的配置。很多配置项要在对应的模式下才有效,因此在开始任务前需要检查一下任务的配置是否正确。这里的检查函数有两个,一个检查 mission 的配置,一个检查 waypoint 的配置:
// 检查任务的参数配置是否有效
mission.checkParameters()
// 检查 waypoint 的配置是否有效
mission.checkValidity()
加载、上传任务
任务的执行是由 DJIWaypointMissionOperator
管理的,所以首先需要把任务加载到 operator 中:
guard let missionOperator = DJISDKManager.missionControl()?.waypointMissionOperator() else { return }
missionOperator.load(mission)
加载成功后需要把任务数据上传到无人机的飞控中。Waypoint 是一个一个上传的,如果 waypoint 比较多可能上传时间会久一些。要注意和无人机的通信状况是否良好,这一步很容易因为通信状况不佳失败。
missionOperator.uploadMission { (error) in
if let error = error {
// 处理上传失败的错误
}
}
考虑到可能有多个对象关心航点的上传进度,DJI 使用观察者模式来处理上传的进度通知。
// 添加观察者
/**
* Adds listener to receive the event related to upload.
*/
- (void)addListenerToUploadEvent:(id)listener
withQueue:(nullable dispatch_queue_t)queue
andBlock:(DJIWaypointMissionOperatorUploadEventBlock)block;
// 移除观察者
- (void)removeListenerOfUploadEvents:(id)listener;
通过回调的 DJIWaypointMissionUploadEvent 实例可以获取到当前的上传进度和任务的状态。
missionOperator.addListener(toUploadEvent: self, with: listenerQueue) { (uploadEvent) in
if let progress = uploadEvent.progress {
print("progress: \(progress.uploadedWaypointIndex)/\(progress.totalWaypointCount)")
}
if uploadEvent.currentState == .readyToExecute {
missionOperator.removeListener(ofUploadEvents: self)
}
}
当 uploadEvent 中的当前任务状态是 readyToExecute
时说明航点已经上传结束,无人机准备就绪。
任务控制
任务的控制有:开始、暂停、继续、停止四种操作。
- (void)startMissionWithCompletion:(DJICompletionBlock)completion;
- (void)pauseMissionWithCompletion:(DJICompletionBlock)completion;
- (void)resumeMissionWithCompletion:(DJICompletionBlock)completion;
- (void)stopMissionWithCompletion:(DJICompletionBlock)completion;
只要任务在对应正确的状态时这些操作才会成功。比如只有当任务是在执行的状态时暂停和停止才能正确执行,否则会返回一个错误。
任务进度监听
与上传航点的监听方式一致,任务的执行进度通知也采用了一样的的观察者模式。
/**
* Adds listener to receive the event related to execution.
*/
- (void)addListenerToExecutionEvent:(id)listener
withQueue:(nullable dispatch_queue_t)queue
andBlock:(DJIWaypointMissionOperatorExecutionEventBlock)block;
ExecutionEvent 返回的 DJIWaypointMissionExecutionEvent 实例。DJIWaypointMissionExecutionEvent 包含了任务当前的状态和任务执行的进度。
@interface DJIWaypointMissionExecutionEvent : NSObject
/**
* The previous state of the operator.
*/
@property (nonatomic, readonly) DJIWaypointMissionState previousState;
/**
* The current state of the operator.
*/
@property (nonatomic, readonly) DJIWaypointMissionState currentState;
/**
* The execution progress of the mission. It is `nil` if there is an error during
* the execution.
*/
@property (nonatomic, readonly, nullable) DJIWaypointExecutionProgress *progress;
/**
* The encountered error during the execution if there is any. Otherwise, it is
* `nil`.
*/
@property (nonatomic, readonly, nullable) NSError *error;
@end
通过 ExecutionEvent 中的 error 属性可以判断执行是否遇到错误,currentState 和 previousState 反应了此时的任务状态。progress 可以知道当前无人机飞过的航点进度。
@interface DJIWaypointExecutionProgress : NSObject
/**
* Index of the waypoint for the next mission to which the aircraft will proceed.
*/
@property(nonatomic, readonly) NSInteger targetWaypointIndex;
/**
* YES when the aircraft reaches a waypoint. After the waypoint actions and heading
* change is complete, the `targetWaypointIndex` will increment and this property
* will become NO.
*/
@property(nonatomic, readonly) BOOL isWaypointReached;
/**
* Current execution state of the aircraft.
*/
@property(nonatomic, readonly) DJIWaypointMissionExecuteState execState;
@end
targetWaypointIndex
表示飞机正在飞向的航点的索引,在飞行过程中 isWaypointReached
的值是 false。当无人机到达航点航点位置时 isWaypointReached
的值会变成 true。接着无人机根据设置调整 heading,执行 waypoint action。执行完成后 targetWaypointIndex
加 1,朝下一个航点飞去。
通常我们认为任务结束时 targetWaypointIndex
会是最后一个点,但是如果刚好 finishAction 是 goFirstWaypoint,无人机飞到最后一个点后会返回第一个航点,所以最后任务结束时的 targetWaypointIndex
会是 0。
另外一个容易理解错误的是 ExecutionEvent 是一个定时回调的事件,不是在 value changed 的时候才回调。所以无人机飞行过程中你可能会一直收到同样的值的 ExecutionEvent。
任务结束监听
任务结束的通知也采用了一样的的观察者模式。
/**
* Adds listener to receive the notification when a waypoint mission is finished.
*/
- (void)addListenerToFinished:(id)listener
withQueue:(nullable dispatch_queue_t)queue
andBlock:(DJICompletionBlock)block;
任务结束的回调有三种可能:
- 回调有 error,任务执行过程中遇到了错误,任务终止
- 回调无 error,到达过最后一个航点,任务正常结束
回调无 error,没有到达过最后一个航点,任务过程中用户主动停止了任务或者过程中触发无人机返航
任务状态
在任务生命周期中很多操作都和任务的状态有关。Operator 上的 currentState 能取到最近一次同步的任务状态。任务状态
DJIWaypointMissionState
总共有以下几种状态:Unknown:和无人机没有正常的通信,无法确认任务当前状态
- Disconnected:无人机断开连接
- Recovering:手机和遥控器、无人机间的连接正在重连,任务状态正在同步中
- NotSupported:连接的设备不支持该任务的状态同步
- ReadyToUpload:无人机现在可以上传航点数据
- Uploading:上传航点数据中
- ReadyToExecute:航点数据上传成功,准备好开始执行任务
- Executing:任务执行中
- Paused:任务被暂停
下载任务
Waypoint mission 因为航点是一次性上传到飞控中,默认又是遥控器丢失信号任务继续执行。所以可能出现任务过程中应用退出,应用重新连接上无人机后,无人机虽然在执行任务,但是 sdk 中已经取不到 waypointMission 中的航点信息了。如果这个时候你需要在任务结束后重新进行一次同样的任务,那么任务 start 的时候就会报错,因为本地没有航点信息可以上传。针对这个情况 Operator 提供了下载航点的方法,和上传航点类似,需要注意的是只有在任务暂停和执行状态时下载航点才有效。 ```objectivec /**- Downloads information of each waypoint from aircraft and save it to
loadedMission
. If a download operation is started, the operator will download- the information of waypoints missing in
loadedMission
one-by-one in ascending - order. If
loadedMission
is already complete (containing all the waypoints), - this method will call
completion
immediately without error. It can only be - called when the
currentState
is one of the following: - DJIWaypointMissionStateExecuting
-DJIWaypointMissionStateExecutionPaused
*/
- (void)downloadMissionWithCompletion:(DJICompletionBlock)completion; // 监听下载的进度
- (void)addListenerToDownloadEvent:(id)listener
```withQueue:(nullable dispatch_queue_t)queue
andBlock:(DJIWaypointMissionOperatorDownloadEventBlock)block;