加速度センサーで、重力加速度つまり地球が引っ張るアレをセンシングできます。これで傾斜とか、向きがわかります。

これで俺もMacSaberできる!(やりません)

論文2つsubmitして6時間寝たら明け方目が覚めて、朝9時から授業のグルワでその後研究室で昼寝。

その後ふらふらになりながら、なんとなく1年以上前に買った加速度センサーに挑戦してみた。

マイコンさわるの1ヶ月半ぶりだけど1時間ぐらいであっさり動いた。慣れたもんだ…

SourceCode(avr-gcc)&Video

使ったのは、秋葉原のツクモロボット館などで売ってるスター精密のACA302。価格は2000円ぐらい。

普通加速度センサーは1万円とかのが色々あるんだけど、手が届かないのでコレで。アンプ内蔵型なのでコレ単体でAVR atmega8のADコンバータにぶち込めば動くお手軽感がいい。実にPhysical Computing向け。

とりあえず、傾斜を検出する分には問題ない。

加速度センサ ACA302の実装



動いている所。ブレッドボードを傾けると、xが540前後から400まで減ったり、650まで増えたりする。詳しくは後述(ビデオ高画質版

■加速度センサをブレッドボードで使えるようにする

ブレッドボードに刺さらないので、両面基盤にはんだづけしてピンを出す

加速度センサ ACA302加速度センサ ACA302加速度センサ ACA302

■回路実装

回路図と実装。データシートより、3Vを給電とのことだったので適当に150Ωをつけてみたら良い感じっぽい

ACA302 回路図加速度センサ ACA302の実装

そのままx,y,zの3ピンをatmega8のADC0,1,2に接続してAD変換する

今思い出したけど、AREF(AD変換基準電圧)を3Vにしてやればもっと正確な値が取れたな…

■プログラムを書く

なるべくノイズを消して正確な値を取りたいので、ADC0,1,2(x,y,z)それぞれ100回ずつ配列に格納して、平均値を求める。用途が制御じゃなくてヒューマンインタフェース用のつもりなので、これで十分な速度・精度が出てると思う。(思いたい)

シリアルで加速度センサのデータ受信

3つの値はテキストにしてシリアル通信で表示させた

■傾きの検出と、x,y,zの出力値の変化

(VCCに150Ωをつけた場合)

1.デフォルトでx,y,zともに530~540が出てる

2.x軸で45度傾ける → xだけ400前後、他変化なし

  さらにx軸を90度まで傾ける → zが400前後まで減少

3.xをマイナス45度 → xは650前後

  さらにマイナス90度まで → zが400まで減少

4.y軸も似た感じ

傾きを検出するには3軸を全部見てやるといい。普通の加速度を正確にやるなら、2軸の方が安くていいのかも。

一応ソースコードも張っておく

/***
ACA302のx,y,z軸の値をADC0,1,2で受け取って
UARTで文字列にして送信し続ける

CPU:ATMEGA816MHz(外付け)
Compiler:WinAVR20060125(AVR-GCC3.4.5)
Date:2006/6/18
Author:ShoHashimoto
WebSite:http://web.sfc.keio.ac.jp/~shokai/
***/
#include<avr/io.h>
#defineTRUE1
#defineFALSE0
#defineNULL'¥0'
#definesbi(BYTE,BIT)BYTE|=_BV(BIT)//BYTEの指定BITに1をセット
#definecbi(BYTE,BIT)BYTE&=~_BV(BIT)//BYTEの指定BITをクリア
/**動作設定**/
#defineFOSC16000000//16MHz
/**UART設定**/
#defineBAUD9600//9600bps
#defineMYUBRRFOSC/16/BAUD-1//UART分周率
//#defineUCSRA_U2X1//倍速フラグ等速ならコメントアウト
#ifdefUCSRA_U2X//倍速が定義されているならば
#defineMYUBRRFOSC/16/(BAUD/2)-1//UART分周率(倍速)
#endif
#defineLED_SET()sbi(PORTB,PB0)//動作確認LED
#defineLED_CLR()cbi(PORTB,PB0)
/*NoOperation*/
voidnop(intcount){
inti;
for(i=0;i<count*100;i++){
}
}
/*PORT設定*/
voidport_init(void){
sbi(DDRB,PB0);
}
/*USART設定*/
voidusart_init(unsignedintubrr){
UBRRH=(unsignedchar)(ubrr>>8);//ボーレート上位8bit
UBRRL=(unsignedchar)ubrr;//ボーレート下位8bit
UCSRB=(1<<RXEN)|(1<<TXEN)|(0<<RXCIE);//送受信許可受信完了割り込み不可
UCSRC=(1<<URSEL)|(3<<UCSZ0)|(0<<USBS)|(0<<UPM0);
//フレーム設定非同期通信8ビット1ストップビットパリティ無し
}
/*UARTで文字列送信*/
voidusart_sendStr(char*str){
while(*str!=NULL){
loop_until_bit_is_set(UCSRA,UDRE);//送信データレジスタ空きまで待機
UDR=*str++;//1文字送信、1文字進む
}
}
/*ADコンバータ設定*/
voidadc_init(void){
ADCSR=_BV(ADEN)|_BV(ADSC)|(0<<ADPS2)|(0<<ADPS1)|(0<<ADPS0)|(0<<ADFR);
//A/D変換許可、1回目変換開始(調整)、分周率2、連続変換しない
}
/*ピンを指定してAD変換return0-1023*/
intadc_convert(charpin){
intad;
ADMUX=pin;//AD変換入力ピン
cbi(ADCSR,ADIF);
sbi(ADCSR,ADSC);
loop_until_bit_is_set(ADCSR,ADIF);
ad=ADCL;
returnad+=(ADCH<<8);//上位2bit取得
}
/*intの桁数を返す*/
chargetDigit(intn){
chari;
i=0;
while(n>0){
n/=10;
i++;
}
returni;
}
/*int->String変換*/
char*intToStr(intn,char*buf){//変換する数、作業領域
inti,digit;
digit=getDigit(n);//桁数
for(i=digit-1;i>=0;i--){//intは最大5桁
buf[i]=n%10+'0';
n/=10;
}
buf[digit]='¥0';//行末改行
returnbuf;
}
intmain(void){
port_init();//PORT設定
usart_init(MYUBRR);//USART設定
adc_init();//ADConverter設定
LED_SET();//動作確認LED

intadX,adY,adZ;
charbuf[6];
inttmpX[100],tmpY[100],tmpZ[100];
inti;

for(;;){

for(i=0;i<100;i++){//100回読む
tmpX[i]=adc_convert(0);
tmpY[i]=adc_convert(1);
tmpZ[i]=adc_convert(2);
}
adX=0;//初期化
adY=0;
adZ=0;
for(i=0;i<100;i++){//平均計算
adX+=tmpX[i]/100;
adY+=tmpY[i]/100;
adZ+=tmpZ[i]/100;
}
//結果表示
usart_sendStr(&qute;x:&qute;);//x軸
usart_sendStr(intToStr(adX,buf));
usart_sendStr(&qute;,&qute;);
usart_sendStr(&qute;y:&qute;);
usart_sendStr(intToStr(adY,buf));
usart_sendStr(&qute;,&qute;);
usart_sendStr(&qute;z:&qute;);
usart_sendStr(intToStr(adZ,buf));
usart_sendStr(&qute;,&qute;);
usart_sendStr(&qute;¥r¥n&qute;);//改行送信
}
}