For this project I have updated and modified the code by Anthony Sturdy for ESP32 based flight tracker. Thanks to Anthony Sturdy for this open-source project. His github repository here.
I've modified the source code to directly upload to the ESP32 CYD module and also you don't need any soldering for this project.
Core Hardware Specs of the module:
· Microcontroller: ESP32-WROOM-32 (Dual-core 240 MHz, 520 KB SRAM, 4 MB Flash).
· Connectivity: Built-in Wi-Fi and Bluetooth.
· Display: 2.8-inch resistive touchscreen with 320 × 240 px resolution (ILI9341 display driver, XPT2046 touch controller).
· Expansion: MicroSD card slot for external storage, plus a few breakout headers for sensors (e.g., DHT11) and extra GPIO pins.
· Power: 5V operating voltage via micro-USB or type-C
· Connectivity: Built-in Wi-Fi and Bluetooth.
· Display: 2.8-inch resistive touchscreen with 320 × 240 px resolution (ILI9341 display driver, XPT2046 touch controller).
· Expansion: MicroSD card slot for external storage, plus a few breakout headers for sensors (e.g., DHT11) and extra GPIO pins.
· Power: 5V operating voltage via micro-USB or type-C
Buying link AliExpress link 1 AliExpress link 2
Note: There are many clones of this board, you may buy the same model "ESP32-2432S028R" as I've used here to avoid setup error.
Source file:
Checkout my drive link here
Note: Two micro-radar-CYD files are given, v2 has some bugs fixed and rotating plane icon.
Setup guideline:
I have made a pdf guideline step by step so you do not have to go through troubles.
Checkout the guideline pdf drive link here
Troubleshooting: Screen orientation fix for some CYD boards
If your screen appears flipped or mirrored, open include/LGFX.h and find these three lines in the panel config block
Change their value to :
cfg.panel_width = 320;
cfg.panel_height = 240;
cfg.offset_rotation = 7;
And reupload .
cfg.panel_height = 240;
cfg.offset_rotation = 7;
And reupload .
If you face any other error please feel free to send email with a subject "Micro Radar CYD" to abid.business01@gmail.com
Visit my YouTube channel
Facebook page



Is that code correct as such...graphics look corrupted on 320x240 resolution?
ReplyDeleteCode is correct, many of the viewers have made it work.
DeleteOk, I see that the LGFX.h has correct width, height...I can see on Amazon that the board that I bought is said to have; Touch screen: ESP32-2432S028R and Driver Chip: ILI9341 . So these should work....but it justdoes not seem to get correct way on screen???
Deleteok, managed to get it...but what ever reason, this seemed to work
Delete- swapping widt/height
- rotation = 5
- not sure if offset_x / y has any meaning
LGFX.h
...
cfg.panel_width = 320;
cfg.panel_height = 240;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 5;
...
I also comment out "tft.setRotation" on main.cpp, is that actually needed if the value is already set on LGFX.h ?
This comment has been removed by the author.
DeleteI can see small difference on your board pictures, one of them seems to have perhaps micro-usb power, and that usb is slightly side, but some are with usb-c and more middle...on my board is usb-c and usb is quite on middle also.
DeleteThanks MarkoK, this fixed it for me as well, although it leaves the usb-c power at the top. I tried use rotation=7 to get the usb-c on the bottom but that messes up the graphics for whatever reason.
DeleteYes, I have tried many combinations, but have not been able to find one that would flip the display 180 degrees, so that USB port would be down without messing the screen completely...
DeleteI'm having these two error come up when running the program: ** [.pio/build/esp32dev/libfd3/LovyanGFX/lgfx/utility/._lgfx_miniz.c.o] Error 1
ReplyDelete*** [.pio/build/esp32dev/libfd3/LovyanGFX/lgfx/Fonts/efont/._lgfx_efont_cn.c.o] Error 1
Are you using Mac? Gemini was quessing following reason.
Delete"If you are working on a Mac (or using a project folder that was zipped/copied on a Mac), macOS automatically creates hidden metadata files called AppleDouble files that start with ._. PlatformIO sees these ghost files, thinks they are actual C source files, and tries to compile them. Because they just contain file metadata and not actual C code, the compiler panics and crashes."
Yes I was. I will switch to windows and run from that and see if it works. Thanks
ReplyDeleteGot it! Works perfectly now. Thanks I did not know that about mac's making those ghost files.
DeleteYou can use Mac also
DeleteStep 1: Clean out the Mac ghost files
You need to purge those hidden ._ files from your project directory.
Open your terminal.
Navigate (cd) into your project folder.
find and destroy all ._ files in your project directory
Step 2: Nuke the build cache
PlatformIO has already cached the bad build files, so you need to force it to start fresh.
In VS Code: Click the PlatformIO icon (the alien head) on the left sidebar, expand your project env, and click Clean.
Alternatively: Just manually delete the entire hidden .pio folder inside your project directory.
To change the units from meters to feet and meters/second to knots, you need to modify the DrawAircraftInfo function within the AircraftManager.cpp
ReplyDeleteThe current code displays the values directly from the OpenSky data, which is provided in meters and m/s. You just need to apply the math conversions and update the label strings.
The Code Change
Locate the DrawAircraftInfo function at the bottom of your file and replace it with this version:
void AircraftManager::DrawAircraftInfo(LGFX_Sprite& backbuffer, int x, int y, const TrackedAircraft& tracked) const
{
const int lineHeight = tft.fontHeight() + 1;
// Convert values
// velocity is in m/s, convert to knots by multiplying by 1.94384
float speedKnots = tracked.state.velocity * 1.94384f;
// baroAltitude is in meters, convert to feet by multiplying by 3.28084
float altitudeFt = tracked.state.baroAltitude * 3.28084f;
backbuffer.setTextSize(1);
backbuffer.setTextColor(lgfx::color888(0, 128, 0));
backbuffer.drawString(tracked.state.callsign, x + 5, y + 5);
// Display Speed in Knots
backbuffer.drawString(String(speedKnots, 0) + "kts", x + 5, y + 5 + lineHeight);
// Display Altitude in Feet
backbuffer.drawString(String(altitudeFt, 0) + "ft", x + 5, y + 5 + lineHeight * 2);
}
Thank you so much for contributing this code. I'm not a coder but was able to do a copy and paste and recompile and it worked! My only problem now is that even after making the changes to the display specifications referenced up above my display is 180 degrees with the USB port on top and not the bottom. If you have any recomendations I sure would appreciate it.
DeleteThis seems to be an issue, perhaps not all boards, but surprisingly many. I tried many combinations, but have not managed to flip screen 180 degrees.
DeleteTo my understanding that offset_rotation=7 should work...but some reason it doesn't...
I did some calculations to change the knots to mph but for whatever reason I dont think the aircraft listed on the radar is actually correct in mph. I show a Boeing flying at 450 kots and yet the radar is showing 267 MPH.. calculation is multipling by 1.151
ReplyDeleteHere is some direct replacement code for DrawAircraftIcon which will rotate the plane icon to the proper heading as opposed to the 4 cardinal directions. (if I knew how to use github I'd put in some sort of request there, but I don't so I didn't, but someone else feel free to).
ReplyDeletevoid AircraftManager::DrawAircraftIcon(LGFX_Sprite& backbuffer, int x, int y, const TrackedAircraft& tracked) const
{
// normalise heading into [0, 360)
float heading = fmodf(tracked.state.trueTrack, 360.0f);
if (heading < 0) heading += 360.0f;
// Create a temporary sprite for the rotated image
LGFX_Sprite rotated;
rotated.setColorDepth(16);
rotated.createSprite(PLANE_ICON_SIZE, PLANE_ICON_SIZE);
// Set swap bytes on the temporary sprite before pushing the image
rotated.setSwapBytes(true);
rotated.pushImage(0, 0, PLANE_ICON_SIZE, PLANE_ICON_SIZE, planeUp, PLANE_ICON_TRANSPARENT);
rotated.setSwapBytes(false);
// Push the rotated sprite to the backbuffer
rotated.pushRotateZoom(&backbuffer, x, y, heading, 1.0, 1.0);
rotated.deleteSprite();
}
Thank you so much for contributing this code. I'm 78 and not a coder but was able to successfully copy and paste and recompile the code and it works great. Your code really adds to the look of the display!
DeleteIs it possible to use a larger display (4” or larger) and does the code need to be changed?
DeleteI cannot test, but on easiest just modifying display width/height values might be enough... assuming any calculations is based on those.
DeleteHi all.The bigger screens use different interface chips, so it would not be an easy task.. Did anyone try?? thanks..
DeleteProbably not, with code that can't even be configured to successfully do a 180° orientation switch I can't imagine getting it to work on a larger display without a complete rewrite.
DeleteBrilliant Work!
ReplyDeleteI have got it working.
I altered the orientation - Thank You MarkoK
I altered the speed and Altitude to Knots and Feet - Thank You Xraydelta101
I altered the Aircraft Logo to face the direction of travel - Thank You Tom
My only issue is that my display has the USB C Port at the top instead of the bottom, but I haven't settled on a case yet....
I've added a swipe down from the top menu screen along with. incorporating the directional plane icons and also a flight details screen (when you click on a plane on the sweep scan screen) and also an option to display the nearest aircraft instead of the sweeps scan screen (also available from the swipe down menu). Used a little bit of Codex / ChatGPT to assist with the additions (don't hate me for it). Also added toggles for metric to imperial, whether to display the sweep, dots or plane icons and refresh interval. Here is a link to my google drive with the project in https://drive.google.com/drive/folders/1upk8_A_npe07qjsYHJDs64Gp99C9OXmE?usp=sharing
ReplyDeleteThis comment has been removed by the author.
DeletePerfect, many thanks!!
DeleteMade some more changes this morning :
ReplyDeleteDO NOT INSTALL THIS IF YOU WANT TO CONTINUE USING THE ORIGINAL OPENSKY DATA SOURCE , THIS VERSION CHANGES FROM USING THE DATA SOURCE TO ADS-B AND IT'S ASSOCIATED ENHANCEMENT DATA SOURCES.
This newer build keeps the original CYD touchscreen flight-radar idea, but changes the aircraft data source, expands the detail screen, and makes the radar sweep behave more like a real scanning display.
## Headline Changes
- Replaced the OpenSky aircraft feed with an ADS-B live position feed.
- OpenSky API credentials are no longer needed.
- Removed the OpenSky client ID and secret fields from the web configuration page.
- Added enrichment lookups for extra aircraft and route information where available.
- Added airline/private display, aircraft make/model, and origin/destination airports to the detail view.
- Added a more realistic scan sweep mode where aircraft only appear or move when the sweep line reaches them.
- Increased the radar sweep speed to one full rotation every 10 seconds.
- Added Hybrid mode and a configurable nearby-aircraft range.
- Added portrait/landscape orientation support.
https://drive.google.com/file/d/1gFVVJwBkIeJ2Bcx6sevQAaCIA5nHfCEB/view?usp=share_link
Hi and thanks. I will stick to the opensky version, much easier than ads-b, Just wordering if it would be possible to pass some of the improvements (for example the realistic sweep mode and the increased sweep speed) to the opensky version. If not no problem, it works well enough. Thanks!!
DeleteNo reason why not. The move to the ads-b source was that it seems to include more aircraft, has the enhanced information source and doesn't require you to setup an API key. Also OpenSky gives a normal authenticated user 4,000 credits per day. For a small local limited scan radius, which is what this project uses (unless you set the degrees very high!), each aircraft-position refresh costs 1 credit. So that means roughly 4,000 data refreshes per day.
DeleteThat sounds like a lot, but a device running all day burns through it quickly, here are the relative refresh rates, vs number of daily calls :
1 second 86,400 Way over limit
5 seconds 17,280 Way over limit
10 seconds 8,640 Over limit
20 seconds 4,320 Slightly over
30 seconds 2,880 Safe
60 seconds 1,440 Safe
So with 4,000 credits/day, the fastest sustainable refresh rate is about one refresh every 21.6 seconds, assuming every request only costs 1 credit.
I felt that this creates a problem for this project because it is meant to feel like a live radar. At 30-60 second refreshes, the aircraft positions can feel stale, especially for planes close overhead. At 5-10 seconds, which feels much better visually, OpenSky credits would run out partway through the day.
There’s also a second issue: OpenSky’s own docs say authenticated users have 5-second time resolution, and anonymous users have 10-second resolution, so requesting faster than that would not really give fresher data anyway. It would mostly just waste credits.
The other big reason for moving away is usage terms: OpenSky says operational REST API use in a live product/service/automated system needs a written agreement, even aside from the technical credit limit.
Thanks for the infos. I use it to show local airport traffic with 0.3 degrees radius, and had no problem with credits. It's OK, and it is a very nice gadget. Thanks again!!
DeleteI've backed out the provider changes and gone back to OpenSky for you, but left in the other enhancements also added the ability to set the orientation of the device so if you sit facing east etc you can set the orientation of the device accordingly. It also uses silhouettes to represent different classes of aircraft (I live near a glider club so have even included gliders!). https://drive.google.com/file/d/1R7lfSOGt_ro8EcngM6TAq0SS6GumSvTu/view?usp=share_link
DeleteThe version with the latest changes and using ADS-B is here https://drive.google.com/file/d/1iesOrCsRJe6SslonlEkUD65kTpeSE2M4/view?usp=sharing
DeleteReally thanks a lot: the opensky version works perfectly now tith the improvements. Thanks again!!!
DeleteCool project, Mr Keep!
DeleteI bought this: https://www.aliexpress.com/item/1005008176009397.html
Besides backlight pin cfg.pin_bl=27 these settings are needed in LGFX.h to get touch to work
private:
lgfx::Panel_ST7789 _panel;
lgfx::Bus_SPI _bus;
lgfx::Light_PWM _light;
lgfx::Touch_XPT2046 _touch;
{
auto cfg = _touch.config();
cfg.x_min = 300;
cfg.x_max = 3900;
cfg.y_min = 200;
cfg.y_max = 3700;
cfg.pin_int = 36;
// Same SPI bus pins as display
cfg.bus_shared = true;
cfg.spi_host = HSPI_HOST;
cfg.freq = 1000000;
cfg.pin_sclk = 14;
cfg.pin_mosi = 13;
cfg.pin_miso = 12;
// Separate CS selects the XPT2046
cfg.pin_cs = 33;
cfg.offset_rotation = 3;
_touch.config(cfg);
_panel.setTouch(&_touch);
}
I'm trying to get Mr Keep's ADS-B version to show aircraft. I have an ADS-B receiver outputting data on Port 30003 that is currently feeding AVR or Beast Raw data to Virtual Radar Server from a Raspberry Pi running Dump1090 on address 192.168.1.222:30003
ReplyDeleteI can't workout how to configure this source, assuming that it is actually compatible with this ADS-B code.
Would appreciate any advice, thanks.
Andy
Great project, thanks!!
ReplyDeleteBacklight pin was different for me:
pin_bl = 27
https://www.aliexpress.com/item/1005008176009397.html