2学期開始!体験授業 受付中 →
ROBO SCIENCE

PID制御 ―
振れをおさえ、ずれを消す

2026.10.15
R3 ER(Expert-rescue)

前の回では、ずれに比例して曲がる比例制御でライントレースをしました。ただ、2つの問題が残りました。線へもどるときに何度も行きすぎるハンチングと、カーブで残るずれです。今回は、比例制御に2つの数字を足して、この2つを片づけます。それが PID 制御です。

比例制御で残った2つの問題

問題起きることKp だけで直そうとすると
ハンチング線へもどるとき、何度も行きすぎてから落ち着く。Kp を上げるほど増えるKp を下げる。するとカーブでずれる
残るずれカーブで、線の外側へずれたまま走るKp を上げる。するとハンチングが増える

Kp を上げても下げても、どちらかが残ります。Kp 1つでは、両方を同時に直せません。

PID の式 ― 3つを足す

曲がる量 = Kp × ずれ + Ki × ずれの合計 + Kd × ずれの変わる速さ
見るもの役目
P(比例)いまのずれずれた分だけ、もどす
I(積分)これまでのずれの合計残りつづけるずれを、消す
D(微分)ずれの変わる速さもどりすぎる前に、ブレーキをかける

P がいまを見るのに対して、I はこれまでを、D はこれからを見ています。

Kp・Ki・Kd は、それぞれをどれくらい効かせるかを決める数字で、まとめてゲインといいます。Kp が比例ゲイン、Ki が積分ゲイン、Kd が微分ゲインです。

D ― ずれの変わる速さにブレーキをかける

ハンチングが起きるのは、線にもどる勢いがついたまま、線を通りこすからです。

D は、ずれが小さくなっていく速さを見ます。速く線へもどっているほど、反対向きに曲がる量を足します。線の手前で勢いがゆるみ、通りこさずに止まります。

線からのずれ ― 円のコース、Kp 3 P だけ Kp 3 P + D Kp 3・Kd 0.2 スタート 12秒後 うすい帯が線の太さ。まん中の線が、線の真上
Kp 3 だけでは振れつづける。Kd 0.2 を足すと、振れがおさまる。

Kd を入れすぎると、こんどは細かくガタつきます。センサーの読みの小さなゆれまで、大きな動きにしてしまうからです。

I ― たまったずれを消す

カーブでずれが残るのは、比例制御ではずれが 0 だと曲がる量も 0 になるからでした。カーブを曲がりつづけるには、ずれを少し残しておくしかありません。

I は、ずれをずっと足しつづけます。外側へずれたままだと、合計がどんどんふえ、曲がる量もふえていきます。ずれが 0 になっても、それまでの合計が残るので、ずれがなくても曲がりつづけられます。

線からのずれ ― 円のコース、拡大 P + D Ki なし P + I + D Ki 3 スタート 12秒後 うすい帯が線の太さ。まん中の線が、線の真上
Ki なしでは、外側へずれたまま。Ki 3 を足すと、線の真上へもどる。縦の目盛りを、上の図の2倍に広げてある。

Ki を入れすぎると、合計がふえすぎて、大きく振れます。また、ロボットを持ち上げたり止めたりすると、そのあいだのずれまで合計にたまります。走りはじめる前に、合計を 0 にもどします。

実験室で確かめる ― Kp・Ki・Kd を動かす

①〜④を順に押すと、ここまでの話が順に見られます。

PID実験室さわって動かせます

曲がる量の内訳

線からのずれ(さいきんの12秒)

まん中の線が、線の真上。うすい帯が線の太さです。上下に波打っていれば、ロボットは振れています。計算で動かしているので、ここで出した Kp・Ki・Kd は実物のロボットではそのまま使えません。

やってみること見えること
① Kp を小さく線の外側へずれたまま走る
② Kp を大きくずれは減るが、左右に振れる
③ Kd を足す振れがおさまる
④ Ki を足す残っていたずれが消える
Kd を 0.8 まで上げる細かくガタつく
Ki を 40 まで上げる大きく振れる

「曲がる量の内訳」を見ると、P・I・D がそれぞれどれだけ効いているかが分かります。円のコースで④にすると、走っているあいだ I が一定の量を出しつづけます。ずれがなくても曲がれるのは、この I のおかげです。

プログラム ― 比例制御に数行足すだけ

from pybricks.pupdevices import Motor, ColorSensor
from pybricks.parameters import Port, Direction
from pybricks.tools import wait

left_motor  = Motor(Port.A, Direction.COUNTERCLOCKWISE)   # 左は逆向きに付いている
right_motor = Motor(Port.B)
left  = ColorSensor(Port.C)
right = ColorSensor(Port.D)

KP = 2.0                              # ゲインは目安の値
KI = 4.0
KD = 0.2
BASE = 200                            # 基準の速さ(1秒に200度)。目安の値
DT = 0.02                             # 20ミリ秒ごとに1回

integral = 0
last_error = 0

while True:
    error = right.reflection() - left.reflection()   # いまのずれ
    integral = integral + error * DT                 # ずれの合計
    derivative = (error - last_error) / DT           # ずれの変わる速さ

    turn = KP * error + KI * integral + KD * derivative

    left_motor.run(BASE - turn)
    right_motor.run(BASE + turn)

    last_error = error
    wait(20)
書き方やっていること
integral + error * DTずれを、時間をかけて足していく(I)
(error - last_error) / DT前の回からどれだけ変わったかを、時間で割る(D)
last_error = error次の回のために、いまのずれを覚えておく
wait(20)20ミリ秒ごとに1回。DT と合わせておく

ゲインと BASE は目安の値です。ロボットとコースに合わせて、次の節の順番で調整します。

前の回の比例制御に、integral と derivative の行が足されただけです。KI と KD を 0 にすれば、比例制御にもどります。

ゲインを決める順番 ― P、D、I の順に

3つを一度に動かすと、どれが効いたのか分からなくなります。1つずつ、決まった順に決めます。

やること
1Ki と Kd を 0 にして、Kp を上げていく。ハンチングが出はじめたところで止める
2Kd を少しずつ足して、ハンチングをおさえる。ガタつきはじめたら少しもどす
3カーブでずれが残るなら、Ki を少しだけ足す
4基準の速さを上げたら、1 からやりなおす

実験室の数字は使わず、自分のロボットを走らせて探します。

動かないときに見るところ ― 症状から原因を引く

症状原因対処
左右に大きく振れるKp か Ki が大きすぎるKi を 0 にして、Kp から決めなおす
細かくガタつくKd が大きすぎるKd を下げる
走りだしてすぐ、急に曲がるずれの合計がたまったまま走りはじめる前に integral = 0 にする
D を足しても何も変わらないlast_error を更新していないループの最後で last_error = error を書く
うしろへ走る。その場で回るモーターの回る向きの指定が、実機と合っていないDirection.COUNTERCLOCKWISE を、右のモーターに付けかえる
線から逃げるように曲がる曲がる向きが逆BASE - turn と BASE + turn を入れかえる
ロボサイエンスについて

ロボカップジュニア2027 に向けて、レスキュー(災害救助)とサッカーの2種目に取り組みます。プログラミングと電子工作の経験は問いません。

前の回:ON-OFF制御と比例制御 ― なめらかに線をたどる →
ロボサイエンスの記録一覧 →
体験授業・お問い合わせ →

← ロボサイエンスの記録一覧へ戻る