Made-with: Cursor
3.9 KiB
GimbalDriver
1. High-Level Overview
Purpose: Implements the ViewLink serial protocol for controlling the ViewPro A40 gimbal. Sends pan/tilt/zoom commands via UART, reads gimbal feedback (current angles), provides PID-based path following, and handles communication integrity.
Architectural Pattern: Hardware adapter with command queue and PID controller.
Upstream dependencies: Config helper (UART port, baud rate, PID gains, mock mode), Types helper
Downstream consumers: ScanController
2. Internal Interfaces
Interface: GimbalDriver
| Method | Input | Output | Async | Error Types |
|---|---|---|---|---|
connect(port, baud) |
str, int | bool | No | UARTError |
disconnect() |
— | — | No | — |
is_alive() |
— | bool | No | — |
set_angles(pan, tilt, zoom) |
float, float, float | bool | No | GimbalCommandError |
get_state() |
— | GimbalState | No | GimbalReadError |
set_sweep_target(pan) |
float | bool | No | GimbalCommandError |
zoom_to_poi(pan, tilt, zoom) |
float, float, float | bool | No (blocks ~2s for zoom) | GimbalCommandError, TimeoutError |
follow_path(direction, pid_error) |
(dx,dy), float | bool | No | GimbalCommandError |
return_to_sweep() |
— | bool | No | GimbalCommandError |
GimbalState:
pan: float — current pan angle (degrees)
tilt: float — current tilt angle (degrees)
zoom: float — current zoom level (1-40)
last_heartbeat: float — epoch timestamp of last valid response
5. Implementation Details
ViewLink Protocol:
- Baud rate: 115200, 8N1
- Command format: per ViewLink Serial Protocol V3.3.3 spec
- Implementation note: read full spec during implementation to determine if native checksums exist. If yes, use them. If not, add CRC-16 wrapper.
- Retry: up to 3 times on checksum failure with 10ms delay
PID Controller (for path following):
- Dual-axis PID (pan, tilt independently)
- Input: error = (path_center - frame_center) in pixels
- Output: pan/tilt angular velocity commands
- Gains: configurable via YAML, tuned per-camera
- Anti-windup: integral clamping
- Update rate: 10 Hz (100ms interval)
Mock Mode (development):
- TCP socket client instead of UART
- Connects to mock-gimbal service (Docker)
- Same interface, simulated delays for zoom transition (1-2s)
Key Dependencies:
| Library | Version | Purpose |
|---|---|---|
| pyserial | — | UART communication |
| crcmod | — | CRC-16 if needed (determined after reading ViewLink spec) |
| struct (stdlib) | — | Binary packet packing/unpacking |
Error Handling Strategy:
- UART open failure → GimbalDriver.connect() returns false → gimbal_available=false
- Command send failure → retry 3x → GimbalCommandError
- No heartbeat for 4s → is_alive() returns false → ScanController sets gimbal_available=false
7. Caveats & Edge Cases
Known limitations:
- Zoom transition takes 1-2s physical time (40x optical)
- PID gains need tuning on real hardware (bench testing)
- Gimbal has physical pan/tilt limits — commands beyond limits are clamped
Physical EMI mitigation (not software — documented here for reference):
- Shielded UART cable, shortest run
- Antenna ≥35cm from gimbal
- Ferrite beads on cable near Jetson
8. Dependency Graph
Must be implemented after: Config helper, Types helper Can be implemented in parallel with: Tier1Detector, Tier2SpatialAnalyzer, VLMClient, OutputManager Blocks: ScanController (needs GimbalDriver for scan control)
9. Logging Strategy
| Log Level | When | Example |
|---|---|---|
| ERROR | UART open failed, 3x retry exhausted | UART /dev/ttyTHS1 open failed: Permission denied |
| WARN | Checksum failure (retrying), slow response | Gimbal CRC failure, retry 2/3 |
| INFO | Connected, zoom complete, mode change | Gimbal connected at /dev/ttyTHS1 115200. Zoom to 20x complete (1.4s) |