Arduinoサーボモーターでハンチングを防止するプログラミングのコツ

UNO-ATmega328

サーボモータを利用した場合、ある角度でモータを停止させるとプルプルと震える現象がよく起こります。これをハンチングと呼びます。ここでは、ArduinoのServeoクラスを利用したサーボモータのコントロールとハンチングの処理について実験してみます。

ハンチングとは

サーボモータのハンチングとは、モーターが目標位置に到達しようとした際に、その位置の周辺で小さく前後に振動する現象を指します。この現象は、サーボモーターが正確な位置制御を試みる過程でよく見られ、特に精密な位置決めが求められるアプリケーションでは問題となることがあります。

ハンチングは主に以下のような要因により引き起こされます:

  1. 制御ゲインの設定過多: サーボモータの制御システム(通常はPIDコントローラ)のゲインが適切でない場合、モーターが目標位置にオーバーシュートし、その後アンダーシュートを繰り返すことでハンチングが発生します。ゲインが高すぎると、モーターは目標位置を素早く正確に追従しようとしますが、それが過剰反応となってしまうのです。
  2. 機械的なバックラッシュ: ギアなどの機械的接続部分に遊びがある場合、この遊びが原因でモーターの動きが不安定になり、ハンチングを引き起こすことがあります。
  3. 外部からの干渉: サーボシステムに外部からの力が加わった場合、それに反応してモーターが微調整を繰り返し、ハンチングが発生することがあります。

ハンチングの抑制方法

ハンチングを抑制するためには、以下の方法が効果的です:

  1. PIDパラメータの調整: サーボモータのコントローラのPIDパラメータを調整し、適切なゲイン設定を見つけ出します。このプロセスは「チューニング」と呼ばれ、多くの場合、試行錯誤が必要です。
  2. ソフトスタートとソフトストップの実装: モーターの加速と減速を徐々に行うことで、モーターの急激な動きを抑え、ハンチングを減少させることができます。
  3. 機械的な改善: モーターと負荷との接続部分のバックラッシュを減らすために、ギアの精度を上げる、または適切な緩衝材を使用するなどの対策を講じます。
  4. フィードバックシステムの改善: エンコーダなどのフィードバックデバイスを利用し、より正確な位置情報を制御システムに提供します。これにより、モーターの動きをより正確に制御することが可能になります。

Arduinoのサーボクラスを使った基本的なプログラムに、以下のアプローチを組み込むことで、ハンチングを最小限に抑えることができる可能性があります。

プログラムの基本構造

まず、基本的なサーボ制御プログラムの構造を示します。

#include <Servo.h>

Servo myservo; // サーボオブジェクトを作成

void setup() {
  myservo.attach(9); // サーボモーターをピン9に接続
}

void loop() {
  myservo.write(90); // サーボモーターを90度に動かす
  delay(1000); // 1秒間待つ
}

ハンチングを抑えるためのアプローチ

ソフトスタートとソフトストップの実装: サーボモーターに急激な動作をさせず、徐々に速度を上げる(または下げる)ことでハンチングを減らすことができます。

void softMove(int targetAngle, int stepDelay) {
  int currentAngle = myservo.read(); // 現在の角度を取得
  if (currentAngle < targetAngle) {
    for (int angle = currentAngle; angle <= targetAngle; angle++) {
      myservo.write(angle);
      delay(stepDelay);
    }
  } else {
    for (int angle = currentAngle; angle >= targetAngle; angle--) {
      myservo.write(angle);
      delay(stepDelay);
    }
  }
}

void loop() {
  softMove(90, 15); // ソフトに90度に移動する
  delay(1000);
}
  1. 位置フィードバックの利用: サーボモーターの実際の位置をフィードバックとして利用し、目標位置に近づくにつれて速度を下げるか、ピンポイントで調整することが可能です。これを実現するためには、サーボモーターから位置情報を取得する必要がありますが、一般的なサーボモーターでは外部センサーが必要になることもあります。
  2. 適切なディレイの調整: 上記のsoftMove関数で使われているstepDelayパラメータを調整することで、サーボの動作速度を調整し、ハンチングを抑制します。ディレイが短すぎるとモーターが急激に動き、ハンチングが発生しやすくなります。

パルス制御で細かく調整してみる

Servoクラスに用意されているwriteMicroseconds()関数を使うと、writeのようにサーボモータを角度ではなくパルスで制御することができます。そのため、角度制御より細かい指定ができます。この方法を流用して、ハンチング処理ができないか試してみます。

#include <Servo.h>

Servo myservo; // サーボオブジェクトを作成
int pos = 1500; // 初期パルス幅をマイクロ秒で指定(通常の中心位置)

void setup() {
  myservo.attach(9); // サーボモーターをピン9に接続
  myservo.writeMicroseconds(pos); // 初期位置に移動
}

void loop() {
  int target = 1700; // 目標パルス幅をマイクロ秒で設定(サーボの種類により調整)

  // ターゲットにゆっくり移動
  if (pos < target) {
    for (int i = pos; i <= target; i += 10) {
      myservo.writeMicroseconds(i);
      delay(20); // 小さなステップでゆっくり移動
    }
  } else if (pos > target) {
    for (int i = pos; i >= target; i -= 10) {
      myservo.writeMicroseconds(i);
      delay(20); // 小さなステップでゆっくり移動
    }
  }
  pos = target; // 現在位置を更新
  delay(1000); // 一定時間待機
  target = (target == 1700) ? 1300 : 1700; // 目標パルス幅を変更
}

プログラムの解説

  • サーボモーターを細かいパルス幅で制御することで、角度の精度を向上させ、ハンチングを抑制します。
  • ループ内でサーボモーターの位置をゆっくりと変更し、急激な動きによる振動を避けます。
  • delay(20)はサーボの移動速度を遅くすることで、より滑らかな動きとなり、ハンチングを抑える効果があります。

ハンチング対応 new_writeMicrosecondsの実験

ハンチングを抑えるためにnew_writeMicroseconds関数を新しく作成してみます。サーボモーターのパルス制御をより細かく、スムーズに行うために利用できます。この関数は、指定されたパルス幅に徐々に遷移することで、急激な動きを避け、ハンチング現象を最小限に抑えます。以下に示すのは、Arduinoで使用可能なサンプルコードです。

#include <Servo.h>

Servo myservo; // サーボオブジェクトを作成
int currentPulse = 1500; // 初期パルス幅をマイクロ秒で指定(通常の中心位置)

void setup() {
  myservo.attach(9); // サーボモーターをピン9に接続
  myservo.writeMicroseconds(currentPulse); // 初期位置に移動
}

void loop() {
  int targetPulse = 1700; // 目標パルス幅をマイクロ秒で設定(サーボの種類により調整)
  new_writeMicroseconds(targetPulse);
  delay(2000); // 2秒待ってから次の動作へ
  targetPulse = 1300; // 目標パルス幅を変更
  new_writeMicroseconds(targetPulse);
  delay(2000); // 2秒待ってから次の動作へ
}

void new_writeMicroseconds(int targetPulse) {
  int stepSize = 10; // パルス幅の変更幅(小さいほど滑らか)
  int delayTime = 20; // パルス幅変更のディレイ時間(ミリ秒)

  if (currentPulse < targetPulse) {
    while (currentPulse < targetPulse) {
      currentPulse += stepSize;
      if (currentPulse > targetPulse) {
        currentPulse = targetPulse; // オーバーシュート防止
      }
      myservo.writeMicroseconds(currentPulse);
      delay(delayTime);
    }
  } else if (currentPulse > targetPulse) {
    while (currentPulse > targetPulse) {
      currentPulse -= stepSize;
      if (currentPulse < targetPulse) {
        currentPulse = targetPulse; // アンダーシュート防止
      }
      myservo.writeMicroseconds(currentPulse);
      delay(delayTime);
    }
  }
}

関数の解説

  • new_writeMicroseconds関数
    • この関数は、現在のパルス幅currentPulseから目標のパルス幅targetPulseまで、指定したstepSizeのステップで徐々に移動します。
    • 移動間隔にはdelayTimeミリ秒の遅延を設けることで、サーボの動きをよりスムーズにし、ハンチングを抑えます。
    • 関数内でパルス幅の増減を行い、オーバーシュートやアンダーシュートが起こらないように調整しています。
タイトルとURLをコピーしました