MAVLink and Arduino: step by step

Hello!
Can you please tell me how I can check if my system is ready to arm?
Is it specific message for this?

Thanks and regards.

I want to use an arduino as a companion computer on a quad copter to measure some temperatures.
Is there a way to have those temperatures displayed in Mission Planner while I am flying?
Is there a way to make these temperatures display on my OSD?
Is there a way to make an alarm show on my OSD if any of the temperatures get too high?
I would appreciate any help or pointing me in the right direction on this.
Thanks for the excellent tutorial!

Easiest would be using a NAMED_VALUE_FLOAT mavlink message, which can be mapped to a custom field in the Missionplanner Current State window (double click on the window to bring up the select options and check a custom field).
I’ve no idea about OSD.

How can I make a library that works with MAVLink1.0 and 2.0 ?

Some of the convenient functions are simple, like the deprecated mavlink_msg_request_data_stream_send() that this guide uses as example.

How should one request messages using the new MAV_CMD_SET_MESSAGE_INTERVAL ?

@jplopezll Thank you for the great work,

I am new to mavlink so please excuse me. My project is a slightly different.

The project is to send telemetry data between two Arduino megas (no pixhawk or other controller involved) using mavlink with a holybro V3 telemetry radio.

I have the desired data for transmission available on the serial monitor (3 float values), but packaging then sending mavlink packets and receiving then unpacking them it where I get lost.

Any input would be greatly appreciated.

Hi ,
I’m new here. I made a display with arduino like the one in the beginnning of this thread.
It work fine with Ardurover and Arduplane.
Now I tried to read data from a Copter with Cube Orange and Arducopter 4.10.
Display shows only Waitinf for Mavlink. I can’t get a datastream. Seems there were
changes in code. I’m not a programmer myself. So I need a little help .
Many thanks for your help
Best Regards
Wolfgang

Hi Wolfgang, welcome to the forum.

Just an idea. Maybe your Arduino code can only initiate MAVLink 1 and the serial port at the flight controller is set to MAVlink 2.

Rolf

Hi Rolf,
I tried both Mavlink1 and 2. Same result on Arducopter. I don’t know what’s the difference
in data between Ardurover/Arduplane and Arducopter.
It seams there is a problem with heartbeat signal from AC4.1
May be they changed something in code.

I got code from this thread here.
Here is the code:

#include <Wire.h>
#include “SSD1306Ascii.h”
#include “SSD1306AsciiWire.h”
#include <mavlink.h>
#include <EEPROM.h>

#define I2C_ADDRESS 0x3C
#define RST_PIN -1
SSD1306AsciiWire oled;

#define MAV_TIMEOUT 5000 //mavlink timeout
#define SERIAL_SPEED 57600 //mavlink input baud, 4800 for qczek 2.10
//#define DEBUG
mavlink_message_t msg;
mavlink_status_t status;
//mavlink_global_position
int32_t alt, relative_alt;
int16_t vx, vy, vz;
uint16_t hdg;
//__mavlink_sys_status_t
int8_t battery_remaining;
uint16_t current_battery, voltage_battery, cpu_load, drop_rate_comm;
//mavlink_gps_raw_int_t
int32_t lat, lon, gps_alt;
uint8_t satellites_visible, fix_type;
uint16_t cog, vel;
//mavlink_rc_channels_raw_t
uint8_t rssi;
//oth
uint8_t flag, eeprom_flag = 0;
uint32_t time_flag;
//------------------------------------------------------------------------------
void setup() {
Wire.begin();
Wire.setClock(400000L);
oled.begin(&Adafruit128x32, I2C_ADDRESS);
display_wait();
//
Serial.begin(SERIAL_SPEED);
//
time_flag = millis();
}
//------------------------------------------------------------------------------
void loop() {
while(Serial.available()) {
uint8_t c= Serial.read();
if(mavlink_parse_char(MAVLINK_COMM_0, c, &msg, &status)) {
flag = 0;
switch(msg.msgid) {
case MAVLINK_MSG_ID_HEARTBEAT: {
break;
}
case MAVLINK_MSG_ID_GLOBAL_POSITION_INT: {
mavlink_global_position_int_t packet;
mavlink_msg_global_position_int_decode(&msg, &packet);
if(packet.hdg == 65535) packet.hdg = 0;
//if(lat != packet.lat) { lat = packet.lat; set_flag(); }
//if(lon != packet.lon) { lon = packet.lon; set_flag(); }
//if(alt != packet.alt) { alt = packet.alt; set_flag(); }
if(relative_alt != packet.relative_alt) { relative_alt = packet.relative_alt; set_flag(); }
//if(vx != packet.vx) { vx = packet.vx; set_flag(); }
//if(vy != packet.vy) { vy = packet.vy; set_flag(); }
//if(vz != packet.vz) { vz = packet.vz; set_flag(); }
if(hdg != packet.hdg) { hdg = packet.hdg; set_flag(); }
break;
}
case MAVLINK_MSG_ID_SYS_STATUS: {
__mavlink_sys_status_t packet;
mavlink_msg_sys_status_decode(&msg, &packet);
if(battery_remaining != packet.battery_remaining && packet.battery_remaining >= 0) { battery_remaining = packet.battery_remaining; set_flag(); }
if(voltage_battery != packet.voltage_battery && packet.voltage_battery != 65535) { voltage_battery = packet.voltage_battery; set_flag(); }
if(current_battery != packet.current_battery) { current_battery = packet.current_battery; set_flag(); }
if(cpu_load != packet.load) { cpu_load = packet.load; set_flag(); }
if(drop_rate_comm != packet.drop_rate_comm) { drop_rate_comm = packet.drop_rate_comm; set_flag(); }
break;
}
case MAVLINK_MSG_ID_ATTITUDE: {
break;
}
case MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN: {
break;
}
case MAVLINK_MSG_ID_RC_CHANNELS_RAW: {
__mavlink_rc_channels_raw_t packet;
mavlink_msg_rc_channels_raw_decode(&msg, &packet);
if(rssi != packet.rssi) { rssi = packet.rssi; set_flag(); }
break;
}
case MAVLINK_MSG_ID_VFR_HUD: {
break;
}
case MAVLINK_MSG_ID_GPS_RAW_INT: {
__mavlink_gps_raw_int_t packet;
mavlink_msg_gps_raw_int_decode(&msg, &packet);
if(packet.cog == 65535) packet.cog = 0;
if(packet.vel == 65535) packet.vel = 0;
if(packet.alt == 65535) packet.alt = 0;
if(lat != packet.lat) { lat = packet.lat; set_flag(); }
if(lon != packet.lon) { lon = packet.lon; set_flag(); }
//if(gps_alt != packet.alt) { gps_alt = packet.alt; set_flag(); }
if(vel != packet.vel) { vel = packet.vel; set_flag(); }
if(cog != packet.cog) { cog = packet.cog; set_flag(); }
if(fix_type != packet.fix_type) { fix_type = packet.fix_type; set_flag(); }
if(satellites_visible != packet.satellites_visible) { satellites_visible = packet.satellites_visible; set_flag(); }
break;
}
default: {
#ifdef DEBUG
Serial.println(msg.msgid); //see unused packet types
#endif
break;
}
}//switch
if(flag == 1) {
display_data();
}//print flag
else {
no_data();
}
}//if mavlink_parse_char
}//while serial available
no_data(); //check no serial input data fuction
}

void set_flag() {
flag = 1;
eeprom_flag = 0;
time_flag = millis();
}
void display_wait() {
oled.setFont(font8x8);
oled.set2X();
oled.clear();
oled.println(“WAIT FOR”);
oled.println(“MAVLINK”);
oled.set1X();
oled.setFont(font5x7);
}

void display_data() {
oled.clear();
printL(lat); //gps
oled.print(" “);
printL(lon);
oled.println();
oled.println((String)“S”+satellites_visible+(String)” F"+fix_type+(String)" R"+map(rssi,0,255,0,100)+(String)"% L"+cpu_load/10+(String)"% E"+drop_rate_comm/100+(String)"%");
oled.println((String)“H”+hdg+(String)" S"+(uint8_t)(vel/100*3.6)+(String)“k A”+relative_alt/1000+(String)“m”);
oled.println(current_battery/100.0+(String)“A “+voltage_battery/1000.0+(String)“v R”+battery_remaining+(String)”%”);
}

void printL(int32_t degE7) {
// Extract and print negative sign
if (degE7 < 0) {
degE7 = -degE7;
oled.print( ‘-’ );
}
// Whole degrees
int32_t deg = degE7 / 10000000L;
oled.print( deg );
oled.print( ‘.’ );
// Get fractional degrees
degE7 -= deg*10000000L;
// Print leading zeroes, if needed
int32_t factor = 1000000L;
while ((degE7 < factor) && (factor > 1L)){
oled.print( ‘0’ );
factor /= 10L;
}
// Print fractional degrees
oled.print( degE7 );
}

void no_data() {
if((millis() - time_flag) > MAV_TIMEOUT ) { //no mavlink data at 2sec
#ifdef DEBUG
Serial.println((String)“LOST MAVLINK DATA”);
#endif
display_wait();
delay(300);
if(eeprom_flag == 0 && lat != 0 && lon != 0 && fix_type > 1) { //if gps coordinates present, save it
#ifdef DEBUG
Serial.println(“save…”);
#endif
EEPROM_int32_write(5, lat);
EEPROM_int32_write(16, lon);
EEPROM.write(30, satellites_visible);
EEPROM.write(32, fix_type);
EEPROM.write(34, cpu_load);
EEPROM.write(40, drop_rate_comm);
EEPROM.write(46, hdg);
EEPROM.write(52, vel);
EEPROM_int32_write(56, relative_alt);
EEPROM.write(66, current_battery);
EEPROM.write(72, voltage_battery);
EEPROM.write(74, battery_remaining);
EEPROM.write(76, rssi);
eeprom_flag = 1;
} else { //no fresh data on mavlink, read from memory
#ifdef DEBUG
Serial.println(“read…”);
#endif
lat = EEPROM_int32_read(5);
lon = EEPROM_int32_read(16);
satellites_visible = EEPROM.read(30);
fix_type = EEPROM.read(32);
cpu_load = EEPROM.read(34);
drop_rate_comm = EEPROM.read(40);
hdg = EEPROM.read(46);
vel = EEPROM.read(52);
relative_alt = EEPROM_int32_read(56);
current_battery = EEPROM.read(66);
voltage_battery = EEPROM.read(72);
battery_remaining = EEPROM.read(74);
rssi = EEPROM.read(76);
eeprom_flag = 1;
}
display_data();
time_flag = millis();
}
}

int32_t EEPROM_int32_read(int addr) // чтение из EEPROM 4 байта unsigned long
{
byte raw[4];
for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
int32_t &data = (int32_t&)raw;
return data;
}
//*****************************************************************
void EEPROM_int32_write(int addr, int32_t data) // запись в EEPROM 4 байта unsigned long
{
byte raw[4];
(int32_t&)raw = data;
for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}

Thanks for your help
Wolfgang

Hi Wolfgang,
Did you manage to resolve this? Did you need to trigger the AutoPilot to send MAVLink messages to you? Still it seems odd if it worked in Rover & Plane but not Copter. Was that all the same version?

HI there,
I am trying to get telemetry data on an arduino board.
I would like to get yaw, pitch and roll telemetry data on my arduino board from the FC card of my drone.
I am thniking about using mavlink protocol and the mavlink library on arduino. but i dont how to code this. Can you help me?
Thanks,
Jean

Hi Jean,

So we can help, maybe you could describe what you have done so far?

  1. Have you wired your Arduino to your FC and are you comfortable with how to configure your FC to talk MAVLink on the port you are connected to?

  2. What Arduino board are you using and have you tried any code yet? If so, could you share what you have?

  3. Are you ok with coding in general on the Arduino and is it just the MAVLink stuff you need help with?

  4. What version of ArduPilot are you using on your FC?

This will help us provide suitable guidance.

Thanks,
Paul

Hi paul,
Thanks you very much to reply to me!

  1. Yes i have linked my fc to the arduino board. Be aware that i plug a 3dr holybro v3 telemetry (transmitter) on my fc. And i plug an other holybro v3 telemetry ( receiver) on the arduino board. Yes i have configurated the fc on inav to communicate on mavlink protocole.
  2. I use an arduino Nano. I didint tried any code yet. I looked at the tutorial but it s little bit complicated for me because my skills in arduino are low. This is why i need your help.
  3. I need help to make a code. Let me explain the first step of my project: i need to get pitch, roll and yaw data telemetry on the arduino board in order to use this data then. Can you help ?
  4. I dont know what you are talking about. The only thing i have done on the fc is to configurate the mavlink protocole on inav. That all
    Thanks for your help !!

Look at this code. I would like the serial monitor print "yaw cool, “pitch cool” and “roll cool” according to the attitude of the drone. Can you help to create this code? look at below what I have done :

Nouveau document texte.txt (9.9 KB)

Hey guys, I’m on a mission to try and get an esp8266 to work as a TCP Client as a ground station that will connect to my TX which acts as a TCP server for MAVlink.

I have a python version of my code running fine on my PC, But I’m haven’t found anyone online who has connected Arduino to mavlink this way so far. I just wanted to check in and see if you guys knew of any projects doing this before I get my head too deep trying to work out how to do it on a lower level?

ESP TCP Client <----------> Tx with TCP server <-----------> Drone

I’m trying to build a super lightweight antenna tracker that pulls my drones gps data off my tx.

any help, hints or tips are appreciated!

Hi Jean,

The first thing I noticed that looks like a problem with your code is that you never initialise the pxSerial interface in your setup() function.
It currently looks like this;

void setup() {
  // put your setup code here, to run once:
 Serial.begin(57600);

#ifdef SOFT_SERIAL_DEBUGGING
  // [DEB] Soft serial port start
  Serial.begin(57600);
  Serial.println("MAVLink starting.");
  mySerial.begin(57600);
#endif
}

but looking at how later in your code you try and use pxSerial to send your Heartbeat to the Flight Controller (I am assuming your Flight Controller is connected to pins 9 & 10 of your Arduino Nano)

#ifdef SOFT_SERIAL_DEBUGGING
    pxSerial.write(buf,len);
    //mySerial.println("Ardu HB");
#else
    Serial.write(buf, len);
#endif

it looks to me like pxSerial is probably still uninitialised.

So maybe try changing your setup() code to look like this

void setup() {
  // put your setup code here, to run once:
 Serial.begin(57600);

#ifdef SOFT_SERIAL_DEBUGGING
  // [DEB] Soft serial port start
  Serial.begin(57600);
  Serial.println("MAVLink starting.");
  pxSerial.begin(57600);        //           <- correctly initialise your pxSerial before using it later in code.
  mySerial.begin(57600);
#endif
}

See how that goes and report back if still stuck :+1:

@Paris007 I forgot to mention, SoftwareSerial is not always reliable, I don’t use it.
I try to use Arduino boards that have additional hardware based Serial ports like the awesome Feather series from Adafruit. https://www.adafruit.com/category/943.

I mainly use their Adafruit Feather M0 Basic Proto boards which have 3 additional hardware Serial ports. I use this guide to learn how to use them. Overview | Using ATSAMD21 SERCOM for more SPI, I2C and Serial ports | Adafruit Learning System

Cheers,
Paul

Hi @Ricky_Millar,

I’m not sure I follow exactly what you are trying to do. Can you elaborate on what your TX is doing in terms of receiving MAVLink from your drone and how it then makes it available over TCP/IP/WiFi?

I have only used the MAVLink methods described in this thread to connect a microcontroller directly over Serial wiring to the Flight Controller running ArduPilot OR inserting a pair of SIK telemetry radios in that same path.

Cheers,
Paul

heya! so my tx has a wifi chip on it that I believe is just working as a mavlink passthrough. I can connect to the TX’s access point from a phone/laptop and run stuff like mission planner or custom code, and receive and send mavlink through it.

My problem is I don’t know how to do this for something like an ESP or arduino, I want to be able to use an arduino or something similar, to connect to my tx’s access point and send/receive mavlink through it. I keep finding serial examples, but no TCP ones (the tx is acting as a TCP server).

(the tx is a tbs tango 2 if that helps)

Hi @Ricky_Millar,
Ahh now I understand what you are trying to do. I was not familiar with the TBS gear. Unfortunately I can’t really help you other than to suggest that you look at the code in QGroundControl, or Mission Planner, and hunt for the bits that talk MAVLink to the Flight Controller over TCP/UDP. That might give you some ideas.
You also need some doco on the TBS, to understand how to either 1) connect your ESP32 to it if the TBS is behaving as a WiFi access point, or 2) have the TBS and your ESP32 join an existing Wifi network.
There should be plenty of examples for ESP32 boards that show you how to connect to a WiFi network and potentially open a generic TCP connection to a host.
At that point you will need the TBS doco and the QGC/MP code to leverage the standard MAVLink libraries (like many have done here but over Serial not TCP) to then operate in that new TCP connection and either request or listen for and parse the MAVLink data etc.
I also find the doco at MAVLink.io really helpful. It takes a while to understand the MAVLink protocols but once you get it you can use the standard MAVLink libraries pretty quickly to listen for different data streams or individual parameters from the FC and/or issue commands back to the FC from you Microcontroller.