MAVLink Command Transmission Problem with RP2040 and Pixsurvey Cube V3

Hi all, I’m encountering some issues.

I’m trying to send Return-To-Launch (RTL) commands from an RP2040/RP2350 to a Pixsurvey Cube V3 via UART.

I followed this guide: Mavlink Peripherals on the RP2040 and successfully sent/received commands using the provided instructions.

I modified the code and was able to send RTL commands to my simulated autopilot (using sim_vehicle.py) via a USB-TTL adapter.

However, when I tried sending commands to real hardware, it failed.

Full details below:

Setup:

  • Microcontroller: RP2040 (MicroPython)
  • Autopilot: Pixsurvey Cube V3
  • Communication: UART (921600 baud) on TELEM2 port
  • Purpose: Sending MAVLink commands to the Cube V3.

Problem:

  • MAVLink commands sent from the RP2040 work perfectly with a simulated autopilot (using sim_vehicle.py) via a USB-TTL adapter.
  • However, commands fail when connected to the real hardware (Pixsurvey Cube V3).
  • Data from the Cube V3 is successfully received, confirming the RX pin is functional.

Weird Behavior:

  • Commands only work if the RX pin is temporarily shorted to 3.3V before while sending data.

Key Observations:

  1. The Cube V3 continuously sends MAVLink data, which may overrun the UART buffer or block the TX line.
  2. Temporarily shorting the RX pin may reset the UART state, enabling commands to go through.
  3. Possible causes include voltage level mismatches, UART framing errors, or protocol synchronization issues.

Attempted Fixes (Failed):

  • Adjusting UART settings, timeouts, and flow control.
  • Pausing RX processing or using separate UARTs for TX/RX.
  • Sending a break condition to reset the line before transmitting.
  • Adding pull-up resistors, capacitors, and Schottky diodes to stabilize the RX signal.
  • Switching serial ports and reconfiguring MAVLink parameters.
  • Using software flow control (XON/XOFF).

the problem is your RP-2040 or the software your running. have you tried another serial port on the RP2040?

Yes, but it doesn’t work. I also tried it on a different RP2040 and the latest Pico (RP2350), but none of them could send MAVLink commands to the Pixsurvey Cube V3.

Out of curiosity, I tested sending commands using Pymavlink on my Raspberry Pi 5, and it worked.

Can you provide a copy of your script to test with? I can check it on my setup (Cube Orange)

Hi Stephen, thank you so much for taking the time to respond and offer your help!

I really appreciate your reply

Here is the full code. You may need to use the modified pymavminimal.py file, as I have added the ‘command_long_encode’ function to it.

rp2040_debug.zip (16.0 KB)

The code is basically the same as yours, but I only modified the baud rate and the command being sent.

That code works fine on my CubeOrange+ and Pico(1).

The only change I needed to make was to change the SysID to 21 to match my current setup. You can make it automatically use the correct SysID/CompID via:

from machine import Pin, Timer, ADC, UART
import time
import pymavminimal as pymav

try:
    import network
    wlan = network.WLAN(network.STA_IF)  # Try to initialize Wi-Fi
    print("This is a Pico W")
    led = Pin("LED", Pin.OUT)
except ImportError:
    print("This is an RP2040 (Pico)")
    led = Pin(25, Pin.OUT)
    
timer = Timer()

uart0 = UART(0, baudrate=921600, tx=Pin(0), rx=Pin(1))
target_System = 0
target_Component = 0

seen_heartbeat = False

def sendCommands(timer):
    if seen_heartbeat:
        # send rtl command
#         cmd = mavobj.command_long_encode(1, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0) # Simulated RTL command
        cmd = mavobj.command_long_encode(target_System, target_Component, 176, 0, 1, 11, 0, 0, 0, 0, 0) # Cube V3 RTL command

        uart0.write(cmd.pack(mavobj))
        print("Sent at {0}".format(time.ticks_ms()))

# Use a timer for sending packets
timer.init(freq=1, mode=Timer.PERIODIC, callback=sendCommands)

# MAVLink
mavobj = pymav.MAVLink()
mavobj.robust_parsing = True

# Keep looping to receive data
while True:
    num = uart0.any()
    # Receive data and process into MAVLink packets
    if num > 0:
        rxData = uart0.read(num)
        pkts = mavobj.parse_buffer(bytearray(rxData))
        if pkts is not None:
            for pkt in pkts:
                if pkt.get_type() == 'HEARTBEAT' and pkt.type not in [pymav.MAV_TYPE_GCS, pymav.MAV_TYPE_ADSB, pymav.MAV_TYPE_GIMBAL, pymav.MAV_TYPE_ONBOARD_CONTROLLER]:
                    led.toggle()
                    if not seen_heartbeat:
                        print("Got heartbeat from {0}:{1}".format(pkt.get_srcSystem(), pkt.get_srcComponent()))
                        mavobj.srcSystem = pkt.get_srcSystem()
                        mavobj.srcComponent = 0 #MAV_COMP_ID_PERIPHERAL
                        target_System = pkt.get_srcSystem()
                        target_Component = pkt.get_srcComponent()
                        seen_heartbeat = True
    time.sleep(0.01)

EDIT:
How are you powering the RP2040? I’ve got mine connected to both the GND and +5V on the TELEM port, so it draws power from the Flight Controller.

Hi Stephen

Thank you so much for testing the code and confirming that it works on your setup!
I really appreciate your detailed feedback and suggestions for improving the SysID/CompID handling—I’ll definitely incorporate those changes.

Regarding the power setup, I’m currently powering the RP2040 via USB.
I’ll also give this updated code a try as soon as I get a chance to go to the lab.

Thanks again for your help!

HI Stephen

Unfortunately, the improved code doesn’t work on my setup.
Out of curiosity, I tested the same code on an ESP32 WROOM, but it didn’t work either.
I was only able to receive data, not transmit it.

EDIT :
I managed to get it working after powering the RP2040 from the Flight Controller’s power supply.