I’ve been tinkering with RC and FPV gear for years, and every now and then I hit a problem that really shouldn’t be a problem. This time it was MSP. More precisely: connecting small Arduino‑based projects to INAV and Betaflight in a clean and predictable way.

On paper it looks simple. MSP is open, documented, and widely used. But once you start digging, you quickly discover that the situation is not as friendly as it should be. There are a few libraries floating around, many of them based on Fabrizio Di Vittorio’s early work, but none of them give you the full package. Missing frame definitions, missing higher‑level logic, missing INAV and Betaflight specifics. You always end up writing half of the protocol yourself.
So I decided to fix that. This is how ApexMSP was born.
The goal is simple: a modern, clean, well‑structured MSP library that works with both INAV and Betaflight, includes all the frame definitions, and exposes higher‑level helpers so you don’t have to reinvent the wheel every time you want to read a sensor or toggle a mode. It’s still a work in progress, but it already covers a lot of ground and includes examples you can use right away.
One of the most common things people want to do is read active flight modes from INAV. ApexMSP makes this very straightforward.
#include <msp_inav.h>
// Adjust to match your wiring
#define FC_RX_PIN 10 // ESP32C3 pin connected to FC TX
#define FC_TX_PIN 8 // ESP32C3 pin connected to FC RX
MspINAV msp;
void setup()
{
Serial.begin(115200);
Serial1.begin(115200, SERIAL_8N1, FC_RX_PIN, FC_TX_PIN);
msp.begin(Serial1, 500); // 500 ms timeout
// List of mode IDs is dynamic; fetch it from the FC first.
// We need it to interpret the ACTIVEBOXES bitmap.
while (!msp.loadBoxIds()) {
Serial.println("BOXIDS request failed, retrying...");
delay(500);
}
Serial.println("BOXIDS loaded");
}
void loop()
{
if (!msp.loadActiveFlightModes()) {
Serial.println("ACTIVEBOXES request failed");
delay(500);
return;
}
Serial.print("Active modes: ");
bool anyActive = false;
for (uint8_t i = 0; i < INAV_MODE_DEFS_COUNT; i++) {
if (msp.isFlightModeActive(INAV_MODE_DEFS[i].permanentId)) {
if (anyActive) Serial.print(", ");
Serial.print(INAV_MODE_DEFS[i].name);
anyActive = true;
}
}
if (!anyActive) Serial.print("none");
Serial.println();
delay(500);
}No manual parsing, no guessing bit positions, no digging through INAV source code. Just a clean structure with named fields that tell you exactly what is happening on the flight controller.
This is the direction I want ApexMSP to grow: practical, readable, and friendly for anyone who wants to build something on top of INAV or Betaflight without spending days decoding MSP packets.
Bear in mind, this is still work in progress and more functions will follow.






