Tampilan LED Gyroscope Interaktif dengan NeoPixel Ring dan Arduino
Komponen dan Perlengkapan
SparkFun Arduino Pro Mini 328 - 5V/16MHz
×
1
Adafruit NeoPixel Ring: WS2812 5050 RGB LED
×
1
SparkFun IMU Breakout - MPU-9250
×
1
Breadboard (generic)
×
1
Male/Male Jumper Wires
×
1
Male/Female Jumper Wires
×
1
4 AA battery holder + battery
×
1
Tentang Proyek Ini
Dalam tutorial ini, kita akan menggunakan MPU6050 gyroscope, NeoPixel Ring dan Arduino untuk membangun perangkat yang menyalakan LED sesuai dengan sudut kemiringan.
Ini adalah proyek sederhana dan menyenangkan yang akan dirangkaikan pada breadboard. Jika Anda mengikuti langkah-langkahnya, Anda akan membangun apa yang Anda lihat di video. Ini adalah tutorial yang baik untuk mempelajari gyroscope dan NeoPixel Ring.
Saya membangun tutorial ini karena minat yang saya lihat pada beberapa tutorial lain. Dalam tutorial ini saya mengganti LED sederhana dengan NeoPixel Ring. Ring ini lebih mudah digunakan melalui perpustakaan Adafruit dan tentu saja lebih spektakuler.
Jadi jika Anda memiliki komponen ini di sekitar, ini adalah cara yang bagus untuk memanfaatkannya, saya akan mencoba membawa Anda langkah demi langkah melalui pembuatan perangkat dan juga menjelaskan cara kerjanya di langkah terakhir.
Langkah 1: Hal yang Diperlukan
Bagian
1. Arduino Pro Mini 328P
2. Breadboard
3. MPU6050 gyroscope
4. 24 NeoPixel LED Ring
5. 4 x AA battery pack with 4 batteries
6. U-shape jumper cables (optional). Saya menggunakan kabel jumper ini karena terlihat lebih baik pada breadboard, dan led lebih terlihat dengan cara ini. Anda dapat menemukan kotak 140 di ebay dengan harga sekitar 4$. Jika Anda tidak memiliki kabel ini, Anda dapat menggantinya dengan dupont wires.
Alat:
1. USB to serial FTDI adapter FT232RL untuk memprogram arduino pro mini
2. Arduino IDE
Keterampilan:
1. Soldering
3. Basic arduino programming
Langkah 2: Pemasangan
Saya telah melampirkan skema fritzing dalam format fzz dan gambarnya untuk visualisasi koneksi yang mudah.
1. Anda perlu solder 3 pin pria di bagian belakang neo pixel ring seperti yang ditunjukkan dalam gambar
- solder pin positif
- solder ground
- solder pin input data
2. Kemudian 4x battery holder harus memiliki cara untuk terhubung ke breadboard, solusi mudah adalah solder dua kabel dupont pria ke terminalnya.
3. Siapkan breadboard.
- tempatkan neo pixel ring, mikrokontroler, dan gyroscope pada breadboard seperti dalam gambar
- tempatkan semua kabel negatif: ke mikrokontroler, neo pixel ring, gyro
- tempatkan semua kabel positif: ke mikrokontroler, neo pixel ring, gyro
- tempatkan semua kabel data:
* SDA dan SCL dari mikrokontroler ke gyro
* pin D6 dari mikrokontroler ke neo pixel ring
- periksa ulang semua koneksi sebelum menyala
- opsi: gunakan karet kanvas, tempel battery pack di bagian belakang breadboard untuk menempatkannya dan membuatnya lebih portabel
Langkah 3: Kode dan Kalibrasi
Pertama Anda perlu mengunduh dan menginstal dua perpustakaan:
1. Adafruit neopixel library untuk mengontrol neopixel
2. MPU6050 library untuk gyroscope
Keduanya adalah perpustakaan hebat yang akan melakukan pekerjaan berat!
Detail lebih lanjut tentang neo pixels di sini
Kemudian unduh dan instal perpustakaan saya dari sini atau salin dari bawah:
#include "I2Cdev.h" #include <Adafruit_NeoPixel.h> #include "MPU6050_6Axis_MotionApps20.h" #include "Wire.h" #define NEOPIXED_CONTROL_PIN 6 #define NUM_LEDS 24 const int MAX_ANGLE = 45; const int LED_OFFSET = 12; MPU6050 mpu; Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NEOPIXED_CONTROL_PIN, NEO_RBG + NEO_KHZ800); unsigned long lastPrintTime = 0; bool initialization = false; // set true if DMP init was successful uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU uint8_t devStatus; // return status after each device operation (0 = success, !0 = error) uint16_t packetSize; // expected DMP packet size (default is 42 bytes) uint16_t fifoCount; // count of all bytes currently in FIFO uint8_t fifoBuffer[64]; // FIFO storage buffer Quaternion q; // [w, x, y, z] quaternion container VectorFloat gravity; // [x, y, z] gravity vector float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high</p><p>void setup() { Serial.begin(9600); Serial.println("Program started"); initialization = initializeGyroscope(); strip.begin(); } void loop() { if (!initialization) { return; } mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus(); fifoCount = mpu.getFIFOCount(); if (hasFifoOverflown(mpuIntStatus, fifoCount)) { mpu.resetFIFO(); return; } if (mpuIntStatus & 0x02) { while (fifoCount < packetSize) { fifoCount = mpu.getFIFOCount(); } mpu.getFIFOBytes(fifoBuffer, packetSize); fifoCount -= packetSize; mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); redrawLeds(ypr[0] * 180/M_PI, ypr[1] * 180/M_PI, ypr[2] * 180/M_PI); } } boolean hasFifoOverflown(int mpuIntStatus, int fifoCount) { return mpuIntStatus & 0x10 || fifoCount == 1024; } void redrawLeds(int x, int y, int z) { x = constrain(x, -1 * MAX_ANGLE, MAX_ANGLE); y = constrain(y, -1 * MAX_ANGLE, MAX_ANGLE); if (y < 0 and z > 0) { lightLeds(y, z, 0, 5, 0, 89); } else if (y < 0 and z < 0) { lightLeds(y, z, 6, 12, 89, 0); } else if (y > 0 and z < 0) { lightLeds(y, z, 13, 19, 0, 89); } else if (y > 0 and z > 0) { lightLeds(y, z, 20, 24, 89, 0); } } void lightLeds(int x, int y, int fromLedPosition, int toLedPosition, int fromAngle, int toAngle) { double angle = (atan((double) abs(x) / (double) abs (y)) * 4068) / 71; int ledNr = map(angle, fromAngle, toAngle, fromLedPosition, toLedPosition); printDebug(x, y, ledNr, angle); uint32_t color; for (int i=0; i < NUM_LEDS; i++) { color = strip.Color(0, 0, 0); if (i == ledNr) { color = strip.Color(0, 180, 0); } else if (i == ledNr - 1) { color = strip.Color(0, 5, 0); } strip.setPixelColor(normalizeLedPosition(i), color); strip.show(); } } int normalizeLedPosition(int position) { if (NUM_LEDS > position + LED_OFFSET) { return position + LED_OFFSET; } return position + LED_OFFSET - NUM_LEDS; } void printDebug(int y, int z, int lightLed, int angle) { if (millis() - lastPrintTime < 500) { return; } Serial.print("a=");Serial.print(angle);Serial.print("; "); Serial.print("ll=");Serial.print(lightLed);Serial.print("; "); Serial.print("y=");Serial.print(y);Serial.print("; "); Serial.print("z=");Serial.print(z);Serial.println("; "); lastPrintTime = millis(); } bool initializeGyroscope() { Wire.begin(); TWBR = 24; mpu.initialize(); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed")); Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize(); mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset(1788); if (devStatus != 0) { Serial.print(F("DMP Initialization failed (code "));Serial.println(devStatus); return false; } mpu.setDMPEnabled(true); Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)...")); attachInterrupt(0, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); Serial.println(F("DMP ready! Waiting for first interrupt...")); packetSize = mpu.dmpGetFIFOPacketSize(); return true; } void dmpDataReady() { mpuInterrupt = true; }
Unggah kode:
Menggunakan adapter FTDI unggah kode ke arduino.
Hubungkan sumber daya (baterai)
Kalibrasi:
Hal terpenting untuk dikalkirkan di sini adalah konstanta "LED_OFFSET". Dalam contoh saya adalah 12. Anda perlu menyesuaikan ini dari 0 hingga 23 sehingga setelah menyala papan led akan menyala di arah Anda memiringkan papan.
Jika Anda ingin mengetahui detail lebih lanjut tentang cara kerjanya lihat langkah berikutnya
Langkah 4: Cara Kerja (opsional)
Pertama sedikit informasi tentang gyroscope MPU6050. Ini adalah gyroscope MEMS (MEMS singkatan dari Microelectromechanical systems).
Setiap jenis gyroscope MEMS memiliki bentuk komponen osilasi dari mana percepatan, dan oleh karena itu perubahan arah, dapat terdeteksi. Ini adalah karena, menurut hukum konservasi gerakan, objek yang bergetar suka terus bergetar pada bidang yang sama, dan deviasi getaran apa pun dapat digunakan untuk menurunkan perubahan arah.
Gyro juga berisi mikrokontroler sendiri untuk menghitung roll, pitch, dan yaw melalui matematika canggih.
Namun data mentah gyro menderita kebisingan dan drift, jadi kami menggunakan perpustakaan eksternal untuk merapikan hal-hal dan memberikan data yang bersih dapat digunakan.
Neopixel adalah led RGB yang dapat diaddress secara individual dan dirantai ke dalam pita dan lingkaran. Mereka bekerja pada 5V dan mereka berisi rangkaian sendiri jadi Anda hanya perlu menyuplai daya neopixels dan berkomunikasi dengan mereka menggunakan garis data. Komunikasi dilakukan dengan satu garis data yang berisi jam dan data (detail lebih lanjut di sini). Adafruit menyediakan perpustakaan yang bersih untuk berinteraksi dengan neo pixel rings.
Kode
Di dalam fungsi loop() perpustakaan MPU6050_6Axis_MotionApps20 dipanggil. Saat perpustakaan memiliki data baru dari gyroscope itu memanggil redrawLeds(x, y, z) dengan 3 argumen yang mewakili yaw, pitch, dan roll
Di dalam redrawLeds():
- kita fokus pada dua sumbu: y, z
- kita membatasi kedua sumbu dari -MAX_ANGLE hingga +MAX_ANGLE, kami mendefinisikan sudut maksimum 45 dan dapat diubah
- kita membagi 360 derajat menjadi 4 kuadran dan memanggil fungsi lightLeds() untuk setiap sebagai berikut:
* y negatif, z positif kuadran pertama akan mengontrol led dari 0 hingga 5, sudut akan dari 0 hingga 89
* y negatif, z negatif kuadran kedua mengontrol led dari 6 hingga 12, sudut akan dari 89 hingga 0
* ...etc
- di dalam fungsi lightLeds
* saya menghitung sudut berdasarkan dua sumbu menggunakan arktangen (lihat gambar yang dilampirkan)
* saya menghitung led mana yang akan ditampilkan menggunakan fungsi map arduino
* saya mereset pita led semua kecuali dua led, satu yang sesuai dengan posisi led yang telah saya hitung sebelumnya dan satu posisi led sebelumnya (untuk menunjukkan efek fade)
* saya menggunakan fungsi bernama normalizeLedPosition() untuk mempertimbangkan kalibrasi neopixel. Kalibrasi berguna karena neo pixel ring dapat diputar sesuai keinginan, dan harus diselaraskan dengan gyroscope
* saya juga mencetak dua sumbu, led mana yang menyala, dan sudut
Matematika
Saya melampirkan gambar lingkaran led dan fungsi trigonometri yang digunakan untuk menentukan sudut.