フェナキストスコープを作成


 フェナキストスコープをストロボを使って作成してみました。

フェナキストスコープの作成について



 フェナキストスコープ工作の作成が、 日本ガイシさんのNGKサイエンスサイトにありましたので、 原画を拝借し、コマ撮りで見る方法とストロボで見る方法を作成してみました。


  コマ撮りで動画を作成


 次のNGKサイエンスサイトさんの原画をコマ撮りで画像を作成し動画にしてみました。


作成方法は、
1.12個の像があるので、Photoshopで30度ごとに画像をずらし、位置と大きさを同じにして12個のコマ画像を作成しました。

2.その12個のコマ画像をSONYのPlayMemories Home(無料)とVideoWave(Roxio Creater)を使い12個のコマ画像を120個繋ぎ動画 にしました。画像の表示速度は1/2にしました。

3.完成したコマ撮り動画です。
アニメーションのようにイルカが動いて見えます。





  Arduinoを使ってストロボで見る


 CDに原画を貼り付け、そのCDをBLCDモーターで回転させ、ストロボをCDに照射してフェナキストスコープを実現しました。

1.完成した動画です。
 光量不足とストロボの影響で見づらく不鮮明な動画ですが、実際には、もっとはっきりとアニメーションとして見えます。

 点滅していますので、気分が悪くなったら見るのをやめてください。



2.ストロボの作成
(1)光源は、ダイソーのクリップライトを使用しました。


(2)Arduino のtimer1を使ってPWMの信号でライトを点滅します。
特定の周波数のPWMを出したいので、Mode15のFast PWM mode を使います。
この場合、OCR1Aの値がTOPになるので、この値を変えることによりPWMの周波数を変えられます。
 したがって、
TCCR1A = _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10) ;
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10) | _BV(CS11) ;
とし、OCR1Aの値をA1ピンに接続したボリュームの値により可変できるようになっています。

 モーターの回転数によっては、TCCR1Bは、TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) ;
でも良いかと思います。

(3)PWMの周波数については、通常のModeの場合
PWMの周波数=16MHz/258(8bit)*prescaler で求められますが、Mode14とMode15の場合は、258(8bit)の所を数値指定できます。

3.BLCDモーターとドライバー
(1)CDの回転は、CDROMに使用されているBLCDモーターを使用しています。
任天堂wiiのDVD-ROMドライブモーターを使用しました。


 ドライバーについては、 Arduino CDROM BLDC Motor Driver, Enhanced Performanceを参考にしました。
ドライバーICとしてL293Dを使用しています。




  工作概要


1.次の図が完成写真です。


 BLCDモーターの固定及び回路基板を入れた台は、「素麺の入った木箱?」を加工して作りました。

2.部品の配置写真です。


*台の背面の部品配置です。




  回路図


1.次の図が回路図です。


2.BLDCモーターの電源3V~3.5VとしてDC-DC Step Down Converterを使用しています。




  プログラム


 NANOの12ピンにプッシュスイッチを接続して、押すごとに10段階で光量が増加するようになっています。
 光源として使用したダイソーのクリップライトでは、結果として光量不足だと思います。 Tape-LEDを使用した方が良いかと思います。

unsigned long startTime = millis();
unsigned long elapsedTime = 500;

const byte MTR_EN_1 = 3;
const byte MTR_IN_1 = 7;
const byte MTR_EN_2 = 4;
const byte MTR_IN_2 = 8;
const byte MTR_EN_3 = 5;
const byte MTR_IN_3 = 9;

const byte phases = 3;
const byte pinmodes = 2;
const byte sigstates = 4;
const byte sigcycle = 6;
const byte signals[sigcycle][sigstates] = {{1,1,1,0},{2,1,0,0},{0,1,0,1},{1,0,0,1},{2,0,1,1},{0,0,1,0}};

byte pins[phases][pinmodes];

boolean dir = 0;
boolean lastDir = 0;
boolean rampUp = true;
boolean slowDown = false;

int wait = 60;
int waitTemp = 7;

#define BASE_FREQ 50
#define MIN_FREQ_OFFSET -12.0
#define MAX_FREQ_OFFSET 12.0
#define MIN_BRIGHTNESS 2          
#define MAX_BRIGHTNESS 10.0       

const byte ButSW = 12;
const byte LED_strip = 10;

byte ButSW_State = 0;            
byte last_ButSW_State = 0;        

float freq_offset = 0.1;
float duty_led = 6;
float freq_led = BASE_FREQ+freq_offset; 

long time_led = round(16000000/32/freq_led);

void setup()
{                    
  for (int i=0; i < phases; i++)
  {
    for (int j=0; j < pinmodes; j++)
      pinMode(pins[i][j], OUTPUT);
  }

  pinMode(LED_strip, OUTPUT);        
  pinMode(ButSW, INPUT_PULLUP);  

  led_on();
  OCR1A = round(time_led);
  OCR1B = round(duty_led*time_led/100L);
  sei();
  
  motorDirUpdate();
}


void loop() 
{  
  if (analogRead(A0) > 500)
  {
    dir = 1;

    if (analogRead(A0) > 900)
      waitTemp = 7;    
    else if (analogRead(A0) > 800)
      waitTemp = 8;
    else if (analogRead(A0) > 700)
      waitTemp = 9; 
    else waitTemp = 12;
       
  }
  else
  {
    dir = 0;

    if (analogRead(A0) < 100)
      waitTemp = 7;    
    else if (analogRead(A0) < 200)
      waitTemp = 8;
    else if (analogRead(A0) < 300)
      waitTemp = 9;
    else
      waitTemp = 12;
  }

if (dir != lastDir)
  {     
    startTime = millis();  
    rampUp = false;
    slowDown = true;
  }
 
  for (int i=0; i < sigcycle; i++)
  {
    for (int j=0; j < phases; j++)
    {
      freq_offset = -(MAX_FREQ_OFFSET - MIN_FREQ_OFFSET)/1023L*analogRead(A1) + MAX_FREQ_OFFSET;
      freq_led = BASE_FREQ+freq_offset;
      
      time_led = round(16000000/32/freq_led);

      OCR1A = round(time_led);
      OCR1B = round(duty_led*time_led/100L);
      
      ButSW_State = digitalRead(ButSW);
      
      if (ButSW_State != last_ButSW_State) 
      {
        if (ButSW_State == LOW) 
        {    
          duty_led = duty_led + 0.4;

          if (duty_led > 9.8)
            duty_led = 6;     
        }
        delay(5);
      }

      last_ButSW_State = ButSW_State;  

      digitalWrite(pins[j][0], signals[i][0]==j?LOW:HIGH);

      digitalWrite(pins[j][1], signals[i][j+1]);
    }

    if (slowDown == true) 
    {
      wait = wait + 1;
      delay(10);
      
      if (wait > 60)
      {
        slowDown = false;
        rampUp = true;
        motorDirUpdate();
      }    
    }

    if (rampUp == true) 
    {
      if (wait > 12)
      {
        wait = wait -1;
        delay(10);
      }
      else
      {
        rampUp = false;
        startTime = millis(); 
      }
    }

    if ((millis()-startTime) > elapsedTime) 
    {
      if (wait > waitTemp)
      {
        wait = wait - 1;
        startTime = millis();
      }
      else if (wait < waitTemp)
      {
        wait = wait + 1;
        startTime = millis();
      }
    }

    delay(wait);     
  }
}

void motorDirUpdate()
{
  if (dir == 1)
  {
    pins[0][0] = MTR_EN_3;      
    pins[0][1] = MTR_IN_3;
    pins[1][0] = MTR_EN_2;
    pins[1][1] = MTR_IN_2;
    pins[2][0] = MTR_EN_1;
    pins[2][1] = MTR_IN_1;
  }
  else
  {
    pins[0][0] = MTR_EN_1;
    pins[0][1] = MTR_IN_1;
    pins[1][0] = MTR_EN_2;
    pins[1][1] = MTR_IN_2;
    pins[2][0] = MTR_EN_3;
    pins[2][1] = MTR_IN_3;
  }        
  lastDir = dir;
}

void led_on() 
{
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10); 
  TCCR1B =  _BV(WGM13) | _BV(WGM12)  | _BV(CS10) | _BV(CS11);
}