Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

I have been attracted to Arduino POV [1] for quite a while, but I didn't have a chance to actually make it myself. Luckily, I found this easy to follow Arduino ...

I have been attracted to Arduino POV[1] for quite a while, but I didn’t have a chance to actually make it myself.   Luckily, I found this easy to follow Arduino POV tutorial[2] on Instructable.com and within an hour, my son and me made two Arduino POV sets and have fun for the entire afternoon.

Material needed for this tutorial:

  • Arduino Nano * 1 (All other kinds of Arduino board will do)
  • LED * 7
  • 220 resistor * 7 
  • Jump wire ~ up to 10 (female to male)
  • Prefboard * 1 
  • Battery pack (If you would like have fun without tethered with USB)

Easy Wire Connection as follow:

  1. LED1 ~ LED7 negative pin to Prefboard GND
  2. Prefboard to Nano(or Uno) GND pin
  3. LED1 ~ LED7 postive pin to Nano(or Uno) D2 ~ D8 pin
  4. USB power to Nano USB port to supply power (or use a battery back to supply power)

Schematic: (I use www.tinkercad.com to draw this schematic below, just in case you interested.)

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)
This is a fun a easy project! First, just connect LED cathode(negative) and resistors on the prefboard.
Then Preboard GND to Arduino Nano GND.
Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

Then connect these LED positive pins to Arduino Nano.

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)


As you can see in the picture below, I’v used Arduino Nano. It’s lighter and smaller for portable devices.  I made the Red one and my son have choose the Green.

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

Programming logic:
When anyone sees an image, the image stays in the retina of the eyes for roughly 1/16th seconds. We can utilize the particular physical characteristic of human eyes, to crate the Arduino POV project. The basic idea is when we want to show a letter, Arduino shows each column of a letter at a time to form the letter to eyes.

See the illustration below on how to show a letter ‘H’. First, Arduino displays column 1 to light up all 7 LEDs at timing 1. While column 1 image stays in human eyes, Arduino shows 2nd column, then 3, 4, and 5th columns at their respectively timing 2~5. Since all these images stays in human eyes temporarily, we will see the letter ‘H’.

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

Actual LED image captured:


Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)



Arduino code here:
Just copy and past into Arduino IDE and it should work.
*Change your own message in the variable msgBody and remember to change msgLength*

/*
 Written by Ahmad Saeed on 22 August 2015
 
 This code is capable of displaying the following characters;
 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ .-_!%&#$,()@?
*/ 

//////////////////// Message to Customize  ///////////////////
#define msgLength 11                                       ///
String msgBody = "This is POV";                            ///
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////




#define delayInChar 3
#define delayBetweenChar 5
#define LED1 2
#define LED2 3
#define LED3 4
#define LED4 5
#define LED5 6
#define LED6 7
#define LED7 8

byte msgCode[(5 * msgLength) + 10];
boolean pintState;
int columnNum = -1;
String charToWrite;

void setup() {
  msgBody.toUpperCase();
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
}

void loop() {
//// Convert all text to binary array ////////////////////////
  if ( columnNum == -1 ) // This block needs to be done once//
  {                                                         //
    for (int c = 0; c < (msgBody.length()); c++)  {         //
      //Separate the following character                    //
      charToWrite = msgBody.substring(c, c + 1);            //
      //Send the separated characted to addChar function    //
      addChar(charToWrite);                                 //
    }                                                       //
      //Add a little space after each character             //
    addChar(" ");                                           //
    addChar(" ");                                           //
  }                                                         //  
//////////////////////////////////////////////////////////////

//// Display the binary arrays after all characters are coded //
  for (int c = 0; c < (sizeof(msgCode)); c++)  {              //
    pintState = (msgCode[c] / B1000000) % B10;                //
    digitalWrite(LED1, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B100000) % B10;                 //
    digitalWrite(LED2, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B10000) % B10;                  //
    digitalWrite(LED3, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B1000) % B10;                   //
    digitalWrite(LED4, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B100) % B10;                    //
    digitalWrite(LED5, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B10) % B10;                     //
    digitalWrite(LED6, pintState);                            // 
                                                              //
    pintState = msgCode[c] % B10;;                            //
    digitalWrite(LED7, pintState);                            //
                                                              //
    delay(delayInChar);                                       //
    // if the character is finished, take a longer off period //
    if ((c + 1) % 5 == 0 ) {                                  //
      digitalWrite(LED1, LOW);                                //
      digitalWrite(LED2, LOW);                                //
      digitalWrite(LED3, LOW);                                //
      digitalWrite(LED4, LOW);                                //
      digitalWrite(LED5, LOW);                                // 
      digitalWrite(LED6, LOW);                                //
      digitalWrite(LED7, LOW);                                //
      delay(delayBetweenChar);                                //
    }                                                         //
  }                                                           //
                                                              //
////////////////////////////////////////////////////////////////
}     


void addChar(String y) {
  if (y == "1") {
    addColumn(B0010001);
    addColumn(B0100001);
    addColumn(B1111111);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "2") {
    addColumn(B0100001);
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B0110001);
  }
  else if (y == "3") {
    addColumn(B0100010);
    addColumn(B1000001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "4") {
    addColumn(B0001100);
    addColumn(B0010100);
    addColumn(B0100100);
    addColumn(B1111111);
    addColumn(B0000100);
  }
  else if (y == "5") {
    addColumn(B1110010);
    addColumn(B1010001);
    addColumn(B1010001);
    addColumn(B1010001);
    addColumn(B1001110);
  }
  else if (y == "6") {
    addColumn(B0111110);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0100110);
  }
  else if (y == "7") {
    addColumn(B1000000);
    addColumn(B1000111);
    addColumn(B1001000);
    addColumn(B1010000);
    addColumn(B1100000);
  }
  else if (y == "8") {
    addColumn(B0110110);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "9") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0111110);
  }
  else if (y == "0") {
    addColumn(B0111110);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B0111110);
  }
  else if (y == "A") {
    addColumn(B0011111);
    addColumn(B0100100);
    addColumn(B1000100);
    addColumn(B1000100);
    addColumn(B1111111);
  }
  else if (y == "B") {
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "C") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0100010);
  }
  else if (y == "D") {
    addColumn(B1111111);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0111110);
  }
  else if (y == "E") {
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1000001);
  }
  else if (y == "F") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1000000);
  }
  else if (y == "G") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000101);
    addColumn(B0100110);
  }
  else if (y == "H") {
    addColumn(B1111111);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B1111111);
  }
  else if (y == "I") {
    addColumn(B0000000);
    addColumn(B1000001);
    addColumn(B1111111);
    addColumn(B1000001);
    addColumn(B0000000);
  }
  else if (y == "J") {
    addColumn(B0000000);
    addColumn(B0000010);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1111110);
  }
  else if (y == "K") {
    addColumn(B1111111);
    addColumn(B0001000);
    addColumn(B0010100);
    addColumn(B0100010);
    addColumn(B1000001);
  }
  else if (y == "L") {
    addColumn(B1111111);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "M") {
    addColumn(B1111111);
    addColumn(B0100000);
    addColumn(B0011000);
    addColumn(B0100000);
    addColumn(B1111111);
  }
  else if (y == "N") {
    addColumn(B1111111);
    addColumn(B0010000);
    addColumn(B0001000);
    addColumn(B0000100);
    addColumn(B1111111);
  }
  else if (y == "O") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0111110);
  }
  else if (y == "P") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B0110000);
  }
  else if (y == "Q") {
    addColumn(B0111100);
    addColumn(B1000010);
    addColumn(B1000010);
    addColumn(B1000010);
    addColumn(B0111101);
  }
  else if (y == "R") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001100);
    addColumn(B1001010);
    addColumn(B0110001);
  }
  else if (y == "S") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0100110);
  }
  else if (y == "T") {
    addColumn(B1000000);
    addColumn(B1000000);
    addColumn(B1111111);
    addColumn(B1000000);
    addColumn(B1000000);
  }
  else if (y == "U") {
    addColumn(B1111110);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B1111110);
  }
  else if (y == "V") {
    addColumn(B1111100);
    addColumn(B0000010);
    addColumn(B0000001);
    addColumn(B0000010);
    addColumn(B1111100);
  }
  else if (y == "W") {
    addColumn(B1111110);
    addColumn(B0000001);
    addColumn(B0000110);
    addColumn(B0000001);
    addColumn(B1111110);
  }
  else if (y == "X") {
    addColumn(B1100011);
    addColumn(B0010100);
    addColumn(B0001000);
    addColumn(B0010100);
    addColumn(B1100011);
  }
  else if (y == "Y") {
    addColumn(B1110000);
    addColumn(B0001000);
    addColumn(B0001111);
    addColumn(B0001000);
    addColumn(B1110000);
  }
  else if (y == "Z") {
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B1000011);
  }
  else if (y == "Z") {
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B1000011);
  }
  else if (y == " ") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == ".") {
    addColumn(B0000000);
    addColumn(B0000011);
    addColumn(B0000011);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "_") {
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "-") {
    addColumn(B0000000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0000000);
  }
  else if (y == "!") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B1111101);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "(") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0111110);
    addColumn(B1000001);
  }
  else if (y == ")") {
    addColumn(B1000001);
    addColumn(B0111110);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "%") {
    addColumn(B1100010);
    addColumn(B1100100);
    addColumn(B0001000);
    addColumn(B0010011);
    addColumn(B0100011);
  }
  else if (y == ",") {
    addColumn(B0000000);
    addColumn(B0000101);
    addColumn(B0000110);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "?") {
    addColumn(B0100000);
    addColumn(B1000101);
    addColumn(B1001000);
    addColumn(B0110000);
    addColumn(B0000000);
  }
  else if (y == "#") {
    addColumn(B0010100);
    addColumn(B0111110);
    addColumn(B0010100);
    addColumn(B0111110);
    addColumn(B0010100);
  }
  else if (y == "@") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1011101);
    addColumn(B1011101);
    addColumn(B0111000);
  }
  else if (y == "$") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B0100110);
  }
}

void addColumn(byte x) {
  columnNum += 1;
  msgCode[columnNum] = (x);
}



Image captured with my POV set:



Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

Image captured with my son’s POV set:

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)





How to capture the image:

I used HTC U11 to shot these photos. First, you have change HTC camera to Pro mode and set the exposure time to greater than 2 seconds to capture this image. Hold the Arduino POV set steadily on one hand and move the POV set slowly towards to left from right.  I believe any camera with Bulb exposure time greater than 2 seconds should be able to capture this image. 

That’s all for this tutorial. See you next time!

Article feferences:

  1. Wikipedia for POV
  2. How to Make a POV Display Using LEDs and Arduino 
  3. Simple-Arduino-POV-Wand 

Done.

==== 中 文 版 本 ====

自從我看個幾個 Arduino POV[1] 專案之後,一直想自己試試做一個來玩玩,但一直有點懶惰,遲遲沒有動手。最近看到一篇很簡單的教學 Arduino POV tutorial[2] ,剛好兒子也在家,我們決定一起動手來做一個來玩。只需約一小時,我們就各自做了一組 Arduino POV,而且整個下午都在試著不同的字串及拿著 HTC U11 拍出很一些有趣的照片。這是一個很好的親子活動的安排哩!現在就看著這篇教學一起動手吧!

這篇教學所需材料:

  • Arduino Nano * 1 (Nano, Pro mini, Uno 都可以)
  • LED * 7
  • 220 歐姆電阻 * 7 
  • 杜邦線 ~ 約 10條 (母對母)
  • 洞洞板 * 1 
  • 電池盒 (不用連接USB,可以更方便的玩,但可有可無)

接線方式:

  1. LED1 ~ LED7 負級 to 220 歐姆電阻
  2. 電阻 to Nano(or Uno) GND
  3. LED1 ~ LED7 正級 to Nano(or Uno) D2 ~ D8 腳位
  4. USB 電源接 Nano USB 來提供電源 (這可以用電池盒來取代)

電路圖: (我是用 www.tinkercad.com 來製作這張電路圖)

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)
這真的是一個很簡單又好玩的範例! 
道先, 先把 LED 負級連到220歐姆的電阻再由電阻連接到洞洞板的負極上。
Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

接著,把LED 1 ~ 7 的正極接到 Arduino 上的 D2 ~ D8 腳位上。

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)


我這次是使用了 Arduino Nano,因為它的體積比較小。下圖中可以看到我們做了兩組,我做了紅色的這組,我兒子則做了綠色的這一組。

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

程式的邏輯如下:
原理是當我們看到一個影像時,這個影像會暫留在視網膜上約 1/16 秒。當影像一個接著一個的顯示後,我們即會看到好像是數個影像的重疊,這些重疊的影像看起來就會形成一幅影像;卡通或動畫即是這樣的原理。Arduino POV 就是利用同樣的原理。

看下例如何顯示 H 字母。首先,Arduino 在 Time 1 顯示了欄位 1 的 7 個 LED,然後 Arduino 在 Time 2 ~ 5 個別的顯示欄位 2 ~ 5。 由於每個欄位都會在視網膜上暫留,我們就可以在到字母 ‘H’。

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

你可以參考這幾個字母放大後的影像如下:


Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

Arduino 程式碼在上方,直接拷貝就可以使用:

*如果你要改變顯示的字串,請記得改變 msgBody 字串以及 msgLength 的字串長度*





下方是我用 HTC U11 照出來的 POV 照片:



Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

這張是用我兒子那一組所拍下來的POV照片。

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)




如何照下 Arduino POV 的照片:

我是使用 HTC U11 來拍攝這些照片的。首先,你必需把手機設定到 PRO 模式 ,然後選定曝光時間到 2 秒以上才能拍的出來。拍攝時,拿著洞洞板,把 LED 朝相機方向,慢慢的由左到右的移動。不過,任何可以選定手動曝光到 2 秒以上的相機應該都可以拍的。

這就是這次的Arduino 範例,下次見!

文章參考:

  1. Wikipedia for POV
  2. How to Make a POV Display Using LEDs and Arduino 
  3. Simple-Arduino-POV-Wand 

1 則留言

發佈留言