Problems interfacing my Holybro Pixhawk 6x with my ESP32

Hi everybody,

I am working on integrating an ESP32 LTE module for telemetry communication using the mobile network. To achieve this, I plan to connect the module to my ESP32.

However, I am having trouble connecting my Pixhawk 6x to my ESP32. Despite my attempts, I cannot establish a connection, and I am not receiving any error messages to help me troubleshoot.

Here are the components I am using:

Firebeetle ESP32-E (for testing only)

Holybro Pixhawk 6x

JST-GH to Pins cable

This is my setup:

I am using the "Telemetry 1" port on my Pixhawk.

The Baud rate is set to 57600.

MAVLink Protocol is on 2, but I have also tested it on 1 and switch to 2.

Regarding the wiring, I have connected:

Pin 1 (Red) -> Vcc

Pin 2 (Black) -> GPIO 16

Pin 3 (Black) -> GPIO 17

Pin 4/5 -> Nothing

Pin 6 -> GND

I have also tried testing the connection by powering the Pixhawk with a power bank and only having GND connected. I have also tested it with only RX/TX connected.

Unfortunately, I cannot establish a connection between the ESP32 and the Pixhawk. I have read the documentation on serial communication and UART wiring, but I am still unable to get it to work. I have also tried other people’s code, but it did not work as expected.

I have created a proof-of-concept code block that should short the SoftwareSerial and Hardware Serial connections, essentially creating a USB-to-Telemetry1 interface, but this also did not work.

Could anyone provide me with guidance on what I am doing wrong? I would greatly appreciate any help to verify that I can interface my Pixhawk with my ESP32.

Proof of concept code:

#include <SoftwareSerial.h>

#define RX_PIN 16
#define TX_PIN 17

SoftwareSerial softSerial(RX_PIN, TX_PIN);

void setup() {
  Serial.begin(115200);
  softSerial.begin(57600);
}

void loop() {
  // Read from USB serial and write to software serial
  while (Serial.available()) {
    byte data = Serial.read();
    softSerial.write(data);
  }
  
  // Read from software serial and write to USB serial
  while (softSerial.available()) {
    byte data = softSerial.read();
    Serial.write(data);
  }
}

Full Code (not claiming full authorship, partially copied):

#include <WiFi.h>
#include <SoftwareSerial.h>

// Wi-Fi network credentials
const char* ssid = [REDACTED];
const char* password = [REDACTED];

// TCP server settings
const char* server_address = [REDACTED];
const int server_port = 5761;

WiFiClient client;
SoftwareSerial swSerial(16, 17);  // RX, TX

void setup() {
  Serial.begin(115200);
  swSerial.begin(57600);
  delay(10);

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Connect to TCP server
  Serial.println("Connecting to TCP server...");
  if (client.connect(server_address, server_port)) {
    Serial.println("Connected to TCP server");
  } else {
    Serial.println("Failed to connect to TCP server");
  }
}

void loop() {
  // Read data from software serial and send it over the TCP connection
  if (swSerial.available()) {
    int numBytesToRead = swSerial.available();
    uint8_t* bytesRead = new uint8_t[numBytesToRead];
    int i = 0;

    while (swSerial.available() && i < numBytesToRead) {
      bytesRead[i++] = swSerial.read();
      delay(10);  // Allow some time for the next byte to arrive
    }

    Serial.print("Sending message: ");
    for (int j = 0; j < i; j++) {
      Serial.print(bytesRead[j], HEX);
      Serial.print(" ");
    }
    Serial.println();
    client.write(bytesRead, i);
    delete[] bytesRead;  // Free the dynamically allocated memory
  }

  // Read data from the TCP connection and write it to software serial
  if (client.available()) {
    int numBytesToRead = client.available();
    uint8_t* bytesRead = new uint8_t[numBytesToRead];
    int i = 0;

    while (client.available() && i < numBytesToRead) {
      bytesRead[i++] = client.read();
      delay(10);  // Allow some time for the next byte to arrive
    }

    Serial.print("Received message: ");
    for (int j = 0; j < i; j++) {
      Serial.print(bytesRead[j], HEX);
      Serial.print(" ");
      swSerial.write(bytesRead[j]);
    }
    Serial.println();
    delete[] bytesRead;  // Free the dynamically allocated memory
  }
}

So, can you see any bytes flowing or is nothing arriving from the Pixhawk?

Is the wiring correct? Do you have ground connected? And are Tx/Rx crossed over? So Tx goes to Rx and vice-versa?

And have you checked mavlink status to check that MAVLink is being sent? And make sure flow control of the Telem 1 mavlink instance is OFF (unless you have flow control pins connected).

Its strange. Most of the time I see nothing, Sometimes I see obvious garbage (Single bytes or like 200 bytes in one message), and sometimes it just mirrors back what I send.

I think the wiring is correct, I have swapped RX and TX to check if this helps, nothing. I have tested it with ground and 5V connected, Only with ground and only RX/TX (Powered over USB Port). Still nothing.

I feel like I am running around in circles. If somebody could give me something that I could flash on my ESP and give me a quick guide what I have to do and what I should be able to see just to verify that I can even talk to my Pixhawk.

Thanks anyway for the advise so far :thumbsup:

That’s what binary MAVLink looks like…

By obvious garbage I did not mean non-string bytes. But it wasn’t in the expected format. (Frames starting with 0xFE, 0x…) but it seem random, so i assumed that it is garbage.

Right, dunno then. Make sure you have the baudrate correct :thinking:. Not sure what else could be wrong.

It seems there was something wrong with the pixhawk firmware. I re flashed the pixhawk with ardupilot and as soon as I did this, my old code started working. I had to fix some sequencing issues, but now it works like expected and I can talk to my Pixhawk using MissionPlanner and QGroundControl.
Thanks for taking a look at it, Your input caused me to consider other error sources other than my code :smiley:

If anybody is interested, this is the code that ended up working. It connects to a Server that acts like a TCP bridge:

#include <WiFi.h>
#include <SoftwareSerial.h>

// Wi-Fi network credentials
const char* ssid = "[REDACTED]";
const char* password = "[REDACTED]";

// TCP server settings
const char* server_address = "[REDACTED]";
const int server_port = 5761;

WiFiClient client;
SoftwareSerial swSerial(16, 17);  // RX, TX

void setup() {
  Serial.begin(115200);
  swSerial.begin(57600);
  delay(10);

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Connect to TCP server
  Serial.println("Connecting to TCP server...");
  if (client.connect(server_address, server_port)) {
    Serial.println("Connected to TCP server");
  } else {
    Serial.println("Failed to connect to TCP server");
  }
}

enum ReadState { WAIT_START, READ_LENGTH, READ_DATA };

ReadState state = WAIT_START;
uint8_t payload_length = 0;
size_t bytesRead = 0;
const size_t bufferSize = 1024;
uint8_t buffer[bufferSize];

void loop() {
  // Read data from software serial and send it over the TCP connection
  while (swSerial.available()) {
    uint8_t c = swSerial.read();
    switch (state) {
      case WAIT_START:
        if (c == 0xFD) {
          buffer[bytesRead++] = c;
          state = READ_LENGTH;
        }
        break;
      case READ_LENGTH:
        payload_length = c;
        buffer[bytesRead++] = c;
        state = READ_DATA;
        break;
      case READ_DATA:
        buffer[bytesRead++] = c;
        if (bytesRead == payload_length + 12) {
          client.write(buffer, bytesRead);
          bytesRead = 0;
          state = WAIT_START;
        }
        break;
    }
  }

  // Read data from the TCP connection and write it to software serial
  if (client.available()) {
    uint8_t c = client.read();
    swSerial.write(c);
  }

  //delay(1);
}

Nice, glad you got it to work. And thanks for sharing the example code.