2017年3月10日金曜日

Arduino でサーボモータの速度制御をしてみた

概要

Arduino でサーボモータの角度制御を速度制御を行ってみました

環境

  • Mac OS X 10.10.5
  • Arduino UNO
  • Arduino IDE 1.6.7
  • サーボモータ SG90

配線

arduino_servo_circuit.jpg

サーボモータから出ている線の

  • 茶色 -> Arduino GND
  • 赤色 -> Arduino 5v電源
  • オレンジ色 -> Arduino GPIO 8 番

という具合に配線します

VarSpeedServo ライブラリをインポート

これ を使います
リリースページから最新版の zip をダウンロードし解凍します

2016/02/02 時点での最新版は v1.1.3 でした
https://github.com/netlabtoolkit/VarSpeedServo/releases/download/v1.1.3/VarSpeedServo.zip

Arduino IDE を起動して

スケッチ -> ライブラリをインクルード -> .ZIP形式のライブラリをインストール

を選択してください
arduino_include_libs.png

ダウンロードした zip ライブラリを選択する画面になるので選択します
arduino_select_zip_libs.png

追加が完了すると「Library added to your libraries. Check “include library” menu」と IDE に表示されればライブラリのインポートは OK です

制御用スクリプト

サンプルコードは以下の通りです

#include <VarSpeedServo.h> 

VarSpeedServo servo;

int pin = 8;
int deg = 0;
int speed = 50; // 1 - 255

void setup() {
  servo.attach(pin);
  Serial.begin(9600);
} 

void move_servo(int deg) {
  servo.write(deg, speed, true);
  servo.detach();
}

int serialRead() {
  char c[4];
  for (int i = 0; i < 3; i++) {
    c[i] = Serial.read();
    if (c[i] == '\0') {
      break;
    }
  }
  return atoi(c);
}

void loop() {
  move_servo(deg);
  if (Serial.available() > 0) {
    delay(10);
    int input = serialRead();
    if ( input >= 0 && input <= 180 ) {
      Serial.println(input);
      servo.attach(pin);
      deg = input;
    }
  }
}

まず setup でサーボモータを制御するピンとシリアルモニタの初期化をします

loop でメイン処理に入ります
move_servo メソッドで引数に与えられた角度にサーボモータを動かします
その際に servo.write(deg, speed, true) を使うことで角度を動かします
2 つ目の引数にサーボモータを動かすスピードを指定することができます
1 から 255 までの範囲で指定することができ、1 が低速で 255 が高速になります
プログラム内の speed という変数で速度を調整できます
最後の true はサーボモータが指定された角度に動くまで次の処理を待ちます

loop 処理内で常にシリアルの入力を受け付けています
シリアルに角度を入力すると入力された角度にサーボモータが動きます

最後に

今回は以上です
Arduino ではサーボモータを制御する標準のライブラリに Servo.h があります
これを使っても角度を動かすことはできますが、速度の制御は自分で実装する必要があります
やるとしたら Servo.write で角度を 1 ずつ変えてその度 delay で休ませる時間を調整する感じになると思います

たぶん、VarSpeedServo を使うほうが断然楽だと思います

参考サイト

5 件のコメント:

  1. 初心者ですがこのスケッチでSG92Rを動かしました。speedを10にしてゆっくり回転させました。始めに高速で90度回転した後にスロー(speed10)で90度反転して停止しました。停止した位置がサーボモーターの機械的な原点0度とみていいのですか(電源offで手で回してみるとそれ以上回転しないのでギアの機械的停止位置のようです。始めに高速で90度近く回転しているようですがそのスケッチ(プログラム)はどれに該当するのでしょうか?
    それからこの回転動作をずーっと繰り返す場合と設定した回数繰り返す場合のスケッチはどうなるのでしょうか?
    追記: 信号線位置を8から9(PWM)に変更しても同じ動きですけどPWMに関係ないのですか?
    全く初歩的な質問ですいません。メールアドレス:  fuji255127@yahoo.co.jp

    返信削除
  2. よろしくお願いいたします。

    返信削除
  3. だいぶ昔の記事なので記憶も知識も薄いのですが、、、

    > 停止した位置がサーボモーターの機械的な原点0度とみていいのですか

    そうですねサーボモータは決められた範囲でのみ可動するので停止した位置が 0 度だと思って大丈夫かなと

    > 始めに高速で90度近く回転しているようですがそのスケッチ(プログラム)はどれに該当するのでしょうか?

    本記事のサンプルはサーボを回すためのライブラリを使っているのでそっち側で 0 度の位置に高速で戻す処理があるのかもしれないです

    > それからこの回転動作をずーっと繰り返す場合と設定した回数繰り返す場合のスケッチはどうなるのでしょうか?

    無限ループであれば loop の Serial.available() の部分をなくせば OK かなと思います
    指定回数繰り返すのであればカウンタ用の変数を準備してあげてその回数に到達したら move_servo をコールしないようにすれば OK かなと

    どうしてもダメってことであれば、Arduino 掘り起こしてこちらで試してみます、、、すぐできるかどうかわからんですが

    返信削除
  4. 早速の返信ありがとうございます。無限ループであれば loop のSerial.available() の部分は具体的にどこからどこまでを削除するのでしょうか。
    if (Serial.available() > 0) を削除したところ動きは1回で止まりました。
    何故か高速で反時計回りに回転する角度は90度でなく60度くらいに変化しています。
    それから本記事のサンプルはサーボを回すためのライブラリを使っているのでそっち側で 0 度の位置に高速で戻す処理があるのかもしれないです
    の意味がよくわかりません。すみません

    返信削除
  5. > if (Serial.available() > 0) を削除したところ動きは1回で止まりました。

    結局 PWM なので信号がうまく遅れてないんだと思います。delay(10); を長くしてみてはどうでしょうか

    > 高速で戻す処理があるのかもしれないです の意味がよくわかりません。

    本記事で紹介しているコード内に高速で戻す処理は実装していないはずです
    なので、servo.attach などをコールした際にライブラリ (VarSpeedServo.h) 側でそういった処理をしている可能性がありそう
    という意味です

    返信削除