OpenDroneKit

DJI WPML (.kmz) waypoint missions

A DJI waypoint mission is a zip with a .kmz suffix holding two KML files: template.kml, the editable plan, and waylines.wpml, the route the aircraft executes. Here is what each contains, a file OpenDroneKit wrote, and what to check before flying it.

Updated 2026-10-02Exporter: mission/exporters.py · examples written at 0ae10e4

Example files written by OpenDroneKit

opendronekit-example-grid.kmz27 waypoints · 4.2 KB
sha256 6d47dfb7…4ebe
aukerman-grid.kmzAukerman Park grid · 14.3 KB
sha256 f5cf41ec…992a

What is a DJI WPML file?

WPML (WayPoint Markup Language) is DJI’s extension of KML for waypoint routes. A route file is a ZIP archive with a .kmz suffix. Inside a wpmz/ folder are template.kml (the “template file”: business parameters a planner can edit) and waylines.wpml (the “execution file”: explicit flight and payload instructions), plus an optional res/ folder for resources. DJI Pilot 2 and FlightHub 2 generate waylines.wpml from the template’s parameters.

Elements in both files use the namespace xmlns:wpml="http://www.dji.com/wpmz/1.0.2" in DJI’s examples. The route’s name is the .kmz file name, and DJI warns that files and folders must follow the documented names or the route may fail to load.

Elements OpenDroneKit writes

ElementPer DJI's specWhat OpenDroneKit writes
wpml:missionConfigMission-wide behaviour: fly-to-route mode, finish action, RC-lost action, take-off security height, transit speedsafely · goHome (autoLand when the plan lands) · executeLostAction / goBack · RTH altitude capped at 100 m · cruise speed within 1 to 15 m/s
wpml:droneInfodroneEnumValue: 77 = M3E/M3T/M3M (sub 0/1/2), 67 = M30/M30T, 60 = M300 RTK, 89 = M350 RTK, 91 = M3D/M3TD77 / 0 (Mavic 3 Enterprise). Public main writes 68, which is not an assigned value
wpml:payloadInfopayloadEnumValue: 66 = Mavic 3E camera, 67 = 3T, 68 = 3M66, position 0
wpml:waylineCoordinateSysParamcoordinateMode and heightMode (template): EGM96, relativeToStartPoint, aboveGroundLevel, realTimeFollowSurfaceWGS84 · relativeToStartPoint, or EGM96 for plans with absolute (AMSL) altitudes
wpml:executeHeightModeRequired in waylines.wpml: WGS84, relativeToStartPoint or realTimeFollowSurfaceNot written (known issue)
Placemark / wpml:index / wpml:executeHeightOne per waypoint: lon,lat point, 0-based index, height in the declared modeEvery planned viewpoint
wpml:waypointHeadingParamHeading mode, angle, POI, path mode (followBadArc = shortest yaw)smoothTransition when the heading is locked, else followWayline
wpml:waypointTurnParamcoordinateTurn, toPointAndStop…, toPointAndPassWithContinuityCurvatureStop at hold points, pass elsewhere; damping 0.2 m
wpml:actionGroupActions on a trigger: reachPoint, betweenAdjacentPoints, multipleTiming, multipleDistancePer waypoint, reachPoint: gimbalRotate (absolute pitch), hover at holds, takePhoto at captures
wpml:waylineActionGroupRoute-level action groupOnly for distance-triggered capture (multipleDistance)

Example file

Written by OpenDroneKit’s exporter for a 90 x 60 m rectangle centred on 41.30420 N, 81.75200 W (Aukerman Park, Ohio): grid template, 55 m above take-off, 8 m/s, 27 waypoints. The first lines:

wpmz/template.kml

<?xml version="1.0" ?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.2">
  <Document>
    <wpml:author>OpenDroneKit</wpml:author>
    <wpml:createTime>0</wpml:createTime>
    <wpml:updateTime>0</wpml:updateTime>
    <wpml:missionConfig>
      <wpml:flyToWaylineMode>safely</wpml:flyToWaylineMode>
      <wpml:finishAction>goHome</wpml:finishAction>
      <wpml:exitOnRCLost>executeLostAction</wpml:exitOnRCLost>
      <wpml:executeRCLostAction>goBack</wpml:executeRCLostAction>
      <wpml:takeOffSecurityHeight>80.0</wpml:takeOffSecurityHeight>
      <wpml:globalTransitionalSpeed>8.0</wpml:globalTransitionalSpeed>
      <wpml:droneInfo>
        <wpml:droneEnumValue>77</wpml:droneEnumValue>
        <wpml:droneSubEnumValue>0</wpml:droneSubEnumValue>
      </wpml:droneInfo>
      <wpml:payloadInfo>
        <wpml:payloadEnumValue>66</wpml:payloadEnumValue>
        <wpml:payloadPositionIndex>0</wpml:payloadPositionIndex>
      </wpml:payloadInfo>
    </wpml:missionConfig>
    <Folder>
      <wpml:templateType>waypoint</wpml:templateType>
      <wpml:templateId>0</wpml:templateId>
      <wpml:waylineCoordinateSysParam>
        <wpml:coordinateMode>WGS84</wpml:coordinateMode>
        <wpml:heightMode>relativeToStartPoint</wpml:heightMode>
      </wpml:waylineCoordinateSysParam>
      <wpml:autoFlightSpeed>8.0</wpml:autoFlightSpeed>
      <Placemark>
        <Point>
          <coordinates>-81.75253872,41.30393020</coordinates>
        </Point>
        <wpml:index>0</wpml:index>
        <wpml:executeHeight>55.00</wpml:executeHeight>
        <wpml:waypointSpeed>8.0</wpml:waypointSpeed>
        <wpml:waypointHeadingParam>
          <wpml:waypointHeadingMode>followWayline</wpml:waypointHeadingMode>
          <wpml:waypointHeadingAngle>90.0</wpml:waypointHeadingAngle>

wpmz/waylines.wpml

<?xml version="1.0" ?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.2">
  <Document>
    <wpml:missionConfig>
      <wpml:flyToWaylineMode>safely</wpml:flyToWaylineMode>
      <wpml:finishAction>goHome</wpml:finishAction>
      <wpml:exitOnRCLost>executeLostAction</wpml:exitOnRCLost>
      <wpml:executeRCLostAction>goBack</wpml:executeRCLostAction>
      <wpml:takeOffSecurityHeight>80.0</wpml:takeOffSecurityHeight>
      <wpml:globalTransitionalSpeed>8.0</wpml:globalTransitionalSpeed>
      <wpml:droneInfo>
        <wpml:droneEnumValue>77</wpml:droneEnumValue>
        <wpml:droneSubEnumValue>0</wpml:droneSubEnumValue>
      </wpml:droneInfo>
      <wpml:payloadInfo>
        <wpml:payloadEnumValue>66</wpml:payloadEnumValue>
        <wpml:payloadPositionIndex>0</wpml:payloadPositionIndex>
      </wpml:payloadInfo>
    </wpml:missionConfig>
    <Folder>
      <wpml:templateType>waypoint</wpml:templateType>
      <wpml:templateId>0</wpml:templateId>
      <wpml:waylineId>0</wpml:waylineId>
      <wpml:waylineCoordinateSysParam>
        <wpml:coordinateMode>WGS84</wpml:coordinateMode>
        <wpml:heightMode>relativeToStartPoint</wpml:heightMode>
      </wpml:waylineCoordinateSysParam>
      <wpml:autoFlightSpeed>8.0</wpml:autoFlightSpeed>
      <Placemark>
        <Point>
          <coordinates>-81.75253872,41.30393020</coordinates>
        </Point>
        <wpml:index>0</wpml:index>
        <wpml:executeHeight>55.00</wpml:executeHeight>
        <wpml:waypointSpeed>8.0</wpml:waypointSpeed>
        <wpml:waypointHeadingParam>
          <wpml:waypointHeadingMode>followWayline</wpml:waypointHeadingMode>
          <wpml:waypointHeadingAngle>90.0</wpml:waypointHeadingAngle>
          <wpml:waypointPoiPoint>0.000000,0.000000,0.000000</wpml:waypointPoiPoint>
          <wpml:waypointHeadingPathMode>followBadArc</wpml:waypointHeadingPathMode>
        </wpml:waypointHeadingParam>
        <wpml:waypointTurnParam>
          <wpml:waypointTurnMode>toPointAndPassWithContinuityCurvature</wpml:waypointTurnMode>
          <wpml:waypointTurnDampingDist>0.2</wpml:waypointTurnDampingDist>
        </wpml:waypointTurnParam>
        <wpml:useStraightLine>1</wpml:useStraightLine>
        <wpml:actionGroup>
          <wpml:actionGroupId>0</wpml:actionGroupId>
          <wpml:actionGroupStartIndex>0</wpml:actionGroupStartIndex>
          <wpml:actionGroupEndIndex>0</wpml:actionGroupEndIndex>
          <wpml:actionGroupMode>sequence</wpml:actionGroupMode>
          <wpml:actionTrigger>
            <wpml:actionTriggerType>reachPoint</wpml:actionTriggerType>
          </wpml:actionTrigger>
          <wpml:action>
            <wpml:actionId>0</wpml:actionId>
            <wpml:actionActuatorFunc>gimbalRotate</wpml:actionActuatorFunc>
            <wpml:actionActuatorFuncParam>
              <wpml:gimbalHeadingYawBase>aircraft</wpml:gimbalHeadingYawBase>
              <wpml:gimbalRotateMode>absoluteAngle</wpml:gimbalRotateMode>

The full Aukerman Park files in the table above come from the run shown on the homepage: the public OpenDroneMap survey, 152 waypoints at 55 m, generated 2026-09-29. Every file’s SHA-256 is listed so a copy can be checked.

What OpenDroneKit writes

OpenDroneKit (export_dji_wpml) writes both files with the same waypoints. template.kml adds author and time fields, waylines.wpml adds the wayline id. Every waypoint gets an action group, because the gimbal angle is always commanded; hover and photo actions are added where the plan holds or captures.

The default aircraft is a Mavic 3 Enterprise (drone 77, sub-enum 0, payload 66). For another aircraft the enums must change: Pilot 2 checks them against the connected drone.

Known issues

Checked against the format’s reference and the exporter code on 2026-10-02. Listed here rather than hidden, so you can correct a file before you fly it.

  • wpml:executeHeightMode is missing from waylines.wpml. DJI’s spec marks it required. The exporter declares the height reference only through waylineCoordinateSysParam/heightMode. Present on both branches. Pilot 2 regenerates waylines from the template, which may mask it; it has not been tested on an aircraft here.
  • Not flight-tested. The files parse as XML and contain both members, but no exported .kmz has been flown on a DJI aircraft as part of this project’s tests.

Public main versus the development branch

The example files were written by the development branch (0ae10e4), which is ahead of the public main you get from a source install (1ef6351). On main:

  • Public main defaults droneEnumValue to 68, which is not an assigned DJI drone enum; the integration branch defaults to 77 (Mavic 3 Enterprise), sub-enum 0 on both.
  • Public main does not cap waypoint speed at 15 m/s and takes the speed from a key the planner does not set (falling back to 8 m/s); it always uses heightMode relativeToStartPoint, where the integration branch uses EGM96 for AMSL plans.

How do I import it into DJI Pilot 2?

  1. Copy the .kmz to the controller (USB, SD card or cloud drive) running DJI Pilot 2.
  2. In Pilot 2’s route library, use the import button and select the .kmz file.
  3. Open the route, confirm the aircraft and camera match, review heights and actions, and save.
  4. DJI Fly has no import button. Third-party tools replace the .kmz of a mission created on the aircraft (renamed to its GUID) with the new file; DJI does not document that route.

Pitfalls

  • A droneEnumValue or payloadEnumValue that does not match the connected aircraft makes Pilot 2 reject or alter the route.
  • relativeToStartPoint heights are measured from where the aircraft takes off. Take off somewhere else and the whole route shifts vertically.
  • realTimeFollowSurface is supported only on some aircraft (DJI lists the M3E/M3T/M3M family for waylines).
  • takeOffSecurityHeight (1.2 to 1500 m with a remote controller) is the climb before the route starts; set it above nearby obstacles.

References

Other formats: QGC .plan · .waypoints · Litchi CSV. Missions come from the mission templates; see mission planning.