2025年11月28日

026-1.SPIKEプライム Python入門(SPIKE App3)-第6回「PID制御を使ったライントレースロボット」

この記事では「レゴ エデュケーションSPIKEプライム(以下、SPIKE)」と専用アプリ(SPIKEアプリ)を使った、Pythonのプログラミング方法について紹介します。原稿執筆時点のSPIKEアプリの最新バージョンは3.5.1です。(文/松原拓也)

◆ PID制御とは

今回はPID制御(比例積分微分制御)を使ったライントレースロボットを作ります。使用するロボットは前回と同じです。
前回作成したプログラムにはスコアの測定機能を搭載させていました。完全にラインの中心を走ると100点と表示される仕組みです。 前回はスコアが40点前後で終わってしまったのですが、この点数を引き上げてみたいと思います。
スコアが低い原因はロボットがラインに対してズレたまま走っているためです。スムーズに走っているので、今までは特に気にしていませんでした。PID制御を導入することで、このズレをできるだけ無くします。

PID制御は比例制御(P制御)と積分制御(I制御)と微分制御(D制御)という3つの制御を組み合わせたものです。
比例制御は目標値から離れるほど出力が大きくなるという制御です。ライントレースの場合、ラインに近づくほどパワーが減ってしまうので、ぴったりとトレースすることが難しいです。一方、微分制御は急激に曲がるようなラインのトレースを得意とします。やはり、ラインに正確に寄せる用途には適していません。
これらの欠点を埋め合わせるのが「積分制御」です。積分と聞くと難しそうに感じますが、実際には単純な足し算を繰り返すだけです。積分制御では小さな誤差を積算することで足りないパワーを補うことができます。パワーの計算式は「反射光の差の合計×積分ゲイン」とします。

積分制御では積算してパワーを求めているので、タイムラグが発生します。ライントレースの場合、ラインの目標地点が激しく変化しますので、タイムラグの影響で見当違いの方向にロボットが進んでしまうかもしれません。この問題を回避するため、古い目標地点を忘れて、新しい目標地点だけを追いかけるようにします。ここでは、リングバッファを導入します。
リングバッファは輪のようにつながっている配列のことです。インデックスを循環させることで、配列を果てしなく読み書きすることができます。

リングバッファの機能を実験するプログラムを作ってみました(ringbuffer.llsp3)。 配列の要素数を26に設定しました。プログラムを実行すると、リングバッファに1、2、3、4、5というデータを順に書き込みます。そして、3つ巻き戻ってデータを読み込むと「2」と表示されます。リングバッファが正常に機能していることを確認できました。


◆ 積分制御

PID制御を使ったライントレースロボットのプログラムです(linetrace8.llsp3)。前回のPD制御のプログラムにリングバッファ機能を追加して、さらに積分制御を追加しています。反射光の差の合計は変数「ref_diff_total」に格納されます。合計する範囲は現在~過去24ループと設定しました。過去24ループより古い値は加算しません。1周=850mm、1周あたり7500ループと仮定すると、24ループは2.72mmに相当します(24×850÷7500)。つまり、積分制御の有効範囲は現在地~後方約2.7mmまでとなります。1ループ=約1ミリ秒で動かしています。

走行中のロボットの見た目とスコアを参考にしてゲインを調整します。調整の手順は次の通りです。
《1走目、比例ゲイン=45、積分ゲイン=1.0の実行結果》
score:54
score_count:7872

スコアが「54」に上がりましたが、ロボットが蛇行してしまいました。積分制御を足したぶんだけ比例制御が余分になって、それが蛇行の原因になっています。そこで、比例ゲインを減らします。つり合いを取るため積分ゲインを増やしました。

《2走目、比例ゲイン=22.5、積分ゲイン=2.0の実行結果》
score:47
score_count:8116

ロボットが蛇行してしまいました。スコアも減って、走行タイムも遅くて、完全に失敗です。積分ゲインを増やしたのが余計でした。

2走目の反省を活かしてて、積分ゲインを減らしてみました(元の値に戻す)。

《3走目、比例ゲイン=22.5、積分ゲイン=1.0の実行結果》
score:46
score_count:7486

蛇行は収まり、タイムも縮みました。ひとまずは完成ですが、もっとスコアを上げたいので、積分ゲインを2走目と3走目の中間の値にしてみました。

《4走目、比例ゲイン=22.5、積分ゲイン=1.5の実行結果》
score:57
score_count:7526

最高スコアの「57」を達成しました。蛇行もしませんし、タイムも正常です。さらに高スコアを望めそうな気がしますが、うまくトレースできたので良しとします。これでPID制御は完成です。

このPythonの連載は今回で一旦終了です。Pythonならではのプログラミングテクニックはまだ沢山ありますので、機会があれば紹介したいと思います。

プログラムを実行中の様子

当ブログの内容は、弊社製品の活用に関する参考情報として提供しております。
記載されている情報は、正確性や動作を保証するものではありません。皆さまの創意工夫やアイデアの一助となれば幸いです。