Introduction: Servo Motorを Arduino(ATmega328P-PU) 8MHzで動作させる

About: Sanuki udon is one of "Japanese taste". it is a food made of noodles of popular wheat in Japan. And my soul food. I'm not good at English. So I am studying English .

内部クロック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の場合は以下になります。

  1. digitalWrite( pin, HIGH );// ON
  2. delayMicroseconds( dutyCicle );
  3. digitalWrite( pin, LOW ); // OFF
  4. delayMicroseconds( 20000 - dutyCicle );

次に、パルス幅は0.5msec〜2.4msecとなっていますが、この値をそのまま入れて0度を指定するとモーターが止まりません。

そこで、Arduino 日本語リファレンスのattach(pin)を見ると、サーボの角度のパルス幅を書いてくれているのでそのまま利用します。

【Arduino 日本語リファレンス抜粋】

min (オプション): サーボの角度が0度のときのパルス幅(マイクロ秒)。デフォルトは544

max (オプション): サーボの角度が180度のときのパルス幅(マイクロ秒)。デフォルトは2400

  1. const int posision0 = (500 + 44) ; //0.5msec.(16MHz) ⇒ 0.544msec.(16MHz)
  2. 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でもサーボモータを回すことができます。