MAVLink Step by Step

#MAVLink - Step-by-Step
by Pedro Albuquerque

This post result from my struggle to find information about the subject to understand the concept, and developing a basic concept test.

My background - I have been using Ardupilot software on Multirotors and airplanes for 1 year.
I learned to program C (C86, Microsoft C, Turbo C) 30 year ago (yes 1986) , i’ve been away from programming in C, eventually only reading some code since then , and recently (2 month ago) I got to know arduino and its IDE.

back to the subject.

##A message system
MAVLink is a message protocol, designed to exchange information between a UAV and a GCS or a subsystem (ex:gimbal controller), using a serial communication channel.

The base structure of the protocol is the message. For perfomance reasons it is binary information, so , eventually not readable by humans without some interpretation.

##A simple message with acknowledge


this is an example of a message (WAYPOINT_CLEAR_ALL) sent by the GCS to a UAV. The UAV receives and executes, and responds with another message (WAYPOINT_ACK).
After sending the initial message, the GCS starts a timer to decide for a timeout state if no ACK messages is received .

##System ID, subsystem ID and Message ID


Most messages will indicate source(originating) system ID (sysid) , subsystem ID (compid), destination system ID, destination subsystem/component ID and a message type ID

GCS system ID should be 255 (see here )
Vehicle ID should be 1
(see here the parameter on Ardupilot http://ardupilot.org/copter/docs/parameters.html?highlight=parameters#sysid-thismav-mavlink-system-id-of-this-vehicle)

Some subsystem codes are already reserved. look for MAV_COMPONENT on this page https://pixhawk.ethz.ch/mavlink/

Source sysID , compID and MSG are all encoded in the message header.

Destination sysID , compID when necessary will be part of the payload.

The payload content/structure for each MSG is defined here (keep calm… will get into practical details later)

##Library support
A library is available to help prepare a message to be sent or to decode a message just received.
Actually, you will have to build your library following this instruction https://github.com/mavlink/mavlink to adjust it to your platform and your programming language.

You end up with a folder with your library called mavlink (or the name you decide eventually)


###example Steps (performed on a Mac):
download the zip from github to a folder named mavlink-master
On a terminal windows , change to that folder and execute the command
“python -m mavgenerate”
on the new window choose
xml folder: …/tmp/mavlink-master/message_definitions/v1.0/ardupilotmega.xml
out folder: …/tmp/MAVLink
language: C
protocol: 1.0

##How to use the result
Once the folder has been generated I moved it to the library folder , in my case as I am using an arduino as a auxiliar system I installed it at
…/libraries/MAVLink
and include it like

##But what does it contain ?
This was something I really strived to discover
Remember, what we want - compose messages to send and receive messages and interpret them.
The message is the focal point.
So before going into coding, we need to first know what messages are available and their meaning/purpose.
The general message list can be found starting here-> https://pixhawk.ethz.ch/mavlink/#HEARTBEAT

Every platform may choose to implement a sub-set and/or additional messages. Arduplilot implemented messages can be found at http://ardupilot.org/dev/docs/mavlink-commands.html
Any message is composed of several fields(struct in C), and is a mavlink_message_t type .

Additionally each specific message has associated with it:

  • a type def for the structure to hold the payload fields
  • a pack function to load the message with the data
  • a decode function to translate the message and load the payload structure (specific for each message)

All of this is defined in a include file with the same name as the message.
(When you include the mavlink.h in your code you are also including all the include files for each message.)

##example: HEARTBEAT

definition file is common/mavlink_msg_heartbeat.h

note: the location of the file can be on platform folder or in common. they are on platform folder if they have some modified from the common definition.

type def: mavlink_heartbeat_t
packing function: mavlink_msg_heartbeat_pack() - load the mavlink_message_t type object with all the necessary information so that it can be sent
decoding function: mavlink_msg_heartbeat_decode() - decode the message and fill the mavlink_hearbeat_t type object with received message information
Note that this definition file serves both purposes, to prepare a message to be sent or to decode a message received.

##Is that all?
We are almost there (able to write a sketch to receive and send a MAVLink message).

###Receiving a message
we need to write a function to read the message from serial com and decode it.

now you just call it when you fill appropriate.

###Sending a message

Sending a message is a bit more tricky.

The system running our software need to have a SysID and a CompID, so we have to decide one.

choose any SysID except 1 ou 255
choose compID 1 is case no match found to reserved codes.

CC_SYSID and CC_COMPID were defined by me for the source system, and I’m sending a message to a ardupilot system (the target system) that has SYSID = 1 and if not for specific component, then use the main that is CompID = 1

msg is an empty object of type mavlink_message_t that will be filled by the pack function
param_id is a char array with the name of the parameter
param_index if set to -1 will use the name, other wise we need to know the index of the parameter in the target system.

copy the message to a byte buffer which is sized to the largest message MAVlink will allow.

finally , just send it to com port.

Note: Remember each message has its own propose and its own payload data, so we need to check os it’s include message file what field do we need as I could not find any other documentation for it.

##What you should achieve

  • Understand what Mavlink is
  • understand the concept and structure of a generic message
  • know how to generate and install a library to deal with MAVLink messages
  • Know where to find the available messages, and the implemented message in Ardupilot
  • know were to look for message definition
  • construct your MAVLink message receive and send routine.

Feel free to send feedback on how to improve this introductory document. Keep in mind that it is meant to help developers get into MAVLink concept and use.

from

35 Likes

Thanks for the great intro to mavlink :slight_smile:

Outstanding presentation!

Thanks

Thank you for posting this excellent explanation! Will there be a part two?

This is a great post - really well done. Please continue to add fantastic posts like these.
Thanks, Grant.

+1. I wish more posts were this informative!

Kelly

Thanks for a very comprehensive tutorial - the only understandable one I’ve seen on MAVlink.

Is there a v1.0 Arduino library available for download, or must I create my own?

-Don

Found it: https://github.com/mavlink/c_library_v1

1 Like

Do you have your source code available anywhere?

Not yet. I’m having the same nightmares that others have experienced.

So have you not been able to run / send / receive at all ? What issues are you facing exactly ? I have the weirdest problem when trying to compile with the mavlink library included:

mavlink/mavlink_conversions.h:37: error: expected constructor, destructor, or type conversion before 'void’
mavlink/mavlink_conversions.h:67: error: expected constructor, destructor, or type conversion before ‘void’

not sure what that’s about!

I was able to compile a sketch to send MAVlink V0.9 heartbeat messages and it worked, but I’ve had nothing but problems trying to generate V1.0messages. After I figured out how to generate the files for MAVlink V1.0, I had a few problems with includes that I worked though. My current compiler errors are all of this nature: error: ‘cosf’ was not declared in this scope. Others are sqrtf, atanf, fabs, atan2f, etc., anything that ends in “f”. It seems that my math.h doesn’t include these functions.

This is great - thanks for posting it. Is there anything special needed to parse ardupilot specific messages? I’ve written a mavlink interface in c++ and I can receive messages from the common set no problem, but it seems messages that are defined in the ardupilotmega.xml seem to just disappear. Is there something different about them from mavlink_parse_char()'s perspective? (I’m currently trying to monitor the messages that are sent between dronekit-sitl and dronekit so I can figure out basic things like arming, taking off, etc. and the utility that I wrote that gets inserted between sitl and dronekit seems to be dropping the APM specific messages)

Well done.A very comprehensive tutorial.
Thanks for the information and the clear presentation.

Fantastic introduction to Mavlink protocol! Could you post here the complete file to work on it? It would be so helpful.

Another question, is SerialMAV supposed to be a SoftwareSerial? Which should be the baudrate to “talk” to ardupilot?

Thank you so much!

Thank you!!! I did not have a clear picture of MAV message until I see your post!!

After spending many hours on this, I’m finally able to launch MAVLink generator and make my Arduino files. I’m working on:

  • Mac OS X El Capitan (10.11.4)
  • Python 2.7.11 (Anaconda 2.1.0)

The issues with I had to deal were:
1) Adding the repo directory to the PYTHONPATH. For that, I used the commands:
nano ~/.bashrc
source ~/.bashrc
to edit and save the PYTHONPATH

2) Installing the TLC/TK dependencies

3) Upgrading the future module since I was getting:
ImportError: No module named builtins
So I fixed it typing the command:
pip install future --upgrade

Now, let’s make the Anti-Coliision Quadcopter work by using Maxbotics and HCSR-04 sonars.

Thanks!

Can anyone tell what type is SerialMAV variable in the example code? Thanks in advance.

1 Like

I am working on setting up an anti-collision quad as well, but using LeddarOne single-element lidar sensors. I have a couple questions on your setut, but I am working on a PC, and am wanting to set it up on a Raspberry Pi.

Also, did you use the Mavgenerate.py GUI tool to setup your include file?

I also would like to know