MSP Protocol Documentation
Welcome to the comprehensive documentation for the MultiWii Serial Protocol (MSP), the standard communication protocol used by Betaflight and other flight controller firmware.
What is MSP?
MSP (MultiWii Serial Protocol) is a lightweight, binary communication protocol designed for bidirectional communication between flight controllers and external devices such as:
- Ground Control Stations (GCS) - Mission planning and telemetry
- Configurators - Betaflight Configurator, INAV Configurator
- Companion Computers - Raspberry Pi, Jetson for autonomous flight
- Telemetry Systems - Real-time flight data transmission
- Custom Applications - Data logging, research platforms
History
MSP originated with the MultiWii project, an early open-source flight controller firmware for Arduino-based boards. The protocol was designed to be:
- Simple to implement
- Low overhead for embedded systems
- Extensible for new features
As flight controller firmware evolved, MSP was adopted and extended by:
- Baseflight - First ARM-based fork
- Cleanflight - Major refactoring and modernization
- Betaflight - Performance-focused fork (most popular today)
- INAV - Navigation-focused fork
Protocol Versions
| Version | Header | Description |
|---|---|---|
| MSPv1 | $M | Original protocol, XOR checksum, 255-byte payload limit |
| MSPv1 JUMBO | $M | Extended v1 with 16-bit payload length |
| MSPv2 | $X | Modern protocol, CRC8 checksum, 16-bit command codes |
| MSPv2 over V1 | $M | V2 wrapped in V1 for backwards compatibility |
Current API Version: 1.48
Quick Start
Here's a minimal example to query the flight controller's API version:
use std::io::{Read, Write};
/// MSP command codes
const MSP_API_VERSION: u8 = 1;
/// Build an MSPv1 request frame
fn build_msp_request(command: u8) -> Vec<u8> {
let mut frame = Vec::with_capacity(6);
// Header
frame.push(b'$');
frame.push(b'M');
frame.push(b'<'); // Request direction
// Payload size (0 for query)
frame.push(0);
// Command
frame.push(command);
// Checksum: XOR of size and command
let checksum = 0 ^ command;
frame.push(checksum);
frame
}
/// Parse an MSPv1 response
fn parse_msp_response(data: &[u8]) -> Option<(u8, Vec<u8>)> {
if data.len() < 6 {
return None;
}
// Verify header
if &data[0..3] != b"$M>" {
return None;
}
let size = data[3] as usize;
let command = data[4];
if data.len() < 5 + size + 1 {
return None;
}
let payload = data[5..5 + size].to_vec();
// Verify checksum
let mut checksum = size as u8 ^ command;
for byte in &payload {
checksum ^= byte;
}
if checksum != data[5 + size] {
return None;
}
Some((command, payload))
}
fn main() -> std::io::Result<()> {
// Open serial port (adjust path for your system)
let mut port = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open("/dev/ttyUSB0")?;
// Send API version request
let request = build_msp_request(MSP_API_VERSION);
port.write_all(&request)?;
// Read response
let mut buffer = [0u8; 64];
let n = port.read(&mut buffer)?;
if let Some((cmd, payload)) = parse_msp_response(&buffer[..n]) {
println!("Command: {}", cmd);
println!("Protocol Version: {}", payload[0]);
println!("API Major: {}", payload[1]);
println!("API Minor: {}", payload[2]);
}
Ok(())
}
Documentation Structure
This documentation is organized into the following sections:
Protocol
- Overview - Protocol fundamentals and comparison
- Frame Structure - Detailed frame formats
- Checksums - XOR and CRC8 algorithms
- Version Detection - Protocol negotiation
Commands
- Command Reference - Complete command code table
- System Info - API version, board info (0-10)
- Configuration - Settings commands (32-62)
- Telemetry - Status and sensor data (101-166)
- Control - SET commands (200-229)
- MSPv2 Extensions - Betaflight extensions
Payloads
- Payload Overview - Data types and conventions
- MSP_STATUS - Flight controller status
- MSP_ATTITUDE - Orientation angles
- MSP_RAW_IMU - Raw sensor data
- MSP_RC - RC channel values
- MSP_MOTOR - Motor outputs
- MSP_PID - PID coefficients
- MSP_ANALOG - Battery and RSSI
Examples
- Connection Sequence - Initial handshake
- Telemetry Loop - Real-time data polling
- Configuration Write - Writing settings
Data Types
Throughout this documentation, the following data type conventions are used:
| Type | Size | Description |
|---|---|---|
U8 | 1 byte | Unsigned 8-bit integer (0-255) |
U16 | 2 bytes | Unsigned 16-bit integer, little-endian |
U32 | 4 bytes | Unsigned 32-bit integer, little-endian |
I8 | 1 byte | Signed 8-bit integer (-128 to 127) |
I16 | 2 bytes | Signed 16-bit integer, little-endian |
I32 | 4 bytes | Signed 32-bit integer, little-endian |
Byte Order: All multi-byte values are transmitted in little-endian format.
Flight Controller Identifiers
Different flight controller firmware can be identified by their 4-character variant code:
| Code | Firmware |
|---|---|
BTFL | Betaflight |
INAV | INAV |
CLFL | Cleanflight |
BAFL | Baseflight |
MWII | MultiWii |
RCFL | Raceflight |
Next Steps
- Read the Protocol Overview to understand MSPv1 vs MSPv2
- Check the Frame Structure for byte-level details
- Browse the Command Reference for all available commands