★ New · feat/multi-sensor-payload

Point the gimbal. Switch the sensor. Zoom in.

3D Map Explorer's payload module turns the desktop into a live gimbal and camera controller. Drive pitch/yaw/roll, toggle between RGB and thermal, and command zoom — all over MAVLink. This is the platform's first command-send path: every prior MAVLink feature only listened.

Gimbal attitudeRGB / ThermalZoom MAV_CMD 1000 / 510 / 531First command-sendGIMBAL_DEVICE_ATTITUDE_STATUSCAMERA_INFORMATION
What it does

From listening to the aircraft — to commanding it.

The MAVLink telemetry stack already ingested HEARTBEAT, GLOBAL_POSITION_INT, and attitude. Payload control promotes the gimbal from a planning parameter into a live, controllable attitude and adds outbound commands to the aircraft.

  • Gimbal attitude — target pitch (-90..+90), yaw (0..359), roll (-45..+45) via MAV_CMD_DO_GIMBAL_MANAGER_ATTITUDE (1000), with Follow / Lock / Free pointing modes.
  • Camera mode — switch the active sensor (RGB ↔ Thermal) via MAV_CMD_SET_CAMERA_MODE (510).
  • Zoom — command optical/digital zoom via MAV_CMD_SET_CAMERA_ZOOM (531).
  • Type auto-detectionCAMERA_INFORMATION (259) + vendor heuristic → RGB / Thermal / LiDAR / Multispectral.
POST /api/payload/command
// point the gimbal nadir, lock yaw north
{
  "sysId": 1,
  "pitchDeg": -90,
  "yawDeg": 0,
  "mode": "Lock"
}
→ MAV_CMD 1000 sent
→ status reflects GIMBAL_DEVICE_ATTITUDE_STATUS
{ "accepted": true, "gimbalPitchDeg": -90 }
Multi-sensor payload control panel with gimbal attitude, RGB/thermal toggle, and zoom slider
The telemetry that drives it

Inbound MAVLink → outbound MAVLink

Payload status is assembled from the same MAVLink stream the telemetry overlay already decodes. The command-send path reuses that link so every command rides the connection that's already proven up.

🧭

Attitude status

GIMBAL_DEVICE_ATTITUDE_STATUS (285) → live pitch/yaw/roll, quaternion→euler.

📷

Camera info

CAMERA_INFORMATION (259) → sensor type + mode from cam_definition_uri or heuristic.

💓

Heartbeat scoping

Component IDs from HEARTBEAT identify gimbal/camera components per sysId.

🎯

Pointing modes

Follow (yaw trails flight direction), Lock, Free — mapped to GIMBAL_MANAGER_FLAGS.

🔄

Staleness tracking

?sysId + ?staleSec on status so stale attitudes are flagged, not trusted.

🛡️

Never-throws sends

Every command send returns a result object; a dead link is reported, never raised.

REST API surface

Command the payload from your own UI

CapabilityEndpointMAVLink
Capability discoveryGET /api/payload/capabilitiesAvailable sensors + gimbal presence
Payload statusGET /api/payload/statusLive attitude + mode (?sysId, ?staleSec)
Gimbal commandPOST /api/payload/commandMAV_CMD 1000 — pitch/yaw/roll + mode
Camera modePOST /api/payload/camera/modeMAV_CMD 510 — RGB ↔ Thermal
Camera zoomPOST /api/payload/camera/zoomMAV_CMD 531 — zoom level

Command mapping reflects PayloadService on commit 73ddba7d0 (feat/multi-sensor-payload). This is the first feature that sends MAVLink commands; earlier features (FlyPath, telemetry overlay) were receive-only. Actual gimbal response depends on the airframe's MAVLink gimbal protocol support.

Part of the UAS loop

Plan → Preflight → Fly → Process → Exploit

Drive the sensor, not just watch it

Live gimbal attitude, RGB/thermal switching, and zoom — the first outbound MAVLink command path on the platform.