AbudoriLab.

自律ロボットで誰でも遊べるよう試行錯誤するブログです。

PIDを用いたモータ制御システムとプログラムの使い方を解説

AbudoriLab.です。
モータ制御記事の第二弾です。
本記事では筆者が設計したモータ制御システムについて紹介します。

はじめに

本シリーズは2部構成になります。

  • PID制御について調査して分かった知識の共有
  • アルゴリズムやパラメータチューニングなどノウハウの紹介 ← 今回はココ

前記事ではモータ制御はなにをコントロールするか?についての概念を紹介しました。
本稿ではモータ制御の実現にはどんな機能が必要なのか?を検討してプログラムに落とし込むまでの内容をまとめています。

振り返り

Lapinでも使っているDCモータは電流を流す方向やその量によって回転方向や速度を変更できます。
その電流量を調整するにはモータに印加する電圧の大きさを制御することが必要です。
印加電圧の大きさは電源をオン/オフする時間を変えることで調整できることがわかりました。

オン/オフする時間(=Duty比)はPIDを用いて求めることができ、モータの回転速度の目標値と現在地を用いてP,I,Dを算出します。

モータ制御システムのフロー

モータ制御システムの設計図

システムのフロー図を元にプログラムを実装する上で必要な機能を抽出すると下記の通りになります。

  • ユーザが定めた指示値をマイコンに入力する機能
  • モータのエンコーダセンサからマイコンにエンコーダカウンタを受信する機能
  • モータの回転速度をマイコンが計測する機能
  • マイコンがモータの回転速度計測値と指示値の差分からPIDを計算する機能
  • PIDで算出したDuty比を入力としてマイコンが電源のオン/オフを調整する機能
  • 現在のモータ回転速度をユーザが確認できる機能

さらに機能間でどんな情報をやり取りするか(=インターフェース)を明確して図示するとモータ制御システム全体の構造が見えるようになりました。

モータ制御のシステム全体の構造

サブシステムに'ユーザ','マイコン','モータ’があり、ユーザが入力した回転速度の指示値とマイコンが計測した現在地を用いてPID制御を行い、算出したDuty比からモータに印加する電圧をマイコンが調整してモータ制御を実現しています。

モータ制御プログラム

モータ制御システムを構成する機能と機能間のデータやりとりをまとめた図(設計図)を元にプログラムを作成したので、使い方について紹介します。 
どのように実装したかまでの詳細は触れませんが、個別でチューニングできる情報を提示します。
モータ制御するにあたって、必要な機器,開発環境は下記の通りです。

  • マイコン : ESP32
  • DCモータ: GM25-370
  • 基板: AbdoriLab.自作 (ピン配置は個人で設定お願いします)
  • PC
  • Arduino IDE

Arduino IDE 環境設定

世界的にも有名なマイコンボード用開発環境のArudionoIDEを使用します。
初心者のプログラミング学習、小規模システム開発に適しておりC/C++ライクに実装が可能です。
インストール手順や設定方法は多くの記事がすでに存在しているため紹介だけになります。
symfoware.blog.fc2.com

ESP32を使用するユーザ向けにライブラリ等が提供されています。
ArduinoIDEの設定後に参照してください。
www.mgo-tec.com

ソースファイル構造

筆者が作成したモータ制御システムのソースファイル構造を下図に示します。

ソースファイル構造

とてもシンプルな構造で、'MoterDrive.ino'でモータ制御のクラスをコンストラクトしてMoterDriveを実行するだけでモータを駆動させることができます。
github.com
githubからcloneした状態で実行した場合は次の動作になります。
3秒ごとに回転速度の指示値が80->120->160->80・・・と切り替わり、モータ制御を行います。
制御方法はPI制御が選択されています。

設定方法

個別に指示値を変更したり、回転方向を変更したい場合に、ソースコードをいじるべき箇所をご紹介します。
【ピン番号の変更】
マイコンや作成した回路毎にピン番号が異なると思います。
その場合の変更はdefine.hで再設定してください。
変更行は4行です。
PinEncoderA,PinEncoderB,PinDriverA,PinDriverBの数字を適切に設定してください。

  /**Pin number of encoder A-terminal */
  int motor1_PinEncoderA = 18;
  /**Pin number of encoder B-terminal*/
  int motor1_PinEncoderB = 19; 
  /**Pin number of motorDirver A-terminal */
  int motor1_PinDriverA = 5;
  /**Pin number of motorDriver B-terminal */
  int motor1_PinDriverB = 23;

【PIDゲインの変更】
使用するモータによっては適切なゲインは異なります。
その場合の変更はdefine.hで再設定してください。
変更行は3行です。kp,ki,kdの数字を適切に設定してください。

  /**P-gain */
  float motor1_Kp = 1.9f;
  /**D-gain */
  float motor1_Ki = 1.26f;
  /**D-gain */
  float motor1_Kd = 0.0f;

【回転方向の変更】
モータの回転方向をを設定することができます。
その場合の変更はdefine.hで再設定してください。
変更行は1行です。reverseを0 or 1(正転 or 逆転)で選択してください。

 /**set reverse motor(0: normal,1:reverse) */
 boolean motor1_reverse = 1;

【回転速度の指示値設定】
個別で回転速度の指示値を設定したくなると思います。
その場合の変更はDefine.hとmotor.hppで再設定してください。
まず、define.hにあるsetVelocityを1以外の数字に設定してください。
次に、moter.hppのDriveMoter関数においてsetVelocityを用いてモードを分けているIf文の中身を変更してください。

  if(setVelocity == 1){
    this->GetTargetVelocity();  
  }else{
    this->VelocityTarget = 100;
  } 

else{}内のVelocityTargetにお好みの数値を入力してください。
【PID制御の設定】
PI制御からP制御,PID制御と切り替えることができます。
その場合はmoter.hppで再設定してください。
DriveMoter関数において、PI行をコメントアウトしてお好みの制御行のコメントは外して下さい。

  //PWM = Kp * P;
  PWM = Kp * P + Ki * I; 
  //PWM = Kp * P + Ki * I + Kd * D; 
  //PWM = Kp * P + Ki * I + + Kd * D + Kf * F; 

さいごに

モータ制御はなにをコントロールすることなのか?についての調査結果からシステムに必要な機能とその機能間でやりとりするデータを整理し、設計図を作成してプログラムまで落とし込みました。
次回は、PID制御で最も重要な適切なゲインの見つけ方について紹介しようと思います。
また、公開したプログラムに少しアレンジを加えれば複数個のモータを制御できるようになります。
是非ご活用ください。