Flying a Waypoint Mission

A waypoint flight is one command, mission.waypoint.execute, with the waypoints and settings inline. This page covers how to send it, the configuration model, pausing and resuming, and how to track progress.

Upgrading from 1.3? The task-based path (createTask + startTask) is gone: the platform no longer starts work through an adapter's task methods. See Upgrading from 1.3.

Which adapters support it

Adapter (2.0.0)mission.waypoint.executePause / resume
DJIYesmission.pause / mission.resume
MAVLinkYesmission.pause / mission.resume
SimulatorYesmission.pause / mission.resume
SAPIENT, Betaflight, RNSNo—

Ask an asset before you send it — getCapabilities(sn) lists the commands it advertises (see Checking what an asset supports).

Building the configuration

The command's parameters are a WaypointTaskConfig (see Configuration):

import com.zqnt.utils.JsonUtils;
import com.zqnt.utils.missionautonomy.domains.WaypointDTO;
import com.zqnt.utils.missionautonomy.domains.config.WaypointTaskConfig;

WaypointTaskConfig config = WaypointTaskConfig.builder()
        .waypoints(List.of(
            WaypointDTO.builder()
                .latitude(52.52000045776367).longitude(13.404999732971191)
                .altitude(30.0f).speed(5.0f).wpOrder(0).build(),
            WaypointDTO.builder()
                .latitude(52.541083304641944).longitude(13.40373026335974)
                .altitude(30.0f).speed(5.0f).wpOrder(1).build()))
        .globalSpeed(5.0f)
        .globalHeight(50.0f)
        .build();

config.validate();   // same rules the adapter applies — fail fast client-side

Use JsonUtils.getMapper() for the conversion

JsonUtils's mapper is configured with Include.NON_NULL, so fields you did not set are omitted and the class defaults apply adapter-side.

A default-configured ObjectMapper serialises nulls instead. Those nulls survive the whole way — the SDK encodes them as protobuf NullValue, and the adapter then deserialises "globalSpeed": null over the field default, wiping it. You would silently lose globalSpeed, waylineFinishAction, rcLostActionEnum and the other safety defaults.

If you use your own mapper, set setSerializationInclusion(JsonInclude.Include.NON_NULL). Unknown properties are ignored adapter-side, so the extra configType / taskType properties Jackson emits are harmless.

Sending it

Run the command through the execution engine. The platform then tracks it like any other execution: it has an id, a status and progress, and it can be cancelled.

import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import com.zqnt.sdk.client.missionautonomy.capabilities.SkillExecutionCommand;

Struct.Builder parameters = Struct.newBuilder();
JsonFormat.parser().merge(JsonUtils.getMapper().writeValueAsString(config), parameters);

var execution = client.missionAutonomy().executeSkill(
        SkillExecutionCommand.simple("SIM-DRONE-001",   // the Asset SN — see "Which SN" below
                "mission.waypoint.execute",
                null,                                    // target: null = the asset itself
                parameters.build(),
                null))                                   // idempotency key
        .join();

log.info("execution {} is {}", execution.getId(), execution.getStatus());

getSkillExecution(id) reads it back, and cancelSkillExecution(...) stops it. A waypoint route can equally be one step of a Skill in an Application — see Applications & Skills. Python (execute_simple(sn, "mission.waypoint.execute", params)) and Go (ma.ExecuteSimple(...)) have the same call.

Directly — as a custom command

The same command, sent straight to the device. The platform does not track it as an execution:

import com.fasterxml.jackson.core.type.TypeReference;
import com.zqnt.sdk.client.remotecontrol.domains.CustomCommandRequest;

Map<String, Object> params = JsonUtils.getMapper()
        .convertValue(config, new TypeReference<Map<String, Object>>() {});

var response = client.remoteControl().sendCustomCommand(
        CustomCommandRequest.builder()
                .sn("SIM-DRONE-001")
                .commandType("mission.waypoint.execute")
                .params(params)
                .build())
        .join();
if (!response.isSuccess()) {
    log.warn("Rejected: {}", response.getError().getErrorMessage());
}

Only sn and commandType are required on the request; tid is generated when omitted.

Pause and resume

Sent as their own commands, with no params — directly, or as Skill executions like the route itself:

client.remoteControl().sendCustomCommand(
    CustomCommandRequest.builder().sn(sn).commandType("mission.pause").build());

client.remoteControl().sendCustomCommand(
    CustomCommandRequest.builder().sn(sn).commandType("mission.resume").build());

Pause holds the aircraft in place; resume continues the same route. On the simulator both are idempotent — pausing an already-paused mission returns success — and both are rejected when no mission is active, which includes the window after the final waypoint when the aircraft has already begun its automatic return home.

Configuration

mission.waypoint.execute takes a WaypointTaskConfig. Per-waypoint entries (WaypointDTO) go in the required waypoints list:

FieldTypeNotes
latitudeDoublerequired
longitudeDoublerequired
altitudeFloatmetres
speedFloatm/s for this leg
flyThroughBooleanpass through instead of stopping
vehicleActionenumVEHICLE_ACTION_NONE, VEHICLE_ACTION_TAKEOFF, VEHICLE_ACTION_LAND
wpOrderIntegerexecution order; array order is used when absent
gimbalPitchIntegerdegrees, for this leg

Mission-level fields, all optional, defaults shown:

FieldDefaultValues / notes
name—free text
globalSpeed5.0must be > 0 and ≤ 15
globalTransitionSpeed8.0speed between legs
globalHeight50.00–500
gimbalPitchModeWGP_MODE_LOOK_DOWNWGP_MODE_MANUAL, WGP_MODE_POINT_SETTINGS, WGP_MODE_LOOK_DOWN
globalGimbalPitch-45−90 to +30
payloadImagingType—free text
flyToWaylineModeFTW_MODE_POINT_TO_POINTFTW_MODE_SAFELY, FTW_MODE_POINT_TO_POINT
waylineTypeWT_WAYPOINTWT_WAYPOINT, WT_MAPPING_2D, WT_MAPPING_3D, WT_MAPPING_STRIP
waylineFinishActionWF_ACTION_GO_HOMEWF_ACTION_GO_HOME, WF_ACTION_NO_ACTION, WF_ACTION_AUTO_LANDING, WF_ACTION_GOTO_FIRST_WAYPOINT, WF_ACTION_STOP
waylineTurnModeWT_MODE_TO_POINT_AND_PASS_WITH_CONTINUITY_CURVATUREalso WT_MODE_COORDINATE_TURN, WT_MODE_TO_POINT_AND_STOP_WITH_DISCONTINUITY_CURVATURE, WT_MODE_TO_POINT_AND_STOP_WITH_CONTINUITY_CURVATURE
useStraightLinetrue
waylinePrecisionTypePRECISION_GPSPRECISION_GPS, PRECISION_RTK
takeOffSecurityHeight10.02–1500
exitWaylineWhenRcLostEnumEWWRL_EXECUTE_RC_LOST_ACTIONEWWRL_CONTINUE, EWWRL_EXECUTE_RC_LOST_ACTION
rcLostActionEnumRC_LOST_ACTION_RETURN_HOMERC_LOST_ACTION_HOVER, RC_LOST_ACTION_LAND, RC_LOST_ACTION_RETURN_HOME
outOfControlActionOOC_RETURN_TO_HOMEOOC_RETURN_TO_HOME, OOC_HOVERING, OOC_LANDING
rthAltitude—metres
rthMode—RTH_MODE_OPTIMAL, RTH_MODE_PRESET
rthSpeed—m/s

externalTaskId, fileUrl, fileMd5, flightAreaFileUrl and flightAreaChecksum are populated by the adapter. Do not set them.

Fidelity is vendor-specific. The mission-level fields are DJI/KMZ concepts. DJI honours them in full. MAVLink applies the per-waypoint fields and ignores most mission-level ones. The simulator reads only latitude, longitude, altitude, speed and wpOrder; everything else is accepted and ignored.

Validation

config.validate() runs the same checks the adapter does:

  • at least 2 waypoints
  • globalSpeed in (0, 15] m/s
  • globalHeight 0–500 m
  • globalGimbalPitch −90 to +30 degrees
  • takeOffSecurityHeight 2–1500 m

Which SN

sn is the Asset SN — the entity registered on the platform:

  • standalone drone registered as an Asset → the drone's SN
  • drone docked in a station → the dock's SN (the dock is the Asset, the drone its SubAsset)

See Assets & Sub-Assets.

Tracking progress

As a Skill execution, the execution itself carries the state: status moves through SKILL_EXECUTION_STATUS_RUNNING to SUCCEEDED, FAILED or CANCELLED, with progress alongside. Poll getSkillExecution(id), or watch the Skill execution events on the notification stream.

Underneath, the adapter reports the command's progress as command execution events, on the notification stream for either way of sending it:

var notifyRequest = new StreamNotificationRequest();
notifyRequest.setSn("DOCK-SN");

client.liveData().streamNotifications(notifyRequest, n -> {
    var event = n.getCommandExecutionEvent();
    if (event == null) return;

    log.info("{} {} {}", event.getCommandId(), event.getStatus(), event.getProgress());
});

CommandExecutionEvent carries commandId, status, progress, message and output. status is COMMAND_EXECUTION_STATUS_RUNNING while it flies, then exactly one of SUCCEEDED, FAILED or CANCELLED.

AdapterProgress reporting
DJIDerived from the dock's own flighttask_progress
MAVLinkRUNNING as waypoints are reached, then SUCCEEDED; FAILED on failure
SimulatorRUNNING with progress as it flies, then one terminal event

SUCCEEDED means every waypoint was reached, not that the aircraft has landed. With the default WF_ACTION_GO_HOME finish action it is normally still flying home when that event arrives. Watch telemetry if you need the actual landing.

Checking what an asset supports

client.remoteControl().getCapabilities(sn)

reports the commands an asset advertises. Note that an adapter's advertised input schema may be deliberately permissive and list fewer properties than it actually accepts — the tables above are authoritative for WaypointTaskConfig.

See also

Was this page helpful?