|
| 1 | +# mavlink2rest API Reference |
| 2 | + |
| 3 | +mavlink2rest exposes a RESTful API over the MAVLink protocol. |
| 4 | +Supports the ardupilotmega MAVLink dialect (includes common, icarous, uavionix). |
| 5 | +All JSON responses are pretty-printed. |
| 6 | + |
| 7 | +You are reading this file from the /llm endpoint. |
| 8 | +The base URL for all API requests is the same origin as this endpoint. |
| 9 | +For example, if you accessed this file at http://192.168.0.10:8088/llm, |
| 10 | +then the base URL for all examples below is http://192.168.0.10:8088. |
| 11 | +Replace http://0.0.0.0:8088 in the examples with your actual address. |
| 12 | + |
| 13 | +## Data Model |
| 14 | + |
| 15 | +Messages are organized hierarchically: |
| 16 | + vehicles/{system_id}/components/{component_id}/messages/{MESSAGE_NAME} |
| 17 | + |
| 18 | +Each message entry contains: |
| 19 | + - message: the MAVLink message fields |
| 20 | + - status.time.first_update: ISO 8601 timestamp of first reception |
| 21 | + - status.time.last_update: ISO 8601 timestamp of last reception |
| 22 | + - status.time.counter: number of times received |
| 23 | + - status.time.frequency: reception rate in Hz |
| 24 | + |
| 25 | +## Endpoints |
| 26 | + |
| 27 | +### GET /v1/mavlink |
| 28 | +Returns all MAVLink messages from all vehicles and components. |
| 29 | + |
| 30 | +Example: |
| 31 | + curl http://0.0.0.0:8088/v1/mavlink |
| 32 | + |
| 33 | +### GET /v1/mavlink/{path} |
| 34 | +Returns a specific nested value using JSON pointer-style path traversal. |
| 35 | + |
| 36 | +Examples: |
| 37 | + # Full ATTITUDE message with status |
| 38 | + curl http://0.0.0.0:8088/v1/mavlink/vehicles/1/components/1/messages/ATTITUDE |
| 39 | + |
| 40 | + # Single field (note: fields are under "message/") |
| 41 | + curl http://0.0.0.0:8088/v1/mavlink/vehicles/1/components/1/messages/ATTITUDE/message/roll |
| 42 | + Returns: 0.14598171412944794 |
| 43 | + |
| 44 | + # Status metadata |
| 45 | + curl http://0.0.0.0:8088/v1/mavlink/vehicles/1/components/1/messages/ATTITUDE/status/time/frequency |
| 46 | + Returns: 10.047618865966797 |
| 47 | + |
| 48 | + # Last update timestamp |
| 49 | + curl http://0.0.0.0:8088/v1/mavlink/vehicles/1/components/1/messages/ATTITUDE/status/time/last_update |
| 50 | + Returns: "2026-03-29T07:14:29.700718126-03:00" |
| 51 | + |
| 52 | +Response for a full message (GET .../messages/ATTITUDE): |
| 53 | +{ |
| 54 | + "message": { |
| 55 | + "type": "ATTITUDE", |
| 56 | + "time_boot_ms": 49624892, |
| 57 | + "roll": 0.14528612792491913, |
| 58 | + "pitch": 0.012282482348382473, |
| 59 | + "yaw": -2.570211410522461, |
| 60 | + "rollspeed": -0.00008160166908055544, |
| 61 | + "pitchspeed": -0.0007044915109872818, |
| 62 | + "yawspeed": -0.00017313705757260323 |
| 63 | + }, |
| 64 | + "status": { |
| 65 | + "time": { |
| 66 | + "first_update": "2026-03-29T07:10:52.701061519-03:00", |
| 67 | + "last_update": "2026-03-29T07:14:19.980848695-03:00", |
| 68 | + "counter": 2075, |
| 69 | + "frequency": 10.024154663085938 |
| 70 | + } |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +Invalid paths return the string "None" with HTTP 200. |
| 75 | + |
| 76 | +### GET /v1/helper/mavlink?name={MESSAGE_NAME} |
| 77 | +Returns a JSON template for any MAVLink message with default values. |
| 78 | +Use this to discover the correct JSON structure before POSTing. |
| 79 | + |
| 80 | +Examples: |
| 81 | + curl "http://0.0.0.0:8088/v1/helper/mavlink?name=HEARTBEAT" |
| 82 | + curl "http://0.0.0.0:8088/v1/helper/mavlink?name=COMMAND_LONG" |
| 83 | + curl "http://0.0.0.0:8088/v1/helper/mavlink?name=COMMAND_INT" |
| 84 | + curl "http://0.0.0.0:8088/v1/helper/mavlink?name=PARAM_SET" |
| 85 | + curl "http://0.0.0.0:8088/v1/helper/mavlink?name=MANUAL_CONTROL" |
| 86 | + |
| 87 | +Response for COMMAND_LONG: |
| 88 | +{ |
| 89 | + "header": { |
| 90 | + "system_id": 255, |
| 91 | + "component_id": 0, |
| 92 | + "sequence": 0 |
| 93 | + }, |
| 94 | + "message": { |
| 95 | + "type": "COMMAND_LONG", |
| 96 | + "param1": 0.0, |
| 97 | + "param2": 0.0, |
| 98 | + "param3": 0.0, |
| 99 | + "param4": 0.0, |
| 100 | + "param5": 0.0, |
| 101 | + "param6": 0.0, |
| 102 | + "param7": 0.0, |
| 103 | + "command": { |
| 104 | + "type": "MAV_CMD_NAV_WAYPOINT" |
| 105 | + }, |
| 106 | + "target_system": 0, |
| 107 | + "target_component": 0, |
| 108 | + "confirmation": 0 |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +Invalid message names return HTTP 404 with "Invalid message name." |
| 113 | + |
| 114 | +### POST /v1/mavlink |
| 115 | +Sends a MAVLink message to the vehicle. The body must be a JSON object with |
| 116 | +"header" and "message" fields matching the structure from the helper endpoint. |
| 117 | + |
| 118 | +The "header" fields: |
| 119 | + - system_id: sender system ID (typically 255 for a GCS) |
| 120 | + - component_id: sender component ID (typically 0 or 240 for a GCS) |
| 121 | + - sequence: message sequence number (typically 0) |
| 122 | + |
| 123 | +The "message" must include: |
| 124 | + - type: the MAVLink message type name (e.g. "COMMAND_LONG") |
| 125 | + - All required fields for that message type |
| 126 | + |
| 127 | +Returns HTTP 200 on success, HTTP 404 with error details on failure. |
| 128 | + |
| 129 | +#### Example: Arm the vehicle |
| 130 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 131 | + -H "Content-Type: application/json" \ |
| 132 | + -d '{ |
| 133 | + "header": { |
| 134 | + "system_id": 255, |
| 135 | + "component_id": 0, |
| 136 | + "sequence": 0 |
| 137 | + }, |
| 138 | + "message": { |
| 139 | + "type": "COMMAND_LONG", |
| 140 | + "param1": 1.0, |
| 141 | + "param2": 0.0, |
| 142 | + "param3": 0.0, |
| 143 | + "param4": 0.0, |
| 144 | + "param5": 0.0, |
| 145 | + "param6": 0.0, |
| 146 | + "param7": 0.0, |
| 147 | + "command": { |
| 148 | + "type": "MAV_CMD_COMPONENT_ARM_DISARM" |
| 149 | + }, |
| 150 | + "target_system": 1, |
| 151 | + "target_component": 1, |
| 152 | + "confirmation": 0 |
| 153 | + } |
| 154 | + }' |
| 155 | + |
| 156 | +#### Example: Disarm the vehicle |
| 157 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 158 | + -H "Content-Type: application/json" \ |
| 159 | + -d '{ |
| 160 | + "header": { |
| 161 | + "system_id": 255, |
| 162 | + "component_id": 0, |
| 163 | + "sequence": 0 |
| 164 | + }, |
| 165 | + "message": { |
| 166 | + "type": "COMMAND_LONG", |
| 167 | + "param1": 0.0, |
| 168 | + "param2": 0.0, |
| 169 | + "param3": 0.0, |
| 170 | + "param4": 0.0, |
| 171 | + "param5": 0.0, |
| 172 | + "param6": 0.0, |
| 173 | + "param7": 0.0, |
| 174 | + "command": { |
| 175 | + "type": "MAV_CMD_COMPONENT_ARM_DISARM" |
| 176 | + }, |
| 177 | + "target_system": 1, |
| 178 | + "target_component": 1, |
| 179 | + "confirmation": 0 |
| 180 | + } |
| 181 | + }' |
| 182 | + |
| 183 | +#### Example: Set flight mode (e.g. MANUAL mode = custom_mode 19 for ArduSub) |
| 184 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 185 | + -H "Content-Type: application/json" \ |
| 186 | + -d '{ |
| 187 | + "header": { |
| 188 | + "system_id": 255, |
| 189 | + "component_id": 0, |
| 190 | + "sequence": 0 |
| 191 | + }, |
| 192 | + "message": { |
| 193 | + "type": "COMMAND_LONG", |
| 194 | + "param1": 19.0, |
| 195 | + "param2": 0.0, |
| 196 | + "param3": 0.0, |
| 197 | + "param4": 0.0, |
| 198 | + "param5": 0.0, |
| 199 | + "param6": 0.0, |
| 200 | + "param7": 0.0, |
| 201 | + "command": { |
| 202 | + "type": "MAV_CMD_DO_SET_MODE" |
| 203 | + }, |
| 204 | + "target_system": 1, |
| 205 | + "target_component": 1, |
| 206 | + "confirmation": 0 |
| 207 | + } |
| 208 | + }' |
| 209 | + |
| 210 | +#### Example: Set a parameter |
| 211 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 212 | + -H "Content-Type: application/json" \ |
| 213 | + -d '{ |
| 214 | + "header": { |
| 215 | + "system_id": 255, |
| 216 | + "component_id": 0, |
| 217 | + "sequence": 0 |
| 218 | + }, |
| 219 | + "message": { |
| 220 | + "type": "PARAM_SET", |
| 221 | + "param_value": 1.0, |
| 222 | + "target_system": 1, |
| 223 | + "target_component": 1, |
| 224 | + "param_id": "SURFACE_DEPTH", |
| 225 | + "param_type": { |
| 226 | + "type": "MAV_PARAM_TYPE_REAL32" |
| 227 | + } |
| 228 | + } |
| 229 | + }' |
| 230 | + |
| 231 | +#### Example: Send manual control input |
| 232 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 233 | + -H "Content-Type: application/json" \ |
| 234 | + -d '{ |
| 235 | + "header": { |
| 236 | + "system_id": 255, |
| 237 | + "component_id": 0, |
| 238 | + "sequence": 0 |
| 239 | + }, |
| 240 | + "message": { |
| 241 | + "type": "MANUAL_CONTROL", |
| 242 | + "x": 0, |
| 243 | + "y": 0, |
| 244 | + "z": 500, |
| 245 | + "r": 0, |
| 246 | + "buttons": 0, |
| 247 | + "target": 1, |
| 248 | + "buttons2": 0, |
| 249 | + "enabled_extensions": 0, |
| 250 | + "s": 0, |
| 251 | + "t": 0, |
| 252 | + "aux1": 0, |
| 253 | + "aux2": 0, |
| 254 | + "aux3": 0, |
| 255 | + "aux4": 0, |
| 256 | + "aux5": 0, |
| 257 | + "aux6": 0 |
| 258 | + } |
| 259 | + }' |
| 260 | + |
| 261 | +#### Example: Request all parameters from the vehicle |
| 262 | +curl -X POST http://0.0.0.0:8088/v1/mavlink \ |
| 263 | + -H "Content-Type: application/json" \ |
| 264 | + -d '{ |
| 265 | + "header": { |
| 266 | + "system_id": 255, |
| 267 | + "component_id": 0, |
| 268 | + "sequence": 0 |
| 269 | + }, |
| 270 | + "message": { |
| 271 | + "type": "PARAM_REQUEST_LIST", |
| 272 | + "target_system": 1, |
| 273 | + "target_component": 1 |
| 274 | + } |
| 275 | + }' |
| 276 | + |
| 277 | +### GET /info |
| 278 | +Returns service version information. |
| 279 | + |
| 280 | +Example: |
| 281 | + curl http://0.0.0.0:8088/info |
| 282 | + |
| 283 | +Response: |
| 284 | +{ |
| 285 | + "version": 0, |
| 286 | + "service": { |
| 287 | + "name": "mavlink2rest", |
| 288 | + "version": "1.0.0", |
| 289 | + "sha": "8c5df007c2726af9db3ef98f6e12d5400ba2e718", |
| 290 | + "build_date": "2026-03-29T10:05:39.95884241Z", |
| 291 | + "authors": "Patrick José Pereira <patrickelectric@gmail.com>" |
| 292 | + } |
| 293 | +} |
| 294 | + |
| 295 | +### WebSocket: /v1/ws/mavlink |
| 296 | +Streams MAVLink messages in real-time over WebSocket. |
| 297 | +Accepts an optional "filter" query parameter with a regex to match message names. |
| 298 | + |
| 299 | + ws://0.0.0.0:8088/v1/ws/mavlink # all messages |
| 300 | + ws://0.0.0.0:8088/v1/ws/mavlink?filter=.* # all messages (explicit) |
| 301 | + ws://0.0.0.0:8088/v1/ws/mavlink?filter=ATTITUDE # only ATTITUDE |
| 302 | + ws://0.0.0.0:8088/v1/ws/mavlink?filter=RC_.* # RC_CHANNELS and RC_CHANNELS_RAW |
| 303 | + |
| 304 | +Each WebSocket frame is a JSON object with "header" and "message": |
| 305 | +{ |
| 306 | + "header": { |
| 307 | + "system_id": 1, |
| 308 | + "component_id": 1, |
| 309 | + "sequence": 37 |
| 310 | + }, |
| 311 | + "message": { |
| 312 | + "type": "RC_CHANNELS", |
| 313 | + "chan1_raw": 1500, |
| 314 | + "chan2_raw": 1500, |
| 315 | + ... |
| 316 | + } |
| 317 | +} |
| 318 | + |
| 319 | +You can also send MAVLink messages through the WebSocket by writing a JSON |
| 320 | +string in the same header+message format. The server will forward it to the |
| 321 | +vehicle and reply with the result. |
| 322 | + |
| 323 | +### GET /docs |
| 324 | +Interactive Swagger UI for exploring the API. |
| 325 | + |
| 326 | +### GET /docs.json |
| 327 | +Raw OpenAPI/Swagger 2.0 specification in JSON format. |
| 328 | + |
| 329 | +## Common Patterns |
| 330 | + |
| 331 | +### Discovering available vehicles and messages |
| 332 | +1. GET /v1/mavlink to see all vehicles, components, and messages. |
| 333 | +2. Navigate the hierarchy: vehicles/{id}/components/{id}/messages/{name} |
| 334 | + |
| 335 | +### Sending a command to the vehicle |
| 336 | +1. GET /v1/helper/mavlink?name=COMMAND_LONG to get the template. |
| 337 | +2. Fill in: command.type, param1-param7, target_system, target_component. |
| 338 | +3. POST /v1/mavlink with the filled-in JSON. |
| 339 | + |
| 340 | +### Monitoring a value in real-time |
| 341 | +Option A (polling): GET /v1/mavlink/vehicles/1/components/1/messages/{MSG}/message/{field} |
| 342 | +Option B (streaming): Connect a WebSocket to /v1/ws/mavlink?filter={MSG} |
| 343 | + |
| 344 | +### Getting a message template for any MAVLink message |
| 345 | +GET /v1/helper/mavlink?name={MESSAGE_NAME} |
| 346 | +Replace {MESSAGE_NAME} with any valid ardupilotmega message name, e.g.: |
| 347 | +HEARTBEAT, ATTITUDE, COMMAND_LONG, COMMAND_INT, PARAM_SET, |
| 348 | +MANUAL_CONTROL, PARAM_REQUEST_LIST, SET_MODE, GPS_RAW_INT, |
| 349 | +GLOBAL_POSITION_INT, BATTERY_STATUS, SYS_STATUS, RC_CHANNELS, |
| 350 | +MISSION_ITEM, MISSION_COUNT, MISSION_REQUEST_LIST, etc. |
| 351 | + |
| 352 | +## Notes |
| 353 | +- Enum fields use {"type": "ENUM_VALUE_NAME"} format (e.g. {"type": "MAV_CMD_COMPONENT_ARM_DISARM"}). |
| 354 | +- Bitfield fields use pipe-separated strings (e.g. "MAV_MODE_FLAG_SAFETY_ARMED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED"). |
| 355 | +- The POST endpoint accepts JSON5 (allows comments and trailing commas). |
| 356 | +- All endpoints under /v1/ are also available without the prefix (e.g. /mavlink works the same as /v1/mavlink). |
0 commit comments