Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

Membuat Gambar Menggunakan Satu LED

Komponen dan persediaan

Motor Stepper NEMA17
× 2
Driver Theremino DRV8825 untuk Motor Stepper untuk Sistem Theremino
× 2
pembaca kartu SD
× 1
Arduino Mega 2560
× 1
Berbagai timing belt dan v-wheels
× 1

Alat dan mesin yang diperlukan

Printer 3D (generik)

Aplikasi dan layanan online

Arduino IDE
GIMP
Autodesk Fusion 360

Tentang proyek ini

Ide

Setelah menonton beberapa video dan melihat banyak artikel tentang lukisan cahaya, saya memutuskan untuk mencobanya. Lukisan cahaya melibatkan penggunaan kamera dengan waktu pencahayaan yang sangat lama untuk menangkap sumber cahaya yang kecil. Hal ini memungkinkan satu cahaya menjadi terangkai menjadi guratan panjang dalam satu gambar.

Tetapi bagaimana jika seseorang ingin membuat gambar yang lebih detail atau menggunakan banyak warna berbeda? Beginilah cara saya mendapatkan ide untuk membuat mesin CNC 2 sumbu yang memiliki LED RGB tunggal yang dapat mengubah warna dan "melukis" gambar.

Rencana

Proyek ini akan membutuhkan empat komponen utama untuk bekerja:mesin CNC 2 sumbu, LED RGB, kartu SD, dan kamera yang mampu mengambil bidikan dengan eksposur lama. Pertama, Arduino Mega akan membaca kartu SD dan menemukan bitmap untuk dicetak.

Kemudian, itu akan melintasi secara horizontal dan menyalakan LED yang sesuai sambil juga bergerak ke bawah satu baris setiap kali lebar gambar terlampaui. Terakhir, ia akan menunggu sebentar dan kemudian mencari bitmap berikutnya, akhirnya berhenti setiap kali tidak ada lagi gambar untuk dibuat.

Membangun Rig

Karena pengalaman saya merancang dan membangun mesin CNC, langkah ini tidak terlalu sulit. Saya ingin membuat sesuatu yang modular yang juga dapat diperluas untuk proyek lain, jadi saya memilih desain sederhana yang menggunakan dua timing belt yang dipasang pada palang yang bergerak di sepanjang ekstrusi aluminium paralel.

Ini memungkinkan panjang setiap sumbu sangat dapat disesuaikan. Ujung sumbu X memiliki penutup ujung yang dicetak 3D, salah satunya memiliki dudukan untuk motor stepper sumbu X dan bantalan.

Membaca Bitmap

Saya memilih format file bitmap karena kesederhanaannya dan betapa mudahnya untuk dibaca. Berdasarkan format file, ada beberapa alamat penting dalam file itu sendiri yang harus dibaca. Ini adalah 0x12 (lebar), 0x16 (tinggi), 0x1C (kedalaman warna), 0xA (lokasi data piksel), dan terakhir 0x36 (tempat data piksel biasanya berada).

Data dibaca dalam potongan dua atau empat byte (16 atau 32 bit), yang juga memajukan penunjuk ke alamat berikutnya. Fungsi baca melewati dan mengambil semua data penting, termasuk offset dan ukuran. Kemudian ia melewati dan membaca setiap piksel, baris demi baris.

Mempersiapkan Gambar

Karena sebagian besar kamera dibatasi hingga maksimum 30 detik waktu pencahayaan, ada batas sekitar 288 piksel total yang dapat ditampilkan dalam jumlah waktu tersebut. Ini setara dengan sekitar gambar 18 x 16. Untuk membuat gambar saya, saya memuat gimp dan mulai membuat seni piksel yang sangat sederhana. Ini termasuk Pokéball, hati, dan Mario yang melompat. Kemudian saya menempatkan ketiga gambar ini ke dalam direktori yang disebut "bitmaps" di direktori root kartu SD. Program membaca semua gambar dari folder ini.

Program Melukis

Karena motor stepper tidak memiliki sistem umpan balik pemosisian internal, posisinya harus dilacak oleh perangkat lunak. Program yang saya tulis melacak posisi LED dengan sistem grid untuk memudahkan penskalaan. Ketika Arduino Mega dinyalakan, posisi stepper diatur ke 0, 0 dan kemudian gambar pertama ditemukan dan dibaca. Kemudian, LED berkedip lima kali untuk memberi tahu fotografer bahwa sudah hampir waktunya untuk mulai memotret. Bitmap dibaca dengan perulangan pertama melalui setiap baris, dan di dalam setiap baris, setiap kolom dibaca. Dengan mengetahui baris dan kolom saat ini, motor stepper dapat dipindahkan ke posisi yang sama. Di setiap posisi, LED diubah menjadi warna piksel yang sesuai.

(kembali)-Membuat Gambar

Setelah memasukkan kartu SD dan mencolokkan sumber daya 12v untuk motor, saatnya untuk menghidupkan mesin. Pada kamera saya, saya mengaturnya untuk waktu eksposur 20 detik, aperture F36, ISO 100, dan kompensasi eksposur -5 stop untuk meminimalkan efek ghosting. Gambar pertama yang diambil adalah pokeball, lihat di sini:

Meski agak buram, bentuknya masih bisa terlihat jelas. Kemudian ia membuat bitmap hati:

Karena gambar ini hanya berukuran 9 kali 9 piksel, setiap piksel individu jauh lebih sedikit didefinisikan. Terakhir, saya melukis gambar Mario melompat:

Gambar ini memiliki ghosting yang tinggi, terutama karena banyaknya piksel berwarna cerah.

Ide Masa Depan untuk Perbaikan

Lukisan cahaya yang saya buat ternyata jauh lebih baik daripada yang saya kira sebelumnya, tetapi masih ada ruang untuk perbaikan. Hal utama yang ingin saya lakukan adalah mengurangi jumlah keburaman dengan membuat LED bergerak saat gelap dan kemudian hanya menyala saat diam. Teknik ini akan sangat meningkatkan kejernihan gambar yang dibuat ulang.

Kode

  • Program Lukisan Cahaya
Program Lukisan RinganC/C++
//Fungsi pembacaan bitmap sebagian dari Adafruit#include #include #include "DRV8825.h"#define MOTOR_STEPS 200#define RPM 150#define MICROSTEPS 4//pin definition#define STEPPER_X_DIR 7#menentukan STEPPER_X_STEP 6#menentukan STEPPER_X_EN 8#menentukan STEPPER_Y_DIR 4#menentukan STEPPER_Y_STEP 5#menentukan STEPPER_Y_EN 12#menentukan X 0#menentukan Y 1#menentukan X_DIR_FLAG-1 untuk membalik arah -1 Y//1# 1 atau -1 untuk membalik arah#menentukan STEPS_PER_MM (3,75 * MICROSTEPS) //langkah yang diperlukan untuk memindahkan 1mm#menentukan SPACE_BETWEEN_POSITIONS 5 //5mm per gerakan#menentukan R A0#menentukan G A1#menentukan B A2#menentukan SD_CS 22int posisi saat ini[] ={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.mulai(SD_CS); buatBitmap(); stepperX.disable(); stepperY.disable(); while(1);}void loop() {}void createBitmaps(){ File dir =SD.open("bitmaps"); while(true){ File bitmap =dir.openNextFile(); if(!bitmap){ istirahat; } paintBitmap(bitmap); penundaan (15000); } }#define BUFFPIXEL 20void paintBitmap(File bmpFile){ int bmpWidth, bmpHeight; uint8_t bmpDepth; uint32_t bmpImageOffset; uint32_t rowSize; // Tidak selalu =bmpWidth; mungkin memiliki padding uint8_t sdbuffer[3 * BUFFPIXEL]; // buffer piksel (R+G+B per piksel) uint8_t buffidx =sizeof(sdbuffer); // Posisi saat ini di sdbuffer boolean goodBmp =false; // Setel ke true pada header yang valid parse boolean flip =true; // BMP disimpan dari bawah ke atas int w, h, baris, col; uint8_t r, g, b; uint32_t pos =0, startTime =milis(); Serial.println(); Serial.print("Memuat gambar '"); Serial.print(bmpFile.name()); Serial.println('\''); // Buka file yang diminta pada kartu SD // Parse header BMP if (read16(bmpFile) ==0x4D42) { // BMP signature Serial.print("File size:"); Serial.println(read32(bmpFile)); (batal) read32(bmpFile); // Baca &abaikan byte pembuat bmpImageOffset =read32(bmpFile); // Mulai dari data gambar Serial.print("Offset Gambar:"); Serial.println(bmpImageOffset, DEC); // Baca header DIB Serial.print("Ukuran header:"); Serial.println(read32(bmpFile)); bmpWidth =read32(bmpFile); bmpHeight =read32(bmpFile); if (read16(bmpFile) ==1) { // # planes -- harus '1' bmpDepth =read16(bmpFile); // bit per piksel Serial.print("Kedalaman Bit:"); Serial.println(Kedalaman bmp); if ((bmpDepth ==24) &&(read32(bmpFile) ==0)) { // 0 =tidak terkompresi goodBmp =true; // Format BMP yang didukung -- lanjutkan! Serial.print("Ukuran Gambar :"); Serial.print(lebar bmp); Serial.print('x'); Serial.println(bmpHeight); // Baris BMP diisi (jika diperlukan) hingga batas 4-byte rowSize =(bmpWidth * 3 + 3) &~3; // Jika bmpHeight negatif, gambar dalam urutan top-down. // Ini bukan kanon tetapi telah diamati di alam liar. if (bmpHeight <0) { bmpHeight =-bmpHeight; membalik =salah; } // Pangkas area yang akan dimuat w =bmpWidth; h =tinggi bmp; if(bmpWidth*bmpHeight>290){ //Too large Serial.println("File terlalu besar untuk dicetak."); kembali; } untuk(uint8_t i=0; i<5;i++){ analogWrite(R, 150); penundaan (500); analogWrite(R, 0); penundaan (500); } for (baris =0; baris=sizeof(sdbuffer)) { // Memang bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx =0; // Atur indeks ke awal } // Konversi piksel dari format BMP ke TFT, tekan untuk menampilkan b =sdbuffer[buffidx++]; g =sdbuffer[buffidx++]; r =sdbuffer[buffidx++]; moveToPosition(kolom, baris); aktifkanLED(r,g,b); // dioptimalkan! //tft.pushColor(tft.Color565(r,g,b)); } // akhir piksel analogWrite(R, 0); analogWrite(G, 0); analogWrite(B, 0); } // end scanline Serial.print("Dimuat di "); Serial.print(millis() - startTime); Serial.println("ms"); } // end goodBmp } } bmpFile.close(); moveToPosition(0,0); if (!goodBmp) Serial.println("Format BMP tidak dikenali.");}uint16_t read16(File f) { hasil uint16_t; ((uint8_t *)&result)[0] =f.read(); // LSB ((uint8_t *)&hasil)[1] =f.read(); // MSB mengembalikan hasil;}uint32_t read32(File f) { hasil uint32_t; ((uint8_t *)&result)[0] =f.read(); // LSB ((uint8_t *)&hasil)[1] =f.read(); ((uint8_t *)&result)[2] =f.read(); ((uint8_t *)&result)[3] =f.read(); // MSB mengembalikan hasil;}void ActivateLED(int r, int g, int b){ Serial.print(F("LED memiliki nilai:")); 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); posisi saat ini[X] =x; posisi saat ini[Y] =y; Serial.print("Posisi stepper:"); Serial.print(Posisi saat ini[X]); Serial.print(", "); Serial.println(currentPositions[Y]);}void init_steppers(){ stepperX.begin(RPM); stepperX.setEnableActiveState(RENDAH); stepperX.enable(); stepperX.setMicrostep(MICROSTEPS); stepperY.begin(RPM); stepperY.setEnableActiveState(RENDAH); stepperY.aktifkan(); stepperY.setMicrostep(MICROSTEPS);}

Suku cadang dan penutup khusus

Skema


Proses manufaktur

  1. Apa yang Membuat Kami Kembali Menggunakan Bahan Alami dalam Desain Produk?
  2. Sensor Gerak menggunakan Raspberry Pi
  3. Panduan manajer pemeliharaan untuk membuat dan menggunakan FMEA
  4. Kirim data sensor dari satu Arduino ke Arduino lainnya menggunakan Firebase
  5. Tukar Dua Variabel Python Tanpa Menggunakan Yang Ketiga
  6. Coffin Dance Melody
  7. Menggunakan Ulang Remote Control Lama
  8. Kontrol Arduino Rover menggunakan Firmata dan Pengontrol Xbox One
  9. 8x Pencahayaan LED dengan Suara
  10. Arduino Quadruped