# 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 Four known Winegard dish variants documented by Gabe Emerson (KL1FI) / saveitforparts: | Detail | HAL 0.0.00 | HAL 2.05.003 | Trav'ler Pro | Carryout | |--------|-----------|-------------|-------------|---------| | **Repo** | Travler_Rotor | Trav-ler-Rotor-For-HAL-2.05 | Travler-Pro-Rotor | Carryout-Rotor | | **Connection** | RS-485 / RJ-25 | RS-485 / RJ-25 | USB A-to-A (`ttyACM0`) | RS-485 / RJ-25 | | **Motor submenu** | `mot` | `motor` | `odu` then `mot` | N/A (`target` + `g`) | | **Motor control** | `a ` | `a ` | `a ` | `g ` only | | **Search kill** | `os` -> `kill Search` | `ngsearch` -> `s` -> `q` | `os` -> `kill Search` | N/A | | **Boot signal** | `NoGPS` | `NoGPS` or `No LNB Voltage` | undocumented | N/A | | **Min elevation** | 15 deg (firmware) | 15 deg (firmware) | 12 deg (firmware) | ~22 deg (physical) | | **Max elevation** | 90 deg | 90 deg | 75 deg (hardware cap!) | NVS 102 override | | **Position query** | `a` -> `AZ = / EL =` | `a` -> `AZ = / EL =` | `a` -> `AZ = / EL =` | raw ints / 100 | | **Tested model** | LG-2112 | LG-2112 | SK2DISH | 2003 Carryout | | **HAL version** | 0.0.00 | 2.05.003 | unknown | 1.00.065 | ### Key Variant Differences - **Trav'ler Pro `odu` command:** The Pro's IDU has its own MCU. You must first tunnel to the ODU with `odu` before entering the motor submenu. The regular Trav'ler's IDU is a dumb RS-485 passthrough. - **Carryout uses `g` not `a`:** The Carryout has no individual motor addressing. It uses `target` to enter targeting mode, then `g ` for combined moves. It also can't query its initial position. - **Carryout has no limit switches:** Uses motor stalling to detect mechanical boundaries (audible grinding). - **Pro has the same leap-frog bug** as the regular Trav'ler (copy-pasted). - **Pro NVS submenu** has a `d` command to dump all NVS values (undocumented for other variants). ## Hardware Specs (SK-1000) | Spec | Value | |------|-------| | Weight | 45 lbs | | Stow dimensions | 10"H x 42"L x 26"W | | Stow height | 9.75" | | Max deployed height | 37" above mount | | Arm reach | 32.5" from base center | | Dish size | ~33" x 23" (Ku-band reflector) | | Azimuth range | 0-455 deg (before cable wrap) | | Power input | 120VAC -> 12VDC (RP-SK87 supply) | | LNB bias | 12-18VDC via coax | | Motor type | Likely stepper with gearing (unconfirmed) | | Satellites (DISH) | 110, 119, 129 (61.5 manual only) | | Satellites (Bell) | 82, 91 | ## 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 finish. Tolerant of rapid command streams from Gpredict. - `g ` — immediate move, aborts on any new keystroke/character. Some firmware has a typo listing the order as az/sk/el. - Skew motor can run simultaneously with AZ or EL (the others are mutually exclusive) - 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 - Console does not accept backspace — hit enter to clear on typo ### 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 odu — tunnel to outdoor unit (Trav'ler Pro only) 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 d — dump all values (Pro only, undocumented on others) e — read NVS value e — write NVS value s — save changes dvb — signal info submenu (Pro only) reboot — reboot firmware stow — fold dish flat (caution: modified feeds may not survive) ``` ### Known NVS Indices | Index | Setting | |-------|---------| | 102 | Max elevation | | 125 | Search minimum elevation | | 127 | Safe minimum elevation | ### Error Messages | Message | Meaning | |---------|---------| | `AZ MOTOR STALLED` | Obstruction preventing rotation | | `EL MOTOR STALLED` | Obstruction preventing elevation change | | `EL Motor Home Failure` | Requires EL recalibration via IDU menu | ### IDU/ODU Cable Wiring (if cut) Top row: Green, Yellow, Orange. Bottom row: Red, Brown, Black. ### Power 120VAC input to RP-SK87 power supply, outputs 12VDC to IDU. Internal coax carries 12-18VDC bias for LNB — do not connect 5V equipment (SDR LNAs, etc.) without bypassing the power injector. ### Physical Setup - Base marked with arrows and "BACK" at 0/360 deg (North) - Align "BACK" with true North for accurate tracking - Gpredict rotor config: 127.0.0.1:4533, 0->180->360 mode, min EL 15, max EL 90 - No obstructions taller than 8" within 32.5" of base center ### Calibration On power-up, the dish performs calibration movements to establish position and cable wrap limits (~10-15 minutes on Carryout, shorter on Trav'ler). After calibration, firmware automatically starts a TV satellite search — the init sequence kills this. EL recalibration (via IDU buttons): POWER -> ENTER (hold 2s) -> User Menu -> INSTALLATION -> Calibrate EL -> confirm hard stop position. ### Emergency Manual Stow Last resort only. 5/16" socket + 6" extension into auxiliary drive hole. Turn clockwise slowly. Ensure arm faces "rear" label before lowering. Improper execution can damage motor. ## 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`. Present in both Trav'ler and Trav'ler Pro repos. See `docs/bugs.md`. ## Upstream References - github.com/saveitforparts/Travler_Rotor (HAL 0.0.00) - github.com/saveitforparts/Trav-ler-Rotor-For-HAL-2.05 (HAL 2.05) - github.com/saveitforparts/Travler-Pro-Rotor (Pro, USB) - github.com/saveitforparts/Carryout-Rotor (Carryout, HAL 1.00.065) - Gabe Emerson / KL1FI — gabe@saveitforparts.com - YouTube: Trav'ler v1 demo (youtu.be/X1hnReHepFI), v2 demo (youtube.com/watch?v=URJZjo5EcpQ) ## Testing No hardware-in-the-loop tests yet. Protocol implementations can be mocked for unit testing — `FirmwareProtocol` is an ABC with clear method contracts.