Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Afbeeldingen maken met één LED

Componenten en benodigdheden

NEMA17 stappenmotor
× 2
Theremino Driver DRV8825 voor stappenmotoren voor Theremino-systeem
× 2
SD-kaartlezer
× 1
Arduino Mega 2560
× 1
Diverse distributieriemen en v-wielen
× 1

Benodigde gereedschappen en machines

3D-printer (algemeen)

Apps en online services

Arduino IDE
GIMP
Autodesk Fusion 360

Over dit project

Idee

Na het bekijken van verschillende video's en het zien van talloze artikelen over lichtschilderen, besloot ik het eens te proberen. Bij lightpainting wordt een camera met een zeer lange belichtingstijd gebruikt om een ​​kleine lichtbron vast te leggen. Hierdoor kan een enkele lichtstraal in een enkele afbeelding worden uitgespreid tot een lange streep.

Maar wat als iemand een meer gedetailleerde foto wil maken of veel verschillende kleuren wil gebruiken? Zo kwam ik op het idee om een ​​2-assige CNC-machine te bouwen die een enkele RGB-LED heeft die van kleur kan veranderen en een afbeelding kan "schilderen".

Het plan

Dit project zou vier hoofdcomponenten nodig hebben om te werken:een 2-assige CNC-machine, RGB-LED, SD-kaart en een camera die in staat is om opnamen met een lange belichtingstijd te maken. Eerst zou de Arduino Mega de SD-kaart lezen en een bitmap vinden om af te drukken.

Dan zou het horizontaal overgaan en de bijbehorende LED's oplichten, terwijl het ook een rij naar beneden gaat telkens wanneer de breedte van het beeld wordt overschreden. Ten slotte wacht het even en zoekt dan naar de volgende bitmap, en stopt uiteindelijk wanneer er geen afbeeldingen meer kunnen worden gemaakt.

De installatie bouwen

Door mijn ervaring met het ontwerpen en bouwen van een CNC-machine was deze stap niet al te moeilijk. Ik wilde iets modulairs maken dat ook voor andere projecten kon worden uitgebreid, dus koos ik voor een eenvoudig ontwerp dat gebruikmaakt van twee distributieriemen die zijn bevestigd aan dwarsbalken die langs parallelle aluminium profielen bewegen.

Hierdoor kan de lengte van elke as zeer aanpasbaar zijn. De uiteinden van de X-as hebben 3D-geprinte eindkappen, waarvan er één een houder heeft voor de X-as stappenmotor en lager.

Bitmaps lezen

Ik koos voor het bitmap-bestandsformaat vanwege de eenvoud en hoe gemakkelijk het kan worden gelezen. Op basis van het bestandsformaat zijn er enkele belangrijke adressen in het bestand zelf die gelezen moeten worden. Dit zijn 0x12 (breedte), 0x16 (hoogte), 0x1C (kleurdiepte), 0xA (locatie van pixelgegevens) en ten slotte 0x36 (waar de pixelgegevens gewoonlijk zijn).

De gegevens worden gelezen in blokken van twee of vier bytes (16 of 32 bits), waardoor de aanwijzer ook naar het volgende adres gaat. De leesfunctie gaat door en pakt alle belangrijke gegevens, inclusief offsets en maten. Dan gaat het door en leest elke pixel, rij voor rij.

De afbeeldingen voorbereiden

Aangezien de meeste camera's een maximale belichtingstijd van 30 seconden hebben, is er een limiet van ongeveer 288 pixels die in die tijd kunnen worden weergegeven. Dit komt overeen met een afbeelding van ongeveer 18 x 16. Om mijn afbeeldingen te maken, laadde ik gimp op en begon ik heel eenvoudige pixelart te maken. Deze omvatten een Pokéball, hart en een springende Mario. Vervolgens plaatste ik deze drie afbeeldingen in een map met de naam "bitmaps" in de hoofdmap van de SD-kaart. Het programma leest alle afbeeldingen uit deze map.

Schilderprogramma

Aangezien stappenmotoren geen intern feedbacksysteem voor positionering hebben, moeten hun posities worden gevolgd door software. Het programma dat ik heb geschreven houdt de positie van de LED bij met een rastersysteem om gemakkelijk te kunnen schalen. Wanneer de Arduino Mega opstart, worden de stepperposities ingesteld op 0, 0 en wordt het eerste beeld gevonden en gelezen. Vervolgens knippert de LED vijf keer om de fotograaf te laten weten dat het bijna tijd is om te beginnen met fotograferen. De bitmap wordt gelezen door eerst elke rij te doorlopen en binnen elke rij wordt elke kolom gelezen. Door de huidige rij en kolom te kennen, kunnen de stappenmotoren naar diezelfde posities worden verplaatst. Op elke positie wordt de LED veranderd in de kleur van die corresponderende pixel.

(Her)-Creëren van een afbeelding

Na het plaatsen van de SD-kaart en het aansluiten van een 12v-stroombron voor de motoren, was het tijd om de machine aan te zetten. Op mijn camera heb ik deze ingesteld op een belichtingstijd van 20 seconden, een diafragma van F36, ISO van 100 en een belichtingscompensatie van -5 stops om nevenbeelden te minimaliseren. De eerste getekende afbeelding was een pokeball, hier te zien:

Hoewel het een beetje wazig is, is de vorm nog steeds duidelijk te zien. Daarna maakte het een hartbitmap:

Omdat deze afbeelding slechts 9 bij 9 pixels was, is elke afzonderlijke pixel een stuk minder gedefinieerd. Ten slotte schilderde ik een foto van Mario die springt:

Deze foto heeft zware nevenbeelden, voornamelijk vanwege de overvloed aan felgekleurde pixels.

Toekomstige ideeën voor verbeteringen

De lichtschilderijen die ik heb gemaakt, zijn veel beter geworden dan ik aanvankelijk had gedacht, maar er is nog ruimte voor verbetering. Het belangrijkste dat ik zou willen doen, is de hoeveelheid onscherpte verminderen door de LED te laten bewegen terwijl hij donker is en alleen op te lichten als hij stil is. Deze techniek zou de helderheid van de opnieuw gemaakte afbeeldingen aanzienlijk verbeteren.

Code

  • Lichtschilderprogramma
LichtschilderprogrammaC/C++
//Bitmap-leesfunctie gedeeltelijk van Adafruit#include #include #include "DRV8825.h"#define MOTOR_STEPS 200#define RPM 150#define MICROSTEPS 4//pin definitions#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 /#_FLAG 1 om de richting om te draaien 1 of -1 om van richting te veranderen#define STEPS_PER_MM (3,75 * MICROSTEPS) //stappen nodig om 1 mm te verplaatsen#define SPACE_BETWEEN_POSITIONS 5 //5mm per beweging#define R A0#define G A1#define B A2#define SD_CS 22int 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); ongeldige setup(115 serieel). init_steppers(); SD.begin(SD_CS); createBitmaps(); stepperX.uitschakelen(); stepperY.disable(); while(1);}void loop() {}void createBitmaps(){ File dir =SD.open("bitmaps"); while(true){ Bestand bitmap =dir.openNextFile(); if(!bitmap){ breken; } paintBitmap(bitmap); vertraging (15000); } }#define BUFFPIXEL 20void paintBitmap(File bmpFile){ int bmpWidth, bmpHeight; uint8_t bmpDepth; uint32_t bmpImageOffset; uint32_t rijSize; // Niet altijd =bmpWidth; heeft mogelijk opvulling uint8_t sdbuffer [3 * BUFFPIXEL]; // pixelbuffer (R+G+B per pixel) uint8_t buffidx =sizeof(sdbuffer); // Huidige positie in sdbuffer boolean goodBmp =false; // Ingesteld op true op geldige header parse boolean flip =true; // BMP wordt van onder naar boven opgeslagen int w, h, rij, col; uint8_t r, g, b; uint32_t pos =0, startTime =millis(); Serieel.println(); Serial.print("Beeld laden '"); Serial.print(bmpFile.name()); Serieel.println('\''); // Open het gevraagde bestand op SD-kaart // Parse BMP-header if (read16 (bmpFile) ==0x4D42) { // BMP-handtekening Serial.print ("Bestandsgrootte:"); Serial.println(read32(bmpFile)); (void)read32(bmpFile); // Lezen en negeren schepper bytes bmpImageOffset =read32 (bmpFile); // Begin van afbeeldingsgegevens Serial.print ("Beeldverschuiving:"); Serial.println(bmpImageOffset, DEC); // Lees DIB-header Serial.print ("Headergrootte:"); Serial.println(read32(bmpFile)); bmpWidth =read32(bmpFile); bmpHeight =read32(bmpFile); if (read16(bmpFile) ==1) { // # planes -- moet '1' zijn bmpDepth =read16(bmpFile); // bits per pixel Serial.print ("Bitdiepte:"); Serial.println(bmpDepth); if ((bmpDepth ==24) &&(read32(bmpFile) ==0)) { // 0 =ongecomprimeerd goodBmp =true; // Ondersteund BMP-formaat -- ga verder! Serial.print("Afbeeldingsgrootte:"); Serial.print(bmpWidth); Serieel.print('x'); Serial.println(bmpHeight); // BMP-rijen worden opgevuld (indien nodig) tot 4-byte grens rowSize =(bmpWidth * 3 + 3) &~3; // Als bmpHeight negatief is, staat de afbeelding in de volgorde van boven naar beneden. // Dit is geen canon, maar is in het wild waargenomen. if (bmpHeight <0) { bmpHeight =-bmpHeight; omdraaien =onwaar; } // Te laden gewasgebied w =bmpWidth; h =bmpHoogte; if(bmpWidth*bmpHeight>290){ //Too large Serial.println("Bestand is te groot om te worden afgedrukt."); opbrengst; } for(uint8_t i=0; i<5;i++){ analogWrite(R, 150); vertraging (500); analoogWrite(R, 0); vertraging (500); } for (row =0; row=sizeof(sdbuffer)) {// Inderdaad bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffx =0; // Stel index in op begin } // Converteer pixel van BMP naar TFT-formaat, druk op om b =sdbuffer [buffidx++] weer te geven; g =sdbuffer[buffidx++]; r =sdbuffer[buffidx++]; moveToPosition(col, rij); activeLED(r,g,b); // geoptimaliseerd! //tft.pushColor(tft.Color565(r,g,b)); } // eindpixel analogWrite (R, 0); analoogWrite(G, 0); analoogWrite(B, 0); } // end scanline Serial.print ("Geladen in "); Serial.print(millis() - startTime); Serial.println ("ms"); } // end goodBmp } } bmpFile.close(); moveToPosition(0,0); if (!goodBmp) Serial.println("BMP-formaat niet herkend.");}uint16_t read16(File f) { uint16_t resultaat; ((uint8_t *)&result)[0] =f.lezen(); // LSB ((uint8_t *)&result)[1] =f.read(); // MSB retourneert resultaat;} uint32_t read32 (File f) { uint32_t resultaat; ((uint8_t *)&result)[0] =f.lezen(); // LSB ((uint8_t *)&result)[1] =f.read(); ((uint8_t *)&result)[2] =f.read(); ((uint8_t *)&result)[3] =f.read(); // MSB retourneert resultaat;} ongeldig activeLED (int r, int g, int b) {Serial.print (F ("LED heeft waarde van:")); Serieafdruk(r); Serieel.print(", "); Serieafdruk(g); Serieel.print(", "); Serieel.println(b); analoogWrite(R, r); analoogWrite(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); huidigePosities[X] =x; huidigePosities[Y] =y; Serial.print("Stepper posities:"); Serial.print(currentPosities[X]); Serieel.print(", "); Serial.println(currentPositions[Y]);}void init_steppers(){ stepperX.begin(RPM); stepperX.setEnableActiveState(LAAG); stepperX.enable(); stepperX.setMicrostep(MICROSTEPS); stepperY.begin(RPM); stepperY.setEnableActiveState (LAAG); stepperY.enable(); stepperY.setMicrostep(MICROSTEPS);}

Aangepaste onderdelen en behuizingen

Schema's


Productieproces

  1. Wat heeft ons ertoe gebracht om natuurlijke materialen te gebruiken in productontwerp?
  2. Bewegingssensor met Raspberry Pi
  3. Een handleiding voor onderhoudsmanagers voor het maken en gebruiken van FMEA's
  4. Stuur sensorgegevens van de ene Arduino naar de andere met Firebase
  5. Verwissel twee Python-variabelen zonder een derde te gebruiken
  6. Coffin Dance Melody
  7. Oude afstandsbedieningen hergebruiken
  8. Bedien Arduino Rover met Firmata en Xbox One Controller
  9. 8x LED-verlichting door geluid
  10. Arduino Quadruped
  11. Gegevensoverdracht met LED-licht (Li-Fi)