Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:vstoica:alexandru.micu1107 [2024/05/26 22:30]
alexandru.micu1107
pm:prj2024:vstoica:alexandru.micu1107 [2024/05/30 08:46] (current)
alexandru.micu1107
Line 48: Line 48:
 <note tip> <note tip>
 {{https://​i.imgur.com/​3iUhPRu.jpeg?​600x600}} {{https://​i.imgur.com/​3iUhPRu.jpeg?​600x600}}
 +
 -Arduino UNO Rev3, ATmega328P -Arduino UNO Rev3, ATmega328P
         ​         ​
Line 64: Line 65:
  
  
-<note tip> 
 {{https://​i.imgur.com/​ArHAzHj.png}} {{https://​i.imgur.com/​ArHAzHj.png}}
-Descrierea codului aplicaţiei (firmware): + 
-  mediu de dezvoltare ​(if any) (e.g. AVR StudioCodeVisionAVR) + *Medii de dezvoltare: Arduino IDEProcessing 
-  * librării şi surse 3rd-party (e.gProcyon AVRlib) + 
-  * algoritmi şi structuri pe care plănuiţi să le implementaţi + libs:  
-  * (etapa 3) surse şi funcţii implementate +        github.com/​bolderflight/​invensense-imu 
-</note>+        github.com/​adafruit/​Adafruit_SSD1306 
 +        github.com/​adafruit/​Adafruit_BusIO 
 +        ​github.com/adafruit/​Adafruit-GFX-Library 
 +    ​
  
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
  
-<note tip> 
 {{https://​i.imgur.com/​vjfrPvy.jpeg?​854×480}} {{https://​i.imgur.com/​vjfrPvy.jpeg?​854×480}}
 {{https://​i.imgur.com/​XVqeO60.jpeg?​854×480}} {{https://​i.imgur.com/​XVqeO60.jpeg?​854×480}}
-</​note>​ 
  
 ===== Concluzii ===== ===== Concluzii =====
 +Proiectul de creare a unui orizont artificial și a unei busole utilizând Arduino și Processing a fost un succes partial, demonstrând capabilitățile senzorului MPU9250 în monitorizarea orientării în spațiu. Implementarea a oferit o experiență vizuală intuitivă și interactivă,​ utilă atât pentru educație, cât și pentru aplicații practice în domeniul aviației. În viitor, proiectul poate fi extins pentru a include mai multe funcționalități și optimizări.  
 +Probleme intampinate:​ nu am reusit sa construiesc o busola care sa redea exact azimutul corect.
 ===== Download ===== ===== Download =====
  
Line 88: Line 90:
  
 Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:​pm:​prj20??:​c?​** sau **:​pm:​prj20??:​c?:​nume_student** (dacă este cazul). **Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**. Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:​pm:​prj20??:​c?​** sau **:​pm:​prj20??:​c?:​nume_student** (dacă este cazul). **Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**.
 +</​note>​
 +
 +==== cod arduino =====
 +
 +<note tip>
 +#include <​Wire.h>​
 +#include <​Adafruit_GFX.h>​
 +#include <​Adafruit_SSD1306.h>​
 +#include "​mpu9250.h"​
 +
 +// OLED display settings
 +#define SCREEN_WIDTH 128
 +#define SCREEN_HEIGHT 64
 +#define OLED_RESET -1
 +#define OLED_I2C_ADDRESS 0x3C
 +Adafruit_SSD1306 display(SCREEN_WIDTH,​ SCREEN_HEIGHT,​ &Wire, OLED_RESET);​
 +
 +// MPU9250 settings
 +bfs::​Mpu9250 imu;
 +
 +// Calibration offsets
 +float pitchOffset = 0;
 +float rollOffset = 0;
 +
 +void setup() {
 +    Serial.begin(115200);​
 +    while (!Serial); // Wait for Serial to be ready
 +
 +    Wire.begin();​
 +
 +    // Initialize the MPU9250 sensor with the primary I2C address
 +    imu.Config(&​Wire,​ bfs::​Mpu9250::​I2C_ADDR_PRIM);​
 +    imu.Begin();​
 +
 +    // Optionally configure sensor ranges and other settings
 +    imu.ConfigAccelRange(bfs::​Mpu9250::​ACCEL_RANGE_2G);​
 +    imu.ConfigGyroRange(bfs::​Mpu9250::​GYRO_RANGE_250DPS);​
 +    imu.ConfigDlpfBandwidth(bfs::​Mpu9250::​DLPF_BANDWIDTH_184HZ);​
 +
 +    Serial.println("​MPU9250 initialized and configured."​);​
 +
 +    // Initialize OLED display
 +    if (!display.begin(SSD1306_SWITCHCAPVCC,​ OLED_I2C_ADDRESS)) {
 +        Serial.println(F("​SSD1306 allocation failed"​));​
 +        for (;;);
 +    }
 +    display.display();​
 +    delay(2000);​
 +    display.clearDisplay();​
 +
 +    // Calibration step: capture initial offsets
 +    if (imu.Read()) {
 +        pitchOffset = atan2(imu.accel_y_mps2(),​ sqrt(imu.accel_x_mps2() * imu.accel_x_mps2() + imu.accel_z_mps2() * imu.accel_z_mps2())) * 180.0 / PI;
 +        rollOffset = atan2(-imu.accel_x_mps2(),​ imu.accel_z_mps2()) * 180.0 / PI;
 +    }
 +}
 +
 +void loop() {
 +    // Update sensor readings
 +    if (!imu.Read()) {
 +        Serial.println("​Failed to read from MPU9250!"​);​
 +        return;
 +    }
 +
 +    // Get accelerometer and gyroscope data
 +    float accelX = imu.accel_x_mps2();​
 +    float accelY = imu.accel_y_mps2();​
 +    float accelZ = imu.accel_z_mps2();​
 +
 +    // Get magnetometer data
 +    float magX = imu.mag_x_ut();​
 +    float magY = imu.mag_y_ut();​
 +
 +    // Calculate pitch, roll, and heading
 +    float pitch = atan2(accelY,​ sqrt(accelX * accelX + accelZ * accelZ)) * 180.0 / PI - pitchOffset;​
 +    float roll = atan2(-accelX,​ accelZ) * 180.0 / PI - rollOffset;
 +    float heading = atan2(magY, magX) * 180.0 / PI;
 +    //Normalize heading between 0-360 degrees
 +    if (heading < 0) {
 +        heading += 360;
 +    }
 +    // Normalize roll to be within -180 to 180 degrees
 +    if (roll > 180) {
 +        roll -= 360;
 +    } else if (roll < -180) {
 +        roll += 360;
 +    }
 +    // Display the results on Serial Monitor
 +    Serial.print(roll,​ 2);
 +    Serial.print("​ ");
 +    Serial.print(pitch,​ 2);
 +    Serial.print("​ ");
 +    Serial.print(heading,​ 2);
 +    Serial.println();​
 +
 +    // Redraw the horizon and airplane only if pitch or roll changes significantly
 +    static float lastPitch = 0;
 +    static float lastRoll = 0;
 +    static float lastheading = 0;
 +    if (abs(lastPitch - pitch) > 0.01 || abs(lastRoll - roll) > 0.01 || abs(lastheading - heading) > 0.01) {
 +        display.clearDisplay(); ​ // Clear the display only when necessary
 +        drawArtificialHorizon(roll,​ pitch);
 +        drawAirplaneSymbol();​
 +        drawAzimuth(heading);​
 +        display.display();​
 +        lastPitch = pitch;
 +        lastRoll = roll;
 +        lastheading = heading;
 +    }
 +}
 +
 +void drawArtificialHorizon(float roll, float pitch) {
 +    int centerX = SCREEN_WIDTH / 2;
 +    int centerY = SCREEN_HEIGHT / 2;
 +
 +    // Convert pitch and roll to radians
 +    float pitchRad = pitch * PI / 180.0;
 +    float rollRad = roll * PI / 180.0;
 +
 +    // Calculate the y-position of the horizon line based on pitch
 +    int horizonY = centerY - (int)(pitchRad * 33); // scale pitch to screen coordinates
 +
 +    // Calculate the x-offset of the horizon line based on roll
 +    int rollOffset = (int)(rollRad * (SCREEN_WIDTH / 2)); // scale roll to screen coordinates
 +
 +    // Draw the horizon line
 +    display.drawLine(0,​ horizonY + rollOffset, SCREEN_WIDTH,​ horizonY - rollOffset, SSD1306_WHITE);​
 +
 +    // Draw perspective lines
 +    display.drawLine(0,​ horizonY + rollOffset, centerX, SCREEN_HEIGHT,​ SSD1306_WHITE);​
 +    display.drawLine(SCREEN_WIDTH,​ horizonY - rollOffset, centerX, SCREEN_HEIGHT,​ SSD1306_WHITE);​
 +
 +    // Draw additional lines parallel to the horizon line for perspective effect
 +}
 +
 +
 +void drawAirplaneSymbol() {
 +    int centerX = SCREEN_WIDTH / 2;
 +    int centerY = SCREEN_HEIGHT / 2;
 +
 +    display.drawLine(centerX - 5, centerY, centerX + 5, centerY, SSD1306_WHITE);​ // Body
 +    display.drawLine(centerX - 10, centerY, centerX - 5, centerY - 3, SSD1306_WHITE);​ // Left wing up
 +    display.drawLine(centerX + 10, centerY, centerX + 5, centerY - 3, SSD1306_WHITE);​ // Right wing up
 +    display.drawLine(centerX - 10, centerY, centerX - 5, centerY + 3, SSD1306_WHITE);​ // Left wing down
 +    display.drawLine(centerX + 10, centerY, centerX + 5, centerY + 3, SSD1306_WHITE);​ // Right wing down
 +    display.drawLine(centerX,​ centerY - 2, centerX, centerY - 7, SSD1306_WHITE);​ // Vertical tail
 +}
 +
 +void drawAzimuth(float heading) {
 +    display.setTextSize(1);​
 +    display.setTextColor(SSD1306_WHITE);​
 +    display.setCursor(32,​ 0); // Top center
 +    display.print("​Bearing:​ ");
 +    display.print(heading,​ 1);
 +}
 +
 +</​note>​
 +
 +==== cod processing ====
 +
 +<note tip>
 +import processing.serial.*;​
 +
 +float Pitch;
 +float Bank;
 +float Azimuth;
 +float ArtificialHoizonMagnificationFactor = 0.7;
 +float CompassMagnificationFactor = 0.85;
 +float SpanAngle = 120;
 +int NumberOfScaleMajorDivisions;​
 +int NumberOfScaleMinorDivisions;​
 +PVector v1, v2;
 +
 +Serial port;
 +float Phi;
 +float Theta;
 +float Psi;
 +
 +void setup() ​
 +
 +  size(1366, 768); 
 +  rectMode(CENTER); ​
 +  smooth(); ​
 +  strokeCap(SQUARE);​
 +
 +  println(Serial.list());​
 +  port = new Serial(this,​ Serial.list()[0],​ 115200); ​
 +  port.bufferUntil('​\n'​); ​
 +}
 +
 +void draw() ​
 +
 +  background(0,​ 0, 102); // Dark blue background
 +  translate(W / 4, H / 2.1);  ​
 +  MakeAnglesDependentOnMPU9250(); ​
 +  Horizon(); ​
 +  rotate(-Bank); ​
 +  PitchScale(); ​
 +  Axis(); ​
 +  rotate(Bank); ​
 +  Borders(); ​
 +  Plane(); ​
 +  Compass(); ​
 +}
 +
 +void serialEvent(Serial port) // Reading the data by Processing.
 +{
 +   ​String input = port.readStringUntil('​\n'​);​
 +   if (input != null) {
 +     input = trim(input);​
 +     ​String[] values = split(input,​ " ");
 +     if (values.length == 3) {
 +       try {
 +         float phi = float(values[0]);​
 +         float theta = float(values[1]);​
 +         float psi = float(values[2]);​
 +         ​println(phi,​ theta, psi);
 +         Phi = phi;
 +         Theta = theta;
 +         Psi = psi;
 +       } catch (Exception e) {
 +         ​println("​Error parsing values: " + e.getMessage());​
 +       }
 +     }
 +   }
 +}
 +
 +void MakeAnglesDependentOnMPU9250() ​
 +
 +  Bank = radians(-Phi);​ // Convert degrees to radians for Processing
 +  Pitch = Theta; ​
 +  Azimuth = Psi;
 +}
 +
 +void Horizon() ​
 +
 +  scale(ArtificialHoizonMagnificationFactor); ​
 +  noStroke(); ​
 +  fill(0, 180, 255); 
 +  rect(0, -100, 900, 1000); ​
 +  fill(95, 55, 40); 
 +  pushMatrix();​ // Save the current transformation matrix
 +  rotate(Bank); ​
 +  rect(0, 400 + Pitch * 10, 900, 800); 
 +  popMatrix();​ // Restore the previous transformation matrix
 +  rotate(-PI - PI / 6); 
 +  SpanAngle = 120; 
 +  NumberOfScaleMajorDivisions = 12; 
 +  NumberOfScaleMinorDivisions = 24;  ​
 +  CircularScale(); ​
 +  rotate(PI + PI / 6); 
 +  rotate(-PI / 6);  ​
 +  CircularScale(); ​
 +  rotate(PI / 6); 
 +}
 +
 +void Compass() ​
 +
 +  translate(2 * W / 3, 0); 
 +  scale(CompassMagnificationFactor); ​
 +  noFill(); ​
 +  stroke(100); ​
 +  strokeWeight(80); ​
 +  ellipse(0, 0, 750, 750); 
 +  strokeWeight(50); ​
 +  stroke(50); ​
 +  fill(0, 0, 40); 
 +  ellipse(0, 0, 610, 610); 
 +  for (int k = 255; k > 0; k = k - 5) 
 +  { 
 +    noStroke(); ​
 +    fill(0, 0, 255 - k); 
 +    ellipse(0, 0, 2 * k, 2 * k); 
 +  } 
 +  strokeWeight(20); ​
 +  NumberOfScaleMajorDivisions = 18; 
 +  NumberOfScaleMinorDivisions = 36;  ​
 +  SpanAngle = 180; 
 +  CircularScale(); ​
 +  rotate(PI); ​
 +  SpanAngle = 180; 
 +  CircularScale(); ​
 +  rotate(-PI); ​
 +  fill(255); ​
 +  textSize(60); ​
 +  textAlign(CENTER); ​
 +  text("​W",​ -375, 0, 100, 80); 
 +  text("​E",​ 370, 0, 100, 80); 
 +  text("​N",​ 0, -365, 100, 80); 
 +  text("​S",​ 0, 375, 100, 80); 
 +  textSize(30); ​
 +  text("​COMPASS",​ 0, -130, 500, 80); 
 +  rotate(PI / 4); 
 +  textSize(40); ​
 +  text("​NW",​ -370, 0, 100, 50); 
 +  text("​SE",​ 365, 0, 100, 50); 
 +  text("​NE",​ 0, -355, 100, 50); 
 +  text("​SW",​ 0, 365, 100, 50); 
 +  rotate(-PI / 4); 
 +  CompassPointer(); ​
 +}
 +
 +void CompassPointer() ​
 +
 +  rotate(PI + radians(Azimuth));  ​
 +  stroke(0); ​
 +  strokeWeight(4); ​
 +  fill(100, 255, 100); 
 +  triangle(-20,​ -210, 20, -210, 0, 270); 
 +  triangle(-15,​ 210, 15, 210, 0, 270); 
 +  ellipse(0, 0, 45, 45);   
 +  fill(0, 0, 50); 
 +  noStroke(); ​
 +  ellipse(0, 0, 10, 10); 
 +  triangle(-20,​ -213, 20, -213, 0, -190); ​
 +  triangle(-15,​ -215, 15, -215, 0, -200); ​
 +  rotate(-PI - radians(Azimuth)); ​
 +}
 +
 +void Plane() ​
 +
 +  fill(0); ​
 +  strokeWeight(1); ​
 +  stroke(0, 255, 0); 
 +  triangle(-20,​ 0, 20, 0, 0, 25); 
 +  rect(110, 0, 140, 20); 
 +  rect(-110, 0, 140, 20); 
 +}
 +
 +void CircularScale() ​
 +
 +  float GaugeWidth = 800;  ​
 +  textSize(GaugeWidth / 30); 
 +  float StrokeWidth = 1; 
 +  float an; 
 +  float DivxPhasorCloser; ​
 +  float DivxPhasorDistal; ​
 +  float DivyPhasorCloser; ​
 +  float DivyPhasorDistal; ​
 +  strokeWeight(2 * StrokeWidth); ​
 +  stroke(255);​
 +  float DivCloserPhasorLenght = GaugeWidth / 2 - GaugeWidth / 9 - StrokeWidth; ​
 +  float DivDistalPhasorLenght = GaugeWidth / 2 - GaugeWidth / 7.5 - StrokeWidth;​
 +  for (int Division = 0; Division < NumberOfScaleMinorDivisions + 1; Division++) ​
 +  { 
 +    an = SpanAngle / 2 + Division * SpanAngle / NumberOfScaleMinorDivisions;  ​
 +    DivxPhasorCloser = DivCloserPhasorLenght * cos(radians(an)); ​
 +    DivxPhasorDistal = DivDistalPhasorLenght * cos(radians(an)); ​
 +    DivyPhasorCloser = DivCloserPhasorLenght * sin(radians(an)); ​
 +    DivyPhasorDistal = DivDistalPhasorLenght * sin(radians(an)); ​  
 +    line(DivxPhasorCloser,​ DivyPhasorCloser,​ DivxPhasorDistal,​ DivyPhasorDistal); ​
 +  }
 +  DivCloserPhasorLenght = GaugeWidth / 2 - GaugeWidth / 10 - StrokeWidth; ​
 +  DivDistalPhasorLenght = GaugeWidth / 2 - GaugeWidth / 7.4 - StrokeWidth;​
 +  for (int Division = 0; Division < NumberOfScaleMajorDivisions + 1; Division++) ​
 +  { 
 +    an = SpanAngle / 2 + Division * SpanAngle / NumberOfScaleMajorDivisions;  ​
 +    DivxPhasorCloser = DivCloserPhasorLenght * cos(radians(an)); ​
 +    DivxPhasorDistal = DivDistalPhasorLenght * cos(radians(an)); ​
 +    DivyPhasorCloser = DivCloserPhasorLenght * sin(radians(an)); ​
 +    DivyPhasorDistal = DivDistalPhasorLenght * sin(radians(an)); ​
 +    if (Division == NumberOfScaleMajorDivisions / 2 || Division == 0 || Division == NumberOfScaleMajorDivisions) ​
 +    { 
 +      strokeWeight(15); ​
 +      stroke(0); ​
 +      line(DivxPhasorCloser,​ DivyPhasorCloser,​ DivxPhasorDistal,​ DivyPhasorDistal); ​
 +      strokeWeight(8); ​
 +      stroke(100, 255, 100); 
 +      line(DivxPhasorCloser,​ DivyPhasorCloser,​ DivxPhasorDistal,​ DivyPhasorDistal); ​
 +    } 
 +    else 
 +    { 
 +      strokeWeight(3); ​
 +      stroke(255); ​
 +      line(DivxPhasorCloser,​ DivyPhasorCloser,​ DivxPhasorDistal,​ DivyPhasorDistal); ​
 +    } 
 +  } 
 +}
 +
 +void Axis() ​
 +
 +  stroke(255, 0, 0); 
 +  strokeWeight(3); ​
 +  line(-115, 0, 115, 0); 
 +  line(0, 280, 0, -280); ​
 +  fill(100, 255, 100); 
 +  stroke(0); ​
 +  triangle(0, -285, -10, -255, 10, -255); ​
 +  triangle(0, 285, -10, 255, 10, 255); 
 +}
 +
 +void Borders() ​
 +
 +  noFill(); ​
 +  stroke(0); ​
 +  strokeWeight(400); ​
 +  rect(0, 0, 1100, 1100); ​
 +  strokeWeight(200); ​
 +  ellipse(0, 0, 1000, 1000); ​
 +  fill(0); ​
 +  noStroke(); ​
 +  rect(4 * W / 5, 0, W, 2 * H); 
 +  rect(-4 * W / 5, 0, W, 2 * H); 
 +}
 +
 +void PitchScale() ​
 +{  ​
 +  stroke(255); ​
 +  fill(255); ​
 +  strokeWeight(3); ​
 +  textSize(24); ​
 +  textAlign(CENTER); ​
 +  for (int i = -4; i < 5; i++) 
 +  {  ​
 +    if ((i == 0) == false) ​
 +    { 
 +      line(110, 50 * i, -110, 50 * i); 
 +    }  ​
 +    text(""​ + i * 10, 140, 50 * i, 100, 30); 
 +    text(""​ + i * 10, -140, 50 * i, 100, 30); 
 +  } 
 +  textAlign(CORNER); ​
 +  strokeWeight(2); ​
 +  for (int i = -9; i < 10; i++) 
 +  {  ​
 +    if ((i == 0) == false) ​
 +    {    ​
 +      line(25, 25 * i, -25, 25 * i); 
 +    } 
 +  } 
 +}
 +
 </​note>​ </​note>​
  
Line 100: Line 534:
 <​note>​ <​note>​
 Listă cu documente, datasheet-uri,​ resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. Listă cu documente, datasheet-uri,​ resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**.
 +
 +Insipiratie:​ https://​mfurkanbahat.blogspot.com/​2014/​11/​artificial-horizon-and-compass-using.html
 +
 +Datasheet mpu9250: https://​invensense.tdk.com/​wp-content/​uploads/​2015/​02/​PS-MPU-9250A-01-v1.1.pdf
 </​note>​ </​note>​
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
  
pm/prj2024/vstoica/alexandru.micu1107.1716751838.txt.gz · Last modified: 2024/05/26 22:30 by alexandru.micu1107
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0