# Winegard Trav'ler Control a Winegard Trav'ler motorized satellite dish via RS-485 for amateur radio satellite tracking. ## Project - **Package:** `travler-rotor` (installed via `uv sync`) - **CLI entry point:** `travler-rotor` (init / serve / pos / move) - **Source layout:** `src/travler_rotor/` (src-layout) - **Original upstream:** `Trav-ler-Rotor-For-HAL-2.05/` — Gabe Emerson's scripts, kept as reference (do not modify) ## Build & Lint ```bash uv sync # Install deps + package uv run ruff check src/ # Lint uv run ruff format --check src/ # Format check uv run travler-rotor --help # CLI smoke test ``` ## Architecture ``` protocol.py — FirmwareProtocol ABC + HAL205Protocol / HAL000Protocol Serial I/O owned here. Each firmware version is a subclass. leapfrog.py — Pure function: apply_leapfrog(target, current) -> adjusted Predictive overshoot to compensate for mechanical motor lag. antenna.py — TravlerAntenna: high-level control wrapping protocol + leapfrog This is what consumers (CLI, rotctld, future MCP server) call. rotctld.py — RotctldServer: Hamlib rotctld TCP protocol (p/P/S/_/q) Bridges Gpredict to the antenna. cli.py — Click CLI with init/serve/pos/move subcommands ``` ## Firmware Variants Three known Winegard dish variants exist (Gabe Emerson / saveitforparts): | Detail | HAL 0.0.00 | HAL 2.05.003 | Trav'ler Pro | |--------|-----------|-------------|-------------| | **Repo** | saveitforparts/Travler_Rotor | saveitforparts/Trav-ler-Rotor-For-HAL-2.05 | saveitforparts/Travler-Pro-Rotor | | **Connection** | RS-485 / RJ-25 | RS-485 / RJ-25 | USB A-to-A | | **Motor submenu** | `mot` | `motor` | `mot` | | **Search kill** | `os` -> `kill Search` -> `q` | `ngsearch` -> `s` -> `q` | `os` -> `kill Search` | | **Boot signal** | `NoGPS` | `NoGPS` or `No LNB Voltage` | undocumented | | **Max elevation** | 90 deg | 90 deg | 75 deg (hardware limit) | | **Tested model** | LG-2112 | LG-2112 | SK2DISH | Related: saveitforparts/Carryout-Rotor (Winegard Carryout, HAL 1.00.065, very similar commands). ## Hardware Protocol Notes - RS-485 serial, 57600 baud, 8N1 (via USB-to-RS232 + DTECH RS232-to-RS485 + RJ-25) - Motor commands: `a ` (0=azimuth, 1=elevation) - Position query: `a` (in motor submenu) returns `AZ = EL = SK = ` - Two motor control methods: - `a ` — queues command, waits for current motor to stop before next - `g ` — immediate move, aborts on any new keystroke - Elevation floor: HAL 2.05 unreliable below 15 degrees with direct motor commands - Cable wrap limit: usually 360 or 455 degrees, dish reverses at limit ### RS-485 Pinout (RJ-25, bottom view, tip up) | Pin | Function | |-----|----------| | 1 | GND | | 2 | T/R- | | 3 | T/R+ | | 4 | RXD- | | 5 | RXD+ | | 6 | Not used | ### Firmware Console Commands ``` ? — list available commands motor / mot — enter motor submenu (firmware-dependent) a — show position (in motor submenu) a — move motor to absolute position g — go to AZ/EL (aborts on new input) q — exit current submenu os — enter OS submenu tasks — list running tasks kill — kill a named task (e.g. "kill Search") ngsearch — enter search submenu (HAL 2.05 only) s — stop search nvs — enter non-volatile storage submenu e — read NVS value e — write NVS value s — save changes reboot — reboot firmware ``` ### Known NVS Indices | Index | Setting | |-------|---------| | 102 | Max elevation | | 125 | Search minimum elevation | | 127 | Safe minimum elevation | ### IDU/ODU Cable Wiring (if cut) Top row: Green, Yellow, Orange. Bottom row: Red, Brown, Black. ### Power 48-52VDC power supply for the IDU. The internal coax supplies 14-18VDC bias — do not connect 5V equipment without bypassing the power injector. ## Known Bugs (from upstream) - Leap-frog elevation bug: original `travler_rotor.py` lines 98-105 modify `target_az` instead of `target_el`. Fixed in `leapfrog.py`. See `docs/bugs.md`. ## Testing No hardware-in-the-loop tests yet. Protocol implementations can be mocked for unit testing — `FirmwareProtocol` is an ABC with clear method contracts.