工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

1つのLEDを使用して画像を作成する

コンポーネントと消耗品

NEMA17ステッピングモーター
× 2
テレミノシステム用ステッピングモーター用テレミノドライバーDRV8825
× 2
SDカードリーダー
× 1
Arduino Mega 2560
× 1
さまざまなタイミングベルトとVホイール
× 1

必要なツールとマシン

>
3Dプリンター(汎用)

アプリとオンラインサービス

>
Arduino IDE
GIMP
Autodesk Fusion 360

このプロジェクトについて

アイデア

<図>

いくつかのビデオを見て、ライトペインティングに関する多くの記事を見た後、私はそれを試してみることにしました。ライトペインティングでは、露光時間が非常に長いカメラを使用して小さな光源をキャプチャします。これにより、1つの画像で1つの光を長いストリークに引き伸ばすことができます。

しかし、誰かがより詳細な画像を作成したり、多くの異なる色を使用したい場合はどうなりますか?このようにして、色を変えて画像を「ペイント」できる単一のRGBLEDを備えた2軸CNCマシンを構築するというアイデアを思いつきました。

<図>

計画

このプロジェクトを機能させるには、2軸CNCマシン、RGB LED、SDカード、長時間露光ショットを撮影できるカメラの4つの主要コンポーネントが必要です。まず、Arduino MegaがSDカードを読み取り、印刷するビットマップを見つけます。

<図>

次に、水平方向に横切って対応するLEDを点灯し、画像の幅を超えるたびに1行下に移動します。最後に、少し待ってから次のビットマップを検索し、作成する画像がなくなると最終的に停止します。

リグの構築

CNCマシンの設計と構築の経験があるため、この手順はそれほど難しくありませんでした。他のプロジェクトにも拡張できるモジュール式のものを作りたかったので、平行なアルミニウムの押し出しに沿って移動するクロスバーに取り付けられた2つのタイミングベルトを使用するシンプルなデザインに決めました。

<図>

<図>

これにより、各軸の長さを非常にカスタマイズできます。 X軸の端には3D印刷されたエンドキャップがあり、そのうちの1つにはX軸ステッピングモーターとベアリング用のマウントがあります。

<図>

ビットマップを読む

シンプルで読みやすいため、ビットマップファイル形式を選択しました。ファイル形式に基づいて、ファイル自体に読み取る必要のある重要なアドレスがいくつかあります。これらは、0x12(幅)、0x16(高さ)、0x1C(色深度)、0xA(ピクセルデータの場所)、そして最後に0x36(ピクセルデータが通常ある場所)です。

<図>

データは2バイトまたは4バイト(16ビットまたは32ビット)のチャンクで読み取られます。これにより、ポインターが次のアドレスに進みます。読み取り機能は、オフセットやサイズなど、すべての重要なデータを調べて取得します。次に、各ピクセルを1行ずつ読み取ります。

画像の準備

<図>

ほとんどのカメラは最大30秒の露光時間に制限されているため、その時間内に表示できる合計ピクセル数は約288ピクセルに制限されています。これは、約18 x16の画像に相当します。画像を作成するために、gimpをロードして、非常にシンプルなピクセルアートを作成し始めました。これらには、ポケボール、ハート、ジャンプするマリオが含まれていました。次に、これら3つのイメージを、SDカードのルートディレクトリにある「ビットマップ」というディレクトリに配置しました。プログラムは、このフォルダからすべての画像を読み取ります。

絵画プログラム

ステッピングモーターには内部測位フィードバックシステムがないため、それらの位置はソフトウェアで追跡する必要があります。私が作成したプログラムは、グリッドシステムを使用してLEDの位置を追跡し、簡単にスケーリングできるようにします。 Arduino Megaが起動すると、ステッパーの位置が0、0に設定され、最初の画像が検出されて読み取られます。次に、LEDが5回点滅して、撮影を開始する時期が近づいていることを写真家に知らせます。ビットマップは、最初に各行をループすることによって読み取られ、各行内で各列が読み取られます。現在の行と列を知ることにより、ステッピングモーターを同じ位置に移動できます。各位置で、LEDは対応するピクセルの色に変更されます。

(再)-画像の作成

SDカードを挿入し、モーター用の12v電源を接続した後、マシンの電源を入れます。私のカメラでは、ゴースティングの影響を最小限に抑えるために、露出時間を20秒、絞りをF36、ISOを100、露出補正を-5ストップに設定しました。描かれた最初の画像は、ここに見られるポケボールでした:

<図>

少しぼやけていますが、形ははっきりと見えます。次に、ハートのビットマップを作成しました:

<図>

この画像はわずか9x 9ピクセルであったため、個々のピクセルの定義ははるかに少なくなっています。最後に、マリオがジャンプする絵を描きました:

<図>

この画像は、主に明るい色のピクセルが豊富にあるため、ゴースティングが激しくなっています。

改善のための将来のアイデア

私が作成したライトペインティングは、当初思っていたよりもはるかに良くなりましたが、まだ改善の余地があります。私がやりたい主なことは、LEDを暗くして動かし、静止しているときにだけ点灯させることで、ブレの量を減らすことです。この手法により、再作成された画像の鮮明度が大幅に向上します。

コード

  • ライトペインティングプログラム
ライトペインティングプログラム C / C ++
 // Adafruitからのビットマップ読み取り機能#include  #include  #include "DRV8825.h" #define MOTOR_STEPS 200#define RPM 150#define MICROSTEPS 4 // pindefinitions#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 // 1または-1で方向を反転#define方向を反転するには1または-1#define STEPS_PER_MM(3.75 * MICROSTEPS)// 1mmを移動するために必要なステップ#defineSPACE_BETWEEN_POSITIONS 5 // 5mm per move#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); void setup(){Serial.begin(115); init_steppers(); SD.begin(SD_CS); createBitmaps(); stepperX.disable(); stepperY.disable(); while(1);} void loop(){} void createBitmaps(){File dir =SD.open( "bitmaps"); while(true){ファイルビットマップ=dir.openNextFile(); if(!bitmap){break; } paintBitmap(bitmap); delay(15000); }} #define BUFFPIXEL 20void paintBitmap(File bmpFile){int bmpWidth、bmpHeight; uint8_t bmpDepth; uint32_t bmpImageOffset; uint32_t rowSize; //常にではない=bmpWidth;パディングuint8_tsdbuffer [3 * BUFFPIXEL]がある場合があります。 //ピクセルバッファ(ピクセルあたりR + G + B)uint8_t buffidx =sizeof(sdbuffer); // sdbufferブール値の現在の位置goodBmp =false; //有効なヘッダーでtrueに設定されますparseboolean brief =true; // BMPは下から上に格納されますintw、h、row、col; uint8_t r、g、b; uint32_t pos =0、startTime =millis(); Serial.println(); Serial.print( "画像の読み込み '"); Serial.print(bmpFile.name()); Serial.println( '\' '); //要求されたファイルをSDカードで開きます// BMPヘッダーを解析しますif(read16(bmpFile)==0x4D42){// BMP署名Serial.print( "ファイルサイズ:"); Serial.println(read32(bmpFile)); (void)read32(bmpFile); //作成者バイトを読み取って無視しますbmpImageOffset =read32(bmpFile); //画像データの開始Serial.print( "画像オフセット:"); Serial.println(bmpImageOffset、DEC); // DIBヘッダーを読み取りますSerial.print( "Header size:"); Serial.println(read32(bmpFile)); bmpWidth =read32(bmpFile); bmpHeight =read32(bmpFile); if(read16(bmpFile)==1){//#プレーン-「1」である必要がありますbmpDepth =read16(bmpFile); //ピクセルあたりのビット数Serial.print( "Bit Depth:"); Serial.println(bmpDepth); if((bmpDepth ==24)&&(read32(bmpFile)==0)){// 0 =非圧縮goodBmp =true; //サポートされているBMP形式-続行します! Serial.print( "画像サイズ:"); Serial.print(bmpWidth); Serial.print( 'x'); Serial.println(bmpHeight); // BMP行は(必要に応じて)4バイト境界にパディングされますrowSize =(bmpWidth * 3 + 3)&〜3; // bmpHeightが負の場合、画像は上から下の順序になります。 //これは標準ではありませんが、実際に観察されています。 if(bmpHeight <0){bmpHeight =-bmpHeight;フリップ=false; } //ロードする領域を切り抜くw =bmpWidth; h =bmpHeight; if(bmpWidth * bmpHeight> 290){//大きすぎるSerial.println( "ファイルが大きすぎて印刷できません。");戻る; } for(uint8_t i =0; i <5; i ++){analogWrite(R、150); delay(500); analogWrite(R、0); delay(500); } for(row =0; row  =sizeof(sdbuffer)){//確かにbmpFile.read(sdbuffer、sizeof(sdbuffer)); buffidx =0; //インデックスを先頭に設定} //ピクセルをBMPからTFT形式に変換し、プッシュして表示しますb =sdbuffer [buffidx ++]; g =sdbuffer [buffidx ++]; r =sdbuffer [buffidx ++]; moveToPosition(col、row); activateLED(r、g、b); //最適化! //tft.pushColor(tft.Color565(r,g,b)); } //ピクセルを終了analogWrite(R、0); analogWrite(G、0); analogWrite(B、0); } //スキャンラインを終了Serial.print( "Loaded in"); Serial.print(millis()-startTime); Serial.println( "ms"); } // goodBmpを終了します}} bmpFile.close(); moveToPosition(0,0); if(!goodBmp)Serial.println( "BMP形式が認識されません。");} uint16_tread16(File f){uint16_t result; ((uint8_t *)&result)[0] =f.read(); // LSB((uint8_t *)&result)[1] =f.read(); // MSBは結果を返します;} uint32_tread32(File f){uint32_t result; ((uint8_t *)&result)[0] =f.read(); // LSB((uint8_t *)&result)[1] =f.read(); ((uint8_t *)&result)[2] =f.read(); ((uint8_t *)&result)[3] =f.read(); // MSBは結果を返します;} 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( "ステッパーの位置:"); 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);} 

カスタムパーツとエンクロージャー

回路図


製造プロセス

  1. 製品設計で天然素材を使用することになった理由は何ですか?
  2. RaspberryPiを使用したモーションセンサー
  3. FMEAの作成と使用に関するメンテナンスマネージャーのガイド
  4. Firebaseを使用して、あるArduinoから別のArduinoにセンサーデータを送信します
  5. 3 つ目の変数を使用せずに 2 つの Python 変数を交換する
  6. 棺ダンスメロディー
  7. 古いリモコンを再利用する
  8. FirmataとXboxOneControllerを使用してArduinoRoverを制御する
  9. 音による8倍のLED照明
  10. Arduino Quadruped
  11. LEDライト(Li-Fi)を使用したデータ転送