Digital compass and tilt display breadboard build with ESP32-C3 SuperMini, MPU6050 sensor, and OLED display showing heading

ผู้เริ่มต้น

สร้างเข็มทิศดิจิทัลและจอแสดงผลการเอียง

เซ็นเซอร์จอแสดงผล

ชี้แล้วดูทิศที่แท้จริงแบบเรียลไทม์บนหน้าจอ การรับรู้การวางแนวที่แท้จริง เซ็นเซอร์ประเภทเดียวกับที่อยู่เบื้องหลังเข็มทิศและการหมุนอัตโนมัติของโทรศัพท์

รวมชิ้นส่วนจริง 3 รายการ

ราคารวมชุดนี้: 1,170.00 ฿

ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน

สิ่งที่คุณต้องใช้

เป้าหมายของโปรเจกต์

โปรเจกต์นี้สร้างหน้าจอแสดงทิศทางที่แท้จริง: เอียงหรือหมุนเซ็นเซอร์แล้วดูหน้าจอแสดงผลตามแบบเรียลไทม์ ซึ่งเป็นเทคโนโลยีการตรวจจับพื้นฐานเดียวกันกับระบบหมุนหน้าจออัตโนมัติของโทรศัพท์และการรักษาสมดุลการบินของโดรนทุกเครื่อง เพียงแต่แสดงผลบนหน้าจอขนาดเล็กแทนที่จะซ่อนอยู่ภายในอุปกรณ์ที่ใหญ่กว่า

คอนโทรลเลอร์ทำอะไร

มันอ่านค่าการเคลื่อนไหวดิบของเซ็นเซอร์อย่างต่อเนื่อง แปลงค่าเหล่านั้นให้เป็นค่าความเอียงหรือทิศทางที่ใช้งานได้ และอัปเดตการแสดงผลหลายสิบครั้งต่อวินาที เพื่อให้การอ่านค่ารู้สึกเหมือนจริงและไม่ล่าช้า

IMU ทำอะไร

มันรวมเอาตัววัดความเร่ง (accelerometer) ซึ่งตรวจจับทิศทางของแรงโน้มถ่วง เข้ากับไจโรสโคป (gyroscope) ซึ่งตรวจจับความเร็วในการหมุน ทำให้คอนโทรลเลอร์มีทุกสิ่งที่จำเป็นในการคำนวณทิศทางและการเคลื่อนไหวแบบเรียลไทม์ผ่านอินเทอร์เฟซ I2C แบบง่าย

จอแสดงผลทำอะไร

มันแสดงค่าความเอียงหรือทิศทางปัจจุบัน ไม่ว่าจะเป็นตัวเลขดิบ หรือหากใช้โค้ดเพิ่มเล็กน้อย ก็สามารถแสดงเป็นตัวบ่งชี้ภาพที่เรียบง่าย เช่น เส้นขอบฟ้าหรือแท่งเอียง

แนวคิดซอฟต์แวร์และไลบรารี

เริ่มต้นด้วยการพิมพ์ค่า accelerometer และ gyroscope ดิบเพื่อยืนยันว่าเซ็นเซอร์เชื่อมต่อสายและสื่อสารได้อย่างถูกต้อง จากนั้นจึงค่อยทำงานกับการรวมค่าเหล่านั้นเข้ากับมุมเอียงที่เสถียรก่อนที่จะกังวลเรื่องการแสดงผลใดๆ

การทดสอบและการแก้ไขปัญหา

  • ค่าที่อ่านได้จะค่อยๆ คลาดเคลื่อนไปตามเวลาแม้ว่าเซ็นเซอร์จะอยู่นิ่งสนิท นี่คือลักษณะปกติของไจโรสโคป ให้ลองใช้ตัวกรองแบบ complementary หรือ Kalman แบบง่ายที่รวมเซ็นเซอร์ทั้งสองเข้าด้วยกันแทนที่จะเชื่อถือไจโรสโคปเพียงอย่างเดียว
  • เซ็นเซอร์ไม่อ่านค่าใดๆ เลย หรืออ่านค่าคงที่ ให้ตรวจสอบสายไฟและที่อยู่ I2C ซ้ำอีกครั้ง และยืนยันว่าไม่มีอุปกรณ์ I2C อื่นบนบัสเดียวกันใช้ที่อยู่ที่ขัดแย้งกัน
  • ค่ามีการกระโดดไปมาเมื่อหยุดนิ่ง เซ็นเซอร์อาจต้องการขั้นตอนการสอบเทียบสั้นๆ ตอนเริ่มต้น โดยการอ่านและหาค่าเฉลี่ยของค่าที่หยุดนิ่งก่อนที่จะใช้เป็นค่าอ้างอิง

การอัปเกรดเสริม

เพิ่มออดจากกล่องอะไหล่เพื่อส่งเสียงเตือนหากมุมเอียงเกินเกณฑ์ ซึ่งเป็นสัญญาณเตือนระดับทางกายภาพแบบง่ายๆ ที่สร้างขึ้นจากเซ็นเซอร์เดียวกัน

การเชื่อมต่อสาย

  • MPU6050 VCC → ESP32-C3 3.3V
  • MPU6050 GND → ESP32-C3 GND
  • MPU6050 SDA → ESP32-C3 GPIO8 (I2C เริ่มต้น)
  • MPU6050 SCL → ESP32-C3 GPIO9 (I2C เริ่มต้น)
  • OLED VCC → ESP32-C3 3.3V
  • OLED GND → ESP32-C3 GND
  • OLED SDA → ESP32-C3 GPIO8 (บัสร่วมกับ MPU6050)
  • OLED SCL → ESP32-C3 GPIO9 (บัสร่วมกับ MPU6050)

จงซื่อสัตย์กับตัวเองว่าโปรเจกต์นี้คืออะไร: MPU6050 เป็นแค่ accelerometer + gyroscope เท่านั้น — ไม่มี magnetometer ดังนั้นมันไม่สามารถตรวจจับทิศเหนือแม่เหล็กได้จริงและไม่สามารถสร้างทิศทางเข็มทิศที่แท้จริงได้ สิ่งที่อยู่ด้านล่างนี้คือการแสดงผลความเอียง/ระดับที่แท้จริงโดยใช้ accelerometer pitch และ roll ซึ่งแม่นยำเมื่ออยู่นิ่งหรือเคลื่อนที่ช้าๆ เข็มทิศแม่เหล็กที่แท้จริงจะต้องมี magnetometer เพิ่มเติม (เช่น HMC5883L หรือ QMC5883L) ซึ่งไม่ได้อยู่ในรายการชิ้นส่วนนี้

แผนภาพการต่อสาย

VCC → 3.3V GND SDA → GPIO8 SCL → GPIO9 VCC → 3.3V GND SDA → GPIO8 SCL → GPIO9 ESP32-C3 MPU6050 OLED

โค้ดเริ่มต้น

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// --- ESP32-C3 SuperMini default I2C pins - adjust if your board differs ---
#define SDA_PIN 8
#define SCL_PIN 9

#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 64
#define OLED_ADDR     0x3C

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);

  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("OLED init failed");
    while (true) delay(1000);
  }

  if (!mpu.begin()) {
    Serial.println("MPU6050 not found - check wiring/address");
    while (true) delay(1000);
  }
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void loop() {
  sensors_event_t accel, gyro, temp;
  mpu.getEvent(&accel, &gyro, &temp);

  // Pitch/roll from the accelerometer's gravity vector - valid at rest / slow motion
  float pitch = atan2(accel.acceleration.y,
                       sqrt(accel.acceleration.x * accel.acceleration.x +
                            accel.acceleration.z * accel.acceleration.z)) * 180.0 / PI;
  float roll = atan2(-accel.acceleration.x, accel.acceleration.z) * 180.0 / PI;

  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Tilt Display");
  display.setCursor(0, 16);
  display.print("Pitch: ");
  display.print(pitch, 1);
  display.println((char)247);
  display.setCursor(0, 28);
  display.print("Roll:  ");
  display.print(roll, 1);
  display.println((char)247);

  // simple bubble-level dot
  int cx = 64, cy = 52;
  int dotX = constrain(cx + (int)roll, 20, 108);
  int dotY = constrain(cy + (int)pitch, 40, 63);
  display.drawCircle(cx, cy, 12, SSD1306_WHITE);
  display.fillCircle(dotX, dotY, 2, SSD1306_WHITE);

  display.display();
  delay(100);
}

ไม่แน่ใจขั้นตอนไหน? ถามเรา