竿燈シミュレータで計算に用いているのは、PID、LQR、Adaptive制御の3つ。学生時代に教わった最も基本的なPID制御は”古典制御”に分類される。
| 分類 | 代表的な制御方法 | 竿燈シミュレータとの対応 | 基本的な考え方 |
| 古典制御 | PID、PI、PD、位相進み・遅れ補償 | PID | 誤差を見て補正する |
| 最適制御 | LQR、LQG、最適レギュレータ | LQR | 評価関数が最小になる操作を計算する |
| ロバスト制御 | H∞制御、μ設計、Sliding Mode | 将来候補 | モデル誤差や外乱があっても安定させる |
| 非線形制御 | Feedback Linearization、Backstepping、Sliding Mode、非線形MPC | 竹の大撓み等では関係が深い | 非線形性をそのまま扱う |
| 予測制御 | MPC、NMPC | 将来候補 | 未来を予測して先回りして操作する |
| 学習制御 | RL、Residual RL、ILC、NN制御、データ駆動制御 | 将来のRL / Residual RL | 経験・データから制御則を改善する |
Adaptive制御は、(考え方が分かれるところだが)無理やりこの分類に入れるとすると、「学習制御」に近いが、厳密には独立した「適応制御」という分類になる。
そもそも「制御」とは何かを考えると、以下の段階を決めることである。つまり全ての「制御」は「状態を観測し、操作量 u を決める」ことである。
|
段階 |
竿燈での意味 |
コンピュータでは |
| 測る | 傾き、傾く速さ、竹のたわみを見る | センサ値・シミュレーション状態 x |
| 判断する | どれくらい戻すか決める | 制御則(PID/LQR/Adaptive) |
| 操作する | 支点に力やトルクを加える | 制御入力 u |
| 結果を見る | 戻ったか、揺れたかを見る | 次の時刻の状態を計算 |
実際の竿燈は竹が曲がり、提灯も揺れ、風も受ける。最初はそれを全部無視して、「1本の棒が倒れようとしている」と考える。傾き角を θ(シータ)、角速度を ω(オメガ)、角加速度を α(アルファ)とする。(本当はシータドット、シータツードットで書きたいがhtml表示では限界があるのでドットはやめた)
|
記号 |
意味 |
時間との関係 |
| θ(シータ) | 傾き角 |
基準となる角度 |
| ω(オメガ) | 角速度 | |
| α(アルファ) | 角加速度 |
I:回転しにくさ(慣性モーメント)
m:質量、g:重力加速度、l:支点から重心までの距離
θ:竿の傾き、u:人または制御器が加えるトルク
d(t):風や外乱。時間とともに変わる「邪魔な力」
この式は、「傾くほど重力の影響でさらに倒れやすくなるが、u を適切に加えれば戻せる」という関係を表している。(符号は座標の取り方によって変わる)
で、コンピュータでは時間を細かく刻むので、数式では時間 t を連続量として扱うが、コンピュータは Δt 秒ごとに計算する。例えば Δt = 0.01 s なら、1秒間に100回状態を更新することになる。

このように、コンピュータでは「角度の差から角速度 ω を求め、角速度の差から角加速度 α を求める」形で計算できる。
■PID制御 (Proportional-Integral-Derivative Control) 比例・積分・微分
PIDは制御工学で最も基本的で、非常に広く使われる方式。目標と現在値の差(誤差)から操作量を決める。竿燈なら目標角度を 0°、つまり鉛直とすることになる。
![]()
鉛直を目標にするなら θref = 0 なので、傾きがそのまま誤差の大きさになる。

|
項 |
数式 | 意味 |
竿燈での直感 |
| P | Kp e | 今の誤差に比例 | 今、大きく傾いているほど強く戻す |
| I | Ki ∫e dt | 誤差の累積を見る | ずっと少し傾いたままなら補正を強める |
| D | Kd de/dt | 誤差の変化速度を見る | 急速に倒れ始めたら早めにブレーキをかける |
class PID:
def __init__(self, kp, ki, kd):
self.kp = kp
self.ki = ki
self.kd = kd
self.integral = 0.0
self.prev_error = 0.0
def step(self, target, theta, dt):
error = target – theta
self.integral += error * dt
derivative = (error – self.prev_error) / dt
u = (self.kp * error
+ self.ki * self.integral
+ self.kd * derivative)
self.prev_error = error
return u
pid = PID(kp=20.0, ki=1.5, kd=5.0)
u = pid.step(target=0.0, theta=0.08, dt=0.01)
このコードでは、積分は「error × dt を毎回足す」、微分は「今回と前回の誤差の差 ÷ dt」で計算している。連続時間の数式が、そのまま差分計算になっている。
■PIDの調整で何が起きるか(ゲイン・チューニング)
|
調整 |
起きやすいこと |
| Kpを大きくする | 戻す力は強くなるが、行き過ぎて振動しやすくなる |
| Kiを大きくする | 定常的なずれを消しやすいが、積分がたまりすぎることがある |
| Kdを大きくする | 急な変化を抑えやすいが、ノイズにも反応しやすい |
続きはLQR制御
