MAVLink and Arduino: step by step

@MAWaayne, I have not direct experience with those messages, but in the library I can see that internal altitude info is replied in messageMAVLINK_MSG_ID_HIL_STATE with ID 90. Units are mm. You can find all the details in the file common\mavlink_msg_hil_state.h. The most interesting part is the structure where message payload is stored:


typedef struct __mavlink_hil_state_t
 uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot)
 float roll; ///< Roll angle (rad)
 float pitch; ///< Pitch angle (rad)
 float yaw; ///< Yaw angle (rad)
 float rollspeed; ///< Roll angular speed (rad/s)
 float pitchspeed; ///< Pitch angular speed (rad/s)
 float yawspeed; ///< Yaw angular speed (rad/s)
 int32_t lat; ///< Latitude, expressed as * 1E7
 int32_t lon; ///< Longitude, expressed as * 1E7
 int32_t alt; ///< Altitude in meters, expressed as * 1000 (millimeters)
 int16_t vx; ///< Ground X Speed (Latitude), expressed as m/s * 100
 int16_t vy; ///< Ground Y Speed (Longitude), expressed as m/s * 100
 int16_t vz; ///< Ground Z Speed (Altitude), expressed as m/s * 100
 int16_t xacc; ///< X acceleration (mg)
 int16_t yacc; ///< Y acceleration (mg)
 int16_t zacc; ///< Z acceleration (mg)
} mavlink_hil_state_t;

For GPS altitude I think you can use MAVLINK_MSG_ID_GPS_RAW_INT with ID 24. Units are also mm. You can find all the details in the file common\mavlink_msg_gps_raw_int.h. The structure for the message payload in this case is:


typedef struct __mavlink_gps_raw_int_t
 uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot)
 int32_t lat; ///< Latitude in 1E7 degrees
 int32_t lon; ///< Longitude in 1E7 degrees
 int32_t alt; ///< Altitude in 1E3 meters (millimeters) above MSL
 uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535
 uint16_t epv; ///< GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535
 uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: 65535
 uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535
 uint8_t fix_type; ///< 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix.
 uint8_t satellites_visible; ///< Number of satellites visible. If unknown, set to 255
} mavlink_gps_raw_int_t;

You will probably also need info on GPS status to make sure you have proper signal lock, check the number of satellites, precission, etc. This info is in mavlink_msg_gps_status.h. Message structure:


typedef struct __mavlink_gps_status_t
 uint8_t satellites_visible; ///< Number of satellites visible
 uint8_t satellite_prn[20]; ///< Global satellite ID
 uint8_t satellite_used[20]; ///< 0: Satellite not used, 1: used for localization
 uint8_t satellite_elevation[20]; ///< Elevation (0: right on top of receiver, 90: on the horizon) of satellite
 uint8_t satellite_azimuth[20]; ///< Direction of satellite, 0: 0 deg, 255: 360 deg.
 uint8_t satellite_snr[20]; ///< Signal to noise ratio of satellite
} mavlink_gps_status_t;

Now you need to know what are the streams to trigger messages to be sent from the Pixhawk. As I told you, I have not direct experience on this. I would say that GPS messages are triggered with MAV_DATA_STREAM_RAW_SENSORS for the GPS altitude message and MAV_DATA_STREAM_EXTENDED_STATUS for GPS status message. Regarding internal altitude, I would try with MAV_DATA_STREAM_POSITION and see if it works. I cannot help more here.

Now I can’t help much more, I have diassembled the quad to do some adjustments and I will not be able to test anything until I find some time to finish it.

If you find the right combination of streams and messages, please revert!


Thank you ever so much for your kind assistance Juan! I’ll try it out, and revert back to you on the progress or if there are any difficulties faced.

Hi @jplopezll Could i seek your help in programming out the code. My email is Thanks!

Excellent tutorial. I have mavlijnk “running” on the arduino and trying to see something on the qgroundcontrol or missionplanner and not getting too far. I was hoping to see decoded hearbeats or something. What is a good “hello world” to test this either to PH or something on the PC?

My ultimate goal is to collect sensor data on the arduino, route it through the PixHawk in TELEM2 and out TELEM1 radio during flight and also to log locally. It will ultimately be my own user defined mavlink data.


Hi, @newts:

Thanks for your nice words!

Unfortunatelly, I do not think that the Pixhawk could behave like a bridge and route messages from Telem2 to Telem1. Thus, you cannot “feed” info in Telem2 and expect to see something in your Ground Control Station via a radio link connected to Telem1.

The idea of an Arduino (or any other MAVLink enabled system) on board is to have a second on-board brain (small in this case) to release the “pilot” flight controller from “crew” duties. In my example, the “pilot” is informing about attitude and emergency situations and the “crew” is in charge of managing the led lights.

If you are interested on sensors information to be transmitted to the Ground Station there are other alternatives. It will depend on what setup you have. If you elaborate a bit more on your goals, maybe I could help. You can PM me if you prefer. I will be glad to try to help!

1 Like

I got this error while compiling the code
sketch_mar31a.ino: In function ‘void loop()’:
sketch_mar31a:39: error: ‘previousMillisMAVLink’ was not declared in this scope
sketch_mar31a:39: error: ‘next_interval_MAVLink’ was not declared in this scope
sketch_mar31a:46: error: ‘num_hbs_pasados’ was not declared in this scope
sketch_mar31a:47: error: ‘num_hbs’ was not declared in this scope
sketch_mar31a:49: error: ‘Mav_Request_Data’ was not declared in this scope
sketch_mar31a:55: error: ‘comm_receive’ was not declared in this scope

it seems that these parameters are really not defined in this code
can you help me solve it
thank you

Hi, @mfzavareh:

Yes, sorry for that. There are some errors in the code I had not noticed before (this is one of them) as I added just yesterday to the post.

Meanwhile I correct the code and rewrite the post, you only need to add this before the void setup() in the sketch:

// Mavlink variables
unsigned long previousMillisMAVLink = 0;     // will store last time MAVLink was transmitted and listened
unsigned long next_interval_MAVLink = 1000;  // next interval to count
const int num_hbs = 60;                      // # of heartbeats to wait before activating STREAMS from Pixhawk. 60 = one minute.
int num_hbs_pasados = num_hbs;

Those are variables I use to control how often you send heartbeats and data to the Pixhawk. You can modify them as per your needs.

If you need any further help, do not hesitate to ask!

you are very kind man
I didnt expect to get answer as quickly as you did
thank you so much for that
your help is appreciated
hope to reply it soon
thank you

but still there are two functions which are not declared
should those be declared in the code or in the liberary?

Hi again, @mfzavareh:

You must code them in your sketch. It is explained in detail in the post…

I’m glad to help!

so you mean I have to define it by my own
"Actually I am new to coding and mavlink so …"

thank you any way
thank you so much

Dear @mfzavareh:

I mean that you have sample code in the post above. If you need something different you can ask me. Better by PM (private message).

Dear Juan,

Thanks for this Step-by-step tutorial, it is indeed a lifesaver as there hardly any end-to-end guidelines for newbie like me.
But the problem that I am facing is that I am getting the heartbeat whenever i try to send data to Ardupilot 2.8 via serial port the program halts as in it does not write anything and write never finishes / returns.

Even when I try c_uart_interface_example and connect with USB I am getting a heartbeat but not able to send any message through its write(fd,buff,len).

Has anyone else faced this problem? Really need some advise on this :slight_smile:

Dear @parnil:

Can you please attach your code and explain a bit better your setup? What arduino board are you using? What pins have you connected?

From your message, do you mean you have the serial port connected to both the telemetry port of the Pixhawk and the arduino serial monitor at the computer? Unless you have an arduino MEGA or similar, you cannot use the same UART to both connect to the Pixhawk AND the computer. To have both comms available you must create an emulated serial port (not explained in detail above, it is something to include in the near future).

Thanks you so much for responding, actually I have connected to Audrupilot 2.8 to Mac via usb. And I am running c++ c_uart_interface_example , where it receives heartbeat message and sysid = 1 compid =1 . I haven’t done any changes to the program but what I have discovered is that all the write operation endlessly keep on waiting and never return.


Gracias por el código está todo muy bien explicado. Hay algo que no acabo de entender, a ver si tu puedes ayudarme.

Estoy intentando crear un mensaje propio en mavlink, concretamente tres mensajes con las IDs 200, 201 y 202. Ambos están guardados en un mensajePropio.xml y usando he compilado la librería en un zip. No se si tu has hecho esto alguna vez, donde me pierdo es en como sabe Pixhawk que son esos mensajes, es decir, supongo que en algún sitio del Firmware de Pixhawk están los mensajes definidos, he mirado en el Firmware en el directorio msg y los mensajes son distintos, o no se como están relacionados. Conoces alguna guía donde esté bien explicado como hacer este proceso?

Un saludo y gracias de antemano por tu tiempo.

Take a loo at the arducopter/GCS_MAVLINK.cpp file
Add your code there.

1 Like

it´s what I´m exactly doing now xD thank u so much

But im still a little confuse

Poco a poco

Hi: Thanks for this info. I was especially interested in your success because I have tried to compile a sketch with MAVLINK before on a NANO. Unfortunately I kept running out of memory. If I compile your sketch above, it uses 107% of the NANO’s memory. Have you erased the bootloader from the NANO to fit the code?


Maybe I should re-phrase that. A copy of your sketch above on my Arduino IDE for NANO

Sketch uses 10910 bytes (35%) of program storage space. Maximum is 30720 bytes.
Global variables use 2206 bytes (107%) of dynamic memory, leaving -158 bytes for local variables. Maximum is 2048 bytes.

I guess that can’t be fixed by removing the bootloader. How much of your NANOs dynamic memory is used?

Hi @KimTyson,

No, I did no modification to the bootloader. I reduced the payload of the messages to reduce the amount of memory needed. Yo do that modifying the file mavlink_types.h, it was line 8 in my library. I reduced from 255 to 100:

#define MAVLINK_MAX_PAYLOAD_LEN 100 ///< Maximum payload length 255

If you do not need long messages, you can reduce even more. Please use it carefully, as long messages will not work properly…

Please check and revert. Kind regards.

1 Like