プロジェクト記録 / 競技終了・華北地区第7位

CongCar:「走行できる」状態から安定した高速走行へ

第21回全国大学生スマートカー競技会の華北地区で第7位。RK3588 上のリアルタイム処理、経路追従の共通化、シーン遷移、歩行者回避を改善した過程。

  • 自律走行車
  • RK3588
  • リアルタイム処理
  • 制御

CongCar の目的は、オフラインで一回だけ推論結果を表示することではない。RK3588 上で画像取得、セマンティックセグメンテーション、物体検出、経路計画、車体制御を連続して実行することである。

車両が実際に動き始めると、平均 FPS だけでは説明できない問題が現れる。古いフレームがキューに残っていないか、シーン判定が短時間で往復しないか、経路追従処理を複数シーンで一貫して利用できるか、速度変化が連続しているか、異常時に安全に停止できるか、といった問題である。

このプロジェクトの改善は、機能を追加するだけではなく、「コースを観測する」時点から「車両へ制御量を送る」時点までの経路を短くし、各段階を観測可能にする作業だった。

第21回全国大学生スマートカー競技会で、CongCar は華北地区第7位となった。競技は終了したため、本稿は継続開発の記録であると同時に、実際のコース結果を起点に、車両の挙動へ影響した設計と今後に残る課題を振り返るプロジェクトレビューでもある。

プロジェクト範囲と担当部分

CongCar はチームで継続的に開発している車両システムであり、リポジトリには複数メンバーによるセグメンテーション、物体検出、シーン処理、制御の実装が含まれる。本稿は、自分が参加し、継続して追跡してきた全体の改善過程を記録するものであり、すべてのモジュールを一人でゼロから実装したという意味ではない。

最近重点的に担当したのは、歩行者シーンにおけるパラメータと状態管理、車体中心のずれが危険判定に与える影響、共通の経路追従モジュールとの連携である。マルチスレッド処理、NPU 推論、分岐処理、その他のシーンについては、チームの実装とコミット履歴に基づいて整理している。

誰が何を変更し、どの条件で検証したかを明確にすることは、単なる役割説明ではない。後から同じ現象を再現し、経験を再利用するために必要な情報である。

リアルタイム処理を分離する

初期構成では、推論、制御、表示が近い実行経路にあり、一つの処理が遅くなるとパイプライン全体が停止しやすかった。その後、処理を次のタスクへ分離した。

  • 画像取得
  • セマンティックセグメンテーション
  • 物体検出
  • 制御
  • 表示・HTTP ストリーミング

各タスクは共有結果を通じて最新状態を参照する。ここで重要な設計判断は、キューが満杯になったときに古いフレームを破棄することである。

録画システムでは全フレームを処理することが重要かもしれない。しかし走行中の車両では、完全だが遅れて届く情報より、多少欠落していても現在に近い情報の方が有用である。したがってリアルタイム最適化の目的は、表示を滑らかにすることではなく、制御が利用する認識結果の「情報年齢」を小さくすることにある。

セグメンテーションと物体検出は RK3588 の異なる NPU コアへ割り当てられ、セグメンテーション側では二つの推論エンジンを交互に利用する構成も試した。しかし並列化は自動的に高速化を意味しない。メモリ転送、ランタイムのスケジューリング、制御側の消費速度がボトルネックであれば、エンジン数の増加は構成だけを複雑にする。

実際に、全体として 1.0 m/s で安定して完走することを優先し、セグメンテーションを一時的に単一コアへ戻したバージョンもある。部分的な推論速度より、車両全体の再現性を優先した判断だった。

FPS ではなくデータの新しさを測る

モデル単体の推論 FPS は分かりやすい一方、システム評価では誤解を招きやすい。セグメンテーションの処理回数が増えても、制御スレッドが古い結果を読んでいれば、車両は早く反応しない。

端から端までの遅延を理解するには、少なくとも次を分けて記録する必要がある。

  • カメラが新しいフレームを生成する頻度
  • セグメンテーションと検出が結果を更新する頻度
  • 制御スレッドが結果を利用した時点での経過時間
  • UART へ制御指令を送信する頻度

したがって、「マルチスレッド化されたか」という問いに、スレッド数だけで答えることはできない。制御のホットパスに待ち時間があるか、古い結果がキューに残るか、制御が常に最新結果を優先して読むかが重要である。

CongCarの実走行デバッグ画面:前方のセマンティックセグメンテーション、右側の鳥瞰経路、制御状態を同時に表示

通常のライン追従シーンで使った現場画面。前方の認識、鳥瞰経路、速度、モデル性能を同時に確認できる。モデルのFPSは局所的な計算速度を示すだけで、カメラ入力の頻度や端から端までの制御の新しさを代替しない。

重複した経路追従から共通 PathFollower へ

通常走行、車両回避、歩行者対応などのシーンが増えると、各シーンが独自に中心線抽出と操舵制御を持つ構成は維持しにくくなる。パラメータが分岐し、一つの不具合を複数箇所で修正する必要が生じるためである。

そこで PathFollower を共通化し、鳥瞰画像上の経路、中心線、前方注視点、操舵制御を統一した。各シーンは、走行不可領域をマスクする、分岐で残す側を選ぶ、停止条件を決定するといった制約だけを変更する。

このリファクタリングの効果は重複コードの削減だけではない。シーンが切り替わっても同じ制御状態を継続できるため、切り替え直後の操舵量の急変を抑えられた。検出結果の短時間変動に対するデバウンスと共通バッファも導入し、一フレームの揺れで行動が反転しないようにした。

一方、共通モジュールには回帰リスクがある。一つの変更が通常走行、車両シーン、歩行者シーン、分岐処理へ同時に影響する。再利用によりコード量は減るが、各シーンで座標、速度、操舵規約が維持されているかを確認する必要は増える。

分岐処理:実装、revert、再設計

分岐路では当初、セグメンテーションマスクから一方の枝を直接消去する方式を実装した。この方法は短期間で動作したが、コミット後に複数回 revert されている。

問題は二つあった。第一に、共有マスクをその場で変更すると、表示や他のシーンが読む結果まで変化する。デバッグ画面に表示されるものがモデルの生出力ではなくなり、問題の発生場所を特定しにくい。第二に、透視画像では手前と奥で道路幅が変化するため、固定ピクセル幅による切除が安定しない。

後の方式では、分岐処理を鳥瞰座標へ移し、実空間に近い等幅の切除を行い、残す側を設定値にした。鳥瞰画像では距離と車体幅を扱いやすく、透視画像のスケール変化への依存も減る。

この履歴で重要なのは、revert を単純な失敗として扱わないことである。実コースで誤った抽象化を早く否定し、制御可能な状態へ戻すことは、コミットを維持することより重要だった。

高速化で拡大した問題

走行速度は 0.7 m/s、1.0 m/s、1.5 m/s と段階的に引き上げられた。速度上限だけを変更しても、安定走行にはならない。速度が上がるほど判断に利用できる時間が短くなり、同じ遅延がより長い実移動距離に対応する。

低速では小さな蛇行に見えた問題が、高速ではコースアウトにつながる。低速では無視できた一フレームの誤検出が、高速では急な操舵や不要停止を発生させる。

これに対して次の改善を行った。

  • カーブでの減速係数を設定ファイルへ移す
  • マーカーや経路を一時的に失った場合の速度減衰
  • 加速時のバッファによる速度指令の急変抑制
  • 鳥瞰画像の横幅拡張
  • モデル、クラス名、表示色、シーン対応関係の JSON 化

設定ファイル化の目的は、形式的に「設計らしく」見せることではない。現場で、変更、走行、観察、再現可能な値の保存という短いフィードバックループを作るためである。

速度を上げるたびに、認識遅延、最大操舵変化、カーブ速度、異常時の動作を再確認する必要がある。「低速で完走できたので、PWM を上げれば高速でも動く」という推論は成立しない。

歩行者シーン:検出と危険判定を分ける

歩行者回避は、自分が重点的に改善した部分である。単純な「人を検出したら停止する」という規則では、実環境に対応できなかった。

遠方の歩行者、走行経路外の歩行者、短時間の誤検出まで停止を引き起こす一方、一フレームだけを見る判定では、実際に危険な状況で反応が遅れる可能性もある。

改良後のシーンでは状態を保持し、次の情報を組み合わせる。

  • 歩行者が計画経路へ入っているか
  • 対象までの距離と危険領域
  • 検出が継続した時間と消失時間
  • 停止後に走行再開を許可する条件
  • 画像中心と実際の車体中心のずれ

最後の項目は見落としやすい。カメラの取り付け位置、画像クロップ、鳥瞰変換によって、画像中央が車両の通過位置と一致するとは限らない。車体中心のオフセットを設定可能にすることで、危険領域を実際の車体軌跡へ合わせた。

最初の規則が不十分だった理由

最初の実装は、検出矩形が指定領域へ入れば停止し、領域外へ出れば再開するというものだった。論理自体は単純で理解しやすいが、時間と経路の文脈がない。

  • 検出矩形が閾値周辺で揺れると、停止と再開を繰り返す
  • 歩行者が近くても、車両が通過しない側にいる場合がある
  • 短時間の見落としを「道路が空いた」と誤認する
  • 停止条件と再開条件が対称だと、早すぎる再発進が起こる

これらの現象から、「歩行者を検出したか」と「衝突リスクがあるか」は別の変数だと分かった。

状態管理による改善

改良後は直近の状態を保持し、危険領域への進入、停止確認、再開許可を分離した。停止側の検出は比較的敏感にし、再開側はより安定した確認を要求する。短時間の見落としではリスク状態を解除せず、計画経路から離れた対象には同じ重みを与えない。

この非対称性は安全ロジックで重要である。不要な停止は主に走行時間を失うが、誤った再開は衝突につながる。パラメータ調整では、滑らかさだけでなく、どちらの誤りをより強く避けるかを明示する必要がある。

必要な検証ケース

歩行者シーンでは少なくとも次のケースを繰り返し確認する必要がある。

テスト条件期待する動作
歩行者が経路を横切る危険領域で停止し、離脱を安定確認して再開
画面端にいるが経路へ入らない単なる検出だけでは停止しない
短時間の遮蔽・未検出直ちに走行再開しない
検出矩形が閾値付近で揺れるシーン状態が高速に往復しない
歩行者不在時の一時的な誤検出継続性と領域条件で除外する

コミット履歴から、ロジックとパラメータを複数回変更したことは確認できる。しかし、標準化した試行回数、誤停止率、再開までの時間分布はまだ十分に記録されていない。これらを整備することが、経験的な閾値追加より研究的な改善につながる。

「走行できる」と「安定性を説明できる」の差

このプロジェクトの履歴には、新機能だけでなく、リファクタリング、一時的な無効化、revert、再実装が含まれる。実際の工学開発では、性能向上が制御問題を表面化させ、シーン追加が共通機能の抽象化を要求し、ハードウェア並列化も端から端までの遅延で評価しなければならない。

改善の有効性は最終的に車両挙動へ戻って判断する。

  • 制御が十分に新しい認識結果を利用しているか
  • 同じ設定で同様の結果を再現できるか
  • シーン遷移時に操舵と速度が連続しているか
  • 誤検出や短時間の機能停止が危険動作を起こさないか
  • 高速化した後も安全限界が明確か

今後の課題

現在のシステムは認識から制御までの閉ループを形成しているが、「完走できる」状態と「安定性を定量的に説明できる」状態の間にはまだ差がある。次の改善が必要である。

  • 主要スレッドで共通タイムスタンプを記録し、認識から制御までの遅延を計測する
  • 典型的な失敗映像と設定を保存し、再生可能な回帰テストを作る
  • シーン遷移を状態図とタイムアウト条件で明示する
  • 速度別の完走率、コースアウト回数、停止距離を記録する
  • ソフトウェア停止、能動制動、ハードウェア非常停止の能力境界を明確にする

このプロジェクトを研究室の教員へ説明する場合、機能数の多さより、現象から仮説を作り、システムを変更し、失敗を認め、次の検証方法を具体化した過程を示したい。

GitHub リポジトリ:Normanchine/CongCar