Fixed-wing UAV Wayline Mission Tutorial
Wayline Mission Tutorial
1. Overview
Fixed-wing UAV wayline missions allow users to manually select target points and automatically generate flight routes through different route planning algorithms. Users can customize flight parameters and camera actions at waypoints. The algorithm library supports ground missions (including waypoint missions, polygon missions, return-to-home missions, landing missions, and online mission planning).
Note: For wayline planning, please refer to the documentation on GitHub: Wayline Planning Algorithm Documentation
2. Wayline Mission Process
2.1 Planning the Route
For route planning, refer to Chapter 3 Route Algorithm Planning
2.2 Writing Planned Route to Local File
Using the NativeHelper.writeNewMissionFile interface, you can convert the planned waypoint information into a binary format that the aircraft can recognize and save it locally.
public static native int writeNewMissionFile(String filePath, PathPlanningParameter parameter);
Description: Write wayline mission file
Input Parameters:
filePath: File path
parameter: Route planning parameters
Output Parameters: 0 for success; non-zero for failure
Related Parameters: PathPlanningParameter
Example code:
val path = cxt.cacheDir?.absolutePath + "/task_${System.currentTimeMillis()}.aut"
cxt.assets?.open("task.json")?.use {
val parameter = Gson().fromJson(it.bufferedReader(), PathPlanningParameter::class.java)
val result = NativeHelper.writeNewMissionFile(path, parameter)
}
2.3 Pre-flight Check
Before executing a mission, the aircraft needs to perform a pre-flight check. For the pre-flight check process, refer to Fixed-wing UAV Pre-flight Check Tutorial. Additionally, you need to check the aircraft battery, base station battery, remote controller battery, and whether there are any abnormalities in various modules reported in the heartbeat.
2.3.1 Check Aircraft Battery
val droneStateData = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getDeviceStateData()
isBatteryOk = (droneStateData?.flightControlData?.batteryRemainingPower ?:) > 15
2.3.2 Remote Controller Battery
Remote controller battery level can be obtained through broadcast messages
val batteryReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val remaining = intent.extras?.getInt("level") // Get current battery percentage
val isRCBatteryOK = (remaining ?: 0) > 15
}
}
//register broadcast receive
val filter = IntentFilter()
filter.addAction(Intent.ACTION_BATTERY_CHANGED)
context.registerReceiver(batteryReceiver, filter)
2.3.3 Base Station Battery
val stationStatusNtfy = KeyTools.createKey(WifiBaseStationKey.KeyBaseStationStatusNtfy)
val stationKeyManager = DeviceManager.getDeviceManager().getBaseStationDevice()?.getKeyManager()
stationKeyManager?.listen(stationStatusNtfy, object : CommonCallbacks.KeyListener<WifiBaseStationStatusNtfyBean> {
override fun onValueChange(oldValue: WifiBaseStationStatusNtfyBean?, newValue: WifiBaseStationStatusNtfyBean) {
val remaining = newValue.batteryLevel //BaseStation battery remaining, [0,100]
}
})
data class WifiBaseStationStatusNtfyBean(
val satellitesNum: Int, //Number of RTK satellites of Base Station
val status: Int, //Base station status information: bit 0: Base station shutdown flag(0-normal operation; 1-about to shut down). bit 1-31 Reserve
val reserve: Int, //Reserved
val batteryLevel: Int, //Base station battery information, range 0-100
val rtkSignalQuality: Int, //Base station RTK signal quality, range 0-5
)
2.4 Upload Mission
2.4.1 Set Mission Status Listener
fun addWaypointMissionExecuteStateListener(
listener: CommonCallbacks.KeyListener<MissionWaypointStatusReportNtfyBean>
)
Description: Set the listener for wayline mission execution status. It can be used to monitor the execution status of the wayline mission, such as: mission file uploading, entering wayline mission flight, mission completion, and other states.
Input Parameters:
listener: Mission status callback
Output Parameters: None
Related Parameters: MissionTypeEnum MissionCurrentStateEnum MissionWaypointStatusReportNtfyBean
data class MissionWaypointStatusReportNtfyBean(
/**
* System timestamp; unit: ms
*/
var timestamp: Long = 0L,
/**
* Mission ID
*/
var missionId: Int = 0,
/**
* Waypoint sequence number
*/
var wpSeq: Int = 0,
/**
* Remaining distance
*/
var remainDistance: Int = 0,
/**
* Mission type
*/
var missionType: MissionTypeEnum = MissionTypeEnum.UNKNOWN,
/**
* Current number of photos taken
*/
var photoNum: Int = 0,
/**
* Remaining time; unit: s
*/
var remainTime: Int = 0,
/**
* Current mission status
*/
var status: MissionCurrentStateEnum = MissionCurrentStateEnum.UNKNOWN,
/**
* Mission guid
*/
var guid: Int = 0,
/**
* Current action sequence number
*/
var actionSeq: Int = 0,
/**
* Waypoint arrival status; 0 - arrived; 1 - Not arrived
*/
var arrived: Int = 0,
/**
* Mission set speed; Unit: 10E-3 m/s
* Note: Unused field, changed to distinguish between kml mission and bin mission
*/
var speedSet: Int = 0,
/**
* Mission progress percentage
*/
var percent: Int = 0,
// Current mission stage
var taskStageIndex: Int = 4,
//Total mileage
var distance: Int = 0
)
Example:
val missionManager = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getWayPointMissionManager()
missionManager?.addWaypointMissionExecuteStateListener(object : CommonCallbacks.KeyListener<MissionWaypointStatusReportNtfyBean> {
override fun onValueChange(oldValue: MissionWaypointStatusReportNtfyBean?, newValue: MissionWaypointStatusReportNtfyBean) {
SDKLog.i(TAG, "mission[${newValue.missionId}, ${newValue.guid}] status: ${newValue.status}")
}
})
2.4.2 Start Uploading Mission
Use the uploadMissionByPath interface of IMissionManager to upload the mission. Detailed parameter information is as follows:
fun uploadMissionByPath(
filePath: String,
missionId: Long,
listener: CommonCallbacks.CompletionCallbackWithProgressAndParam<Long>
)
Description: Upload mission to aircraft
Input Parameters:
filePath: File path, must be consistent with the path in Writing Planned Route to Local File
guid: Mission unique identifier
listener: Upload progress and result callback
Output Parameters: None
Example:
val missionId = System.currentTimeMillis().toInt()
val missionManager = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getWayPointMissionManager()
missionManager.uploadMissionByPath(path, missionId.toLong(), object: CommonCallbacks.CompletionCallbackWithProgressAndParam<Long> {
override fun onProgressUpdate(progress: Double) {
SDKLog.i(TAG, "prepareMission onProgressUpdate = $progress")
}
override fun onSuccess(guid: Long?) {
SDKLog.e(TAG, "prepareMission onSuccess = $guid")
}
override fun onFailure(error: IAutelCode, msg: String?) {
SDKLog.e(TAG, "prepareMission onFailure error = $error msg = $msg")
}
})
2.5 Start Executing Mission
After the file upload is complete, use IMissionManager's startDragonFishMission function to notify the aircraft to start executing the mission. The detailed parameter information for this function is as follows:
fun startDragonFishMission(
mission: DFStartMissionBean,
callback: CommonCallbacks.CompletionCallbackWithParam<DFCommonAck>
)
Description: Upload mission to aircraft
Input Parameters:
mission: Mission information
callback: Result callback
Output Parameters: None
Related Parameters: DFStartMissionBean, DFCommonAck
data class DFStartMissionBean(
var data0: Int = 0, //Default: 0
var missionId: Int = 0 //Mission unique identifier, consistent with upload
)
//Start mission result information
data class DFCommonAck(
var ackStatus: Int = 0, //0: Success, otherwise abnormal
var errorCode1: Int = 0, //Error code
var errorCode2: Int = 0,
) {
fun isSuccess():Boolean{
return ackStatus == 0
}
/**
* Left servo abnormal
*/
fun isLeftSteerFault(): Boolean {
return (errorCode1 and 0x1) == 1
}
/**
* Right servo abnormal
*/
fun isRightSteerFault(): Boolean {
return (errorCode1 shr 1 and 0x1) == 1
}
/**
* Elevator abnormal
*/
fun isFontSteerFault(): Boolean {
return (errorCode1 shr 2 and 0x1) == 1
}
/**
* Airspeed meter abnormal
*/
fun isAirSpeedFault(): Boolean {
return (errorCode1 shr 3 and 0x1) == 1
}
/**
* RTK abnormal
*/
fun isRtkFault(): Boolean {
return (errorCode1 shr 4 and 0x1) == 1
}
/**
* GPS abnormal
*/
fun isGpsFault(): Boolean {
return (errorCode1 shr 5 and 0x1) == 1
}
/**
* Magnetometer abnormal
*/
fun isMagnetometerFault(): Boolean {
return (errorCode1 shr 6 and 0x1) == 1
}
/**
* IMU abnormal
*/
fun isImuFault(): Boolean {
return (errorCode1 shr 7 and 0x1) == 1
}
/**
* Barometer abnormal
*/
fun isBarometerFault(): Boolean {
return (errorCode1 shr 8 and 0x1) == 1
}
/**
* Remote controller disconnected
*/
fun isRcDisconnect(): Boolean {
return (errorCode1 shr 9 and 0x1) == 1
}
/**
* Attitude unavailable
*/
fun isAttitudeNotUse(): Boolean {
return (errorCode1 shr 10 and 0x1) == 1
}
/**
* Heading unavailable
*/
fun isHeadingNotUse(): Boolean {
return (errorCode1 shr 11 and 0x1) == 1
}
/**
* Speed unavailable
*/
fun isSpeedNotUse(): Boolean {
return (errorCode1 shr 12 and 0x1) == 1
}
/**
* Position unavailable
*/
fun isPositionNotUse(): Boolean {
return (errorCode1 shr 13 and 0x1) == 1
}
/**
* Height unavailable
*/
fun isHeightNotUse(): Boolean {
return (errorCode1 shr 14 and 0x1) == 1
}
/**
* Remaining power unavailable
*/
fun isElectricityNotUse(): Boolean {
return (errorCode1 shr 15 and 0x1) == 1
}
/**
* Speed Euler unavailable
*/
fun isSpeedEulerNotUse(): Boolean {
return (errorCode1 shr 16 and 0x1) == 1
}
/**
* Mandatory lock
*/
fun isMandatoryLock(): Boolean {
return (errorCode1 shr 17 and 0x1) == 1
}
/**
* Airspeed calibration fault
*/
fun isAirSpeedCalibrationFault(): Boolean {
return (errorCode1 shr 18 and 0x1) == 1
}
/**
* Magnetometer calibration fault
*/
fun isMagnetometerCalibrationFault(): Boolean {
return (errorCode1 shr 19 and 0x1) == 1
}
/**
* Aircraft in no-fly zone
*/
fun isNoFlyZone(): Boolean {
return (errorCode1 shr 20 and 0x1) == 1
}
/**
* Battery 1 temperature too high
*/
fun isOneBatteryHighTemp(): Boolean {
return (errorCode1 shr 21 and 0x1) == 1
}
/**
* Battery 1 temperature too low
*/
fun isOneBatteryLowTemp(): Boolean {
return (errorCode1 shr 22 and 0x1) == 1
}
/**
* Battery 1 damaged
*/
fun isOneBatteryBad(): Boolean {
return (errorCode1 shr 23 and 0x1) == 1
}
/**
* Battery 2 temperature too high
*/
fun isTwoBatteryHighTemp(): Boolean {
return (errorCode1 shr 24 and 0x1) == 1
}
/**
* Battery 2 temperature too low
*/
fun isTwoBatteryLowTemp(): Boolean {
return (errorCode1 shr 25 and 0x1) == 1
}
/**
* Battery 2 damaged
*/
fun isTwoBatteryBad(): Boolean {
return (errorCode1 shr 26 and 0x1) == 1
}
/**
* Battery power mismatch
*/
fun isBatteryElectricityNotBalance(): Boolean {
return (errorCode1 shr 27 and 0x1) == 1
}
/**
* Battery quantity mismatch
*/
fun isBatteryNumNotBalance(): Boolean {
return (errorCode1 shr 28 and 0x1) == 1
}
/**
* Navigation attitude initialization
*/
fun isNavigationInitialization(): Boolean {
return (errorCode1 shr 29 and 0x1) == 1
}
/**
* Maintenance reminder 30
*/
fun isMaintenancReminder(): Boolean {
return (errorCode1 shr 30 and 0x1) == 1
}
/**
* Version matching
*/
fun isVersionMatching(): Boolean {
return (errorCode1 shr 31 and 0x1) == 1
}
/**
* Mobile base station RTK information validity
* true-valid, false-invalid
*/
fun isBaseStationRTKInvalid(): Boolean {
return (errorCode2 and 0x1) == 1
}
/**
* Mobile base station RTK Heading2 information validity
* true-valid, false-invalid
*/
fun isBaseStationRTKHeadingTwoInvalid(): Boolean {
return (errorCode2 shr 1 and 0x1) == 1
}
/**
* Mobile base station RTK Heading information validity
* true-valid, false-invalid
*/
fun isBaseStationRTKHeadingInvalid(): Boolean {
return (errorCode2 shr 2 and 0x1) == 1
}
/**
* Mobile base station RTK position information validity
* true-valid, false-invalid
*/
fun isBaseStationRTKPositionInvalid(): Boolean {
return (errorCode2 shr 3 and 0x1) == 1
}
/**
* Mobile base station RTK speed information validity
* true-valid, false-invalid
*/
fun isBaseStationRTKSpeedInvalid(): Boolean {
return (errorCode2 shr 4 and 0x1) == 1
}
/**
* Mobile base station RTK attitude information status
* true-normal, false-abnormal
*/
fun isBaseStationRTKAttitudeInvalid(): Boolean {
return (errorCode2 shr 5 and 0x1) == 1
}
/**
* Mobile return point information status
* true-normal, false-abnormal
*/
fun isMoveHomePositionInvalid(): Boolean {
return (errorCode2 shr 6 and 0x1) == 1
}
/**
* Mobile base return point precision difference status
* true-normal, false-abnormal
*/
fun isMoveHomePrecisionInvalid(): Boolean {
return (errorCode2 shr 7 and 0x1) == 1
}
/**
* Near no-fly zone
*/
fun isCloseNFZ(): Boolean {
return (errorCode2 shr 8 and 0x1) == 1
}
/**
* Inside no-fly zone
*/
fun isInTheNFZ(): Boolean {
return (errorCode2 shr 9 and 0x1) == 1
}
/**
* Near flight zone edge
*/
fun isCloseEdgeFlyZone(): Boolean {
return (errorCode2 shr 10 and 0x1) == 1
}
/**
* Outside flight zone
*/
fun isOutFlyZone(): Boolean {
return (errorCode2 shr 11 and 0x1) == 1
}
/**
* Aircraft near mandatory flight zone edge
*/
fun isCloseEdgeMandFlyZone(): Boolean {
return (errorCode2 shr 12 and 0x1) == 1
}
/**
* Whether to sync geofence information
*/
fun isNeedUploadGenFence(): Boolean {
return (errorCode2 shr 13 and 0x1) == 1
}
/**
* Battery temperature below 25°C and power below 60%, do not take off
*/
fun isBatteryLowTempAndHeating(): Boolean {
return (errorCode2 shr 14 and 0x1) == 1
}
/**
* Whether flight controller board or CPU overheating prevents unlocking
*/
fun isFlightControllerOverheating(): Boolean {
return (errorCode2 shr 15 and 0x1) == 1
}
//16-21 reserved for 75KG
/**
* Aircraft configuration status mismatch, takeoff prohibited
*/
fun isStatusMismatch(): Boolean {
return (errorCode2 shr 22 and 0x1) == 1
}
/**
* Left wing reached maintenance period, takeoff prohibited
*/
fun isLeftWingReachedMaintenance(): Boolean {
return (errorCode2 shr 23 and 0x1) == 1
}
/**
* Right wing reached maintenance period, takeoff prohibited
*/
fun isRightWingReachedMaintenance(): Boolean {
return (errorCode2 shr 24 and 0x1) == 1
}
/**
* Elevator reached maintenance period, takeoff prohibited
*/
fun isTailWingReachedMaintenance(): Boolean {
return (errorCode2 shr 25 and 0x1) == 1
}
/**
* Whether self-check was successful
*/
fun isAutoCheckSuc(): Boolean {
return (errorCode2 shr 26 and 0x1) == 0
}
}
Example:
val bean = DFStartMissionBean(0, missionId)
val missionManager = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getWayPointMissionManager()
missionManager?.startDragonFishMission(bean, object: CommonCallbacks.CompletionCallbackWithParam<DFCommonAck> {
override fun onSuccess(t: DFCommonAck?) {
if (t?.ackStatus == 0) {
SDKLog.i(TAG, "startDragonFishMission onSuccess")
} else {
SDKLog.i(TAG, "startDragonFishMission error: $t")
}
}
override fun onFailure(error: IAutelCode, msg: String?) {
SDKLog.e(TAG, "startDragonFishMission onFailure error = $error msg = $msg")
}
})
2.6 Cancel Mission
During wayline mission execution, you can terminate the mission early
fun stopDragonFishMission(callback: CommonCallbacks.CompletionCallbackWithParam<Void>)
Description: Cancel the currently executing mission
Input Parameters:
callback: Result callback
Output Parameters: None
Related Parameters: None
Example:
val missionManager = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getWayPointMissionManager()
missionManager?.stopDragonFishMission(object: CommonCallbacks.CompletionCallbackWithParam<Void> {
override fun onSuccess(t: Void?) {
SDKLog.i(TAG, "stopDragonFishMission onSuccess")
}
override fun onFailure(error: IAutelCode, msg: String?) {
SDKLog.e(TAG, "stopDragonFishMission onFailure error = $error msg = $msg")
}
})
3. Route Algorithm Planning
A waypoint mission consists of multiple waypoints. When the aircraft reaches each waypoint, it executes preset actions. After completing the action, the aircraft flies to the next waypoint to execute its preset action, continuing until all waypoint tasks are completed.
For detailed field definitions, see PathPlanningParameter
3.1 Waypoint Mission Algorithm Planning
The following example waypoint mission data contains 4 waypoints with different camera actions (timed photo, distance-based photo, video recording, and no action) and different turn modes (early turn, turn at point, timed loiter, and count loiter).
{
"forceLandInfo": [],
"introInfo": {
"CycleMode": 0,
"EndSubID": 1,
"EndWPID": 1.0,
"MaxVz": 3.0,
"MinRadius": 200.0,
"StartSubID": 1,
"StartWPID": 1.0,
"forceLandNum": 6,
"initAlt": 0.0,
"initLat": 22.6711518,
"initLon": 114.401592,
"planningType": 11,
"subMisNum": 1
},
"landInfo": {
"altType": 2,
"approachAlt": 100.0,
"approachLat": 22.67115217201107,
"approachLon": 114.40852555068489,
"approachR": 200.0,
"approachVel": 20.0,
"homeAlt": 0.0,
"homeAltType": 2,
"homeLat": 22.671151890825084,
"homeLon": 114.40159203995298,
"transAlt": 40.0
},
"launchInfo": {
"altType": 2,
"departureAlt": 100.0,
"departureLat": 22.67115217201107,
"departureLon": 114.39465852922104,
"departureR": 200.0,
"departureVel": 20.0,
"launchAlt": 0.0,
"launchLat": 22.6711518,
"launchLon": 114.401592,
"transAlt": 40.0
},
"missionInfo": [
{
"FinishMove": 1,
"IANum": 0,
"InterestArea": [],
"LinkLostMove": 2,
"WPNum": 4,
"subMissionInfo": {
"airLineDir": 0.0,
"baseAlt": 0.0,
"focalLength": 0.0,
"overlapAlong": 0,
"overlapSide": 0,
"pixNumX": 0,
"pixNumY": 0,
"resolution": 0.0,
"sensorOrient": 1,
"sensorSizeX": 0.0,
"sensorSizeY": 0.0
},
"subMissionType": 1,
"wpInfo": [
{
"actionParam1": 2.0,
"gimbalPitch": -20.0,
"gimbalYaw": 20.0,
"payloadAction": 2,
"wpAlt": 100.0,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 1,
"wpLat": 22.674328180678019,
"wpLon": 114.4047683298059,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 1,
"wpTurnParam1": 1.0,
"wpType": 4,
"wpVel": 20.0
},
{
"actionParam1": 30.0,
"gimbalPitch": -21.0,
"gimbalYaw": -12.0,
"payloadAction": 3,
"wpAlt": 100.0,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 2,
"wpLat": 22.675962253677754,
"wpLon": 114.41498908190119,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 2,
"wpTurnParam1": 1.0,
"wpType": 4,
"wpVel": 20.0
},
{
"actionParam1": 0.0,
"gimbalPitch": 0.0,
"gimbalYaw": 0.0,
"payloadAction": 4,
"wpAlt": 100.0,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 3,
"wpLat": 22.670988151474945,
"wpLon": 114.41920251410528,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 3,
"wpTurnParam1": 1.0,
"wpType": 4,
"wpVel": 20.0
},
{
"actionParam1": 0.0,
"gimbalPitch": 0.0,
"gimbalYaw": 0.0,
"payloadAction": 0,
"wpAlt": 100.0,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 4,
"wpLat": 22.664984623824226,
"wpLon": 114.41750881521046,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 4,
"wpTurnParam1": 1.0,
"wpType": 4,
"wpVel": 20.0
}
]
}
]
}
3.2 Polygon Mission Algorithm Planning
A polygon mission must have 4 or more vertices. Below is an example of a rectangular mission:
{
"forceLandInfo": [],
"introInfo": {
"CycleMode": 0,
"EndSubID": 1,
"EndWPID": 1.0,
"MaxVz": 3.0,
"MinRadius": 200.0,
"StartSubID": 1,
"StartWPID": 1.0,
"forceLandNum": 0,
"initAlt": 0.0,
"initLat": 22.6711518,
"initLon": 114.401592,
"planningType": 11,
"subMisNum": 1
},
"landInfo": {
"altType": 2,
"approachAlt": 100.0,
"approachLat": 22.675126780890964,
"approachLon": 114.40010098056912,
"approachR": 200.0,
"approachVel": 19.820269,
"homeAlt": 0.0,
"homeAltType": 2,
"homeLat": 22.6711518,
"homeLon": 114.401592,
"transAlt": 40.0
},
"launchInfo": {
"altType": 1,
"departureAlt": 800.0,
"departureLat": 22.675126780890964,
"departureLon": 114.38623355723455,
"departureR": 200.0,
"departureVel": 19.820269,
"launchAlt": 0.0,
"launchLat": 22.6711518,
"launchLon": 114.401592,
"transAlt": 40.0
},
"missionInfo": [
{
"FinishMove": 1,
"IANum": 0,
"InterestArea": [],
"LinkLostMove": 2,
"WPNum": 4,
"subMissionInfo": {
"airLineDir": 0.0,
"baseAlt": 0.0,
"focalLength": 0.0,
"overlapAlong": 80,
"overlapSide": 70,
"pixNumX": 0,
"pixNumY": 0,
"resolution": 5.0,
"sensorOrient": 1,
"sensorSizeX": 0.0,
"sensorSizeY": 0.0
},
"subMissionType": 2,
"wpInfo": [
{
"actionParam1": 0.0,
"gimbalPitch": -90.0,
"gimbalYaw": 0.0,
"payloadAction": 1,
"wpAlt": 800.00006,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 1,
"wpLat": 22.684655369221415,
"wpLon": 114.3899909790489,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 2,
"wpTurnParam1": 0.0,
"wpType": 5,
"wpVel": 19.820269
},
{
"actionParam1": 0.0,
"gimbalPitch": -90.0,
"gimbalYaw": 0.0,
"payloadAction": 1,
"wpAlt": 800.00006,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 2,
"wpLat": 22.684655369221415,
"wpLon": 114.40269613846066,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 2,
"wpTurnParam1": 0.0,
"wpType": 5,
"wpVel": 19.820269
},
{
"actionParam1": 0.0,
"gimbalPitch": -90.0,
"gimbalYaw": 0.0,
"payloadAction": 1,
"wpAlt": 800.00006,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 3,
"wpLat": 22.67195020980967,
"wpLon": 114.40269613846066,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 2,
"wpTurnParam1": 0.0,
"wpType": 5,
"wpVel": 19.820269
},
{
"actionParam1": 0.0,
"gimbalPitch": -90.0,
"gimbalYaw": 0.0,
"payloadAction": 1,
"wpAlt": 800.00006,
"wpAltType": 2,
"wpClimbMode": 1,
"wpIndex": 4,
"wpLat": 22.67195020980967,
"wpLon": 114.3899909790489,
"wpRadius": 200.0,
"wpReserved1": 0.0,
"wpTurnMode": 2,
"wpTurnParam1": 0.0,
"wpType": 5,
"wpVel": 19.820269
}
]
}
]
}
4. Geofencing
Geofencing is a location-based technology that triggers specific actions (such as notifications, data reporting, or device control) by defining virtual geographic boundaries. Autel's fixed-wing aircraft supports user-defined geofences that can be uploaded to the aircraft.
4.1 Geofence Examples
Autel's fixed-wing aircraft supports both circular and polygon geofences. Below are examples of both types. For detailed field definitions, refer to GeoFenceModel
Circular geofence example:
{
"areaColor": "#F20000",
"areaLevel": 0,
"areaShape": "CIRCLE",
"areaType": "NO_FLY",
"createTime": 1741179913420,
"effectiveTimeEnd": -1,
"effectiveTimeStart": 0,
"height": 8000.0,
"id": 2,
"isHeightValid": true,
"latLngs": [],
"latestUpdateTime": 1741179913420,
"latitude": 22.64629050297846,
"longitude": 114.3346175862734,
"maxHeight": 0,
"minHeight": 0,
"name": "fence2",
"polygonNum": 0,
"radius": 2000.0,
"updateStatus": 0,
"userId": "",
"uuid": "72ddf9d232c948aa8e68e5e2b9e4b7e7"
}
Polygon geofence example:
{
"areaColor": "#F20000",
"areaLevel": 0,
"areaShape": "POLYGON",
"areaType": "NO_FLY",
"createTime": 1741179851929,
"effectiveTimeEnd": -1,
"effectiveTimeStart": 0,
"height": 8000.0,
"id": 1,
"isHeightValid": true,
"latLngs": [
{
"altitude": 0.0,
"id": 3,
"latitude": 22.675001560243169,
"longitude": 114.37438646253925
},
{
"altitude": 0.0,
"id": 4,
"latitude": 22.68069474562877,
"longitude": 114.39080895728216
},
{
"altitude": 0.0,
"id": 5,
"latitude": 22.675001560243169,
"longitude": 114.40202524789506
},
{
"altitude": 0.0,
"id": 6,
"latitude": 22.649501312682724,
"longitude": 114.40202267856681
},
{
"altitude": 0.0,
"id": 7,
"latitude": 22.646094901064495,
"longitude": 114.38854917796918
},
{
"altitude": 0.0,
"id": 8,
"latitude": 22.649501312682724,
"longitude": 114.37438903186752
}
],
"latestUpdateTime": 1741179851929,
"latitude": 22.68069474562877,
"longitude": 114.39080895728216,
"maxHeight": 0,
"minHeight": 0,
"name": "fence1",
"polygonNum": 6,
"radius": 2000.0,
"updateStatus": 0,
"userId": "",
"uuid": "ed64b0abe17e4bde8ddcaa373a7a88c6"
}
4.2 Uploading Geofences
4.2.1 Generate Binary File
Use the NativeHelper.writeGeoFenceFile interface to convert geofence information into a binary format that the aircraft can recognize and save it locally.
public static native boolean writeGeoFenceFile(String filePath, ArrayList<GeoFenceModel> data);
Description: Write geofence file
Input Parameters:
filePath: File path
data: Geofence information, supports converting multiple geofences together
Output Parameters: true for success; false for failure
Related Parameters: GeoFenceModel
Example code:
val path = ctx.cacheDir?.absolutePath + "/geofence_${System.currentTimeMillis()}"
ctx.assets?.open("task.json")?.use {
val model = Gson().fromJson(it.bufferedReader(), GeoFenceModel::class.java)
val result = NativeHelper.writeGeoFenceFile(path, listOf(model))
}
4.2.2 Upload Geofence
fun uploadNoFlyZoneFile(file: File, fileType: FileTypeEnum, listener: FileTransmitListener<String?>)
Description: Upload no-fly zone file to aircraft
Input Parameters:
file: File
fileType: No-fly zone type
listener: Upload progress and result callback
Output Parameters: None
Related Parameters: FileTypeEnum
enum class FileTypeEnum(var value: Int) {
/**
* Elevation file
*/
ELEVATION,
/**
* Fixed no-fly zone file
*/
FIXED_NO_FLY_ZONE,
/**
* Temporary no-fly zone file
*/
TEMP_NO_FLY_ZONE(3),
/**
* Authorized zone file
*/
AUTHORIZED_ZONE(4),
/**
* Geofence
*/
ELECTRIC_BARRIER(5),
/**
* Flyable zone file
*/
FLY_ZONE(14),
/**
* Unknown
*/
UNKNOWN(-1)
}
Example code:
val fileManager = DeviceManager.getDeviceManager().getFirstDroneDevice()?.getFileServiceManager()
fileManager?.uploadNoFlyZoneFile(file, FileTypeEnum.ELECTRIC_BARRIER, object : FileTransmitListener<String?> {
override fun onSuccess(result: String?) {
SDKLog.i(TAG, "uploadNoFlyZoneFile onSuccess: ${file.absoluteFile}, result: $result")
}
override fun onProgress(sendLength: Long, totalLength: Long, speed: Long) {
SDKLog.d(TAG, "uploadNoFlyZoneFile onProgress: ${file.absoluteFile}, sendLength: $sendLength, totalLength: $totalLength, speed: $speed")
}
override fun onFailed(code: IAutelCode, msg: String?) {
SDKLog.e(TAG, "uploadNoFlyZoneFile onFailed: ${file.absoluteFile}, msg : $msg")
}
})
5. Reference Code
For wayline-related sample code, please refer to MissionFragment in the Sample