Interaktives Gyroskop-LED-Display mit NeoPixel-Ring & Arduino
Komponenten & Zubehör
| Bauteil | Anzahl | Hinweise |
|---|---|---|
| SparkFun Arduino Pro Mini 328 (5 V / 16 MHz) | 1 | Kompakt, braucht FTDI-Adapter zum Programmieren |
| Adafruit NeoPixel Ring (24 × WS2812 5050 RGB) | 1 | Einzeladressierbar, 5 V |
| MPU-6050 (oder MPU-9250) Breakout | 1 | I2C, 3-Achsen Gyro + Beschleunigung |
| Steckbrett (Breadboard) | 1 | Aufbau |
| Jumper-Kabel (M/M, M/F) | 1 Set | Optional: U-förmige für sauberen Aufbau |
| 4× AA-Batteriehalter + Batterien | 1 | ca. 6 V → Raw-Pin Pro Mini |
Werkzeuge & Skills
- FTDI-Adapter (FT232RL) zum Flashen des Pro Mini
- Arduino IDE
- Lötkolben (Pins an Pro Mini, NeoPixel, MPU)
- Grundkenntnisse Arduino-Programmierung
Projektidee
Ein Neigungsanzeiger: Die 24 LEDs des NeoPixel-Rings leuchten dort auf, wo die „Senkrechte“ (Schwerkraftvektor) den Ring schneidet. Kippt man die Platine, „wandert“ der Lichtpunkt entsprechend. Ideal zum Verständnis von IMU-Daten, Quaternion, DMP und NeoPixel-Ansteuerung.
Aufbau (Fritzing-Schema)
- NeoPixel-Ring: 3 Pins anlöten (VCC, GND, Data In).
- Batteriehalter: Zwei Dupont-Drähte anlöten für Breadboard.
- Komponenten auf Steckbrett platzieren (siehe Bilder).
- Verdrahtung:
- GND: Pro Mini, NeoPixel, MPU-6050 gemeinsam.
- VCC (5 V): Pro Mini (RAW oder VCC), NeoPixel, MPU (VCC/VDD).
- I2C: MPU SDA → A4, SCL → A5 (Pro Mini).
- NeoPixel Data → Pin D6 (Pro Mini).
- MPU INT-Pin → Pin D2 (Interrupt 0) für DMP-Ready-Signal.
- Alle Verbindungen prüfen, dann Batterie anschließen.
- Optional: Batteriehalter mit Klebeband auf Breadboard-Rückseite fixieren.
Benötigte Libraries
- Adafruit_NeoPixel (Library Manager)
- MPU6050_6Axis_MotionApps20 (von jrowberg/i2cdevlib) – enthält DMP-Firmware für quaternion-basierte Orientierung.
- I2Cdev (Basis für MPU-Lib)
Code & Kalibrierung
Der vollständige Sketch ist auf GitHub: Repository.
Kernlogik
#include "I2Cdev.h"
#include <Adafruit_NeoPixel.h>
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
#define NEOPIXEL_PIN 6
#define NUM_LEDS 24
const int MAX_ANGLE = 45; // Begrenzung Neigungswinkel
const int LED_OFFSET = 12; // Kalibrierung: Null-Position am Ring
MPU6050 mpu;
Adafruit_NeoPixel strip(NUM_LEDS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
// DMP-Variablen
uint8_t mpuIntStatus, devStatus; uint16_t packetSize, fifoCount;
uint8_t fifoBuffer[64];
Quaternion q; VectorFloat gravity; float ypr[3];
volatile bool mpuInterrupt = false;
void setup() {
Serial.begin(9600);
Wire.begin(); TWBR = 24; // 400 kHz I2C
mpu.initialize();
devStatus = mpu.dmpInitialize();
// Offsets müssen pro Sensor kalibriert werden!
mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788);
if (devStatus == 0) {
mpu.setDMPEnabled(true);
attachInterrupt(0, dmpDataReady, RISING);
packetSize = mp.dmpGetFIFOPacketSize();
}
strip.begin(); strip.show(); // All off
}
void dmpDataReady() { mpuInterrupt = true; }
void loop() {
if (!mpuInterrupt) return;
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
fifoCount = mpu.getFIFOCount();
if (mpuIntStatus & 0x10 || fifoCount == 1024) { 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);
// ypr[0]=Yaw, [1]=Pitch, [2]=Roll in Radiant
redrawLeds(ypr[0]*180/M_PI, ypr[1]*180/M_PI, ypr[2]*180/M_PI);
}
}
void redrawLeds(int x, int y, int z) {
// Nur Pitch (y) & Roll (z) nutzen, Yaw ignorieren
y = constrain(y, -MAX_ANGLE, MAX_ANGLE);
z = constrain(z, -MAX_ANGLE, MAX_ANGLE);
// 4 Quadranten → 4 LED-Segmente à 6 LEDs (24/4)
if (y < 0 && z > 0) lightLeds(y, z, 0, 5, 0, 89); // Q1
else if (y < 0 && z < 0) lightLeds(y, z, 6, 12, 89, 0); // Q2
else if (y > 0 && z < 0) lightLeds(y, z, 13, 19, 0, 89); // Q3
else if (y > 0 && z > 0) lightLeds(y, z, 20, 23, 89, 0); // Q4
}
void lightLeds(int y, int z, int fromLed, int toLed, int fromAng, int toAng) {
// Winkel im Quadranten berechnen: atan(|y|/|z|) → 0–89°
double angle = (atan((double)abs(y) / abs(z)) * 4068) / 71; // ≈ *180/PI
int led = map(angle, fromAng, toAng, fromLed, toLed);
// Debug-Ausgabe alle 500 ms
static unsigned long lastPrint=0;
if (millis()-lastPrint > 500) {
Serial.print("a=");Serial.print(angle);Serial.print("; ll=");Serial.print(led);
Serial.print("; y=");Serial.print(y);Serial.print("; z=");Serial.println(z);
lastPrint = millis();
}
// LEDs setzen: Haupt-LED grün, Nachbarn dimmgrün, Rest aus
for (int i=0; i
Wichtige Kalibrierung: LED_OFFSET
Da der NeoPixel-Ring mechanisch beliebig zum MPU ausgerichtet sein kann, verschiebt LED_OFFSET (0–23) die Anzeige. Nach dem Start den Ring so drehen, dass die leuchtende LED genau in Richtung der Neigung zeigt, dann Wert notieren und im Code fest einbauen.
Funktionsweise im Detail
MPU-6050 & DMP
Der MPU-6050 ist ein MEMS-Sensor (Microelectromechanical Systems). Er enthält schwingende Masseelemente; Beschleunigung/Drehung ändert die Schwingungsebene (Corolis-Effekt). Ein interner Prozessor berechnet daraus Orientierung. Rohdaten sind verrauscht & driften. Die DMP (Digital Motion Processor) führt Sensorfusion (Gyro + Accel) durch und liefert stabile Quaternionen → Euler-Winkel (Yaw, Pitch, Roll).
NeoPixel-Ring
24 WS2812-LEDs in Kette. Ein Datenpin (D6) steuert alle über zeitkritisches Protokoll (800 kHz). Adafruit-Library übernimmt Timing.
Mathematik der LED-Position
Der Schwerkraftvektor projiziert auf die X-Y-Ebene des Rings ergibt einen Winkel. Der Ring wird in 4 Quadranten à 6 LEDs geteilt. In jedem Quadranten wird der Winkel via atan(|Pitch|/|Roll|) berechnet und auf den LED-Index gemappt. Ein Nachbar-LED wird gedimmt für weichen Übergang.
Erweiterungsideen
- Farbliche Kodierung der Neigungsstärke (grün → gelb → rot).
- Yaw mit einbeziehen (z. B. Drehung = Farbwechsel).
- Batteriesparmodus (Sleep zwischen Messungen).
- Gehäuse drucken → tragbares Neigungsinstrument.
- Mehrere Ringe für 3D-Visualisierung (Kugel).
Herstellungsprozess
- Echtzeit-Gyroskop-Spiel mit Arduino Nano & MPU-6050
- Stilvolle Wanduhr mit Adafruit 60-LED Neopixel-Ring & Arduino
- K30 CO₂-Sensor: Echtzeit-Luftqualitätsmessung mit Arduino
- Kommunikationshilfe für Taubblinde: 1Sheeld + Arduino + Sprachausgabe & Anzeige
- DIY Arduino USB Gaming Controller – Bauen Sie Ihren eigenen High-Performance Gamepad
- Smartes Sparschwein: Münzprüfer mit Arduino Nano steuern
- Pixie: DIY NeoPixel-Armbanduhr mit Arduino Pro Mini – Schick & Selbstgebaut
- LED per Bluetooth mit Arduino steuern – Einfache DIY-Anleitung
- DFRobot Kapazitiver Fingerabdrucksensor mit Arduino oder ESP8266 einbinden
- Spracherkennung & Sprachsynthese auf Arduino Due meistern