Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Componentes y materiales

Herramientas y máquinas necesarias

Aplicaciones y servicios online

Sobre el proyecto

Idea

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Tras ver varios videos y artículos sobre pintura de luz, decidí probarlo. La pintura de luz usa una cámara con exposición muy larga para capturar una pequeña fuente de luz, convirtiendo un punto de luz en una estela larga en una sola imagen.

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Pero, ¿qué pasa si alguien quiere crear una imagen más detallada o usar muchos colores? Así surgió la idea de construir una máquina CNC de 2 ejes con un solo LED RGB que cambie de color y "pinte" una imagen.

El Plan

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

El proyecto requiere cuatro componentes principales: una máquina CNC de 2 ejes, un LED RGB, una tarjeta SD y una cámara capaz de tomas de larga exposición. Primero, el Arduino Mega lee la tarjeta SD y busca un bitmap para imprimir. Luego recorre horizontalmente encendiendo los LEDs correspondientes mientras baja una fila cada vez que supera el ancho de la imagen. Finalmente espera y busca el siguiente bitmap, deteniéndose cuando no hay más imágenes.

Construcción de la estructura

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY
Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Gracias a mi experiencia diseñando máquinas CNC, este paso no fue difícil. Quería algo modular y expandible, así que usé un diseño simple con dos correas dentadas unidas a travesaños que se mueven sobre perfiles de aluminio paralelos. Esto permite personalizar mucho la longitud de cada eje. Los extremos del eje X tienen tapas impresas en 3D, una con soporte para el motor y rodamiento del eje X.

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Lectura de Bitmaps

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Elegí el formato bitmap por su simplicidad y facilidad de lectura. Según el formato, hay direcciones importantes en el archivo: 0x12 (ancho), 0x16 (alto), 0x1C (profundidad de color), 0xA (ubicación de datos de píxeles) y 0x36 (inicio típico de datos de píxeles). Los datos se leen en bloques de 2 o 4 bytes (16 o 32 bits), avanzando el puntero. La función de lectura obtiene todos los datos importantes, incluyendo offsets y tamaños, y luego lee cada píxel fila por fila.

Preparación de las imágenes

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Como la mayoría de cámaras limitan la exposición a 30 segundos, hay un límite de ~288 píxeles totales en ese tiempo, equivalentes a una imagen de ~18x16 píxeles. Creé arte pixel simple en GIMP: una Pokéball, un corazón y Mario saltando. Los coloqué en una carpeta "bitmaps" en la raíz de la tarjeta SD. El programa lee todas las imágenes de esta carpeta.

Programa de Pintura

Como los motores paso a paso no tienen retroalimentación de posición interna, sus posiciones deben trackearse por software. Mi programa usa un sistema de cuadrícula para rastrear la posición del LED y permitir escalado fácil. Al iniciar, las posiciones de los steppers se ponen a 0,0 y se lee la primera imagen. El LED parpadea 5 veces para avisar al fotógrafo que es hora de empezar la captura. El bitmap se lee recorriendo cada fila y dentro de cada fila cada columna. Conociendo la fila y columna actual, los motores mueven el LED a esa posición y cambian su color al del píxel correspondiente.

(Re)Creando una imagen

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Tras insertar la tarjeta SD y conectar 12V para los motores, encendí la máquina. En la cámara: exposición 20s, apertura F36, ISO 100, compensación -5 EV para minimizar ghosting. La primera imagen fue una Pokéball. Aunque un poco borrosa, la forma se ve clara.

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Luego creó un corazón (9x9 píxeles), donde cada píxel se define menos.

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Finalmente, Mario saltando. Esta imagen tiene mucho ghosting por la abundancia de píxeles brillantes.

Ideas futuras para mejoras

Los resultados fueron mejores de lo esperado, pero hay margen de mejora. Lo principal: reducir el desenfoque haciendo que el LED se mueva apagado y solo se encienda cuando está quieto. Esta técnica mejorarían enormemente la nitidez.

Código

Programa de Pintura de Luz (C/C++)

// Lectura de bitmap parcialmente de Adafruit
#include <SD.h>
#include <SPI.h>
#include "DRV8825.h"
#define MOTOR_STEPS 200
#define RPM 150
#define MICROSTEPS 4
// Definiciones de pines
#define STEPPER_X_DIR 7
#define STEPPER_X_STEP 6
#define STEPPER_X_EN 8
#define STEPPER_Y_DIR 4
#define STEPPER_Y_STEP 5
#define STEPPER_Y_EN 12
#define X 0
#define Y 1
#define X_DIR_FLAG -1
#define Y_DIR_FLAG 1
#define STEPS_PER_MM (3.75 * MICROSTEPS)
#define SPACE_BETWEEN_POSITIONS 5
#define R A0
#define G A1
#define B A2
#define SD_CS 22

int currentPositions[] = {0, 0};
DRV8825 stepperX(MOTOR_STEPS, STEPPER_X_DIR, STEPPER_X_STEP, STEPPER_X_EN);
DRV8825 stepperY(MOTOR_STEPS, STEPPER_Y_DIR, STEPPER_Y_STEP, STEPPER_Y_EN);

void setup() {
  Serial.begin(115200);
  init_steppers();
  SD.begin(SD_CS);
  createBitmaps();
  stepperX.disable();
  stepperY.disable();
  while(1);
}

void loop() { }

void createBitmaps(){
  File dir = SD.open("bitmaps");
  while(true){
    File bitmap = dir.openNextFile();
    if(!bitmap){ break; }
    paintBitmap(bitmap);
    delay(15000);
  }
}

#define BUFFPIXEL 20
void paintBitmap(File bmpFile){
  int bmpWidth, bmpHeight;
  uint8_t bmpDepth;
  uint32_t bmpImageOffset;
  uint32_t rowSize;
  uint8_t sdbuffer[3 * BUFFPIXEL];
  uint8_t buffidx = sizeof(sdbuffer);
  boolean goodBmp = false;
  boolean flip = true;
  int w, h, row, col;
  uint8_t r, g, b;
  uint32_t pos = 0, startTime = millis();
  
  Serial.println();
  Serial.print("Loading image '");
  Serial.print(bmpFile.name());
  Serial.println("'");

  if (read16(bmpFile) == 0x4D42) {
    Serial.print("File size: "); Serial.println(read32(bmpFile));
    (void)read32(bmpFile);
    bmpImageOffset = read32(bmpFile);
    Serial.print("Image Offset: "); Serial.println(bmpImageOffset, DEC);
    Serial.print("Header size: "); Serial.println(read32(bmpFile));
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) {
      bmpDepth = read16(bmpFile);
      Serial.print("Bit Depth: "); Serial.println(bmpDepth);
      if ((bmpDepth == 24) && (read32(bmpFile) == 0)) {
        goodBmp = true;
        Serial.print("Image size: "); Serial.print(bmpWidth); Serial.print('x'); Serial.println(bmpHeight);
        rowSize = (bmpWidth * 3 + 3) & ~3;
        if (bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; }
        w = bmpWidth; h = bmpHeight;
        if(bmpWidth*bmpHeight > 290){
          Serial.println("File is too large to be printed."); return;
        }
        for(uint8_t i=0; i<5; i++){
          analogWrite(R, 150); delay(500); analogWrite(R, 0); delay(500);
        }
        for (row = 0; row < h; row++) {
          moveToPosition(0, row);
          if (flip) pos = bmpImageOffset + (bmpHeight - 1 - row) * rowSize;
          else pos = bmpImageOffset + row * rowSize;
          if (bmpFile.position() != pos) {
            bmpFile.seek(pos); buffidx = sizeof(sdbuffer);
          }
          for (col = 0; col < w; col++) {
            if (buffidx >= sizeof(sdbuffer)) {
              bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0;
            }
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            moveToPosition(col, row);
            activateLED(r,g,b);
          }
          analogWrite(R, 0); analogWrite(G, 0); analogWrite(B, 0);
        }
        Serial.print("Loaded in "); Serial.print(millis() - startTime); Serial.println(" ms");
      }
    }
  }
  bmpFile.close();
  moveToPosition(0,0);
  if (!goodBmp) Serial.println("BMP format not recognized.");
}

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read();
  ((uint8_t *)&result)[1] = f.read();
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read();
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read();
  return result;
}

void activateLED(int r, int g, int b){
  Serial.print(F("LED has value of: ")); Serial.print(r); Serial.print(", "); Serial.print(g); Serial.print(", "); Serial.println(b);
  analogWrite(R, r); analogWrite(G, g); analogWrite(B, b);
}

void moveToPosition(int x, int y){
  int newPosX = (x-currentPositions[X])*STEPS_PER_MM*X_DIR_FLAG*SPACE_BETWEEN_POSITIONS;
  int newPosY = (y-currentPositions[Y])*STEPS_PER_MM*Y_DIR_FLAG*SPACE_BETWEEN_POSITIONS;
  stepperX.move(newPosX);
  stepperY.move(newPosY);
  currentPositions[X] = x;
  currentPositions[Y] = y;
  Serial.print("Stepper positions: "); Serial.print(currentPositions[X]); Serial.print(", "); Serial.println(currentPositions[Y]);
}

void init_steppers(){
  stepperX.begin(RPM); stepperX.setEnableActiveState(LOW); stepperX.enable(); stepperX.setMicrostep(MICROSTEPS);
  stepperY.begin(RPM); stepperY.setEnableActiveState(LOW); stepperY.enable(); stepperY.setMicrostep(MICROSTEPS);
}

Piezas personalizadas y envolventes

Archivos CAD disponibles en el proyecto original.

Esquemáticos

Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY

Proceso de manufactura

  1. Dominando el AMFE: Guía paso a paso para gerentes de mantenimiento para construir y usar Análisis de Modos de Falla y Efectos
  2. Por qué los diseñadores vuelven a los materiales naturales en el diseño de productos
  3. Controle un LED con Sensor PIR de Movimiento en Raspberry Pi
  4. Transferir datos de temperatura y humedad entre dos Arduinos usando Firebase
  5. Proyecto Arduino Melodía Coffin Dance: Construya y Reproduzca el Viral Tune
  6. Revitaliza mandos a distancia antiguos: Crea dispositivos inteligentes DIY con Arduino
  7. Controla un Rover Arduino con Firmata y Mando Xbox One - Guía Completa
  8. Pantalla de 8 LED activada por sonido con Arduino
  9. Construye un Robot Cuadrúpedo Inteligente con Arduino: Guía Paso a Paso
  10. Transferencia Inalámbrica de Datos por LED (Li-Fi) con Arduino
  11. Intercambie dos variables Python sin variable temporal: fácil y limpio