仕事の関係で約半年ぶりの更新となりました。
今回は、サーボモーターをArduinoで動かしてみたいと思います。サーボモーターは電子工作などでよく使われるSG90で試してみます。
- Arduino NANO(互換品)
- サーボモーターSG90
- モーター用電源(単3x4本)
- ブレッドボード
- ジャンパーワイヤ
部品等の購入先リンクは記事の一番下に記載してあります。
サーボモーターについて
サーボモーターは、模型の車や飛行機、ロボットの関節部分などに使用される、受信したパルス幅(PWM)によって特定の角度まで回転するモーターです。今回は、電子工作でよく使われるモーター、ギヤボックス、制御基板が一体になった「SG90」を使用して、Arduinoでモーターを動かしてみます。
サーボモーターのPWM制御
サーボモーターにはワイヤーが3本あり、そのうち2本は電源、残りの1本が信号となります。今回使用した「SG90」では、赤線はVCC、茶線はGND、オレンジ線が信号です。
入力されたパルス(PWM信号)を制御回路が受け取りモーターを回転させます。モーターの出力軸はポテンショメーターとつなげられており、どのくらいモーターが回転したかを読み取ります。その情報を制御回路に渡して指定角度までモーターを動かし、その角度を維持したまま止まるという構造となっています。制御信号(PWM)により回転角度が制御されている間は、その角度を保持しようとする電気的なブレーキが働きますので、無理な力を加えると、ギヤボックスやモーターを破損するので注意が必要です。
ArduinoでサーボモーターSG90をPWM制御してみる
モーター用の電源は別電源として(Arduinoの電源は省略)、信号線はデジタルピンD7としました。
SG90のデータシートを見ると、PWMサイクルは20ms(周波数に直すと1/0.02 = 50Hz)となっています。これは、1秒間に50回の信号をサーボモーターに送るということで、この周期の中にどれくらい「HIGH」としているかによって、サーボモーターが動く角度を指定することができます。
また、データシートのデューティーサイクルを見てみると0.5~2.4msと記載されていますので、周期の中でHIGHの時間を0.5msとすると、サーボモーターは最低角度(0度)に動き、2.4mとすると最大角度(180度)にサーボモーターが動くという事になります。90°へ動かしたい場合は、その中間の1.45msとなります。
0度 => 90度 => 180度の順で動かす
プログラムではパルス幅で角度を指定しなければなりませんので、角度を指定してパルス幅は計算するようにします。
パルス幅は、「角度÷180×(2400-500)」で計算できますが、このままの計算式では「角度÷180」の部分が少数となってしまう場合があります。角度を扱う変数をfloatにすればよいのですが、整数値としたいので計算式を「角度x10.556」と変形します。また、角度を指定すると、パルス幅に変換してモーターを動かす関数を作ってみました
スケッチ(×)
const int SERVO_PIN = 7;
void motor_servo(int angle) {
int pulse_width = 500+angle*10.556;
digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(pulse_width);
digitalWrite(SERVO_PIN, LOW);
delay(20);
}
void setup() {
pinMode(SERVO_PIN, OUTPUT);
}
void loop() {
motor_servo(0);
delay(1000);
motor_servo(90);
delay(1000);
motor_servo(180);
delay(1000);
}
このプログラムでは、指定した位置まで動き終わる前にPWM信号が切れてまい、指定した角度まで回転する前に途中で止まってしまいます。そこで、回転が終わるまで待機すればよいと考えました。SG90の回転速度は0.12秒/60度ですので、指定した角度の位置へ回転が終わるまで繰り返すようにプログラム変更してみます。回転角度は最大でも180度ですので、スペック通りの速度で回転すれば、どの位置へも0.36秒あれば回転し終わるはずです。プログラムでは、余裕を見て0.5秒待機するようにしています。
スケッチ(〇)
const int SERVO_PIN = 7;
void motor_servo(int angle) {
int pulse_width;
int starttime;
pulse_width = 500+angle*10.556;
starttime = millis();
while(true) {
if(millis()-starttime > 500) break;
digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(pulse_width);
digitalWrite(SERVO_PIN, LOW);
delay(20);
}
}
void setup() {
pinMode(SERVO_PIN, OUTPUT);
}
void loop() {
motor_servo(0);
delay(1000);
motor_servo(90);
delay(1000);
motor_servo(180);
delay(1000);
}
servoライブラリを使って制御してみる
Arduinoのサーボモーターを制御するservoライブラリを使って、もっと楽にSG90サーボモーターを制御してみます。先程やったPWMパルス生成部分をライブラリが処理してくれるため、角度を指定するだけで動かすことができます(パルス幅の指定もできます)。なお、「servo.h」は、最大12個のチャネルを割り当てられます。
ライブラリのインクルード
スケッチ先頭に、「#include
インスタンス生成
サーボモーターを使えるように、インスタンスを生成します。スケッチ例では、「motor_servo」としています。
出力ピン割り当て(attach)
PWMの出力ピンを割り当てます。スケッチ例ではデジタルピンD7を使用しています。パラメータは(ピン番号,min, max)の3つで後ろの2つは省略可能です。「min」はサーボの角度が0度のときのパルス幅[us]で、デフォルトは544。「max」はサーボの角度が180度のときのパルス幅[us]で、デフォルトは2400。
指定した角度に動かす(write)
サーボの角度(0~180)を指定すると、指定された回転角にするためのパルスが「attach」で指定したピンから出力されます。
指定したパルス幅で動かす(writeMicroseconds)
サーボモータへの出力を、角度ではなくパルス幅(マイクロ秒)で指定します。サーボモータに与えられるパルスは20ms周期で、1周期中のHigh時間を直接指定します。出力したいパルス幅(μs)の範囲は「1~19999」で「0」を指定すると出力OFFとなります。
ライブラリを使ったスケッチ
角度指定
#include <Servo.h>
Servo motor_servo;
void setup() {
motor_servo.attach(7,500,2400);
}
void loop() {
motor_servo.write(0);
delay(1000);
motor_servo.write(90);
delay(1000);
motor_servo.write(180);
delay(1000);
}
パルス幅指定
#include <Servo.h>
Servo motor_servo;
void setup() {
motor_servo.attach(7,500,2400);
}
void loop() {
motor_servo.writeMicroseconds(500);
delay(1000);
motor_servo.writeMicroseconds(1450);
delay(1000);
motor_servo.writeMicroseconds(2400);
delay(1000);
}
当たり前ですが、ライブラリを使用した方が楽ですね。しかし、サーボモーターをどのようにして制御するかを知っておくためにも、ライブラリを使わないで動かすことは無駄ではないと思います。次回は、連続回転のサーボモーターを動かしてみたいと思います。
部材購入先リンク
モーターは秋月の方が安いです。