Skip to main content

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

Wayline Mission Flow

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