サーボモータと光センサーで太陽の追尾装置を作ってみた。 太陽追尾というか、よーするに明るいところを追いかける装置です。
マイコンは、16F1827、センサーは、Cdsセルで、上下左右、4つのセンサーで、上下でより明るい方、左右でより明るい方を向くようにサーボモータをコントロール。 上下で120度、左右180度の可動範囲になっています。
センサーの隔壁は、最初、筒型のパトリオットミサイルのランチャーみたいなのを試してみたのですが、いまいち、うまく作動しなかったので、シンプルな、田の字型の隔壁スタイルにしたら、わりと良さげだったので、これを採用。
一応、基盤は汎用性をもたせて、サーボのコントロール部分をメイン基盤とし、センサー部分は、ドーターボードのようにして別基盤にしています。
ライトでグリグリやると、なんか面白いです。
サーボモータで光を追跡
回路図は、以下
ほんでもって、PICのプログラムは、以下です。
/* Project Twin servo control PIC16F1827 with two servo moter and 4 Cds cell sensor trace the britest spot (Sun tracker) */ /*PIN of 16F1827 asign RA0 : Cds1 (Upper) RB0 : Servo PWM Vertical RA1 : Cds2 (Lower) RB1 : Servo PWM Holizontal RA2 : Cds3 (Right) RB2 : Rx RA3 : Cds4 (Left) RB3 : RA4 : RB4 : RA5 : MCLR RB5 : Tx RA6 : RB6 : RA7 : RB7 : */ #include <pic.h> #define _XTAL_FREQ 8000000 // delay用(クロック8MHzで動作時) #define INT_START 25536 //20msの割り込みの初期値(65536-25536=40000) __CONFIG( WRT_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSC & CP_OFF & CPD_OFF) ; __CONFIG(PLLEN_OFF & STVREN_ON & BORV_25 & LVP_OFF); unsigned short next1,next2; //next1 for UpDown, next2 for RightLeft void delay(unsigned char d){ int i; for(i=0;i<d;i++) __delay_ms(10); } void interrupt pwm( void ) { // タイマ1割り込み処理 if( TMR1IF ) { RB0 = 1; RB1 = 1; CCPR1H = (next1>>8); //next1 for UpDown, next2 for RightLeft CCPR1L = (0x00ff & next1); CCPR2H = (next2>>8); CCPR2L = (0x00ff & next2); TMR1 = INT_START; // 20msec毎に割り込み TMR1IF = 0; // タイマ割り込みフラグをクリア } // CCP1割り込み処理 if( CCP1IF ) { RB0 = 0; CCP1IF = 0; // コンペアマッチ割り込みフラグをクリア } // CCP2割り込み処理 if( CCP2IF ) { RB1 = 0; CCP2IF = 0; // コンペアマッチ割り込みフラグをクリア } } void main(void){ int m1,m2,vdata; //m1 for UpDown, m2 for RightLeft int v1,v2,h1,h2; //ADC value m1=3000; //1.5mSec m2=3000; vdata=0; OSCCON = 0b01110010; // 内部クロックは8MHzとする OPTION_REG = 0b00000000; //割り込み設定 CCP1CON=0b00001010; //compair mode CCP2CON=0b00001010; T1CON=0b00000100; //1:1 PreScaler // CCP1M=0b1010; //CCP1 Compair Interrupt // CCP2M=0b1010; //CCP2 Compair Interrupt //pin設定 TRISA = 0b00101111; // 1で入力 0で出力 RA0-RA3:Input RA6-RA7:Outputに設定(RA5は入力専用) TRISB = 0b00000000; // RB1-RB7全てを出力に設定 RB0,RB1をサーボ制御に使用 ANSELA = 0b00001111; //RA0-RA3 をADCにセット ANSELB = 0b00000000; //汎用ポート RB3(AN9)をADCにセット PORTA = 0b00000000 ; // RA出力ピンの初期化(全てLOWにする) PORTB = 0b00000000 ; // RB出力ピンの初期化(全てLOWにする) //ADC設定 ADCON0 = 0b00100100; ADCON1 = 0b11000000; //右寄せ, Fosc/8 //割り込み初期値 TMR1IE = 1; // タイマ1割り込み有効 CCP1IE = 1; // コンペアマッチ割り込み有効 CCP2IE = 1; // コンペアマッチ割り込み有効 TMR1 = INT_START; next1 = INT_START + 3000; // 1.5msec next2 = INT_START + 3000; // 1.5msec TMR1ON = 1; // タイマ1 開始 TMR1IF = 0; CCP1IF = 0; CCP2IF = 0; PEIE = 1; GIE = 1; // 全割り込み有効 while(1) { //ADC //ADC0 ADCON0=0b00000011; __delay_us(50); GO_nDONE=1; while(GO_nDONE); vdata=ADRESH; vdata<<=8; vdata|=ADRESL; v1=vdata; //ADC1 ADCON0=0b00000111; __delay_us(50); GO_nDONE=1; while(GO_nDONE); vdata=ADRESH; vdata<<=8; vdata|=ADRESL; v2=vdata; //ADC2 ADCON0=0b00001011; __delay_us(50); GO_nDONE=1; while(GO_nDONE); vdata=ADRESH; vdata<<=8; vdata|=ADRESL; h1=vdata; //ADC3 ADCON0=0b00001111; __delay_us(50); GO_nDONE=1; while(GO_nDONE); vdata=ADRESH; vdata<<=8; vdata|=ADRESL; h2=vdata; //Compair brightness //Vertical direction if(v1>v2){ if((v1-v2)>3){ m1=m1+(v1-v2); if(m1>=4000){m1=4000;} } } else if(v1<v2){ if((v2-v1)>3){ m1=m1-(v2-v1); if(m1<=1900){m1=1900;} } } next1=INT_START+m1; //Holizontal direction if(h1>h2){ if((h1-h2)>3){ m2=m2+(h1-h2); if(m2>=4800){m2=4800;} } } else if(h1<h2){ if((h2-h1)>3){ m2=m2-(h2-h1); if(m2<=1000){m2=1000;} } } next2=INT_START+m2; delay(10); } //End of While } //End of main