edit readme
This commit is contained in:
parent
e7301db427
commit
9c38c10300
|
|
@ -1,136 +1,214 @@
|
||||||
# Firmware
|
# FireWatchTower — 2-Axis Gimbal Controller
|
||||||
|
|
||||||
Arduino sketch for the LattePanda's onboard ATmega32U4 (Leonardo). Controls two stepper motor axes via TMC5160 drivers, manages thermal regulation, and communicates with the host over the serial link.
|
Firmware for a 2-axis motorised gimbal (yaw + pitch) running on an Arduino-compatible AVR microcontroller. Built around the TMC5160 stepper driver chip, with encoder feedback, automatic homing, thermal management, and a serial command interface.
|
||||||
|
|
||||||
## PlatformIO Configuration
|
---
|
||||||
|
|
||||||
Target: `leonardo` (ATmega32U4) at 115200 baud.
|
## Hardware
|
||||||
|
|
||||||
```bash
|
| Component | Details |
|
||||||
pio run --environment megaatmega2560 --target upload
|
|---|---|
|
||||||
```
|
| MCU | ATmega32U4 (Arduino Leonardo-compatible) |
|
||||||
|
| Motor driver | TMC5160 × 2 (one per axis) |
|
||||||
|
| Communication | SPI @ 4 MHz, Mode 3 |
|
||||||
|
| Temperature sensor | DHT11 |
|
||||||
|
| Fan control | PWM output + tachometer input |
|
||||||
|
|
||||||
### Dependencies
|
### Pin assignments
|
||||||
|
|
||||||
| Library | Version | Purpose |
|
| Pin | Function |
|
||||||
|---------|---------|---------|
|
|---|---|
|
||||||
| adafruit/DHT sensor library | ^1.4.4 | DHT22 temperature/humidity readings |
|
| 8 | TMC5160 CS — Yaw |
|
||||||
| adafruit/Adafruit Unified Sensor | ^1.1.4 | Unified sensor abstraction |
|
| 7 | TMC5160 EN — Yaw |
|
||||||
| TMC5160 (bundled) | — | Stepper motor driver via SPI |
|
| 1 | TMC5160 CS — Pitch |
|
||||||
|
| 0 | TMC5160 EN — Pitch |
|
||||||
|
| 9 | DHT11 data |
|
||||||
|
| 10 | Fan PWM output |
|
||||||
|
| 11 | Fan tachometer input |
|
||||||
|
|
||||||
## Architecture
|
### Axis parameters
|
||||||
|
|
||||||
|
| Parameter | Yaw | Pitch |
|
||||||
|
|---|---|---|
|
||||||
|
| Steps per revolution | 177,000 | 500,000 |
|
||||||
|
| Gear ratio | 739.56 | 739.56 |
|
||||||
|
| Default speed (VMAX) | 50,000 | 250,000 |
|
||||||
|
| Global current scaler | 80 | 50 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project structure
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├── main.cpp # Entry point, main loop
|
├── main.cpp
|
||||||
├── config/
|
├── config/
|
||||||
│ ├── Constants.h # All tunable parameters
|
│ ├── Constants.h — tuning values, thresholds, timing
|
||||||
│ └── Pins.h # Pin assignments
|
│ └── Pins.h — pin assignments
|
||||||
├── motor/
|
├── motor/
|
||||||
│ ├── MotorConfig.h # Axis IDs, status enum
|
│ ├── MotorConfig.h — axis IDs, EEPROM layout, gimbal_status enum
|
||||||
│ ├── MotorDriver.* # TMC5160 initialization, power control
|
│ ├── MotorAxis.h/.cpp — per-axis state and TMC5160 register interface
|
||||||
│ ├── MotorAxis.* # Per-axis state, register reads, SGT/encoder handling
|
│ ├── MotorDriver.h/.cpp— SPI init, register config, enable/disable
|
||||||
│ └── Homing.* # Endstop homing routine
|
│ └── Homing.h/.cpp — homing state machines (non-blocking)
|
||||||
├── serial/
|
├── serial/
|
||||||
│ └── CommandParser.* # Serial command dispatch
|
│ └── CommandParser.h/.cpp — serial command protocol
|
||||||
└── thermal/
|
├── thermal/
|
||||||
└── ThermalManager.* # DHT sensor + PWM fan control
|
│ └── ThermalManager.h/.cpp — DHT11 reading and fan PWM control
|
||||||
|
└── hal/
|
||||||
|
└── SPI_HAL.cpp — TMC-API SPI callbacks (chip select per axis)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Pinout
|
---
|
||||||
|
|
||||||
| Pin | Function |
|
## Building
|
||||||
|-----|----------|
|
|
||||||
| 0 | TMC5160 ENABLE (Pitch) |
|
|
||||||
| 1 | TMC5160 CS (Pitch) |
|
|
||||||
| 7 | TMC5160 ENABLE (Yaw) |
|
|
||||||
| 8 | TMC5160 CS (Yaw) |
|
|
||||||
| 9 | DHT22 DATA |
|
|
||||||
| 10 | Fan PWM |
|
|
||||||
| 11 | Fan sense |
|
|
||||||
|
|
||||||
## Motor Configuration
|
This project uses [PlatformIO](https://platformio.org/).
|
||||||
|
|
||||||
Both axes use TMC5160 stepper drivers with closed-loop control.
|
**Build:**
|
||||||
|
```bash
|
||||||
| Parameter | Yaw | Pitch |
|
pio run
|
||||||
|-----------|-----|-------|
|
|
||||||
| Steps/round | 177,000 | 500,000 |
|
|
||||||
| Gear ratio | 739.556 | 739.556 |
|
|
||||||
| Global scaler | 80 | 50 |
|
|
||||||
| Default Vmax | 50,000 | 250,000 |
|
|
||||||
| Endstop speed | 25,000 | 150,000 |
|
|
||||||
|
|
||||||
Key constants in [config/Constants.h](src/config/Constants.h):
|
|
||||||
- `ENC_DEVIATION_LIMIT` — Maximum allowed encoder-position deviation (1500 steps)
|
|
||||||
- `ACCELERATION` — Default acceleration profile (20,000)
|
|
||||||
|
|
||||||
### Gimbal Status States
|
|
||||||
|
|
||||||
```c
|
|
||||||
typedef enum {
|
|
||||||
GIMBAL_STATUS_ERROR = -2,
|
|
||||||
GIMBAL_STATUS_BOOT = -1,
|
|
||||||
GIMBAL_STATUS_RESET = 0,
|
|
||||||
GIMBAL_STATUS_ENC_INIT = 1,
|
|
||||||
GIMBAL_STATUS_INITIALIZED= 2,
|
|
||||||
GIMBAL_STATUS_AUTO = 3,
|
|
||||||
GIMBAL_STATUS_MANUAL = 4
|
|
||||||
} gimbal_status;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Serial Protocol
|
**Build and upload:**
|
||||||
|
```bash
|
||||||
Commands are received character-by-character. A leading command character is followed by optional comma-separated numeric arguments (hex by default; append `d` for decimal).
|
pio run --target upload
|
||||||
|
|
||||||
### Command Reference
|
|
||||||
|
|
||||||
| Command | Args | Description |
|
|
||||||
|---------|------|-------------|
|
|
||||||
| `r` | — | Reset motor params, power on both axes |
|
|
||||||
| `q` | — | Run endstop homing on yaw then pitch |
|
|
||||||
| `!` | — | Power off both motors |
|
|
||||||
| `*` | — | Power on both motors |
|
|
||||||
| `m` | pos, speed | Move yaw to position with given speed |
|
|
||||||
| `s` | — | Stop both motors |
|
|
||||||
| `b` | — | Reset encoder deviation warning flags |
|
|
||||||
| `t` | — | Set Xenc to Xact (sync encoder to actual position) |
|
|
||||||
| `e` | — | Reset SGT (step goal threshold) on both axes |
|
|
||||||
| `w` | value | Set SGT value |
|
|
||||||
| `u` | step_len | Set auto-scan step length (must be > 2) |
|
|
||||||
| `h` | axis, hdg | Set heading calibration, save to EEPROM |
|
|
||||||
| `y` | axis | Load heading calibration from EEPROM |
|
|
||||||
| `d` | — | Set yaw to manual mode |
|
|
||||||
| `p` | — | Step yaw to next position (used for scan trigger) |
|
|
||||||
| `v` | speed | Set yaw Vmax |
|
|
||||||
| `+` | — | Record right encoder position |
|
|
||||||
| `-` | — | Record left encoder position |
|
|
||||||
| `/` | right, left | Set right and left encoder positions |
|
|
||||||
| `?` | — | Print encoder range info |
|
|
||||||
| `;` | value | Write raw value to Yaw register 0x21 |
|
|
||||||
|
|
||||||
### Telemetry Output
|
|
||||||
|
|
||||||
Every `INFO_PRINT_INTERVAL_MS` (250 ms), both axes print status lines prefixed with `$`:
|
|
||||||
```
|
|
||||||
$Xenc;Xerr;sgt_val;sgt_stat;is_moving;control_status;hdg;deviation_warn;humid;temp;fan_pwm
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Thermal Management
|
**Clean:**
|
||||||
|
```bash
|
||||||
|
pio run --target clean
|
||||||
|
```
|
||||||
|
|
||||||
DHT22 sensor on pin 9 drives a PWM fan on pin 10.
|
**Serial monitor:**
|
||||||
|
```bash
|
||||||
|
pio device monitor --baud 115200
|
||||||
|
```
|
||||||
|
|
||||||
| Parameter | Value | Description |
|
---
|
||||||
|-----------|-------|-------------|
|
|
||||||
| `THERMAL_FAN_ON_TEMP` | 25°C | Fan activation threshold |
|
|
||||||
| `THERMAL_FAN_GAIN` | 20 | PWM gain per degree above threshold |
|
|
||||||
| `THERMAL_FAN_MAX_PWM` | 255 | Maximum PWM duty cycle |
|
|
||||||
| `THERMAL_LOOP_INTERVAL` | 250 ms | Sensor read interval |
|
|
||||||
|
|
||||||
Fan PWM = `min(255, (temp - 25) * 20)`
|
## Axis lifecycle
|
||||||
|
|
||||||
## EEPROM Storage
|
Each axis progresses through the following states after power-on:
|
||||||
|
|
||||||
Heading calibration data is stored at EEPROM address 0:
|
```
|
||||||
- Offset 0: `float` — current heading (`c_hdg`)
|
BOOT → RESET → ENC_INIT → INITIALIZED → AUTO / MANUAL
|
||||||
- Offset 4: `int32_t` — encoder distance offset from heading reference
|
↓
|
||||||
|
ERROR (homing failed)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **BOOT** — initial state, hardware not yet configured
|
||||||
|
- **RESET** — registers written, motor enabled, ready to home
|
||||||
|
- **ENC_INIT** — homing sequence in progress
|
||||||
|
- **INITIALIZED** — endstop limits known, axis ready for operation
|
||||||
|
- **AUTO** — stepping through positions automatically
|
||||||
|
- **MANUAL** — responding to direct move commands
|
||||||
|
- **ERROR** — homing failed; send `r` to reset and try again
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Homing
|
||||||
|
|
||||||
|
Each axis must be homed before normal operation. Send `q` over serial to start.
|
||||||
|
|
||||||
|
**Yaw** uses stallGuard (encoder deviation detection) as a virtual endstop — the motor drives into a mechanical stop, the TMC5160 detects the current spike, and the position is recorded. No physical switches required.
|
||||||
|
|
||||||
|
**Pitch** uses physical hardware endstop switches. The TMC5160 latches the position (XLATCH) the instant a switch triggers, giving an accurate limit reading.
|
||||||
|
|
||||||
|
Once both limits are found, the axis validates the measured travel range and moves to the centre position.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Serial command protocol
|
||||||
|
|
||||||
|
Connect at **115200 baud**. Commands are single characters sent over the serial port.
|
||||||
|
|
||||||
|
**Format:** `<cmd>[y|p][d]<arg1>,<arg2>`
|
||||||
|
|
||||||
|
- Axis specifier (optional): `y` = yaw only, `p` = pitch only, omit = both
|
||||||
|
- Base specifier (optional): `d` after axis = decimal arguments (default is hex)
|
||||||
|
|
||||||
|
### Command reference
|
||||||
|
|
||||||
|
| Command | Description | Arguments |
|
||||||
|
|---|---|---|
|
||||||
|
| `r` | Reset: re-init registers and enable coils | — |
|
||||||
|
| `q` | Start homing sequence | — |
|
||||||
|
| `!` | Disable motor coils (free-wheel) | — |
|
||||||
|
| `*` | Enable motor coils (holding torque) | — |
|
||||||
|
| `m` | Move to absolute position | `<position>, <speed>` |
|
||||||
|
| `;` | Overwrite XACTUAL register directly | `<value>` |
|
||||||
|
| `s` | Stop (decelerate to zero) | — |
|
||||||
|
| `b` | Clear encoder deviation warning flag | — |
|
||||||
|
| `t` | Sync encoder to actual position | — |
|
||||||
|
| `e` | Clear stallGuard event flag (both axes) | — |
|
||||||
|
| `w` | Set stallGuard threshold | `<sgt>` |
|
||||||
|
| `u` | Enter AUTO stepping mode | `<num_steps>` (must be > 2) |
|
||||||
|
| `h` | Save heading calibration to EEPROM | `0, <heading_value>` |
|
||||||
|
| `y` | Load heading calibration from EEPROM | `0` |
|
||||||
|
| `d` | Enter MANUAL mode | — |
|
||||||
|
| `p` | Advance yaw one step (AUTO mode) | — |
|
||||||
|
| `v` | Set yaw speed | `<vmax>` |
|
||||||
|
| `+` | Set yaw right limit to current position | — |
|
||||||
|
| `-` | Set yaw left limit to current position | — |
|
||||||
|
| `/` | Set both yaw limits manually | `<right>, <left>` |
|
||||||
|
| `?` | Print current yaw endstop positions | — |
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
q — home both axes
|
||||||
|
qy — home yaw only
|
||||||
|
md 500000,35000 — move both axes to position 500000 at speed 35000 (decimal)
|
||||||
|
my 1F400,8888 — move yaw to 0x1F400 at speed 0x8888 (hex, default)
|
||||||
|
!p — disable pitch motor
|
||||||
|
w 60 — set stallGuard threshold to 60 on both axes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Serial status output
|
||||||
|
|
||||||
|
Every 250 ms the firmware prints a status line for each axis:
|
||||||
|
|
||||||
|
**Yaw:**
|
||||||
|
```
|
||||||
|
YAW: <X_enc>, <X_act>, <X_err>, <dev_warn>, <sg_event>, <sg_status>, <sg_stop>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pitch:**
|
||||||
|
```
|
||||||
|
PITCH: <X_enc>, <X_act>, <X_err>, <dev_warn>, <sg_event>, <sg_status>, <sg_stop>, <endstop_l>, <endstop_r>
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `X_enc` | Encoder position (external encoder) |
|
||||||
|
| `X_act` | Step counter position (internal) |
|
||||||
|
| `X_err` | Tracking error (X_act − X_enc) |
|
||||||
|
| `dev_warn` | Encoder deviation warning flag |
|
||||||
|
| `sg_event` | StallGuard event flag |
|
||||||
|
| `sg_status` | StallGuard status bit |
|
||||||
|
| `sg_stop` | StallGuard stop flag |
|
||||||
|
| `endstop_l` | Left endstop state (pitch only) |
|
||||||
|
| `endstop_r` | Right endstop state (pitch only) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Thermal management
|
||||||
|
|
||||||
|
The DHT11 sensor is read every 250 ms. The fan PWM output is controlled proportionally:
|
||||||
|
|
||||||
|
- Below 25 °C: fan off
|
||||||
|
- Above 25 °C: PWM = (temperature − 25) × 20, capped at 255
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
Managed automatically by PlatformIO:
|
||||||
|
|
||||||
|
- `TMC-API` — Trinamic vendor library for TMC5160 register access
|
||||||
|
- `DHT sensor library` — Adafruit DHT11/22 driver
|
||||||
|
- `Adafruit Unified Sensor`
|
||||||
|
- `SPI` — Arduino built-in
|
||||||
|
- `EEPROM` — Arduino built-in
|
||||||
Reference in New Issue