turret 0.1.2

MAVLink Gimbal Manager and CLI for STorM32 RC Commands gimbals
Documentation

Turret

Command-line tool for STorM32 gimbal controllers. Uses the RC Commands protocol.

Features

  • CLI Mode: Direct command-line control
  • Daemon Mode: Background service with Unix socket IPC and MAVLink
  • Auto-detects STorM32 devices
  • Set gimbal angles, pan modes, standby
  • Query status and firmware info
  • Structured logging with verbosity levels
  • Priority-based command arbitration

Installation

Download Binary

Download the latest release from Releases for your platform.

OR:

From source

With a recent Rust installed:

cargo install turret

Usage

CLI Mode (Direct Control)

# Basic commands (auto-detects device)
turret status
turret set 10.0 0.0 -15.0
turret set -10,0,15          # comma-separated
turret set 1.5:-2.3:0        # colon-separated
turret center
turret version

# Manual device specification
turret --device /dev/ttyUSB0 status

# Verbose output for debugging
turret -v status          # info
turret -vv status         # debug
turret -vvv status        # trace (shows raw protocol)

# Individual axis control
turret pitch 1500         # RC values 700-2300, 0 to recenter
turret roll 0             # recenter roll

# Pan mode and standby
turret pan-mode 3         # PANPANPAN mode
turret standby true

Daemon Mode (Background Service)

# Start daemon (auto-detects device)
turret --daemon

# Or with custom config
turret --daemon --config turret.yaml

# Connect via Unix socket (JSON commands)
echo '{"cmd": "status"}' | nc -U /tmp/turret.sock
echo '{"cmd": "set", "pitch": 10.0, "roll": 0.0, "yaw": -15.0}' | nc -U /tmp/turret.sock
echo '{"cmd": "center"}' | nc -U /tmp/turret.sock
echo '{"cmd": "pan_mode", "mode": 3}' | nc -U /tmp/turret.sock
echo '{"cmd": "standby", "enabled": true}' | nc -U /tmp/turret.sock
echo '{"cmd": "help"}' | nc -U /tmp/turret.sock     # full schema

# MAVLink on UDP:14550 - use pymavlink or QGroundControl
# Implements Gimbal Manager protocol

The IPC wire format uses snake_case for both the cmd discriminator and field names — matches the response shape (firmware_version, pan_mode, ...) and standard JSON conventions. Send {"cmd":"help"} for the full machine-readable schema.

Yaw calibration

If your gimbal's IMU yaw reading is biased relative to its commanded zero (typical symptom: set yaw=0 then status returns yaw≠0 by a fixed amount), calibrate from the daemon — no GUI required:

# Auto-calibrate: daemon centers the gimbal, samples raw IMU yaw,
# stores the bias as the new offset.
echo '{"cmd": "calibrate_yaw"}' | nc -U /tmp/turret.sock
# → {"status":"ok","data":{"yaw_offset_deg": -4.48, "prior_yaw_offset_deg": 0.0}}

# Or set an explicit value (e.g. from a measurement you took elsewhere):
echo '{"cmd": "set_yaw_offset", "deg": -4.5}' | nc -U /tmp/turret.sock

# 0.0 disables the offset:
echo '{"cmd": "set_yaw_offset", "deg": 0.0}' | nc -U /tmp/turret.sock

The offset persists to $XDG_STATE_HOME/turret/calibration.toml (default ~/.local/state/turret/calibration.toml) and is auto-loaded on daemon start. The current offset is included in every status response as "yaw_offset_deg".

Read-side correction model: commands hit the device exactly as you wrote them (the gimbal physically goes to the asked-for angle), and the calibration offset is subtracted from the IMU's report before it reaches any consumer (IPC status, MAVLink GIMBAL_DEVICE_ATTITUDE_STATUS).

Self-test

Verify SP→PV agreement across the gimbal's working range without leaving the daemon — useful both as a post-calibration check and as a quick-and-dirty health probe before a mission:

echo '{"cmd": "selftest"}' | nc -U /tmp/turret.sock -q 20

The daemon sweeps (0,0,0) → (15,0,0) → (-15,0,0) → (0,0,15) → (0,0,-15) → (0,0,0), waits 2.5 s after each step, samples operator-frame attitude, and returns per-sample SP/PV/error plus per-axis max error and a pass/fail against a 1° tolerance. The whole run takes ~16 s. Refuses with an error if standby is engaged. The original pose is restored at the end.

A clean run on a calibrated gimbal looks like:

{"passed": true,
 "tolerance_deg": 1.0,
 "max_error_deg": {"pitch": 0.03, "roll": 0.0, "yaw": 0.27},
 "samples": [...]}

If the gimbal hasn't been calibrated yet, the failing samples make the bias obvious — that's a good cue to run {"cmd":"calibrate_yaw"}.

Configuration (turret.yaml):

device:
  path: auto

ipc:
  socket_path: /tmp/turret.sock

mavlink:
  enabled: true
  udp_port: 14550
  sysid: 1
  compid: 154

Priority System: MAVLink autopilot (highest) > GCS > Unix socket > CLI (lowest)

Daemon behavior:

  • 1 Hz HEARTBEAT (advertises MAV_TYPE_GIMBAL on MAV_COMP_ID_GIMBAL)
  • 5 Hz GIMBAL_MANAGER_STATUS, broadcast to every recorded peer
  • 4 Hz attitude poll → GIMBAL_DEVICE_ATTITUDE_STATUS broadcast. COMMS_ERROR flag is set for ~1 s after any failed poll.
  • 8 consecutive poll failures → automatic reconnect (scan + reopen, exponential backoff to 10 s).
  • SIGTERM / SIGINT start a 2 s grace shutdown; in-flight tasks are drained, then aborted; the IPC socket file is removed.
  • A critical task exiting unexpectedly (IPC, MAVLink, reconnect) tears the daemon down instead of leaving it half-running.

Use as a library

Two consumption modes:

  • Lean driver (default-features = false): just the Storm32RC driver and the GimbalDevice trait. Pulls 4 direct deps (serde / serialport / thiserror / tracing) and no tokio.

    [dependencies]
    turret = { version = "0.1", default-features = false }
    
    let mut g = turret::detect_gimbal("/dev/ttyACM0")?;
    g.set_attitude(10.0, 0.0, -15.0)?;
    # Ok::<_, turret::Error>(())
    
  • Embedded MAVLink manager: bring your own dyn GimbalDevice (different protocol, simulator, network-attached gimbal) and let Turret handle MAVLink discovery, primary-control arbitration, hot attitude broadcast, IPC, and bounded shutdown. The default features pull tokio + the daemon stack.

    See turret::daemon module-level docs for the full embedding example.

Develop

With a recent Rust installed:

# Clone and build
git clone https://github.com/luofang34/turret
cd turret
cargo build --release

Protocol

Uses STorM32 RC Commands protocol over serial (115200 baud).

Message format: [0xFA][len][cmd][payload][crc16]

Supports: version query, angle setting, status reading, pan modes.

Device Detection

Auto-detects STM32 Virtual COM Port (VID:0x0483, PID:0x5740). Falls back to common patterns: /dev/ttyACM*, /dev/ttyUSB*, COM*

Troubleshooting

  • No device found: Check USB connection and power
  • Permission denied: Add user to dialout group or use sudo
  • Communication errors: Verify 115200 baud rate and cable quality