「黒が見えたら曲がる」。これで線はたどれます。ただ、ロボットは左右に振れながら進みます。今回は、ずれを数字にして、ずれが大きいほど大きく曲がる走り方に変えます。前の走り方を ON-OFF 制御、新しい走り方を比例制御といいます。
ON-OFF制御 ― 曲がるか、曲がらないか
これまでのライントレースは、黒が見えたほうへ決まった強さで曲がりました。
# ON-OFF制御 ― 黒が見えたほうへ、決まった強さで曲がる
while True:
if left.reflection() < 50: # 左が黒
left_motor.run(0)
right_motor.run(BASE)
elif right.reflection() < 50: # 右が黒
left_motor.run(BASE)
right_motor.run(0)
else: # どちらも白
left_motor.run(BASE)
right_motor.run(BASE)
ロボットにできることは、左へ曲がる・右へ曲がる・まっすぐの3つだけです。曲がる強さは、いつも同じです。これを ON-OFF 制御といいます。
ON-OFF 制御のロボットは、ずれているか、いないかしか知りません。少しずれただけでも同じ強さで曲がるので、線を通りこします。通りこすと、こんどは反対へ同じ強さで曲がります。
| ON-OFF 制御で困ること | 理由 |
|---|---|
| タイムが落ちる | 振れるぶん、走る距離が伸びる |
| 速くできない | 速くすると振れが大きくなり、線を見失う |
| カーブに弱い | 振れている途中でカーブに入ると、曲がりきれない |
ずれを数字にする ― 右の値 − 左の値
なめらかに走らせるには、どれくらいずれているかが要ります。
2個のセンサーを反射光で読みます。値は、白い床で大きく、黒い線に近づくほど小さくなります。この2つを引き算します。
| ずれ = 右の値 − 左の値 |
| ロボットの位置 | 左の値 | 右の値 | ずれ |
|---|---|---|---|
| 線のまん中 | 77 | 77 | 0 |
| 少し右へずれた | 62 | 88 | +26 |
| 大きく右へずれた | 38 | 96 | +58 |
| 少し左へずれた | 88 | 62 | −26 |
引き算1つで、ずれの向きと大きさが同時に分かります。プラスなら右へ、マイナスなら左へずれています。0 なら線のまん中です。
ロボットが右へずれると、線は左のセンサーに近づきます。左の値が小さくなるので、ずれはプラスになります。表の数字は例で、実際の値は自分のロボットで測ります。
比例制御 ― ずれが大きいほど、大きく曲がる
| 曲がる量 = Kp × ずれ |
ずれが 0 なら、曲がる量も 0 です。ずれが小さければ少しだけ曲がり、大きければ大きく曲がります。線に近づくほど曲がり方が弱くなるので、線を通りこしにくくなります。
この曲がる量を、左右のモーターに分けます。
| モーター | 速さ |
|---|---|
| 左 | 基準の速さ − 曲がる量 |
| 右 | 基準の速さ + 曲がる量 |
ずれがプラス(右へずれた)なら、左が遅く、右が速くなります。ロボットは左へ曲がり、線へもどります。
Kp(ケーピー)は、どれくらい強く曲がるかを決める数字です。ずれに比例して曲がるので、この走り方を比例制御といいます。Kp のように効き方の強さを決める数字をゲインといい、Kp は比例ゲインです。
同じコースを同じ速さで走らせると、ずれはこうちがいます。
実験室で比べる ― ON-OFF と比例
同じコースを、2つの走り方で走らせます。
線からのずれ(さいきんの12秒)
まん中の線が、線の真上。うすい帯が線の太さです。上下に波打っていれば、ロボットは振れています。計算で動かしているので、ここで出した Kp は実物のロボットではそのまま使えません。
| やってみること | 見えること |
|---|---|
| 「ON-OFF」で走らせる | 線の左右へ、振れながら進む |
| 「比例」に切りかえる | 振れがおさまり、線にそって進む |
| Kp を 0.3 まで下げる | カーブで曲がりきれず、外側へふくらむ |
| Kp を 3 まで上げる | ON-OFF のように、左右へ振れだす |
| 速さを上げる | 同じ Kp でも振れやすくなる |
プログラム ― 引き算とかけ算で2行
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 = 1.0 # 目安の値。ここを調整する
BASE = 200 # 基準の速さ(1秒に200度)。目安の値
while True:
error = right.reflection() - left.reflection() # ずれ
turn = KP * error # 曲がる量
left_motor.run(BASE - turn)
right_motor.run(BASE + turn)
wait(20)
| 書き方 | やっていること |
|---|---|
| reflection() | 反射光を 0〜100 で読む |
| right − left | ずれを出す。右へずれるとプラス |
| KP * error | ずれに比例した、曲がる量 |
| run(BASE - turn) | モーターの速さを「1秒に何度回るか」で渡す |
KP と BASE は目安の値です。ロボットとコースに合わせて調整します。
ON-OFF 制御にあった if が、なくなりました。場合分けのかわりに、計算で曲がる量を決めています。
ゲインの決め方 ― Kp を小さいほうから上げて、振れる手前で止める
Kp は計算では決まりません。走らせて探します。
| Kp | 走り方 |
|---|---|
| 小さすぎる | ゆっくりもどる。カーブで曲がりきれず、線から外れる |
| ちょうどよい | すっともどり、そのまま線にそう |
| 大きすぎる | 線を何度も行きすぎて、左右に振れる。これをハンチングという |
| やること | |
|---|---|
| 1 | Kp を小さい値から始める |
| 2 | 少しずつ上げて、そのたびに走らせる |
| 3 | 振れはじめたら、その少し手前にもどす |
| 4 | 基準の速さを上げたら、1 からやりなおす |
速さを変えると、ちょうどよい Kp も変わります。大会の会場でも、床と明るさがちがうので探しなおします。
比例制御で残るもの ― ハンチングと、カーブのずれ
Kp がちょうどよくても、ずれた位置から線へもどるときは、数回行きすぎてから落ち着きます。比べるグラフの比例制御の線で、はじめに波打っているところです。Kp を上げるほど、このハンチングは増えます。
実験室のコースを「円」にして、比例制御で走らせます。ロボットは振れずに走りますが、線の外側へ少しずれたままです。
理由は式にあります。カーブを曲がりつづけるには、曲がる量が要ります。ところが比例制御では、ずれが 0 だと曲がる量も 0 です。だから、ずれを少し残したまま走ることになります。
Kp を上げると、カーブのずれは小さくなります。しかしハンチングが増えます。ハンチングをおさえることと、ずれをなくすことを、Kp だけでは両立できません。ここに2つの数字を足したものが PID 制御です。次の回でやります。
動かないときに見るところ ― 症状から原因を引く
| 症状 | 原因 | 対処 |
|---|---|---|
| 線から逃げるように曲がる | 曲がる向きが逆 | BASE - turn と BASE + turn を入れかえる |
| うしろへ走る。その場で回る | モーターの回る向きの指定が、実機と合っていない | Direction.COUNTERCLOCKWISE を、右のモーターに付けかえる |
| 線のまん中でも曲がる | 2個のセンサーの値がそろっていない | 同じ白い紙の上で2個を読み、差をたしかめる |
| 左右に激しく振れる | Kp が大きすぎる | Kp を下げる。または基準の速さを下げる |
| カーブで外れる | Kp が小さすぎる | Kp を上げる。または基準の速さを下げる |
ロボカップジュニア2027 に向けて、レスキュー(災害救助)とサッカーの2種目に取り組みます。プログラミングと電子工作の経験は問いません。