简单的流程就是如下图所示分为三步:
连接上飞机,切换成 virtualStickControl 模式
发送 control data
结束后关闭 virtualStickControl 模式
VirtualStickMode
在确定连接上飞行机后,从 DJIAircraft 对象上获取 DJIFlightController 实例:flightController。
切换到 api 控制模式的代码很简单,只有一行:
flightController.setVirtualStickModeEnabled(true, withCompletion: nil)
但是这行代码执行未必都会成功,需要满足以下两种情况才能切换:
飞控程序没有在执行控制飞行器运动路径。如果飞行器在执行 waypoint、hotpoint、跟随任务时,无法切换。
FlightOrientationMode 需要设置为 aircraftHeading。
flightController.setFlightOrientationMode(.aircraftHeading, withCompletion: nil)
FlightOrientationMode 默认方向定位模式就是根据当前无人机朝向。加这个限制应该是出于安全的原因,想要移动飞行器,通常是根据图传视频来判断位置移动。FlightOrientationMode 还有两种方式:Course Lock 和 Home Lock。都是锁定了某个位置来判断移动方位,特殊任务中有帮助,但是如果通过程序控制飞行器还是按照飞行器的当前朝向符合直觉。
成功切换到程序控制飞行器运动后,遥控器上的操作杆会出于无效的状态
这是非常非常重要且被忽略的一点。这个设计应该也是出于安全考虑,希望飞行器在某个时刻只有一个明确的控制权,如果一个时刻遥控器发出往左,程序控制往右。两个指令都拥有一样的优先级,不知道谁优先。所以在控制运动完成后切记把 VirtualStickMode 设置为 false。
VirtualStickFlightControlData
在切换到程序控制运动模式后,就可以发送控制指令了。和遥控器上的两个摇杆控制能力一样,你可以控制飞行器的升降、水平旋转、水平方向的前进后退、向左向右。
运动指令的参数是一个 DJIVirtualStickFlightControlData 类型的结构体,前面提到可以控制四个维度的运动,因此有四个浮点型的值可以设置:
typedef struct
{
float pitch;
float roll;
float yaw;
float verticalThrottle;
} DJIVirtualStickFlightControlData
为了让用户可以更加灵活的控制飞行器运动,这四个维度的参数值在不同模式下代表着不同的含义。
RollPitchControlMode
水平方向 X、Y 轴的运动的控制模式是一致的,因此组合在一起,枚举名叫 RollPitchControlMode。
在设置水平运动的值时需要先确定此时选择的参考坐标系。为了更方便的控制姿态,DJI 提供了两个坐标系:Body Coordinate 和 Ground(World) Coordinate。
坐标系
设置坐标系的方式很简单,设置 rollPitchCoordinateSystem 即可:
flightController.rollPitchCoordinateSystem = .ground
机身坐标系:Body Coordinate机身坐标系类似第一人称视角,飞行器的正前方是 X 轴,与前方垂直的侧面测试 Y 轴。
世界坐标系:Ground(World) Coordinate地面坐标系就像是地面有个控制中心的视角,南北方向是 X 轴,东西方向是 Y 轴。
RollPitchControlModeAngle
如果是机身坐标系,角度就是机身X、Y轴的旋转角度。取值范围是 - 30 到 30 度。
如果是地面坐标系,那么就是相对地面的移动角度。
RollPitchControlModeVelocity
X、Y 轴的移动速度,取值范围 -15 到 15 米每秒。根据坐标系不同 X、Y 轴的方向不同,前面已经说明过。
YawControlMode
Yaw 从地面角度看就是飞机原地旋转,也就是调整机头方位。同样参数有两种模式:
Angle
相对于机头的旋转角度,取值范围注意不是 0 - 360,而是 -180 到 180。正的角度表示顺时针旋转,负的角度值表示逆时针。
AngularVelocity
旋转时的角速度,取值范围是 -100 到 100。负数表示逆时针方向旋转。如果你想要飞行器以个指定的角速度匀速旋转,那么应该选择这个模式。
VerticalControlMode
Velocity
调整高度的速度,取值范围是 -4 到 4。正的值表示往高处飞,负数表示下降时的速度。
Position
直接设置想要到达的高度值,取值范围是 0 到 500 米。也就是说最高可以让飞行器飞到 500 米的高度。
发送指令
发送控制的指令代码很简单,只有一行:
flightController.send(controlData, withCompletion: { error in })
但是事情并不如代码看上去这样简单。VirtualStick API 设计参照的是遥控器操纵杆的通讯方式,比如你把一个摇杆往上推,飞行器此时对应的操作是升高。那么在你往上推的时刻,遥控器是以一个频率持续给飞行器发送升高指令。在你松开的时候,摇杆回到中心,指令停止。并不是只发送了一条指令。和这个场景类似,如果你要控制飞行器运动,你的指令也应该是持续发送的。
官方给出的发送频率是 10 到 25 赫兹。换算一下,那么程序应该以 0.04 秒 - 0.1 秒的频率就发送一次控制指令。可能对于程序而言,非常清楚飞行器运动的终点是哪,觉得只要调用一次接口,但是出于安全考虑,如果指令不是持续发送的,飞行器收到指令也可能不去执行。
为了避免发出指令飞行器认为是通讯失误而没有执行,可以采取用一个 timer 以一个固定的 interval 发送指令。简单一些可以正确的频率发送 5 次,如果是 0.1 秒的频率,那么等于确保一条指令飞行器认可花 0.5 秒时间。另外一个思路是指令发送后从 KeyManager 获取飞行器的姿态信息(DJISDKVector3D),如果指令发送过程中姿态数据改变了,那么一定是执行了控制指令。
奇志动联 MeshKit 是奇志信息科技有限公司旗下的一个基于无人机+人工智能的物联网作业平台,为企业级用户及专业级个人用户提供易用便捷的无人机软件及云计算解决方案,通过任务自动化、多机协同、场景定制开发功能、人工智能等核心技术,大幅提升客户使用无人机等智能物联网设备解决实际生产问题的效率。
我们在杭州和深圳招聘 iOS、Android 工程师,如果感兴趣欢迎给我们投简历:奇志信息科技招聘信息。