How to Define MAVLink Messages & Enums

MAVLink enums, messages, commands, and other elements are defined within XML files and then converted to libraries for supported programming languages using a code generator.

This topic provides practical guidance for defining and extending MAVLink XML elements, including conventions and best-practice.

For detailed information about the file format see MAVLink XML Schema (you can also inspect common.xml and other dialect files).

Messages vs Commands

There are two ways to send information between MAVLink systems (including commands, information and acknowledgments):

  • Messages are encoded using message elements. The message structure/fields and handling are largely unconstrained (i.e. up to the creator).
  • MAVLink Commands are defined as entries in the MAV_CMD enum, and encoded into real messages that are sent using the Mission Protocol or Command Protocol. Their structure is defined (they have 7 float parameters or 5 float and 2 int32_t parameters) and handling/responses depend on the protocol used to send them.

The guidance below provides some suggestions on when one or the other might be more appropriate.

Consider using a proper message if:

  • The required information does not fit into a command (i.e. it can't fit into the 7 available numeric fields).
  • The message is part of another protocol.
  • The message must be broadcast or streamed (i.e. no ACK required)

Consider using a command if:

  • The message should be executed as part of a mission.
  • There is an existing mission command that you wish to use outside of missions. Depending on the autopilot you may be able to handle the message using the same code for both modes.
  • You're working with MAVLink 1 and there is no free id for the new message (MAVLink 1 has a much larger free pool of ids for MAVLink commands than for message ids).
  • It is important that your command message is not missed, so an ACK/NACK is required. Using the existing protocol acknowledgments may be faster/easier than defining another message for acknowledgments.

Otherwise either method may freely be used.

The "official" project XML files are stored in the Github repo mavlink/mavlink under /message_definitions/v1.0/.

MAVLink systems typically fork and maintain a copy of this repo (e.g. ArduPilot/mavlink). The downstream repo should pull common.xml changes (see next section) down from the main repo and push dialect-specific changes back to it.

The official repo is forked and/or cloned into your environment when you Install MAVLink.

A project/dialect doesn't have to push changes back to MAVLink. However this makes sense if you want to publish your messages more widely, and potentially get them moved into the common.xml message set.

The enums and messages that are generally useful for many flight stacks and ground stations are stored in a file named common.xml, which is managed by the MAVLink project. The MAVLink elements supported by a particular autopilot system or protocol are referred to as dialects. The dialects are stored in separate XML files, which typically include (import) common.xml and define just the elements needed for system-specific functionality.

When a MAVLink library is generated from a dialect file, code is created for all messages in both the dialect and any included files (e.g. common.xml), and entries for a particular enum are merged. The generator reports errors if there are name or id clashes between imported messages or enum entries.

Where you define an element depends on whether it is common or a dialect, and whether the project is public or private.

Elements that are potentially useful for multiple ground stations and autopilots

Elements specific to a particular MAVLink dialect

  • Add these elements to the dialect file in the owning system's fork of the repo.
  • Raise a PR with your suggested changes and discuss with the dialect project through that mechanism.
  • The dialect project should then (ideally) push the changes back to mavlink/mavlink.

Elements for a private project

  • If your enums/messages won't ever sync back to the MAVLink project then define them wherever you like!

Creating a Dialect File

To create a new dialect file:

  1. Fork mavlink/mavlink for your system and clone to your system
  2. Create a dialect file named after your MAVLink system (e.g. flight stack) in message_definitions/v1.0/
  3. Copy the following text into the new file.

    <?xml version="1.0"?>
    <mavlink>
    
        <include>common.xml</include>
        <!-- <version>9</version> -->
        <dialect>8</dialect>
    
        <enums>
            <!-- Enums are defined here (optional) -->
        </enums>
    
        <messages>
            <!-- Messages are defined here (optional) -->
        </messages>
    
    </mavlink>
    

    The template assumes that your dialect:

    • imports common.xml (<include>common.xml</include>)
    • takes its version from common.xml (which is why the version tags are commented out).
  4. Update the include(s):

    • if the dialect is not based on common.xml remove the existing include line
    • Add additional <include> </include> elements to import additional files/dialects.

      Includes in nested files are ignored.

  5. Update the version:
    • Most dialects should leave the version commented out (i.e. all dialects that include common.xml).
    • Dialects that are not based on common.xml can uncomment the <version>6</version> line and use whatever version is desired.

      The version specified in the top level file is used by default, if present.

      If it is not present in the file, then a `version` from an included file is used. 
      
  6. Update the <dialect>8</dialect> line to replace 8 with the next-largest unused dialect number (based on the other files in the folder).
  7. Optionally remove the enums or messages sections if you don't plan on declaring any elements of these types.
  8. Add enums or messages as described in the following sections.
  9. Save the file, and create a PR to push it back to the mavlink/mavlink project repo.

Messages

Messages are used to send data between MAVLink systems (including commands, information and acknowledgments).

Every message has mandatory id and name attributes. Serialised packets include the id in the message id section and an encoded form of the message data within the payload section. The name is typically used by generators to name methods for encoding and decoding the specific message type. When a message is received the MAVLink library extracts the message id to determine the specific message, and uses that to find the appropriately named method for decoding the payload.

A typical message (SAFETY_SET_ALLOWED_AREA) is shown below:

    <message id="54" name="SAFETY_SET_ALLOWED_AREA">
      <description>Set a safety zone (volume), which is defined by two corners of a cube. This message can be used to tell the MAV which setpoints/waypoints to accept and which to reject. Safety areas are often enforced by national or competition regulations.</description>
      <field type="uint8_t" name="target_system">System ID</field>
      <field type="uint8_t" name="target_component">Component ID</field>
      <field type="uint8_t" name="frame" enum="MAV_FRAME">Coordinate frame. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down.</field>
      <field type="float" name="p1x" units="m">x position 1 / Latitude 1</field>
      <field type="float" name="p1y" units="m">y position 1 / Longitude 1</field>
      <field type="float" name="p1z" units="m">z position 1 / Altitude 1</field>
      <field type="float" name="p2x" units="m">x position 2 / Latitude 2</field>
      <field type="float" name="p2y" units="m">y position 2 / Longitude 2</field>
      <field type="float" name="p2z" units="m">z position 2 / Altitude 2</field>
    </message>

Creating a Message

Messages must be declared between the <messages></messages> tags in either common.xml or dialect files. Each message is defined using <message id="" name="LIBRARY_UNIQUE_NAME"> ... </message> tags (with unique id and name attributes).

The only only difference between messages defined in common.xml or dialect files is they they must use different id ranges in order to ensure that the ids are unique. See Message Id Ranges for more information.

The main rules for messages are:

  • Messages must include the mandatory id and name
    • These must be unique across the generated library.
    • See Message Id Ranges below for more information.
  • Messages should (very highly recommended) include a description.
  • Point to point messages must include a field for target_system (exactly as shown above).
  • Point to point messages that are relevant to components must include a field for target_component(exactly as shown above).
  • The total payload size (for all fields) must not exceed 255 bytes.
  • All other fields are optional.
  • There may be no more than 64 fields.
  • The <wip/> tag may be added to messages that are still being tested.
  • Fields:
    • must have unique names within a message.
    • should have a description.
    • should use the units attribute rather than including units in the description. Each field should only have one or no units.
    • should use the enum attribute where possible results are finite/well understood.

You cannot rely on generators to fully test for compliance with the above rules. The mavgen code generator tests for duplicate message ids, duplicate field names and messages with more than 64 fields. It does not check for other issues (e.g. duplicate names, or over-size payloads). Other generators may provide better validation

Message Id Ranges

All messages within a particular generated library must have a unique ID - this is important because the id is used to determine the format of the message payload (i.e. what generated method can decode the message).

For MAVLink 2, each dialect is allocated a specific range from which an id can be selected. This ensures that any dialect can include any other dialect (or common.xml) without clashes. It also means that messages can move from a dialect to common.xml without any code needing to change.

When creating a new message you should select the next unused id for your dialect (after the last one defined in your target dialect file).

The allocated ranges are listed below.

DialectRange
Common.xml300 - 10000
uAvionix.xml10001-10999
ArduPilotMega.xml11000 - 11999
icarous.xml42000 - 42999

If you are creating a new public dialect, create an issue to request your own message id range. For private dialects, you can use whatever range you like.

You should not create messages with ids in the "MAVLink 1" range (MAVLink v1 only has 8 bit message IDs, and hence can only support messages with ids 0 - 255).

Modifying a Message

Changing the name or id of a message will make it incompatible with older versions of the generated library.

Adding or removing a field, or changing the name or type of a field, will make a message incompatible with older versions of the generated library (the generated message decoding method is hard coded with the field number, order, type and position at build time - if these change, decoding will fail).

If a message needs to be changed in these ways then there are several options:

  • A new message can be created with the desired behaviour. At some point the old message may be marked as deprecated.
  • The message can be updated, and the dialect version number iterated.

For either case, all users of the message will need to be updated with new client libraries.

For a message in common.xml either change requires the agreement of major stakeholders

  • Create a PR and discuss in the MAVLink developer meeting.

    Before proposing changes to common.xml check the codebase of major stakeholder to confirm impact.

It is possible to change the message and field descriptions without breaking binary compatibility. Care should still be taken to ensure that any changes that alter the way that the field is interpreted are agreed by stakeholders, and handled with proper version control.

Messages are very rarely deleted, as this may break compatibility with legacy MAVLink 1 hardware that is unlikely to be updated to more recent versions.

MAVLink 2 Message Extensions

The exception to the above rule is that when using MAVLink 2 you can add new fields to messages with an id of 0 - 255 using the tag without breaking compatibility. These fields will not be sent when the MAVLink 1 protocol is used.

Otherwise the rules are the same; once added you cannot modify or remove fields. You can however continue to add new fields as long as you do not exceed the maximum field number or payload size limits.

Extension fields are appended to the end of the original MAVLink 1 message fields and are not reordered. A decoding library that does not understand a new extension field will ignore it, but will not incorrectly decode the fields that it does understand.

Enums

Enums are used to define named values that may be used as options in messages - for example to represent errors, states, or modes.

Every enum has mandatory name attribute and may contain a number of entry elements (with enum-unique names) for the supported values. The same enum may be declared in common.xml and multiple dialects. The generated library will merge the entry values, and should report an error if there are any duplicate names.

A typical enum (LANDING_TARGET_TYPE) is shown below:

<enum name="LANDING_TARGET_TYPE">
    <description>Type of landing target</description>
    <entry value="0" name="LANDING_TARGET_TYPE_LIGHT_BEACON">
        <description>Landing target signaled by light beacon (ex: IR-LOCK)</description>
    </entry>
    <entry value="1" name="LANDING_TARGET_TYPE_RADIO_BEACON">
        <description>Landing target signaled by radio beacon (ex: ILS, NDB)</description>
    </entry>
    <entry value="2" name="LANDING_TARGET_TYPE_VISION_FIDUCIAL">
        <description>Landing target represented by a fiducial marker (ex: ARTag)</description>
    </entry>
    <entry value="3" name="LANDING_TARGET_TYPE_VISION_OTHER">
        <description>Landing target represented by a pre-defined visual shape/feature (ex: X-marker, H-marker, square)</description>
    </entry>

Creating an Enum

Enums must be declared between the <enums></enums> tags in common.xml and/or dialect files. Each enum is defined using <enum name="SOME_NAME"> ... </enum> tags (with a name attribute).

There is no difference between enums defined in common.xml or dialect files (other than management of the namespace).

The main rules for enums are:

  • Enums must include the mandatory name attribute.
    • Entries are merged for all enums that share the same name.
  • Enums should (very highly recommended) include a description. If enums are merged, only one description will be used (usually the first that is encountered).
  • Enums may be marked as deprecated.
  • Enums must have at least one enum entry.
  • Entries:
    • must have a name attribute.
      • The name must be unique across all entries in the enum.
      • By convention, the name should be prefixed with the enum name (e.g. enum LANDING_TARGET_TYPE has entry LANDING_TARGET_TYPE_LIGHT_BEACON).
    • should have a value attribute, and if assigned this must be unique within the (merged) enum. A value will be automatically created for the generated library if not assigned, but this is not recommended.
    • should (very highly recommended) include a description element.
    • may represent bitmasks, in which case values will increase by a power of 2.
    • may be marked as deprecated.

You cannot rely on specific generators to fully test for compliance with the above rules. mavgen tests for duplicate names in enums, duplicate names for (merged) enum entries, duplicate values for enum entries.

Modifying an Enum

Changing the name or removing an enum will make any messages that use the enum incompatible with older versions of the generated library. Similarly, changing an enum entry name or value, or removing an enum entry, will make messages that use the enum incompatible with older versions of the generated library.

Care must be taken when adding a new enum entry/value as this may make the generated library incompatible:

  • Autogenerated entry values may change
  • Client code may not handle new values.

If an enum needs to be changed then there are several options:

  • A new enum can be created with the desired entries. At some point the old enum may be marked as deprecated.
  • The enum can be updated, and the dialect version number iterated.

For either case, all users of the enum will need to be updated with new generated libraries.

Before proposing changes to common.xml check the codebase of major stakeholder to confirm impact.

For an enum in common.xml either change requires the agreement of major stakeholders

  • Create a PR and discuss in the MAVLink developer meeting.

It is possible to change enum/enum entry descriptions without breaking binary compatibility. Care should still be taken to ensure that any changes that alter the way that they are interpreted are agreed by stakeholders, and handled with proper version control.

Enums are very rarely deleted, as this may break compatibility with legacy MAVLink 1 hardware that is unlikely to be updated to more recent versions.

MAVLink commands are defined as entries in the MAV_CMD enum. They are used to define operations used in autonomous missions (see Mission Protocol or to send commands in any mode (see Command Protocol).

A typical mission command is (MAV_CMD_NAV_WAYPOINT) is shown below:

    <enum name="MAV_CMD">
      <description>Commands to be executed by the MAV. They can be executed on user request, or as part of a mission script. If the action is used in a mission, the parameter mapping to the waypoint/mission message is as follows: Param 1, Param 2, Param 3, Param 4, X: Param 5, Y:Param 6, Z:Param 7. This command list is similar what ARINC 424 is for commercial aircraft: A data format how to interpret waypoint/mission data.</description>
      <entry value="16" name="MAV_CMD_NAV_WAYPOINT">
        <description>Navigate to waypoint.</description>
        <param index="1">Hold time in decimal seconds. (ignored by fixed wing, time to stay at waypoint for rotary wing)</param>
        <param index="2">Acceptance radius in meters (if the sphere with this radius is hit, the waypoint counts as reached)</param>
        <param index="3">0 to pass through the WP, if &gt; 0 radius in meters to pass by WP. Positive value for clockwise orbit, negative value for counter-clockwise orbit. Allows trajectory control.</param>
        <param index="4">Desired yaw angle at waypoint (rotary wing). NaN for unchanged.</param>
        <param index="5">Latitude</param>
        <param index="6">Longitude</param>
        <param index="7">Altitude</param>
      </entry>
      ...
    </enum>

The rules for MAVLink commands are exactly the same as for other enums. There are a few of additional conventions.

Command (Entry) Values

All mission command entries must have a value (this is not enforced by the toolchain but, as for other enums, it reduces the chance of values unintentionally changing and breaking other systems).

Each dialect is allocated a specific range from which entry ids can be selected. This ensures that any dialect can include any commands from any other dialect (or common.xml) without clashes. It also means that messages can move from a dialect to common.xml without any code needing to change.

Dialects can choose any values within their range for any message. However we recommend that all related commands be kept in the same block of ids, and if there are likely to be more similar commands in future then spaces might be left for new commands.

The allocated ranges are listed below.

DialectRange
Common.xml30000 - 39999
asluav.xml40001 - 41999
ArduPilotMega.xml42000 - 42999
slugs.xml10001 - 11999

If you are creating a new public dialect, create an issue to request your own command id range. For private dialects, you can use whatever range you like.

There are a number of common and ArduPilot commands that are outside the ranges (e.g. 16, 200, etc.). Generally you would only use these these ranges in order to give a new command an id that is close to related to that of related commands. This can be done provided that the command id value is not used by any other XML file in the mavlink/mavlink repo.

Entry Names

As with other enums, enum entry names should be prefixed with the enum name (i.e. MAV_CMD_). In addition, there are some other "standard" prefixes which are used for common types of commands:

  • MAV_CMD_NAV_: NAV commands are used for navigation/movement commands (commands to go to a particular waypoint or move in a particular way).
  • MAV_CMD_DO_: DO commands are used for setting modes, changing altitude or speed etc.
  • MAV_CMD_CONDITION_: CONDITION_ commands are used to define conditions before the mission state machine will move to the next item (e.g. a time after reaching a waypoint before taking a picture).
  • MAV_CMD_REQUEST_: For requesting information from a system.

The rules for the above prefixes are flexible; some DO commands might reasonably be NAV commands. Ins some cases a request for information might be a MAV_CMD_REQUEST_ and in others it might be a stand alone message.

Standard Mappings

Commands have an index from 1 to 7. Where a command contains position information, this is always stored in: Param 5 (x / latitude), Param 6 (y / longitude), Param 7 (z, altitude). Whether the value is local (x,y,z) or global (latitude, longitude, altitude) depends on the command and the frame used (frame often defined in the parent message).

results matching ""

    No results matching ""