本来なら車輪の再発明はなるべく避けるべきと言いたいところですが
Arduinoのライブラリはちょっと挙動が特殊だったりするので自分で書いたほうが安全のような気もします.
見解まとめ
少なくとも公式のPIDライブラリはデフォルトの設定を一度見直して使うべきです。
アンチワインドアップがないのでI制御のゲインはなるべく落とすなど,ちょっとしたチューニングをいじる必要がありそうです.
発展的な事をしたい場合やリアルタイム性が気になる場合は「自分で書こう」
というのが結論。
公式のPIDライブラリ
公式のページをどうぞ。
Classできちんと書かれており、見た目すっきりとした感じで書くことができます。
Arduino Playground - PIDLibrary
以下日本語で解説してくれている人もいますね。
ArduinoのPIDライブラリ - カラクリの館
中身について
Arduino-PID-Library/PID_v1.cpp at master · br3ttb/Arduino-PID-Library · GitHub
Compute関数の中をみると、まず前回との時間差分をとってサンプリング時間を超えているかどうか調べて,PIDゲインを更新。
うーん,,,うーん,,,,
追記:一周回ってまずまずなんじゃないかと思ってきました。
毎時更新されるわけじゃないので以下のようにif文を使ったほうが安全です。
if(myPID.Compute()){//値が更新されたならTrueが帰る // 出力値の更新をここに書く }
計算自体は特に離散化するでもなく,連続系のままPID制御をしています。(安全っちゃ安全)
「初心者が比較的安全に動かせる」「ゲインをハンドチューニングする」ことを念頭において作られているようです.
不満
- 一定周期で関数を実行してくれない。
- サンプリング時間のデフォルトが200ms(遅すぎ)
- デフォルトで負値の信号を生成しない(Limitがかけられている)
- 出力制限はかけているのにアンチワインドアップが組み込まれていない。
デフォルトの設定が悪すぎるのが一番の問題。
モータ制御とかをしたいと思ったら200msの制御周期とワインドアップ,負値の出力不可の三連コンボでまず振動・発散します。
泣く泣くI制御を切る初心者の顔が浮かぶ(´・ω・`)
ArduPIDライブラリ
Gitに個人の作ったライブラリがあります。
GitHub - Tellicious/ArduPID-Library: A PID Library for Arduino digitalized with the Tustin's method with Anti-Windup
良いところ
- きちんとTustin変換で離散化した制御器(離散化による不安定化とかいう負の側面もあるけど)
- AntiWindupを2種類搭載
この上の2つだけで公式ライブラリより推したいところです。
プログラムの使い勝手としてはまぁまぁでしょうか。
サンプル時間をきちんと管理していない場合,AutoCompute()機能を使わないと少々変な挙動になったりするので要注意です。
あと,疑似微分の時定数もちゃんといじれたりと制御屋が作ったんだなぁと感じさせるライブラリ。
不満
- 依然厳密なサンプル時間で実行しているわけではない。
- 私のコードにバグが残っている所(このライブラリは多分悪くない)
- これが公式ではないという点(一番の問題点)
結論・再び
あまり良いものがないのできちんとしたものを書けば多方面から感謝されること請け合い。
(つべこべ言わずに自分で書いてはどうだろうか。)
余談:タイマ割り込みとシリアル通信の相性の悪さ
タイマ割り込みを実装しようとすると一部関数やピンが使えなくなるようです。
arduino使い方:タイマー割り込み(MsTimer2)
もっと問題なのはシリアル通信などを阻害するというケースがある点で,ROSのSubscriberとかと共存させるのにちょっと手の込んだ事をする必要がありそうですね。
Enabling timer overflow interrupt breaks rosserial - ROS Answers: Open Source Q&A Forum
arduino rosserial with interrupt - ROS Answers: Open Source Q&A Forum
解決法はもう少し暇で余裕のあるときに探します。