photo
photo

Code for ESP32


#include <Wire.h>
#include <MPU6050.h>

MPU6050 mpu;

float ax, ay, az;
float pitch, roll;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);   // ESP32 I2C
  mpu.initialize();

  if (!mpu.testConnection()) {
    Serial.println("MPU6050 ERROR");
    while (1);
  }
}

void loop() {
  mpu.getAcceleration(&ax, &ay, &az);

  pitch = atan2(ax, sqrt(ay * ay + az * az)) * 180 / PI;
  roll  = atan2(ay, az) * 180 / PI;

  // Формат барои Processing
  Serial.print(pitch);
  Serial.print(",");
  Serial.println(roll);

  delay(20); // ~50Hz
}
  

Code for Processing

import processing.serial.*;

Serial myPort;

float pitchRaw = 0;
float rollRaw  = 0;

float pitch = 0;
float roll  = 0;

float alpha = 0.08;

int R = 200;

void setup() {
  size(600, 600);
  smooth(8);

  println(Serial.list());
  myPort = new Serial(this, Serial.list()[0], 115200);
  myPort.bufferUntil('\n');
}

void draw() {
  background(15);
  translate(width/2, height/2);

  // smoothing
  pitch -= (pitchRaw + pitch) * alpha;
  roll  += (rollRaw  - roll ) * alpha;

  // ================= MOVING PART =================
  push();
  clip(-R, -R, R*2, R*2);

  pushMatrix();
  rotate(radians(-roll));

  float p = pitch * 4;

  // SKY
  noStroke();
  fill(70, 140, 200);
  rect(-600, -600 + p, 1200, 600);

  // GROUND
  fill(160, 100, 60);
  rect(-600, p, 1200, 600);

  // HORIZON
  stroke(255, 220, 0);
  strokeWeight(4);
  line(-250, p, 250, p);

  // ===== PITCH LADDER =====
  stroke(255);
  strokeWeight(2);
  textSize(12);
  textAlign(CENTER, CENTER);

  for (int deg = -30; deg <= 30; deg += 5) {
    if (deg == 0) continue;

    float y = p + deg * 4;

    if (abs(y) < R - 20) {
      float len = (deg % 10 == 0) ? 120 : 60;

      // line
      line(-len/2, y, len/2, y);

      // numbers only every 10°
      if (deg % 10 == 0) {
        fill(255);
        text(abs(deg), -len/2 - 15, y);
        text(abs(deg),  len/2 + 15, y);
        noFill();
      }
    }
  }

  popMatrix();
  noClip();
  pop();

  // ================= STATIC SCALE =================
  drawStaticScale();

  // AIRCRAFT SYMBOL
  stroke(255, 220, 0);
  strokeWeight(4);
  line(-30, 0, 30, 0);
  line(0, 0, 0, 18);
}

void drawStaticScale() {
  // outer ring
  noFill();
  stroke(230);
  strokeWeight(6);
  ellipse(0, 0, R*2, R*2);

  // roll ticks & numbers
  stroke(220);
  strokeWeight(3);
  textAlign(CENTER, CENTER);
  textSize(14);
  fill(220);

  for (int a = -90; a <= 90; a += 10) {
    float ang = radians(a - 90);

    float x1 = cos(ang) * (R - 10);
    float y1 = sin(ang) * (R - 10);
    float x2 = cos(ang) * (R - (a % 30 == 0 ? 30 : 20));
    float y2 = sin(ang) * (R - (a % 30 == 0 ? 30 : 20));

    line(x1, y1, x2, y2);

    if (a % 30 == 0 && a != 0) {
      float xt = cos(ang) * (R - 45);
      float yt = sin(ang) * (R - 45);
      text(abs(a), xt, yt);
    }
  }

  // top triangle
  fill(255, 220, 0);
  noStroke();
  triangle(0, -R + 8, -8, -R + 25, 8, -R + 25);
}

void serialEvent(Serial myPort) {
  String data = myPort.readStringUntil('\n');
  if (data != null) {
    data = trim(data);
    String[] v = split(data, ',');
    if (v.length == 2) {
      pitchRaw = float(v[0]);
      rollRaw  = float(v[1]);
    }
  }
}