ArduinoでSTEM教育​ 実践編:ライントレースカーをPID制御する

ArduinoでSTEM教育​ 実践編:ライントレースカーをPID制御する

前回作成したライントレースカーはガタガタ走行でした。今回は、自動制御でよく用いられるPID制御で、ラインに対して滑らかな走行ができるようにプログラムします。難しそうに感じるかもしれませんが、実際にモノを作ってみると理解度が断然上がります。

使用する部品一覧

使用する車は、前回の記事(ArduinoでSTEM教育​ 実践編:ライントレースカー)で作成したものを使用します。 電子部品の説明、回路図、ブレッドボード図はこちらを参照してください。

PID制御とは

前回作成したライントレースカーは、左右のフォトリフレクタがラインを検出する/しないの2値で、車の進行方向を制御していました。単純な制御なので理解しやすいですが、車はガタガタ走行になってしまいます。滑らかに走行するためには、フォトリフレクタのライン検出をアナログ値で取得して、 車の進行方向を 細かく調整してあげれば良いのです。その手法というのが、PID制御です。

PID制御は、出力値が目標値に近づくように、入力値を制御する、フィードバック制御の一種です。PIDは、「Proportional-Integral-Differential」を略した表記です。 Proportional は比例、Integralは積分、Differentialは微分を意味します。 これを式で表すと、下記のとおりとなります。 ライントレースカーでは、出力値は左右のフォトリフレクタの検出値、目標値は左右のフォトリフレクタがラインを検出しない値、入力値は左右のタイヤ(モータ)の回転速度です。

t:時間、u:操作量、r:目標値、y:出力値、e:偏差
PID制御における、ゲイン調整による応答の変化

P制御

P制御(比例制御)は、ある時における操作量(タイヤの回転速度)を出力値(フォトリフレクタ検出値)と目標値(フォトリフレクタのライン未検出値)の差分の1次関数として制御します。すなわち、ラインから大きくハズレている場合は、左右のタイヤ回転速度差を大きくして、素早くラインに戻ります。ラインから少ししか外れていない場合は、 左右のタイヤ回転速度差を 小さくして、徐々にラインに戻ります。しかし、P制御には弱点が2つあります。

1つ目の弱点は、オフセットです。差分を操作量とするため、目標値近辺では操作量が非常に小さくなり、目標値から少しずれたところで安定してしまいます。これをオフセットまたは定常偏差と呼びます。

2つ目の弱点は、オーバーシュートです。目標値から大きくハズレているときは操作量が大きいので、目標値に到達してもすぐには反応できず、大きく通り過ぎてしまいます。これをオーバーシュートと呼びます。

P制御の応答性

I制御

I制御(積分制御)は、P制御の弱点であるオフセットを補います。直線を走っている状態であれば、P制御だけでも安定して走ることができます。しかし、カーブでは、オフセットによってカーブの外側で安定しようとします。そのため、曲がれきれずにコースアウトし易くなります。これを改善するために、 過去から現在までの偏差の累積をもとに制御します。 もう少し具体的に説明すると、小さなオフセットで安定していたとしても、そのオフセットを10ms毎に積み重ねていくと、100ms後には10倍の値になります。この値に応じてタイヤの回転速度を制御します。

PI制御の応答性

D制御​​

D制御(微分制御)は、P制御の弱点であるオーバーシュートを補います。直線から急カーブに突入すると、素早く対応できずにコースアウトしてしまいます。これに対応するためには、「過去の偏差」と「現在の偏差」の差分に応じて制御します。 PI制で 直線で安定走行している場合の偏差はゼロですが、カーブに突入すると偏差が急に大きくなります。カーブが急であればあるほど大きくなります。

PID制御の応答性

限界感度法によるPIDパラメータ調整

PIDの各パラメータ(Kp, Ki, Kd)は、シミュレーションを基に実物を動作させながら合わせ込むのが一般的です。とはいえ、全てのパラメータをランダムに調整していては、とてつもなく時間がかかってしまう。そこで、パラメータ調整の経験則として知られている「限界感度法」を用います。限界限度法の手順を以下に示します。

最初はP制御だけで調整します。Kpを0から少しずつ大きくしていき、制御量が安定して、それ以上大きくすると振動が発散してコースアウトする手前の状態を求めます。このときのKpを限界感度と呼び、Kuで表します。また、その時の制御量の振動周期をPuとします。これらの値は、シリアルプロッタでグラフを見ながら調整すると良いと思います。

次に、KpとKdを求めるために、 積分ゲインをKi = Kp / Ti、 微分ゲインをKd = Kp * Tdとして、最初のPID制御式に代入すると、下記のとおりになります。

さらに、伝達関数で表現すると、下記の式になります。

TiとTdは、限界限度法の経験則から下表のように算出できます。

制御の種類KpTiTd
P0.50Ku
PI0.45Ku0.83Pu
PID0.60Ku0.50Pu0.125Pu

例えば、Ku=0.5, Pu=0.8secだった場合、PID制御パラメータは以下のように計算できます。
Kp = 0.60Ku = 0.6*0.5 = 0.3
Ki = Kp/Ti = 0.3/(0.50*0.8) = 0.75
Kd = Kp*Td = 0.3*(0.125*0.8) = 0.03

プログラム

I制御やD制御をするためには、フォトリフレクタの過去の検出値を保持しておく必要があります。フォトリフレクタは左右に2個あるため、それぞれ個別に保持しなければならないので、PIDクラスを作成します。

メインプログラムは、前回の記事(ArduinoでSTEM教育​ 実践編:ライントレースカー) をベースにPID制御を組み込んでいます。3行目~6行目のパラメータは、各々の環境で調整して決めてください。フォトリフレクタの目標値は「 const int valTarget = 940 」で設定しています。これはラインの無い床を検出した場合の値になります。PID制御では真ん中のセンサを使用しないため、プログラムから削除しても構いませんが、デバッグ用途で利用できるかもしれないため残しています。

<参考にしたサイト>
https://ja.wikipedia.org/wiki/PID%E5%88%B6%E5%BE%A1
https://monoist.atmarkit.co.jp/mn/articles/1007/26/news083.html

Arduino実践編カテゴリの最新記事