MAVLink and Arduino: step by step

Hi @Vinoth_Kumar,

In the sample code I provided in GitHub - pauljeffress/Pulsar-MAVLink-Tester your could modify the code for the 2nd menu item

[2].......STREAM   - mavlink_request_datastream(MAV_DATA_STREAM_RAW_SENSORS)

to request MAV_DATA_STREAM_RC_CHANNELS

If you look at line 108 in file SerSrvMnu_fns.cpp,
mavlink_request_datastream(MAV_DATA_STREAM_RAW_SENSORS);

you could change it to
mavlink_request_datastream(MAV_DATA_STREAM_RC_CHANNELS);

then run the program on an Arduino connected to your AutoPilot and have a look at the output coming from the AutoPilot and you should see the following messages;

RC_CHANNELS_SCALED ( #34 )

RC_CHANNELS_RAW ( #35 )

SERVO_OUTPUT_RAW ( #36 )

check what the values look like when you change your throttle on your RC and you should see them change in those packets.

Let us know how you go.

Cheers,
PJ

1 Like

Hi @ZvikaF,
That’s great to hear, let us know if you get stuck at any stage.
Also, could you share what changes you made to get the code working on an ESP32, as I might update the code on the Github page to do that as well :+1:
Thanks,
Paul

Hello @pauljeff
First, thanks for all your work, helped a lot :slight_smile:

sorry for me loading in such a way, do not know how to upload programs…

Following is the sketch start, mainly using PixhawkArduinoMAVLink.h
moving mavlink headers to the SRC library, and doing the changes in the headers so the location of the included files is OK.

// Mavlink working test
// Zvika Fayer 13-01-23
//
// using ESP32 Doit DevKit V1
// Pixhawk connecting Rx=16 Tx=17
// Payload connecting Rx=9 Tx=10
//
// Pixhawk Telem 2, protocol Mavlink 2:
// Yellow to TX2 on ESP32
// Green to RX2 on ESP32
//
// There are three serial ports on the ESP known as U0UXD, U1UXD and U2UXD usind 3.3V level.
//
// U0UXD is used to communicate with the ESP32 for programming and during reset/boot.
// U1UXD is unused and can be used for your projects. Some boards use this port for SPI Flash access though
// U2UXD is unused and can be used for your projects.
//
// UART RXIO TXIO CTS RTS
// UART0 GPIO3 GPIO1 N/A N/A
// UART1 GPIO9 GPIO10 GPIO6 GPIO11
// UART2 GPIO16 GPIO17 GPIO8 GPIO7
//
// system_id ID of this system
// component_id ID of this component (e.g. 200 for IMU)
//
// full Mavlink ardupilot plane parameter list: Complete Parameter List — Plane documentation
//
//

#include <PixhawkArduinoMAVLink.h>

HardwareSerial &payloadPort = Serial1; // serial 1 as payload UART
HardwareSerial &ardupilotPort = Serial2; // serial 2 as ardupilot UART

// Mavlink variables

#define ARDUPILOT_RX 16 // ESP32 RX pin for ardupilot
#define ARDUPILOT_TX 17 // ESP32 TX pin for ardupilot

#define PAYLOAD_RX 9 // ESP32 RX pin for Payload
#define PAYLOAD_TX 10 // ESP32 TX pin for Payload

#define CC_SYSID 2 // MAVLink System ID (of the ESP32).
#define CC_COMPID 200 // MAVLink Component ID (of the ESP32).
#define AP_SYS_ID 1 // MAVLink target System ID (of the autopilot).
#define AP_COMP_ID 1 // MAVLink target Component ID (of the autopilot).

OK. Thank you so much.
I do check this.
Wishes

Hi, im using an arduino mega to try to get mavlink data out of a pixhawk 4. I can see the pixhawk is sending some form of data as if i mirror the data received and send it to the serial monitor i get this. Theres some readable text in there as well such as “PreArm: Hardware safety switch⸮⸮⸮$” etc

I can’t however get into this if statement in the code. "if(mavlink_parse_char(MAVLINK_COMM_0, c, &msg, &status)) { "
Has anyone got any ideas to try.
Thanks

I am looking for an example of a device with it’s own MAVLink parameters (so that parameters of this device can be manipulated from a GCS.)
Please post and or/PM me if you are aware of some program that does this.

Thanks for sharing this @ZvikaF, much appreciated.

Hi @howlingj,
It does look like you are receiving data from the MAVLink stream successfully, but perhaps you are not doing it fast enough to catch every char in a full MAVLink packet successfully. Are you doing anything that may be taking a while between calls to check for and process chars?
I assume you are using something like the following wrapped around your mavlink_parse_char?

// code snippet…
while (Serial1.available() && !gotFullMsg && !timedOut)
{
uint8_t c = Serial1.read();
// add new char to what we have so far
if (mavlink_parse_char(MAVLINK_COMM_0, c, &msg, &status)) // and see of we have a full Mavlink msg yet
gotFullMsg = true; // will cause us to bust out of the while()

    // Check if we have timed out, which will be evaluated at next pass through the while()
    if ((millis() - start) >= (FMX_MAVLINK_RX_WINDOW_REGULAR_MS))
    {
        timedOut = true;
        debugPrintln("void mavlink_receive() - WARNING - we timed out");
    }
}

Are you getting timeout messages?

When I was having some issues I ended up printing out each char I received in Hex and then manually checking it against the MAVLink packet structure, to ensure I was seeing all chars etc.,

@howlingj I would also look at the variables msg and status each time you call mavlink_parse_char, I reckon that will give you a pretty good indication of whats happening.

Thanks for you’re reply. I’ve realised that i can output the data i need direct from mission planner to a serial port so thats actually an easier option for me, and was dead easy to set up. I’ll have a look into what you’ve suggested and see if i can get a better understanding of whats happening still.

Hi @Andre-K,

I haven’t done exactly this, but it shouldn’t be too hard to do, once you have an Arduino receiving and decoding MAVLink like the examples in this thread. Most of what I have done via an Arduino board is listen to the AutoPilot and either catch what I want from the MAVLink stream it emits (position info etc) OR send commands to the AutoPilot to ARM/DISARM etc.

But given that ArduPilot automatically routes MAVLink messages, see MAVLink Routing in ArduPilot — Dev documentation , an Arduino attached to ArduPilot will see messages the GCS sends to the Arduino’s MAVLink SysID/CompID. You could explicitly look for those messages with your Arduino, decode them and act on them.

I’m not sure how you get a GCS to send messages specifically to you Arduino’s SysID/CompID, but I’m sure someone else here will :slight_smile:

Let us know how you go or if you need more help.

Cheers,

Paul

Hello @pauljeff

it looks that you’re an expert on MavLink …
Have an ECU for EFI motor that is not supported by the Ardupilot.
made a sub control unit with ESP32 that reads the EFI data and transmit it by UART Mavlink to the AP. all is working well… but could not make the Mission planner show the data as it arrives with a different component ID (as seen in the attached) using 1,0 for the ID’s.
changing the ID to 1,1 did fuse the data but the MP was getting zeros data …

what should i do to fuse the data into the AP stream ? would also like it to be logged in the AP

thanks

Hello everyone, i want to know if someone has experienced problems like this one. I am using this code

#include <mavlink.h>


// 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 = 10;                      // # of heartbeats to wait before activating STREAMS from Pixhawk. 60 = one minute.
int num_hbs_pasados = num_hbs;

void setup() {
  Serial.begin(57600);
  while(!Serial);
  Serial1.begin(57600);
}
void loop() {
  int sysid = 1;
  int compid = 0;
  int type = MAV_TYPE_QUADROTOR;

  uint8_t system_type = MAV_TYPE_GENERIC;
  uint8_t autopilot_type = MAV_AUTOPILOT_INVALID;

  uint8_t system_mode = MAV_MODE_PREFLIGHT; ///< Booting up
  uint32_t custom_mode = 0;                 ///< Custom mode, can be defined by user/adopter
  uint8_t system_state = MAV_STATE_STANDBY; ///< System ready for flight

  // Initialize the required buffers
  mavlink_message_t msg;
  uint8_t buf[MAVLINK_MAX_PACKET_LEN];

  // Pack the message
  mavlink_msg_heartbeat_pack(sysid,compid, &msg, type, autopilot_type, system_mode, custom_mode, system_state);

  // Copy the message to the send buffer
  uint16_t len = mavlink_msg_to_send_buffer(buf, &msg);

  unsigned long currentMillisMAVLink = millis();
  if (currentMillisMAVLink - previousMillisMAVLink >= next_interval_MAVLink)
  {
    previousMillisMAVLink = currentMillisMAVLink;
    Serial1.write(buf, len);
    num_hbs_pasados++;
    if (num_hbs_pasados >= num_hbs) {
      Mav_Request_Data();
      num_hbs_pasados = 0;
    }
  }
  comm_receive();
}


void Mav_Request_Data()
{
  mavlink_message_t msg;
  uint8_t buf[MAVLINK_MAX_PACKET_LEN];


  // To be setup according to the needed information to be requested from the Pixhawk
  const int  maxStreams = 1;
  const uint8_t MAVStreams[maxStreams] = {MAV_DATA_STREAM_EXTENDED_STATUS};
  const uint16_t MAVRates[maxStreams] = {0x02};

  for (int i = 0; i < maxStreams; i++) {
    mavlink_msg_request_data_stream_pack(2, 200, &msg, 1, 0, MAVStreams[i], MAVRates[i], 1);
    uint16_t len = mavlink_msg_to_send_buffer(buf, &msg);
    Serial1.write(buf, len);

    Serial.print("Stream ");
    Serial.print(i);
    Serial.println(" Requested");
  }
}

void comm_receive() {
  mavlink_message_t msg;
  mavlink_status_t status;

  while (Serial1.available() > 0) {
    uint8_t c = Serial1.read();
    if (mavlink_parse_char(MAVLINK_COMM_0, c, &msg, &status)){
      switch(msg.msgid) {
        case MAVLINK_MSG_ID_HEARTBEAT:
          {
          Serial.println("FC HB");
          }
          break;
        case MAVLINK_MSG_ID_SYS_STATUS:
          {
            mavlink_sys_status_t sys_status;
            mavlink_msg_sys_status_decode(&msg, &sys_status);
            Serial.print("FC SYS STATUS: ");
            Serial.print("[Bat (V): ");
            Serial.print(sys_status.voltage_battery);
            Serial.print("], [Bat (A): ");
            Serial.print(sys_status.current_battery);
            Serial.print("], [Comms loss (%): ");
            Serial.print(sys_status.drop_rate_comm);
            Serial.println("]");
          }
          break;
        default:
          Serial.print("--- Otros: ");
          Serial.print("[ID: ");
          Serial.print(msg.msgid);
          Serial.print("], [seq: ");
          Serial.print(msg.seq);
          Serial.println("]");
          break;
      }
    }
  }
} 

And it shows me this on the serial monitor, i only want to be able to read some data from the fc but i cant make it work

00:50:51.154 -> FC HB
00:50:52.136 -> FC HB
00:50:53.132 -> FC HB
00:50:54.139 -> Stream 0 Requested
00:50:54.139 -> FC HB
00:50:54.139 -> --- Otros: [ID: 66], [seq: 245]
00:50:55.116 -> FC HB
00:51:04.150 -> Stream 0 Requested
00:51:14.150 -> Stream 0 Requested
00:51:24.150 -> Stream 0 Requested
00:51:34.134 -> Stream 0 Requested
00:51:44.139 -> Stream 0 Requested

Does it matter if the fc is in failsafe or unable to arm mode ? Any help would be apreciated.

Hi I need some help i want to send externel Sensor data from Arduino (like humidity or temperature which is connected with Arduino) to pixhawk can it is possible i just use Serial port of pixhawk like telem2 and do arduino serial write on Pixhawk telem2 port and see data on Mission planner Messages

Hi @ZvikaF,
Unfortunately I can’t help you with this one :frowning:
Have you tried posting in some of the other areas of the forum, like in the GCS sections etc?

1 Like

Hi @Mateo_Morales ,
I think the problem may be that in your

You should set your target sysID to 1 and your target compID to 1 as well. You look to be targeting a compID of 0.

So more like;

mavlink_msg_request_data_stream_pack(2, 200, &msg, 1, 1, MAVStreams[i], MAVRates[i], 1);

I think that will fix it.

Hi @Mirza_Shahriyar_Baig,
Yes you should be able to do what you are asking. It is very similar to what @ZvikaF is doing in similar posts here.
ArduPilot will route MAVLink messages between destinations such as the AutoPilot/FlightController and the GCS. It’s explained in the documentation here MAVLink Routing in ArduPilot — Dev documentation

I have had success sending messages in both directions between an Arduino and my PixHawk AutoPilot. I have not looked to see if I can send them from the Arduino > AutoPilot > Mission Planner yet but will try and give it a try. @ZvikaF may get to it first though. :slight_smile:

Also I suggest you start just by getting reliable MAVLink connection between an Arduino and your AutoPilot and then when that is working look at getting the messages all the way from Arduino > AutoPilot > Mission Planner. I made some demo code GitHub - pauljeffress/Pulsar-MAVLink-Tester that may help you get started.

Thanks,
Paul

Hello @pauljeff ,
Thanks for your answer… asking in the GCS section is an excellent idea, will do

Hello Paul, thanks for your help now i can succesfully receive data form the ardupilot, but now i want to set waypoints from the arduino to the ardupilot, i want to know if you have some useful link or an a example, thanks.

Hi @Mateo_Morales,
Cool, glad that helped.
I have managed to set waypoints from my Arduino to Ardupilot. It took a lot of figuring out reading the MAVLink and Ardupilot documentation. I will share some examples shortly :+1:.
Thanks,
Paul