Code for ESP32
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <MPU6050.h>
// ================= TFT =================
#define TFT_CS 5
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ST7735 tft(TFT_CS, TFT_DC, TFT_RST);
// ================= MPU =================
MPU6050 mpu;
int16_t axR, ayR, azR; // raw accelerometer data
float pitchRaw, rollRaw;
float pitch = 0, roll = 0;
// filter strength (smaller = smoother)
const float alpha = 0.08;
// screen parameters
int W, H, CX, CY;
// ================= SETUP =================
void setup() {
Wire.begin(21, 22);
mpu.initialize();
tft.initR(INITR_BLACKTAB);
tft.setRotation(1);
W = tft.width();
H = tft.height();
CX = W / 2;
CY = H / 2;
tft.fillScreen(ST77XX_BLACK);
}
// ================= READ MPU + FILTER =================
void readMPU() {
mpu.getAcceleration(&axR, &ayR, &azR);
float ax = axR / 16384.0;
float ay = ayR / 16384.0;
float az = azR / 16384.0;
pitchRaw = atan2(ax, sqrt(ay * ay + az * az)) * 180 / PI;
rollRaw = atan2(ay, az) * 180 / PI;
// Low-pass filter (removes vibration)
pitch += (pitchRaw - pitch) * alpha;
roll -= (rollRaw + roll) * alpha;
}
// ================= ROTATED LINE =================
void drawRotLine(int x1, int y1, int x2, int y2, float a) {
float s = sin(a);
float c = cos(a);
x1 -= CX; y1 -= CY;
x2 -= CX; y2 -= CY;
int rx1 = x1 * c - y1 * s + CX;
int ry1 = x1 * s + y1 * c + CY;
int rx2 = x2 * c - y2 * s + CX;
int ry2 = x2 * s + y2 * c + CY;
tft.drawLine(rx1, ry1, rx2, ry2, ST77XX_WHITE);
}
// ================= DRAW HORIZON =================
void drawHorizon() {
tft.fillScreen(ST77XX_BLACK);
// pitch -> rotation
// roll -> vertical shift
float ang = radians(-pitch);
static float shiftF = 0;
shiftF += ((roll * 2.0) - shiftF) * 0.2;
int shift = shiftF;
// ===== MOVING HORIZON LINES =====
for (int d = -40; d <= 40; d += 10) {
int y = CY + d * 3 + shift;
int len = (d % 20 == 0) ? 50 : 30;
drawRotLine(
CX - len / 2,
y,
CX + len / 2,
y,
ang
);
}
// ===== CENTER LINE =====
tft.drawFastHLine(CX - 30, CY, 60, ST77XX_YELLOW);
// ===== AIRCRAFT SYMBOL =====
tft.drawFastHLine(CX - 18, CY, 36, ST77XX_YELLOW);
tft.drawFastVLine(CX, CY, 12, ST77XX_YELLOW);
}
// ================= LOOP =================
void loop() {
readMPU();
drawHorizon();
delay(30); // ~40 FPS smooth animation
}