前回(テーブルモード編)、私は自分のレース競技 aira で「オープンループ(指令の再生)ではレースに勝てない、フィードバック(クローズドループ)が必要だ」というところまでをデータで確かめました。
では、そのフィードバックで実際にどこまで行けるのか。今回はルールベース制御を限界まで攻めます。出発点は旧ルールベースの最速 46.1s(衝突4回)。目標は、前回 人が手で握った開ループの攻めお手本 21.6s に挑むこと。結論から言うと、クローズドループの自動アルゴリズムが、その21.6sを再現性を保ったまま下回りました(21.4s・衝突0)。
本記事は運営者(開発者)としての検証です。掲載タイムは挙動を調べる参考値で、競技リーダーボードへの参加記録ではありません。
1. Stage A:まず"見え方"を変える(色 vs 白線)
最初に手を入れたのは制御ではなく知覚です。旧来は白線の sliding-window で横位置を推定していましたが、白線はコーナーで画面外へ逃げ、片側推定に頼って不安定でした(テーブル編で確認済み)。
そこで、3色レーン(内=青/中=緑/外=赤)の緑レーン重心追従に差し替え。色は鮮やかでコーナーでも画面に残り、横位置が直接取れます。DriverModel は無改造のまま知覚だけを入れ替えて、公平なアブレーションで比較しました。
| 知覚 | 完走 | 衝突 | SOC残 | 軌跡 |
|---|---|---|---|---|
| 白線 sliding-window | ✅ | 6〜8 | 0.23〜0.31 | ガタガタ・電池枯渇 |
| 色(緑重心) | ✅ 3/3 | 0 | 0.71 | 高再現 |
色の頑健さがデータで裏づけられました。ただしタイムは 70.6s と遅い。旧driver(pulse+カーブ減速)が、色の大きめの横誤差に対して慎重すぎたためで、**「綺麗だが遅い」**状態。土台はできた、次は速度です。

[色ベース知覚:緑レーンを検出し重心(橙ドット)を毎フレーム追従。左下に Lateral / Theta / 曲率を算出している。コーナーでも緑は画面に残る]
2. Stage B:速度を解放する(torque-FF を P制御として使う)
診断すると、旧最速46.1s ですら終端速度の33%しか使っていないことが判明。速度の頭打ちが主因でした。
速度を同定すると 1次系 v̇ = a·torque − b·v − c(a=13.2, b=10.96, c=−0.58, 時定数≈0.09s)。当てはまりは弱い(R²=0.30)のですが、1次系という構造が効きます。目標速度 v* に対する定常トルク torque_ff = (b·v* + c) / a を指令するだけで、速度は v に収束する*。つまりv を観測できなくても実質的にP制御になる。
旧来の pulse ハック(実効スロットル0.35頭打ち+サージング)は撤廃し、直線は全開・コーナーは制御速度に。カーブ度を severity = 0.7·|steer|/lim + 0.3·|θ|/35° で測って v_target を決め、トルクを逆算します。
結果、27.1s・全完走・衝突0・SOC0.73残。速度利用率は 33%→57%。減速は v_target が下がるとトルクが落ち、抗力優勢で自然に効く(明示制動は補助)。軌跡はまだ中央付近、電池も大幅に余る=伸びしろが明確でした。
3. 崖を探す:コーナー速度ラダーと摩擦限界
V_MAX を 1.0→1.1 に上げても改善しません。このオーバルは短い直線+長い右スイーパーで、直線で 1.0 に達する前に次コーナーの減速が始まる=コーナー律速だからです。
そこで V_MAX=1.0 固定で、コーナー最低速 v_corner_min をラダーで上げていきました。
| v_corner_min | time | 結果 |
|---|---|---|
| 0.45 | 27.1s | 完走・衝突0 |
| 0.60 | 25.6s | 完走・衝突0 |
| 0.75 | 23.1s | 完走・衝突0 |
| 0.90 | 22.0s | 完走・衝突0 |
| 0.95 | 21.8s | 完走・衝突0 |
| 1.00 | — | 初コーナーで落下 |
1.0 でコーナー横Gが摩擦限界(A_LAT_MAX)を超えて落下。完走の上限は vc 0.9〜1.0 の間だと実測できました。そして 21.8s で、開ループお手本21.6s にほぼ並んだ。しかもクローズドループは再現性が高く・衝突0・電池に余裕という質的優位つき。
ついでに「直線は全開キープ+細かい操舵をやめる」という直線モードも試しましたが、効果なし。診断すると直線判定の発動率はわずか1%——ほぼ全周がコーナーで、直線の伸びしろが構造的に無い。筋は良い仮説でしたがトラック形状で否定された(有用な負の知見)。
なお、落下は
status=Fallen+終端 pos_y < −0.1の二重で検出。テーブル編で見つけた旧statusバグへの保険が、ここで効きました。
4. 崖を上げにいく:アウト・イン・アウトの失敗と、apex 内寄せ
速度のラダーは vc=1.0 の落下崖で頭打ち。崖そのものを上げるには、コーナーを直線化して「経験する曲率」を下げる=アウト・イン・アウトです。
まず教科書どおり、区間で狙う色を切り替え(緑→外赤→内青アペックス→外赤)。結果は全落下でした。原因は2つ。
- 狭い3レーン路に"アウト"の余白が無い:外(赤)・内(青)レーンの外側が即・落下境界。端レーンの重心を狙う=トラック端を走る=落下余裕ゼロ。
- 色のハード切替で横目標が飛ぶ:steer が急反転(例 −0.52→+0.40)して逸脱。vc を 0.6 に落としても落下=速度でなくライン自体の問題。
教科書的 out-in-out は外側余白が前提で、この狭路では成立しない(負の知見:コース幅が攻めラインを制約する)。
そこで安全側に倒し、色切替なしで apex だけ内へ滑らかに小オフセット(|θ| 依存、ジャーク無し、境界余裕を残す)。結果、bias40 / vc0.95 → 21.4s・衝突0・SOC0.7残。
ここでクローズドループが、開ループお手本21.6s を下回りました(21.4s)。
5. 限界の理解:崖は硬い物理限界
内寄せは経路を僅かに短縮しますが、同時に半径も小さくなるので崖は上がらない(vc=1.0 は bias の有無に関わらず落下)。さらに操舵をPD化して崖際の安定余裕を広げられるか試しましたが、上がらず。落下は yaw>100°・最大舵角でも滑る、純粋なグリップ限界でした。
速度系の全レバーが頭打ち=このオーバル×狭路3レーンの物理限界に到達した、という理解です。
6. 結論:自動アルゴリズムが、手握り最速を超えた
| Stage | 構成 | time | 衝突 | SOC残 |
|---|---|---|---|---|
| 旧ルールベース | 白線・pulse | 46.1s | 4 | 0.65 |
| A 色知覚 | 緑重心追従 | 70.6s | 0 | 0.71 |
| B 速度profile | torque-FF | 27.1s | 0 | 0.73 |
| 崖際 vcラダー | vc=0.95 | 21.8s | 0 | 0.70 |
| C apex内寄せ | bias40 / vc0.95 | 21.4s | 0 | 0.70 |
| (参考)開ループお手本 | 手握りCSV | 21.6s | — | 非再現・~25%完走 |
旧ルールベース 46.1s(衝突4)→ 21.4s(衝突0)= 2.15倍速・クリーン。最速構成(V_MAX=1.0 / v_corner_min=0.95 / inside_bias=40)で3本連続走らせると 21.46〜21.57s・全完走・衝突0・ばらつき±0.1s。
速いだけではありません。安定・再利用可能・説明可能——この3つが、前回の開ループ(非再現・~25%完走)との本質的な差です。前回「フィードバックは必須」と示したことの、これが答え合わせでした。
---7. AIと協働して開発するために効いたこと
最後に、ソロ開発で AI(実装)と二人三脚で詰めるうえで効いた進め方を。
- 可視化レポートを"共有の軸"にした:各Stageの軌跡・3パネル・知覚mp4を HTML 化し、前後を一目で並べて方針を合意。文章より速く認識が揃う。
- 1レバーずつ・env で切替・既定は安全側:変更を小さく刻み、いつでも戻せる状態を保った。
- 負の知見を捨てない:out-in-out 全落下、直線モード効かず、PDで崖上がらず——これらを記録したことが、次の一手の判断材料になった。
- 設計と引き継ぎを残す:方向性のズレを早めに直しながら積み上げた。
——速さも、失敗も、物理限界も、すべて理由を説明できる形で残す。これが aira の掲げる 「説明できる知性(Explainable Intelligence)」 が指すものです。次はいよいよ、AIモード(学習)でこの 21.4s に挑みます。
おまけ:aira について
aira は、仮想ロボットで自律走行アルゴリズムを競う、誰でも参加できる物理AIレース競技です(Race Your Algorithm)。PC1台・参加無料。現在 Race_260601(タイムアタック) と Race_260615 を開催中です。
