Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino

Компоненты и материалы

SparkFun Arduino Pro Mini 328 — 5V/16MHz × 1 шт.
Adafruit NeoPixel Ring: WS2812 5050 RGB LED (24 пикселя) × 1 шт.
SparkFun IMU Breakout — MPU-9250 (используется как MPU6050) × 1 шт.
Макетная плата (breadboard) × 1 шт.
Перемычки Male/Male × 1 комплект
Перемычки Male/Female × 1 комплект
Кейс для 4×AA батареек + батарейки × 1 шт.

О проекте

В этом уроке мы используем гироскоп MPU6050, кольцо NeoPixel и Arduino для создания устройства, которое зажигает светодиоды, соответствующие углу наклона. Простой и зрелищный проект на макетной плате. Хороший способ изучить работу с гироскопом и NeoPixel Ring.

Автор заменил в своём раннем проекте отдельные светодиоды на NeoPixel Ring — проще через библиотеку Adafruit и выглядит впечатляюще. Если у вас есть эти компоненты — отличный способ их применить. Пошаговая инструкция сборки и объяснение принципа работы в конце.

Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino

Шаг 1: Необходимые детали и инструменты

Детали

  1. Arduino Pro Mini 328P
  2. Макетная плата
  3. Гироскоп MPU6050
  4. NeoPixel LED Ring (24 светодиода)
  5. Кейс 4×AA с батарейками

Инструменты

  1. USB-Serial адаптер FTDI (FT232RL) для прошивки Pro Mini
  2. Arduino IDE

Навыки

  1. Паяльник
  2. Базовое программирование Arduino

Шаг 2: Сборка

Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino
Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino

Схема в формате Fritzing (.fzz) и фото для наглядности прилагаются.

  1. Припаяйте 3 малевых пина на обратной стороне NeoPixel Ring (как на фото): питание (+), земля (GND), данные (Data In).
  2. К батарейному отсеку припаяйте два дупоновских провода для подключения к макетке.
  3. Разместите компоненты на макетке как на изображении:
    • Все отрицательные провода: к микроконтроллеру, NeoPixel, гироскопу
    • Все положительные провода: к микроконтроллеру, NeoPixel, гироскопу
    • Данные: SDA и SCL от микроконтроллера к гироскопу; D6 от микроконтроллера к NeoPixel
  4. Дважды проверьте все соединения перед подачей питания.
  5. Опционально: закрепите батарейный отсек на задней стороне макетки скотчем — для переносимости.

Шаг 3: Код и калибровка

Сначала установите две библиотеки:

  1. Adafruit NeoPixel — управление лентой/кольцом
  2. MPU6050 — для гироскопе (библиотека MPU6050_6Axis_MotionApps20.h с DMP)

Затем скачайте/скопируйте код автора (ниже или GitHub).

Загрузка кода

Через FTDI-адаптер загрузите скетч в Arduino Pro Mini.

Питание и калибровка

Подключите батарейный отсек. Главная калибровка — константа LED_OFFSET (в примере 12). Подбирайте от 0 до 23 так, чтобы после включения загорался тот светодиод, в сторону которого наклонена плата.

Подробности работы — в следующем шаге.

#include "I2Cdev.h"
#include 
#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; // КАЛИБРОВКА: 0-23

MPU6050 mpu;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NEOPIXED_CONTROL_PIN, NEO_GRB + NEO_KHZ800);

unsigned long lastPrintTime = 0;
bool initialization = false;
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
volatile bool mpuInterrupt = false;

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, -MAX_ANGLE, MAX_ANGLE);
    y = constrain(y, -MAX_ANGLE, MAX_ANGLE);

    if (y < 0 && z > 0)       { lightLeds(y, z, 0, 5, 0, 89); }
    else if (y < 0 && z < 0)  { lightLeds(y, z, 6, 12, 89, 0); }
    else if (y > 0 && z < 0)  { lightLeds(y, z, 13, 19, 0, 89); }
    else if (y > 0 && z > 0)  { lightLeds(y, z, 20, 24, 89, 0); }
}

void lightLeds(int x, int y, int fromLed, int toLed, int fromAngle, int toAngle) {
    double angle = (atan((double)abs(x) / (double)abs(y)) * 4068) / 71;
    int ledNr = map(angle, fromAngle, toAngle, fromLed, toLed);
    printDebug(y, z, 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; // 400kHz I2C
    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 = mpq.dmpGetFIFOPacketSize();
    return true;
}

void dmpDataReady() {
    mpuInterrupt = true;
}

Шаг 4: Как это работает (опционально)

Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino

MPU6050 — MEMS-гироскоп

MEMS (Microelectromechanical systems). Внутри — колебательный элемент. По закону сохранения импульса вибрирующий объект стремится продолжать вибрацию в той же плоскости; отклонение вибрации позволяет определить изменение направления. Внутренний микроконтроллер вычисляет roll, pitch, yaw. Сырые данные шумны и дрейфуют — библиотека DMP (Digital Motion Processor) сглаживает и выдаёт чистые данные.

NeoPixel

RGB-светодиоды с индивидуальной адресацией, цепочкой в кольца/ленты. Работают от 5V, содержат свой драйвер — нужно только питание и одна линия данных (с встроенным тактированием). Библиотека Adafruit даёт удобный API.

Алгоритм кода

В loop() библиотека MPU6050_6Axis_MotionApps20 при новых данных вызывает redrawLeds(yaw, pitch, roll).

В redrawLeds():

В lightLeds():

Математика

На схеме показано кольцо и тригонометрическая функция для определения угла.

Код

GitHub репозиторий с полным кодом

Схемы

Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino
sketch_gMlSrk3rCX.fzz

Производственный процесс

  1. Создание игры в реальном времени на Arduino Nano с гироскопом MPU-6050 и OLED-дисплеем
  2. Стильные настенные часы на четырех кольцах Adafruit Neopixel 60 LED и Arduino
  3. Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
  4. Устройство для общения глухосліпых людей с помощью 1Sheeld и Arduino
  5. DIY USB-геймпад на Arduino: собственный высокопроизводительный контроллер
  6. Умная копилка: управление монетоприёмником на Arduino Nano
  7. Pixie: DIY-наручные часы на Arduino Pro Mini и NeoPixel — стильный светодиодный тахометр времени
  8. Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
  9. Интеграция ёмкостного сканера отпечатков DFRobot с Arduino или ESP8266
  10. Освоение распознавания и синтеза речи на Arduino Due