A DIY satellite tracker built on an ESP32 and two SG90 servos. A Python script computes where a satellite is in the sky using SGP4 orbital propagation, and sends azimuth/elevation commands to the ESP32 over HTTP to keep a small pan-tilt rig pointed at it.
This is a hobby-scale visual tracker (point a camera, phone, or antenna at a pass) — not a precision satcom ground station. Built to learn SGP4 and embedded control, and shared in case it's useful or interesting to others doing the same.
- Firmware (ESP32): joins your WiFi network, exposes a small HTTP
API (
/set?axis=az|el&value=0-180), and moves the two servos accordingly. No tracking logic lives here — it just does what it's told. - Controller (Python): pulls a TLE for the target satellite, computes its live azimuth/elevation using Skyfield, maps that to servo angles, and sends commands to the ESP32.
Because SG90 servos only cover 180°, the mount can't physically reach the entire sky from a fixed base position. Passtrace handles this with a manual-flip routine: when the satellite moves into the unreachable half of the sky, it parks the elevation servo and asks you to manually rotate the base 180°, then resumes tracking on the other side. Full details in docs/how-it-works.md.
passtrace/
├── firmware/ ESP32 firmware (PlatformIO/Arduino)
├── controller/ Python tracking script (SGP4 + servo control)
├── hardware/ 3D-printed mount reference
└── docs/ Design notes and explanations
- ESP32 dev board
- 2x SG90 micro servos
- Pan-tilt mount — used an existing design instead of designing one from scratch: link to model
- Copy
firmware/config.h.exampletofirmware/config.hand fill in your WiFi credentials. - Flash
firmware/src/main.cppto the ESP32 (PlatformIO or Arduino IDE). - Once connected, the device is reachable at
http://passtrace.local(or check the serial monitor for its IP).
- Copy
controller/config.py.exampletocontroller/config.pyand fill in your location and a current TLE for your target satellite (get one from Celestrak). - Install dependencies:
pip install -r controller/requirements.txt - Run:
python controller/tracker.py
- No feedback on whether the manual base rotation actually happened — it's trust-based. A continuous-rotation base servo/stepper would remove the need for manual flips entirely.
- No persistent logging of passes.
- Single satellite at a time (one TLE hardcoded in config).
MIT — see LICENSE.