February 18, 2026
Description
NOTE: THIS IS FOR TOUCH VERSION ONLY ON THE T-DISPLAY S3; I am working on the non-touch version of the model which will come in a future update.
there is now a GPS Version which I’ve uploaded as a remix, otherwise it’s all the same!
Quick Start
This section covers the minimum steps required to get SatTrack powered on, configured, and tracking satellites.
Install Arduino IDE
Install all required libraries (see Notes on Code)
Update the TFT_eSPI library configuration:
Edit User_Setup_Select.h
Set:
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>
(Optional) Add your Wi-Fi credentials in the main code:
const char* WIFI_SSID = "YourSSID";
const char* WIFI_PASS = "YourPassword";
Select the correct board and port, then upload the sketch
Insert a charged LiPo battery
Slide the power switch ON
On first boot, SatTrack will:
Attempt to connect to Wi-Fi
If unsuccessful, create its own Wi-Fi access point
If SatTrack cannot connect to Wi-Fi automatically:
On your phone, connect to the Wi-Fi network:
SatTrack-Setup
Open your browser and navigate to the address shown on the screen
Enter:
Your home Wi-Fi SSID and password
Save settings and reboot if prompted
Once connected to Wi-Fi:
SatTrack will automatically download satellite TLE data
During this process the message
“TLE Sync in progress, please wait”
will be displayed
⏱ Sync time: 10–30 seconds
⚠ The device cannot be used while syncing.
Use the 2D Map view to quickly cycle through satellites
Look for a pass with a good elevation angle
Switch to:
3D Map for orbit visualisation
Next Passes to compare upcoming passes
Mount SatTrack to your antenna using a zip tie
Switch to POV Live View
Move and aim the antenna while watching the on-screen indicator
Keep the satellite centred during the pass for best reception
Once TLE data is synced, SatTrack works fully offline
For best accuracy:
Reconnect to Wi-Fi periodically
TLE data refreshes automatically every 6 hours when connected
Quick Tips
2D view = fastest navigation
3D view = slower but shows pass details
POV view = best for real-time antenna aiming
If tracking seems “off”, check IMU orientation settings in the code
For those interested in tracking weather satellites, there is an excellent 3D-printed Helicone antenna available that can be used to capture live weather satellite imagery. The dish design can be found here:
https://www.thingiverse.com/thing:6436342
While using a satellite-tracking app on my phone, I had the idea to create a stand-alone ESP32-based satellite tracker that provides both satellite information and a POV (point-of-view) aiming display, allowing you to manually aim the antenna during a satellite pass.
The result is SatTrack — a compact handheld device that can be mounted directly to an antenna and used to visually track satellites in real time. It can also be used independently for general satellite tracking, such as monitoring ISS passes when conditions are right.
The included mount allows the tracker to be attached directly to the antenna and secured using a simple cable/zip tie, keeping everything lightweight and portable.
Link to Onshape CAD file: https://cad.onshape.com/documents/5aeab5f9aba89eb3795178b6/w/ab21e545d350b869fc64b96b/e/3834b45ca03d3da6a54aef2d?renderMode=0&uiState=69792c885fdeb78672680232
SatTrack supports up to 20 configurable satellites, which can be managed via a built-in web portal once the device is connected to Wi-Fi. You can also set or update your geographic location through the portal.
The device offers four different display modes to suit different tracking needs:
2D Map
A fast, simple view showing the selected satellite’s orbit path, including the previous and next orbit (+1 / −1).
3D Map + Next Pass Info
A 3D visualisation of the satellite’s path around Earth, including calculated next-pass information.
Next Passes
Displays the next three upcoming passes, including:
Pass time
Maximum elevation above the horizon
This is particularly useful for deciding whether to wait for a better pass when planning to capture data.
POV (Live Aim View)
A real-time point-of-view display that allows you to “look around” and see exactly where the satellite is in the sky, making it easy to hand-aim an antenna during a pass.
The 4 Green Dots on this view represent the status of Calibration, from left to right
Overall System Calibration - confidence high
Accelerometer
Gyro
Magnetometer - this one is highly sensitive and will ensure you correct Azimuth readings, outside this will calibrate well.
Once satellite data has been synced, SatTrack will continue to work fully offline.
However, if the device is left offline permanently, the TLE data (used to calculate satellite positions) will gradually become less accurate over time.
When connected to Wi-Fi:
TLE data syncs on boot
Automatically refreshes every 6 hours while powered on
Note:
When the device displays “TLE Sync in progress, please wait”, it is temporarily unavailable. During this time, the data is being downloaded and cached.
This process typically takes 10–30 seconds.
1x LILYGO T-DISPLAY S3 1.9inch LCD or T-DISPLAY S3 Touch.
Note: I found LILYGO website had best prices rather than AliExpress - Amazon was expensive overall (~£10 on lilygo site, ~£20-30 on Amazon/AliExpress)
https://lilygo.cc/products/t-display-s3?variant=42589373268149
1x GY-BNO055 9axis IMU unit
Can also be found on Amazon (AliExpress £5-10 - Amazon £20+)
1x Slider Switch SS-12F15 with 4mm switch height
Can also be found on Amazon
1x 850Mha LiPo 3.7V 102535- Critical dimension 25mm wide / rounded style
can be found on Amazon (£5-£15)
Connector doesn't matter - T-Display S3 comes with battery connector and ill be soldered via the switch
Assorted 22AWG solid core wire (or wire of your preference)
Assorted shrink wrap (or tape if you so choose)
Matte PLA filament (Normal should work just fine)
Zip Tie for mounting to Antenna
NOTE: if you do not wish to use a LiPo battery, you can power via USB C connector
Notes on BoM:
Though this project does not use the touch function, I designed (and prefer) to use the touch variant of the T-Display S3 Module mainly I designed the case from scratch to fit this module, and it has effectively a protective cover on the screen for added durability
Any GY-BNO055 IMU unit will work, the case is designed to fit the cheapest version with no mounting holes
case designed to take 102535 battery but could accommodate up to 40mm or more in length
Total BoM cost can be as low as £30(~$35 not accounting for tariffs) when shopping via AliExpress for components other than the ESP module
Tools Required:
3D printer
Soldering Iron - precision tip and a flat tip
Needle files & sand Paper
Hot glue gun
something to strip the wires
Computer with Arduino IDE (ESP32 boards need to be installed and libraries need to be installed)
[ESP32] GPIO44 to [IMU] SCL/RX
[ESP32] GPIO43 to [IMU] SDA/TX
[ESP32] Ground(G) to [IMU] GND
[ESP32] 3V to [IMU] VIN
remaining pins unconnected
IMPORTANT NOTE: Jump pads on the IMU need to be shorted, top 2 and bottom 2 need to be connected, please check your IMU, some arrive jumped, some don't, this is ESSENTIAL to the communication between the IMU and ESP32. (See Circled in RED)
Ensure all required libarries are installed via the Arduino IDE Library Manager - some will need to be downloaded from github etc.
You must modify the TFT_eSPI library to select the correct board configuration:
In User_Setup_Select.h, update line 27 to:
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>You may hard-code your Wi-Fi credentials for automatic connection on first boot:
const char* WIFI_SSID = "IOTNetwork";
const char* WIFI_PASS = "";If left blank, Wi-Fi can be configured later via the device’s setup portal.
Different BNO055 modules can report different axis orientations, even when they appear identical.
If your orientation is incorrect, you can adjust the following values in the code:
static constexpr float BODY_FWD_X = 0.0f;
static constexpr float BODY_FWD_Y = -1.0f;
static constexpr float BODY_FWD_Z = 0.0f;
static constexpr float DECLINATION_DEG = 0.0f;
static constexpr float WORLD_YAW_OFFSET_DEG = -90.0f;
static constexpr int WORLD_SIGN_X = -1;
static constexpr int WORLD_SIGN_Y = +1;
static constexpr int WORLD_SIGN_Z = +1;
// =========================================================
// POV CAMERA AXIS REMAP (BODY -> CAMERA)
// Camera convention used by projectToScreen():
// +X = screen right
// +Y = screen up
// +Z = into screen (depth / forward)
//
// These map which IMU BODY axis becomes camera X/Y/Z.
// axis: 0=X, 1=Y, 2=Z sign: +1 or -1
// =========================================================
static constexpr int CAM_X_AXIS = 0; // try BODY Y -> screen X
static constexpr int CAM_X_SIGN = -1;
static constexpr int CAM_Y_AXIS = 2; // try BODY Z -> screen Y (up)
static constexpr int CAM_Y_SIGN = +1;
static constexpr int CAM_Z_AXIS = 1; // try BODY X -> camera Z (forward/depth)
static constexpr int CAM_Z_SIGN = -1;Unfortunately the behaviour of these can be unintuitive for what they change. the WORLD_YAW_OFFSET is key, i've had some be off by 90 degrees. WORLD_SIGN will mirror behaviour of axis. while CAM_?_AXIS will effect how it's Projected in the Aim View. those two are the next most important. I shall endeavour to create a more robust routine that can be done on the device in future.
No screws or fasteners are used in this design.
The slider switch is secured by melting and flattening the mounting pins using a wide, flat soldering tip at ~120 °C.
The battery slides into place with slight case flex and is held by friction. If loose, add a layer of tape for a snug fit.
The ESP32 module is designed to snap into place. Some light filing may be required depending on print tolerances.
Feedback on this assembly method is very welcome.
Battery will slot in with a slight flex of the back case and should be held firmly just by friction. if yours is a little use, use some tape on the battery until required fit is achieved.
The ESP32 Modules will snap into place, this may require some pressure on the case or some filing of the small protrusions to allow it to click into place, it is designed to be push-fit.
Basic Operation:
Buttons:
Holding the bottom button opens the Info Page, which displays:
Device IP address
Access to satellite and location configuration via IP address
If you have not preloaded wifi SSID and Password into the code, then the SatTrack will create it's own WiFi Access point which you can connect via your phone and input the SSID and Password that way, or if you're out in the field, this is a handy way to update you list on the go, when it fails to connect to wifi, the AP will be active, by default it is not password protected, if you wish to password protect you can change WIFI_PORTAL_USE_PASS to True and add your password in the code.
// Portal AP details
static const char* WIFI_PORTAL_AP_PREFIX = "SatTrack-Setup";
static const char* WIFI_PORTAL_AP_PASS = "SatTrack"; // >=8 chars
static const bool WIFI_PORTAL_USE_PASS = false;
The WiFi Setup can take some time to pop up once connected, please be patient!
The 2D page is the quickest page to switch through satellite to find which one you would like to track, it shows +1 and -1 Orbits. the 3D page will also calculate the next pass info, this take some extra time so is slower to cycle through. the next passes can be used to judge if you have a better pass coming up and it's worth waiting if you're planning to capture data from Satellites.
Use this section if SatTrack does not boot, connect, track correctly, or behaves unexpectedly.
Battery is charged
Battery polarity is correct
Power switch is wired correctly and in the ON position
Battery connector solder joints are solid
No shorts or bridged pads on the ESP32
Tip:
Try powering the device via USB to rule out battery or switch wiring issues.
Correct board selected in Arduino IDE
TFT_eSPI is configured for:
Setup206_LilyGo_T_Display_S3
Firmware uploaded successfully with no compile errors
USB cable supports data, not charge-only
Screen protective layer removed (if applicable)
Buttons are not physically obstructed by the case
Case tolerances allow buttons to fully depress
Reboot and test the board outside the case if necessary
SSID and password are correct (case-sensitive)
Network is 2.4 GHz (ESP32 does not support 5 GHz)
Power cycle the device and retry
Connect to the SatTrack-Setup access point if auto-connect fails
If the access point is password protected, ensure it is at least 8 characters
Tip:
A phone hotspot can be used as a temporary network for setup or syncing.
Wait at least 30 seconds
Ensure a stable Wi-Fi connection
Power cycle and retry
Confirm the network allows outbound HTTP traffic
Attempt syncing on a different Wi-Fi network
This is typically related to IMU orientation.
Ensure the device is stationary during startup
Restart and allow the IMU to stabilise
Adjust the following parameters in code if needed:
WORLD_YAW_OFFSET_DEG
WORLD_SIGN_X, WORLD_SIGN_Y, WORLD_SIGN_Z
CAM_* axis mappings
Most common cause:
Yaw offset incorrect by approximately ±90 degrees.
Invert the appropriate WORLD_SIGN_* values
Adjust CAM_X_AXIS, CAM_Y_AXIS, or CAM_Z_AXIS
Rotate the device physically to identify which axis is incorrect
Recommendation:
Change one parameter at a time and test.
TLE data is outdated
Reconnect to Wi-Fi and allow a fresh sync
Verify IMU wiring:
GPIO44 to SCL
GPIO43 to SDA
IMU is powered from 3.3 V, not 5 V
IMU jump pads are shorted (top pair and bottom pair)
Test with another BNO055 module if available
Important:
Missing jumper connections will prevent communication entirely.
Battery voltage is too low
Loose battery or switch wiring
Excessive current draw during Wi-Fi activity
Intermittent power due to cold solder joints
POV mode performs more calculations than 2D view
Reduce satellite switching frequency
Ensure the IMU is firmly mounted and not flexing within the case
Still Having Issues?
If problems persist:
Test the device outside the enclosure
Power the device via USB only
Disable Wi-Fi temporarily to isolate the issue
Swap the IMU module if possible
some have asked to donate who have followed the development, so if you'd like to genuinely buy me some coffee and/or support the development of future projects, this is where the money will go! https://buymeacoffee.com/mulymule
License:
Creative Commons — Attribution