WEB版ETロボコンシミュレータについて（ライントレース編）

https://qiita.com/YoshitakaAtarashi/items/877d1a0cc5ba94a39755

https://qiita.com/YoshitakaAtarashi/items/4e9985f9751260cbe20e

こちらの続きです。

# ライントレースに必須となるカラーセンサについて

HackEV走行体には下図のように、アームにカラーセンサが備え付けられています。アームを固定することでカラーセンサの取得値を安定させることができます。カラーセンサには複数のAPIが用意されています。
ev3_color_sensor_get_reflectはセンサについているライトの反射光を受けて、輝度値を返す関数です。初心者がライントレースに用いるには一番簡単な関数です。黒色が9、白色が38くらいになるように設定されているので、ライントレースの目標値としてこの間の値を選択するとよいでしょう。
カラーセンサの本来の役割であるRGB値（赤、緑、青）を取得する関数として、ev3_color_sensor_get_r、ev3_color_sensor_get_g、ev3_color_sensor_get_bが用意されています。実際の走行体ではreflectとrgbは同時に取得できないのですが、本シミュレータでは簡単化のため、両方問題なく取得できてしまいます。
ライントレースには使えませんが、色を判別するための関数としてev3_color_sensor_get_colorが用意されています。[EV3RT C API](https://www.toppers.jp/ev3pf/EV3RT_C_API_Reference/group__ev3sensor.html#gaf11750614f023e665f98eca0b1f79c2f)のcolorid_tに書かれている順で0～7の値を返します。ただし、本シミュレータでは無色と茶の判定をさぼっており、黒(1)、青(2)、緑(3)、黄(4)、赤(5)、白(6)を返す実装となっています。内部的にはRGBをHSVに変換して距離の最も近い色を選んでいます。RGBのまま距離計算をすると黄と緑の判定精度が落ちることが知られています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1804036/78942b1f-40c2-f62f-4dab-e70d0fe01d07.png)

# ライントレースの仕組み

カラーセンサの値を見て、白ならライン方向へ、黒ならラインの外側へ走行体を向かせて前に進むことでラインに沿って走行することができます。簡単だけどガタガタな動きをするオンオフ制御、なめらかだけど急カーブに弱いP制御、急カーブにも耐えられるがノイズに弱いPD制御などがあります。ETロボコン名物のコースの魔物は、目に見えないノイズ（外光、影、カメラの赤外線など）が正体なのかもしれません。より技術的な説明は[過去の記事](https://monoist.atmarkit.co.jp/mn/articles/1004/21/news102.html)を参考にするとよいでしょう。

# MiniScriptでのオンオフ制御

下記のようなプログラムを実行してみましょう。ちょっと極端な例ですが、黒に近づくと左車輪を動かし、白に近づくと右車輪を動かします。これでも結構いいところまで進みますが、ゴールに到達することはできません。数値を調整して、ゴールまでたどり着けるようにしてみてください。

```
// オンオフ制御で走る。
for i in range(0,10000)
    ref=ev3_color_sensor_get_reflect 
    if ref<18 then // 目標値18より小さい場合（黒） 
        ev3_motor_set_power_left  50 
        ev3_motor_set_power_right 0
    else // 目標値18以上の場合（白） 
        ev3_motor_set_power_left  0 
        ev3_motor_set_power_right 50
    end if
    yield
end for 
```

# MiniScriptでのP制御

オンオフ制御では走行体のガタガタがどうしても残ります。下記のようにP制御を採用することで、ラインのエッジに近いときほど旋回制御量を減らすことができ、より滑らかに走らせることができます。目標値やP制御の係数を調整することで、より速く、より安定した走りをめざすことができます。

```
// P制御で走る。
v=50 // まっすぐの時の速度指令値
for i in range(0,10000) // 10000周期分動かす。
    ref=ev3_color_sensor_get_reflect // カラーセンサから反射光の強さを取得する。
    p=(ref-18)*2 // 目標値18からの差分に係数2をかける。
    ev3_motor_set_power_left (v-p)  // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。
    ev3_motor_set_power_right (v+p) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。
    yield // 次の制御周期まで待つ
end for 
```

# MiniScriptでのPD制御

ETロボコンで最も使われる制御だと思います。上記P制御の例に対して、1周期前の反射光の値を覚えておいて、現在の反射光の値との差を出すことでD（微分値）を計算することができます。P制御と比べて何か変わりましたか？　目に見える変化はないはずです。右エッジ（簡単な方）の場合、P制御でも十分走り切れることが多いです。ただし、速度を上げたり、左エッジ（カーブが多い方）を走る場合は、急なカーブを曲がるためにPD制御が必要になります。ここからは自分で工夫してみてください。

```
// PD制御で走る。
v=50 // まっすぐの時の速度指令値
old_ref=18
for i in range(0,10000) // 10000周期分動かす。
    ref=ev3_color_sensor_get_reflect // カラーセンサから反射光の強さを取得する。
    diff=ref-old_ref
    p=(ref-18)*2 // 目標値18からの差分に係数2をかける。
    d=diff*10 // 微分値に係数をかける。
    print d
    ev3_motor_set_power_left (v-p-d)  // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。
    ev3_motor_set_power_right (v+p+d) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。
    old_ref=ref
    yield // 次の制御周期まで待つ
end for 
```

# 外乱について

本シミュレータは現時点(2021/7/27)では外乱がないためかなり安定した走行ができます。一方で、大会用のETロボコンシミュレータではスポットライトの強度や影の向きを変えられるため、より繊細な制御が求められます。そして、実機ではコースの歪みやたわみとの闘いも起こります。本シミュレータの今後の拡張として、外乱やセンサノイズの導入は必要になると考えています。

# 最後に

本稿ではMiniScriptによるライントレースの方法について説明しました。カラーセンサの特徴をよく知ることで、高速かつ滑らかなライントレースを実現することができます。ぜひ、本シミュレータでチューニングの楽しさを体験してみてください。