Introduction: Servo Motorを Arduino(ATmega328P-PU) 8MHzで動作させる
内部クロック8MHzのArduino(ATmega328P-PU)では、servo.hを使って180度を指定すると、120度ぐらいは向いてくれているのですが、180度へ向いてくれないため、昨日から途方に暮れていたのですが、サーボモータのデータシートを見ていますと、頑張ればPWMを自分でも書けそうなので、データシートを元にサンプルスケッチを作成してみました。
servo.hのソースコードは確認していませんが、(きっと)内部クロック8MHzに対応していないかと思います・・・
内部クロック8MHzのArduinoのスペックは次の通り
- ATMEGA328P-PU
- ブートローダ:ATmegaBOOT_168_atmega328_pro_8MHz.hex
- フューズビット:Low:0xE2, High:0xDA, Ext:0x05
Step 1: データシートからプログラムを作成してみる
いきなり8MHzは難しいので、とりあえず16Mhzから・・・
サーボモータ(SG90)のデータシートを眺めていると、20msecの中で、サーボの角度に応じてパルス幅(dutyCicle)を指定してやればよいみたいなので、16Mhzの場合は以下になります。
- digitalWrite( pin, HIGH );// ON
- delayMicroseconds( dutyCicle );
- digitalWrite( pin, LOW ); // OFF
- delayMicroseconds( 20000 - dutyCicle );
次に、パルス幅は0.5msec〜2.4msecとなっていますが、この値をそのまま入れて0度を指定するとモーターが止まりません。
そこで、Arduino 日本語リファレンスのattach(pin)を見ると、サーボの角度のパルス幅を書いてくれているのでそのまま利用します。
【Arduino 日本語リファレンス抜粋】
min (オプション): サーボの角度が0度のときのパルス幅(マイクロ秒)。デフォルトは544
max (オプション): サーボの角度が180度のときのパルス幅(マイクロ秒)。デフォルトは2400
- const int posision0 = (500 + 44) ; //0.5msec.(16MHz) ⇒ 0.544msec.(16MHz)
- const int posision180 = (2400 + 0) ; //2.4msec.(16MHz)
Step 2: しかし、動かないorz
最初は、次のようなコードを書いてみましたが、サーボモータがピクピクするだけで、ちゃんと回ってくれません。
サーボモータは回ろうとはしているので、何かサーボを回す条件が足りないようです。
const int pmwPin = 8; // PWM制御に8ピンを使用
//マニュアルどおりの秒数だとモータが回りっぱなしなので補正値(44msec)を入れる
const int posision0 = (500 + 44) ; //0.5msec.(16MHz) ⇒ 0.544msec.(16MHz)
const int posision180 = (2400 + 0) ; //2.4msec.(16MHz)
const float oneDeg = (posision180 - posision0) / 180.0;
void setup() {
pinMode( pmwPin, OUTPUT );
}
void loop(){
sg90write(pmwPin, 0 );
delay(1000);
sg90write(pmwPin, 180 );
delay(1000);
}
/*
* SG90 PWM control
*/
int sg90write(int pin, int deg) {
int dutyCicle;
if ( deg >= 0 && deg <= 180 ) {
dutyCicle = posision0 + deg * oneDeg;
digitalWrite( pin, HIGH );// ON
delayMicroseconds( dutyCicle );
digitalWrite( pin, LOW ); // OFF
delayMicroseconds( 20000 - dutyCicle ); //20ms(50Hz)(16Mhz) PWM Period
}
}
Step 3: そういえば、PWM ってPulse Width Modulationですよね
PWM Periodが20msecですと、20msec周期でオンとオフを繰り返えさないといけない・・・ですよね。
で、loopの中身を修正してみました。
unsigned long time = 0;
unsigned long nextTime = 0;
int deg = 0;
void loop() { time = millis();
//2秒間隔で0度と180度を切り替える
if (time >= nextTime) {
if (deg == 180)
deg = 0;
else
deg = 180;
nextTime = time + 2000;
}
sg90write( pmwPin, deg );
}
Step 4: 16MHzで動作したので8MHzで試してみました
8MHzで動作しましたので、サンプルスケッチを置いておきます。
デジタルピン3, 5, 6, 9, 10,11ピン以外のピンでサーボモータを回すことができます。
もちろん、3, 5, 6, 9, 10,11でもサーボモータを回すことができます。
Comments
8 years ago on Introduction
Thanks for sharing your project!