コンテンツにスキップ

CommonRoad solution checker の判定リファレンス

1 回の再生について PASS / FAIL を言うものが 2 つあり、それぞれ別の問いに答えて います。

誰が問うか何を意味するかいつ得られるか
公式 7 検査commonroad-drivability-checkerこの解は本当に planning problem を解いたかsolution の隣に .verdict.json を読ませたとき
drawtonomy 自身の判定drawtonomy (再生中)この再生は、あなたが書いた fail 条件を踏んだか常に。追加のファイルは不要

drawtonomy 自身の判定は「何も入れずにすぐ見える目安」、checker の判定が「権威」です。 どちらも他方を上書きしません。verdict は失格を足すことはあっても、消すことは ありません。drawtonomy が衝突を見た解を checker が通していたら、両方の答えが出ます。

drawtonomy-cr verdict が回すのはちょうどこの 7 つで、この順に、その結果を そのまま書きます。

検査落ちる条件
solved_all_problemsシナリオが立てた planning problem のうち、解が入っていないものがある。
goal_reached軌跡が planning problem のゴール (位置、および速度区間が設定されていればそれも) を一度も満たさなかった。
starts_at_correct_state解の最初の状態が planning problem の initialState と一致しない。全属性を比較し、許容差は 0.1 (速度は 2.0) です。
obstacle_collisionego の footprint がシナリオの障害物と重なった。タイムステップ区間と障害物 id 付きで報告されます。
boundary_collisionego が走行可能な道路境界の外に出た。必要な triangle パッケージが無いときは SKIP で報告されます。
ego_collision協調解 (cooperative solution) の ego 同士が衝突した。ego が 1 台だけの解ではぶつかる相手がいないので通ります。
solution_feasible記録された軌跡が、解が宣言している車両モデル (KS / PM …) で再現できない。許容される入力ではその状態列に到達できない。

solution_feasible は drawtonomy 自身には到達できない種類の判定です。衝突がなくても、 どんな車にも走れない軌跡はあり得ます。

検査は SKIP で返ることもあります。これは合格でも不合格でもありません。 checker が答えに辿り着けなかったので、その解について言えることが何も無い、という 状態です。現在これが起きるのはちょうど 1 つの場合だけです。boundary_collision は 道路を三角形分割するのに triangle パッケージを必要としますが、triangle は 商用利用が無償ではないため既定では 入れていません。入れるときは [boundary] extra を使ってください (pip install "drawtonomy-commonroad[checker,boundary]")。

これ以外の例外は、ego が実際に道路外に出た場合も含めて、今までどおり FAIL です。 パッケージが無いことが「あなたの軌跡が道路から出た」と読めてはいけません。

SKIP はバッジの数え上げから外します。 boundary_collision が SKIP で残り 6 検査が判定されて合格なら、表示は PASS 6/7 ではなく Checker PASS 6/6 です。分母は常に「実際に答えが出た検査の数」で、 分子は手前の語と同じものを数えます。PASS n/N なら n は合格数、FAIL m/N なら m は不合格数です。Checker FAIL 3/7 は「判定した 7 件のうち 3 件が FAIL」です。

CLI では括弧に次の一手が付いた 1 行になり、exit code は 0 のままです。

[SKIP] boundary_collision (pip install triangle)

再生中に評価されるのは FAIL CONDITIONS で、なかでも重要なのが Collision です。 これは描いたシナリオでも import したシナリオでも既定で入っています。衝突させる つもりのシナリオは、その条件を外すまで FAIL になります。これは fail 条件に対する 実行時判定であって、シナリオそのものの検証ではありません。

再生後、transport 行に RUN バッジが出ます。入力指紋が照合済みの判定だけが、そのtooltip・RUN評価・タイムラインのFAILマーカーに反映されます。

未照合の判定は、別の琥珀色 CHECK ? バッジで表示します。tooltipには同一性を確認できない理由と、ファイルが報告した検査結果を示します。その結果はRUNの合否を変えず、FAILマーカーも追加しません。指紋なしの判定 (drawtonomy-commonroad 0.1.0、または他ツールの出力) はこちらの経路です。drawtonomy自身の実行時チェックは独立に動作します。

以下の画像とPASS/FAILの説明は照合済み判定の経路を示します。画像は指紋照合と7検査への拡張より前のもので、4/4 / 2/4 と出ています。7検査がそろう照合済みサイドカーの分母は7です。現在の未照合バッジの画像ではありません。

transport 行の RUN PASS バッジと開いた tooltip。「Playback result: this run ended normally (stop condition met or all events completed) with no fail condition triggered. This is a runtime check against the fail conditions only, not a validation of the scenario itself.」「Replay: planner_solution.xml, CommonRoad KS · 190 states」「Checker PASS 4/4 (commonroad-drivability-checker)」「min TTC 0.05s @ 12.4s (vs OverTaker)」が並ぶ

checker が通した解。tooltip には replay のファイル名、車両モデル (KS)、状態数、 そして何件通ったかが並びます。通った検査は数えるだけで、名前は並べません。

RUN FAIL バッジと開いた tooltip。「Checker FAIL 2/4 (commonroad-drivability-checker)」「obstacle_collision · obstacle 15 · 12.7–13.3 s」「solution_feasible · whole trajectory」「Replay: planner_solution.xml, CommonRoad KS · 190 states」「min TTC 0.05s @ 12.4s (vs OverTaker)」が並ぶ

FAIL のとき。通らなかった検査だけが 1 件 1 行で、検査名・相手の障害物・秒が出ます。 FAIL の出どころが checker なら、このブロック自体が理由なので、Fail condition: の 行として重ねて書きません。

読み取るべきものは 3 つです。

  • Checker PASS 7/7 / Checker FAIL 2/7: 要約。分母は判定できた検査の数なので、 全部そろったサイドカーなら 7、SKIP があったり サイドカーがその検査を持っていなければ小さくなります (上の 2 枚が 4/4 / 2/4 なのはこのためで、7 検査になる前に書かれたサイドカーです)。分子は手前の語と同じものを 数えます (7 件が合格 / 2 件が不合格)。verdict を読み込んだときの toast と同じ文言 なので、toast が消えたあとも同じ語で辿れます。
  • 通らなかった検査だけ 1 件 1 行: 検査名、checker が持っていれば障害物 id と 時刻区間が · 区切りで付きます (timeline の fail マーカーと同じ形)。通った検査は 要約の数に入るだけです。飛ばした検査は boundary_collision · SKIP と出て説明も 残します。checker の定型文 (“There is a collision between the scenario obstacles and the ego vehicle…”) は 出さず、実際の診断 (“76 of 179 state transitions … position drifts up to 149.6 cm”) は検査の下に 字下げして残します。
  • 時刻は秒です (サイドカーのタイムステップから換算)。時刻を持つ検査は timeline の その秒に fail マーカーが立ちます。時刻を持たない検査 (素の solution_feasible の ような軌跡全体への判定) は replay の末尾に置かれ、whole trajectory と出ます。

verdict は solution の隣に置く小さな JSON です。以下は衝突する解に対する checker の 答えです。

{
"schema": "drawtonomy-verdict/1",
"solutionFingerprint": "sha256:aacc4bad344c5b62adf139dd9889319cc3236f28d38f756445965b0862c09b50",
"scenarioFingerprint": "sha256:914a4300443dcf4bc585c7e43769983b4932c22bf69be37ac02bd086c1d5ab33",
"benchmarkId": "PM1:JB1:ZAM_Untitled202609011139-1_1_T-1:2020a",
"scenarioId": "ZAM_Untitled202609011139-1_1_T-1",
"dt": 0.1,
"tool": { "name": "commonroad-drivability-checker", "version": "2025.4.0" },
"generatedAt": "2026-09-03T04:52:49Z",
"checks": [
{ "name": "obstacle_collision", "status": "FAIL",
"message": "CollisionException: There is a collision between the scenario obstacles and the ego vehicle in planning problem solution 16",
"timeSteps": [127, 133], "obstacleId": 15 },
{ "name": "boundary_collision", "status": "PASS" },
{ "name": "goal_reached", "status": "PASS" },
{ "name": "solution_feasible", "status": "FAIL",
"message": "Exception: infeasible for planning problems [16]",
"vehicleModel": "PM" }
]
}
  • schema は必須。checks[].status は PASS / FAIL / SKIP。
  • checks[].name は自由文字列ですが、drawtonomy が timeline に置き方を知っているのは 上の公式 7 名です。
  • message は公式の例外をそのまま ({型}: {本文})。表示側は型の接頭辞を落として 本文だけを出します。
  • timeSteps は [first, last] (両端含む、0 起点)。秒は step × dt です。

このファイルを作るのに drawtonomy-cr を使う必要はありません。自前の CI ジョブから 書ける程度に小さく、判定の部分は公式 API の 7 呼び出しです。引数の順は 関数ごとに違うので注意してください。

from commonroad.common.file_reader import CommonRoadFileReader
from commonroad.common.solution import CommonRoadSolutionReader
from commonroad_dc.feasibility.solution_checker import (
solved_all_problems, goal_reached, starts_at_correct_state,
obstacle_collision, boundary_collision, ego_collision, solution_feasible)
from commonroad_dc.feasibility.vehicle_dynamics import VehicleDynamics
scenario, pps = CommonRoadFileReader("scenario.xml").open()
solution = CommonRoadSolutionReader.open("solution.xml")
checks = [
("solved_all_problems", lambda: solved_all_problems(pps, solution)),
("goal_reached", lambda: goal_reached(scenario, pps, solution)),
("starts_at_correct_state", lambda: starts_at_correct_state(solution, pps)),
("obstacle_collision", lambda: obstacle_collision(scenario, pps, solution)),
("boundary_collision", lambda: boundary_collision(scenario, pps, solution)),
("ego_collision", lambda: ego_collision(scenario, pps, solution)),
]
for name, fn in checks:
try:
fn(); print("PASS", name)
except Exception as e:
print("FAIL", name, e)
vehicle_dynamics = VehicleDynamics.from_model(
solution.vehicle_model, solution.vehicle_type)
print(solution_feasible(solution, scenario.dt, vehicle_dynamics))

valid_solution(scenario, pps, solution) は 7 つを 1 呼び出しでまとめて回し、 最初に落ちたところで例外を投げます。上のループは同じ判定を検査ごとに分けたもので、 サイドカーに 1 件 1 行で書くためにこうしています。

feasibility は「合否」より多くを言う

Section titled “feasibility は「合否」より多くを言う”

公式 checker は planning problem ごとの bool しか返さないので、どこで・なぜが 分かりません。そこで drawtonomy-cr は公式の state_transition_feasibility を隣接 2 状態ごとに当て直し、車両モデルで再現できない遷移、再構成された入力がどの限界に 張り付いたか、記録状態と模擬状態のずれを報告します。数値はすべて公式 API の返り値です。 公式コーパスの ZAM_Tjunction-1_42_T-1 の KS 解では次のようになります。

{ "name": "solution_feasible", "status": "FAIL",
"message": "14 of 147 state transitions (4.2-6.1 s) need a steering rate beyond the KS limit of 0.4 rad/s; position drifts up to 5.8 cm from the simulated state (tolerance 2 cm), orientation up to 0.019 rad (tolerance 0.03).",
"timeSteps": [42, 61], "reason": "steering_rate",
"infeasibleTransitions": 14, "transitions": 147,
"maxPositionError": 0.0581, "maxOrientationError": 0.0186,
"steeringRateLimit": 0.4, "accelerationLimit": 11.5, "vehicleModel": "KS" }

reason は最も多く当たった限界で、steering_rate / acceleration / friction_circle / input_bounds / state_deviation のいずれかです。timeSteps が 付くので、fail マーカーは末尾ではなく 4.2 s に立ちます。

対応付け: verdict は 1 つの解のもの

Section titled “対応付け: verdict は 1 つの解のもの”

solutionFingerprint / scenarioFingerprint は省略可能で、値は sha256: + 小文字hex64桁です。UTF-8本文の先頭BOMを除去し、CRLF/CRをLFへ正規化してから計算します。両側に値がある場合だけ比較し、不一致は拒否、欠落は同一性未確認として読み込みを継続します。未確認は手動で閉じる琥珀色の警告と専用の CHECK ? バッジで示します。tooltip に報告された検査結果を表示しますが、RUN の合否やタイムラインの FAIL マーカーへは合流しません。シーン編集時は現在の判定を外し、原文scenario指紋を失効させます。その後の指紋なし再読込も未確認として扱います。

verdict は scenario id と、両側にある場合の solution / scenario 本文の SHA-256 指紋で対応付きます (scenarioId、無ければ benchmarkId から <model>:<cost>: と :2020a を剥いだもの)。一致しなければ verdict は 適用されず、両方の id を名指しした 1 行が理由を言います。

other_scenario.verdict.json was not applied: it was computed for scenario
"ZAM_Other-1_1_T-1" but the loaded replay is for "ZAM_CutIn-1_1_T-1".

replay 自体は載ったままです。関連するルールが 2 つあります。

  • verdict だけ読ませても何も起きません。 解が載っていなければ判定する対象が ありません。先に solution を読むか同時にドロップするよう toast が促します。
  • シーンを編集すると verdict は降り、replay は残ります。 checker の答えは編集前の シーンに対して計算されたものだからです。ego は planner の軌跡を追い続け、 「その trace は編集より前のものだ」と toast が言います。編集後のシーンについての 答えが欲しければ planner を回し直してください。

drawtonomy-cr verdict:

code
0サイドカーを書けた。FAIL の判定でも 0 です。失格は JSON の中身だからです。
3checker が入っていない ([checker] extra、Linux x86_64)。インストール方法を 1 行で出します。