サービスロボット導入シミュレーション Log#15 | 寝ている間に店を回す準備ができた
パソコンの中に作ったファミレスで、配膳ロボットを何台入れると店がどう変わるかを調べています。お客さんが来て、スタッフが案内し、ロボットが料理を運ぶ。Unity(ゲームを作る道具)で作った3Dの店を、混む2時間ぶん動かして、待ち時間などを数えます。1回に10分ほどかかり、これまでは人がボタンを押して、1回ずつ回していました。
これを、人が寝ている間も回し続けられるようにしたいと考えました。条件を変えた回を夜のうちに何十回も回し、朝には結果が「正常」「直す候補」などに振り分けられている状態です。そのための準備をまる1日かけて進め、画面を出さずに回せる実行ファイルと、結果を自動で振り分ける仕組みができました。
ただ、準備の途中で思いがけないことが分かりました。比べる相手にしていた18回の結果(基準データ)の一部が、当時の Unity の状態に引きずられて、ずれていたとみられます。同じ店・同じ条件で、ある店の形では、入店待ちが基準では6.16分、開き直したばかりの Unity で回すと4.54分でした。何十回も続けて回した長い作業のあとで回したか、開き直してすぐに回したか。見つかった違いはそれだけで、これだけ数字が変わっていました(開き直して回したのは1回だけで、何が残っていたのかまでは突き止めていません)。夜に何十回も回す前に気づけたのは幸いでした。
ほかにも2つ分かったことがあります。1つは、同じ条件・同じ乱数で回しても、結果が毎回少しずつ違うこと。もう1つは、ロボットどうしが速さを落としてすれ違う動きを入れたら、すれ違いは増えたのに、店全体は悪くなったことです。入店待ちが約3倍になりました。おもな原因は、幅1.2mの通路で2台が右に寄ると、人が通れる隙間がなくなることでした。間を詰めすぎて2台とも止まったままになる場面もありました。
やったことの全体です。
| やったこと | なぜ | 結果 |
|---|---|---|
夜の結果を自動で振り分けるスクリプトを作った | 人が全部を見なくても、朝に「正常」以外だけ見ればよくするため | 18回で試して、正しく振り分けられた |
判定の線を、これまでの18回の実データで決めた | 線を勘で決めないため | 同じ条件でも乱数で入店待ちが最大11倍違い、1条件の乱数は3つから10個に増やした |
シミュレーションを、ロボットアームの Unity プロジェクトから分けた | 同居していると、画面なしで回すための設定を変えられなかったため | 新しいプロジェクトで同じ動きになることを確かめた |
同じ乱数で2回回すと結果がずれる原因を調べた | 夜に何本も同時に回すと、結果が偏るおそれがあったため | 心配していた「Mac が忙しいと人の道の計算が遅れる」は元ではなかった。小さな揺れは残るので、乱数10個の中央値で比べる |
比べる相手の18回を作り直した | 古い18回が、当時の Unity の状態に引きずられていた見込みが高いため | 新しいプロジェクトの18回を基準にした |
ロボットどうしのすれ違いを試した | 実物の配膳ロボットは、止まらずにすれ違うため | 店全体が悪くなった。人が通れるかを見てから寄るように直した |
画面なしの実行ファイルと、夜の実行係を作った | エディタを開かずに、何本も同時に回すため | できた。実物で動かして不具合を2つ直した |
ここから下は作業ログです。効果のうち「見込める効果」と書いた所は、まだ測っていない見込みです。測った数字はそのまま載せています。
作業ログ ― 夜の結果を振り分ける線を、18回の実データで決めた
区切りにした基準データ v2(段階B・cs:144 の18回)
前の日までに、店の形2つ(③効率重視・入口が角、⑦その通路を0.95mにした店)× ロボット0・1・2台 × 乱数の種0・1・2 の18回を回していました。Unity の版は cs:144(Unity Version Control の変更の番号)、サイトの試算は v2.8 です。この18回を「基準データ v2」と呼び、夜の仕組みを作る前の区切りにしました。
夜に回した結果を自動で振り分けるには、「どこからを問題とみなすか」という線が要ります。前の日に出したたたき台は次の4つでした。
| 項目 | たたき台 |
|---|---|
| 立ち往生 | 同じ場所で30秒動かなければ |
| ロボットどうしの向かい合い | 60秒止まったら問題 |
| 試算とのずれ | 向きが逆か、大きさが2倍以上ずれたら試算を見直す |
| 1条件の乱数の種 | 3つ |
18回で確かめた結果:乱数の種によって入店待ちが最大11倍違う
18回の記録(止まり・譲り合い・台帳)を読むスクリプト c3_judge_lines.py を書いて、たたき台の線を当てました。スクリプトと出力の全量は、記事の終わりの「コードと記録の全量」に載せています。
| 項目 | 18回で分かったこと |
|---|---|
| 立ち往生 | Unity はもともと「60秒動けなければ『動けなくなった』」という作りで、205件がちょうど60秒。30秒の線にすると、30〜60秒の止まりが99件増える |
| 向かい合い60秒 | 今の版ではもう起きていない。ロボットどうしの待ちは最長20.1秒。ただし30秒以上の止まり304件のうち156件は「もう1台のロボット」が原因 |
| 試算とのずれ2倍 | 入店待ちはすべての条件で1.9〜5.7倍、「席は空いているのに待った」は4〜12倍。この線だと毎晩すべての回に印が付き、判定にならない |
| 種3つ | 同じ条件でも、入店待ちが種によって1.5分〜18分。最大÷最小は7.5〜11.3倍。種0はどの条件でも1.5〜2.1分、種2は11〜18分 |
いちばん大きかったのは種の差でした。ロボットの台数を変えたときの差より、種を変えたときの差のほうが大きいので、種3つでは「ロボットを増やすと待ちが減るか」という向きが読めません。
この結果を見て、次のように決めました。
| 項目 | 決めたこと |
|---|---|
| 種の数 | 1条件あたり10個(種0〜9) |
| 立ち往生 | ロボットが1回で30秒以上止まったら数える。判定のためだけの線で、Unity の「60秒で動けなくなった」の作りは変えない |
| 試算とのずれ | 差の大きさは記録するだけ。印を付けるのは、基準データから外れたときと、ロボットを増やしたときの向きが種の過半数で試算と逆のときだけ |
| 終わる時刻 | 時刻で止めない。並べた回が全部終わるまで回す |
結果を4つに振り分ける judge_night.py
決めた線で、夜の結果を振り分けるスクリプト judge_night.py を書きました。
| 振り分け | 当たるとき |
|---|---|
| 回の失敗 | 台帳に行がない・最後まで回っていない・全員が帰っていない・ロボットが1コマで0.05mを超えて動いた |
| Unity の作り | 30秒以上の止まり・動けなくなった・卓を空けた・瞬間移動・打ち切りの、種の中央値が、基準の同じ条件の最大を超えた |
| 試算を見直す候補 | ロボットを増やしたときの向きが種の過半数で試算と逆、または Unity÷試算 が基準の範囲から外れた |
| 正常 | どれにも当たらない |
確かめとして、基準データ v2 を自分自身にかけると18回とも「正常」でした。1つ前の版(cs:143・試算は v2.7)の18回にかけると、逃がし弁を直す前の「卓を空けた」の多さ(8〜25回、基準は0〜4回)を拾って、18回とも「Unity の作り」に振り分けられました。狙いどおりに働いています。
あとで、Claude Code が実行係から呼んで試したときに4つの穴が見つかり、直しました。台帳にだけ行がある失敗の回を数えていなかったこと、やり直した回(_try2)と元の回を両方数えていたこと、基準に同じ条件がないと全部「Unity の作り」になっていたこと、の3つと、基準の既定の入れ替えです(あとの節)。さらに、ロボットどうしのすれ違いを「入」にした回を別の条件として分け、同じ夜の「切」と並べる表を出すようにしました。最終の版を全量に載せています。
夜の仕組みの設計と、Claude Code への依頼文
判定のスクリプトのあとに作るものを、設計 night_runs_design_v0.md にまとめ、Claude Code(Unity のコードを書く係)への依頼文を2本書きました。
| 依頼 | 中身 |
|---|---|
| v11 | シミュレーションを新しい Unity プロジェクトに分け、同じ結果が出るか確かめる |
| v12 | 画面なしの実行ファイル・1回ずつ回す入口・何本同時でも台帳を壊さない鍵・夜の実行係・何本同時に回せるかの実測 |
台帳(1回1行の記録の CSV)の決まりにも、何本も同時に書くときの決まりを足しました(data_manifest_rules.md の10-3)。
- 新しいプロジェクトの版は
ServiceSim/cs:Nと書く(番号が1から振り直されるため) - 鍵ファイル
unity_ledger_v1.lockを排他で開けてから1行書く - 実行係が止めた回・落ちた回は、実行係が stopped / failed の行を書く。やり直しは名前に
_try2を付ける - 列は増やさない。何本同時か・どの実行ファイルかは各回の run_info.json に書く
設計と依頼文の全量も、記事の終わりに載せています。
作業ログ ― シミュレーションを、ロボットアームの Unity プロジェクトから分けた
「新しいシーンはビルド設定に足さない」は、AI が自分で付けた用心だった
画面なしで回すには、エディタを開かずに動く実行ファイルが要ります。実行ファイルを作るには、店のシーンを Unity のビルド設定に入れる必要があります。前に Claude Code がこれを「新しいシーンはビルド設定に足さない、というお約束に触る」と言い、そのときは見送っていました。
調べると、この「お約束」は人が決めたものではありませんでした。シミュレーションの準備のコードを書いたとき、Claude Code が説明の中に自分で書いた1行でした。シミュレーションは、ロボットアーム(mechArm)の Unity プロジェクトの中に同居していて、アームの側を壊さないように「シミュレーションのフォルダの外は変えない」という用心を付けていました。ビルド設定はフォルダの外にあるので、そこから派生した1行です。それを、あとで私(Claude)が判断の理由に使っていました。
これサービスロボット導入シミュレーションで新しくプロジェクト作った方がいいのでは?
この一言で、プロジェクトを分けることにしました。
- ねらい:同居のための用心をなくし、時間・物理・ビルドの設定をシミュレーションに合わせられるようにする
- 変わったこと:
/Users/shimazueiichi/Robotics_UX/ServiceSim/に新しいプロジェクトを作り、Unity Version Control の新しいリポジトリ(ServiceSim/ServiceSim)に入れた - 見込める効果:画面なしの実行ファイルを遠回りせずに作れる。シミュレーションだけのプロジェクトなので、そのまま公開して他の人が同じ手順で回せる形に近づく
新しいプロジェクトに写したもの・そろえた設定
Claude Code が、シミュレーションが頼っているものを洗い出してから写しました。
| 項目 | 結果 |
|---|---|
| Unity のバージョン | 2022.3.62f3(同じ) |
シミュレーションのフォルダの外を指す参照 | 0件(たどった guid 118件。外に出るのは Unity の組み込みの2つだけ) |
| 使っているパッケージ | 6つ(ai・physics・imageconversion・jsonserialize・imgui・collab-proxy)。新しいプロジェクトは13件(前は42件) |
ProjectSettings | 19件は1バイトも違わない。わざと変えたのは4件(描画方式・ビルド設定・名前・アーム用のタグ) |
| 描画方式 | 前のプロジェクトは URP(Unity の描画の仕組みの1つ)を設定してあるのに、設定のファイルの参照が切れていて、実際は標準の描き方だった。新しいプロジェクトは最初から標準の描き方にした。絵も数字も変わらない |
| 写したファイル | 227件(.meta の欠け0・guid そのまま) |
Unity Version Control のリポジトリは、Claude Code のコマンドからは作れませんでした(Unity Cloud の画面でプロジェクトを先に作る決まり)。Unity Cloud の画面で ServiceSim のプロジェクトとリポジトリを手で作り、Claude Code が最初の check-in(cs:1・273件)をしました。
途中で1つ詰まりました。新しいプロジェクトの1つ上のフォルダ /Users/shimazueiichi/Robotics_UX/ が、4月の整理で残った古いワークスペースとして登録されていて、新しいワークスペースを作れませんでした。古い登録は、生きている Robotics_UX_New と同じ番号(ac1b3bde)だったので、番号ではなく場所を指定して1行だけ外しました。外す前の登録ファイルは .bak で残し、古い .plastic フォルダも消さずに名前を変えて残しています。
Setup が書き足した15項目は、前のプロジェクトの初期値と同じだった
新しいプロジェクトで準備のメニュー(Setup)を押すと、保留(check-in していない変更)が12件出ました。ロボットの設定のファイルに、cornerMaxX・yieldOrderEnabled などの項目が書き足されていました。
前のプロジェクトのファイルにはこれらの項目がなく、cs:144 の18回はコードの初期値で動いていました。Setup が書いた値を初期値と1つずつ比べると、15項目すべて同じでした。台帳の cs:144 の18行(yield_order_enabled 1・robot_first_wait_s 120)とも合っていたので、cs:2 として check-in しました。
作業ログ ― 同じ乱数で2回回すと、結果がずれた
移せたかの確かめ:③ロボット1台・種1を2回
新しいプロジェクトで、③ロボット1台・種1を2回回しました。同じ店・同じ条件・同じ乱数なので、同じ数字になるはずでした。
| 項目 | 1回目 | 2回目 | 基準 v2(cs:144) |
|---|---|---|---|
| 入店待ち(分) | 1.5452 | 1.702 | 3.2965 |
席は空いているのに待った(分) | 0.0023 | 0.0636 | 1.6683 |
| 動けなくなった | 11 | 0 | 6 |
| 往復の回数 | 64 | 72 | 66 |
2回の数字がずれました。全部の記録を1行ずつ比べると、お客さんの来方(来た時刻・席に着いた時刻)は2回とも同じでした。動きが最初にずれたのは、店の中の時間で1,546秒、スタッフ(Staff03)が道を譲った所で、譲って待った長さが0.4秒と0.2秒、つまり4コマ(1コマは0.05秒)だけ違っていました。1,546秒までは、譲り合いも止まりも小数4桁まで同じでした。その2秒後、ロボット1号機が同じスタッフとすれ違って止まった長さが1.05秒と0.95秒にずれ、そこから連鎖して、最後には大きく変わっていました。
同じ乱数で同じ結果が出ないと、「移せたか」を数字の一致で確かめられません。さらに心配だったのは、もしずれの元が Mac の忙しさで変わるものなら、夜に何本も同時に回したとき、結果が一方向に偏ることでした。
1コマごとの記録で、ずれ始めのコマを探した
Claude Code が、1コマごとに人とロボットの位置の合計を書き出す仕掛け(det_frames.csv)を入れ、設定を変えて2回ずつ回しました。
| 試し | 変えたこと | 2回は一致したか | 最初にずれたコマ |
|---|---|---|---|
| 試し1 | 1コマに道を探す量を 5000 に増やした | ずれた | 19,178コマ目(958.76秒)。人の位置の合計が 191507181 と 191507198。道を待っている人は2回とも0人 |
| 試し4 | 人の道を同期で引き、人どうしのよけ方(局所回避)も切った | ずれた | 30,537コマ目(1,527.18秒)。人の位置の合計が 195291062 と 195289556 |
試し1で、道を待っている人が0人のコマで人の位置がずれ始めたので、最初の見立て(人の道の計算を待つ時間が Mac の忙しさで変わる)は当たっていませんでした。Claude Code も、1コマに道を探す量は回数で決まっていて、1コマ0.05秒で進めている限り忙しさでは変わらない、と見立てを取り消しました。試し4(人の道を同期で引き、人どうしのよけ方も切った)ではずれ始めが遅くなりましたが、2つを同時に変えたので、どちらが効いたかは分かりません。切ってもまだずれたので、これだけが元ではありません。
ほかに調べて外れたもの:乱数の種を使わない乱数(0か所)、Unity が Play のたびに付け直す番号に頼る所(0か所)、ロボットのセンサーの切り捨て(4回とも0件・最大6件で枠32件)。
「必ず同じ」は追わず、乱数10個の中央値で比べることにした
元が1つずつ見つかっても、まだ残っている見込みが高く、追い続けると夜の仕組みが止まったままになります。一方で、心配していた「Mac が忙しいと人の道の計算が遅れ、人が鈍る」という仕組みは、元ではありませんでした。ただ、Mac をわざと忙しくして回す試しはしていません。あとで本数を変えて回したとき、空いているほど詰まりが少なく見える気配が出たので、別に確かめることにしました(画面なしの節)。
そこで、同じ乱数でも少し揺れる前提で、乱数10個の中央値で比べることにしました。1コマごとの記録の仕掛けは、切り替えを切った状態で残し(cs:3)、あとで「必ず同じ」を追うときに使います。
調べる中で、記録の時計のずれも見つかりました。店の中の時計を、0.05秒を小数で足し続けて数えているため、179分の回の終わりでは20秒以上ずれます。来客を止める時刻(7,200秒)の比べにこの時計を使っていて、実際は7,209.3秒まで来客を受け付けていました。直すと基準の数字が動くので、今は既知のずれとして残しています。
作業ログ ― 基準の18回は、当時の Unity の状態でずれていた
新しいプロジェクトの18回:③は合い、⑦だけ9回とも待ちが短い
移せたかを、2回の一致ではなく、18回をまとめて基準と比べて確かめることにしました。新しいプロジェクトで段階Bの18回を夜に回し(cs:7)、判定にかけました。回の失敗0件、Unity の作り0件でした。ところが、店ごとに分けると様子が違いました。
入店待ち(分、種0 / 種1 / 種2):
| 条件 | 基準 v2(cs:144) | 新しいプロジェクト(cs:7) |
|---|---|---|
| ③ 0台 | 1.56 / 3.90 / 13.13 | 1.47 / 3.80 / 13.43 |
| ③ 1台 | 1.51 / 3.30 / 11.37 | 1.40 / 3.00 / 11.99 |
| ③ 2台 | 1.47 / 2.03 / 16.64 | 1.57 / 2.41 / 11.95 |
| ⑦ 0台 | 1.70 / 6.16 / 18.07 | 1.53 / 4.18 / 13.32 |
| ⑦ 1台 | 1.77 / 8.22 / 16.22 | 1.43 / 2.04 / 10.92 |
| ⑦ 2台 | 2.08 / 4.06 / 16.21 | 1.63 / 1.50 / 11.92 |
③はおおむね合っています(③2台・種2だけ 16.64分と11.95分で離れています)。⑦は9回すべてで待ちが短く出ていて、「卓を空けた」(逃がし弁)も基準の0〜4回から全部0回になっていました。ロボット0台でも同じなので、ロボットの動きのせいではありません。9回そろって同じ向きなので、揺れでもありません。
道を探す量は原因ではなかった(100回でも5000回でも同じ)
最初に疑ったのは、試し1で5000にした「1コマに道を探す量」が、エディタを閉じるまで残っていたことでした。Claude Code がコードを読むと、切り替えを切っても「上書きをやめる」だけで、100に戻してはいませんでした。そこで、毎回はっきり値を入れて、実際の値を run_info.json に書く形に直し(cs:8)、Unity を開き直して⑦0台を3回ずつ回しました。
| ⑦0台(種0 / 1 / 2) | 入店待ち(分) | 人のあきらめ |
|---|---|---|
| 基準 v2(cs:144) | 1.70 / 6.16 / 18.07 | 37 / 37 / 66 |
新しいプロジェクト(cs:7) | 1.53 / 4.18 / 13.32 | 6 / 7 / 31 |
道を探す量 100(開き直したあと) | 1.54 / 4.13 / 13.50 | 7 / 8 / 21 |
| 道を探す量 5000 | 1.53 / 4.22 / 13.27 | 9 / 12 / 27 |
100でも5000でもほとんど同じで、原因ではありませんでした。条件と設定のファイル(conditions.json)も、新しく足した項目以外は基準と全部同じでした。入れている値は同じなのに、新しいプロジェクトでは⑦の人の動きが速く出ています。
前のプロジェクトを開き直して回すと、新しいプロジェクトと同じだった
前のプロジェクト(Robotics_UX_New)には、cs:144 のシミュレーションがそのまま残っています。何も変えずに Unity を開き直し、⑦0台・種1を1回回しました。
| ⑦0台・種1 | 入店待ち | 卓の回転 | 人のあきらめ |
|---|---|---|---|
基準 v2(cs:144・10/25 昼に回した) | 6.16分 | 16.4分 | 37 |
前のプロジェクトを開き直して回した | 4.54分 | 12.3分 | 11 |
新しいプロジェクト(cs:7・cs:9) | 4.13〜4.22分 | 11.9分 | 7〜12 |
同じ cs:144 のプロジェクトでも、開き直したばかりで回すと新しいプロジェクトと同じ帯になりました(この1回は、台帳に書かない回し方で回しています)。新しいプロジェクトで同じ種を3回回した入店待ちは 4.18・4.13・4.22分と揺れが小さく、6.16分は揺れでは届かない数字です。基準 v2 の⑦は、何十回も Play を重ねた長いエディタの中に残っていた何かに引きずられていた見込みが高い、と判断しました。 何が残っていたのか、なぜ③は引きずられなかったのかは、突き止めていません。前のプロジェクトの中に、Play のたびに Unity 全体の設定を書き換えるスクリプトがないかも読んで探しましたが、手で押すメニュー(30fps に落とす熱対策)しかありませんでした。
- ねらい:比べる相手の数字を、エディタの状態に引きずられていないものにする
- 変わったこと:判定の基準を、基準 v2(cs:144 の18回)から新しいプロジェクトの18回(ServiceSim/cs:7)に入れ替えた。cs:7 の18回を自分自身にかけると18回とも「正常」
- 見込める効果:画面なしの実行ファイルは1回ごとに新しく起動するので、長いエディタに状態が残る、という種類のずれは入る余地がなくなる。最初の夜(乱数10個)の結果で確かめる
2つの作業が同じプロジェクトを触り、回している途中の回が切れた
基準を作り直す18回の1回目は、台帳に行が残りませんでした。同じ時間に別の会話で、ロボットどうしのすれ違いの依頼(v13)が始まり、別の Claude Code が 19:41〜19:43 にシミュレーションのコードを書き換えました。Unity がコードを読み込み直し、回していた回は最後まで回って出力も書き出されたのに、台帳の行だけが書かれずに終わりました(台帳にない回として、そのまま残しています)。Run All を押し直し、もう一方の Claude Code は止めてもらいました。それからは、ServiceSim を触る作業は一度に1つにしています。
作業ログ ― ロボットどうしのすれ違いを入れたら、店全体は悪くなった
実物の配膳ロボットは、止まらずにすれ違う
実店舗の配膳ロボットの動画を見ると、空のロボット2台が狭い所で速さを落とし、止まらずに体どうしの間を詰めてすれ違っていました。Unity では、ロボットどうしが向かい合って長く止まることがありました。そこで、すれ違いを実物に合わせる動き(v13)を、初期値「切」で入れました。2m先にこちらへ向かってくるロボットがいたら、2台とも0.3m/秒まで落とし、右に寄って間を0.1mまで詰めて通ります。
入と切を1回ずつ(③ロボット2台・種1)
| すれ違い 入 | すれ違い 切 | 参考:基準 cs:7 | |
|---|---|---|---|
| ロボットどうしが出会った回数 | 120 | 84 | ― |
| すれ違えた | 88 | 56 | ― |
| 向かい合って止まった | 16 | 28 | ― |
| 幅が足りず今の決まりに戻った | 16 | ― | ― |
| 入店待ち(分) | 6.11 | 2.05 | 2.41 |
| 動けなくなった | 40 | 26 | 23 |
| 人のあきらめ | 98 | 51 | 59 |
| ロボットが運んだ割合 | 0.80 | 0.81 | ― |
すれ違い自体は狙いどおり増え、向かい合っての止まりは減りました。ところが店全体は悪くなり、入店待ちが3倍、人のあきらめが2倍になりました。
原因は、幅1.2mの通路で2台が寄ると人が通れないことと、詰めすぎて止まること
Claude Code が詰まりの場所を分けました。
| 場所 | 入 | 切 |
|---|---|---|
| 細い通路 A01 | 353件 | 0件 |
| 細い通路 A02 | 6件 | 51件 |
| 細い通路 A03 | 486件 | 29件 |
| 受け渡し口 | 15件 | 107件 |
受け渡し口の詰まりは減った一方で、細い通路3本の詰まりは合わせて80件から845件に増えていました。③の通路は3本とも幅1.2mです。寄せる幅は(ロボットの直径0.5m+間0.1m)÷2=0.3mで、2台が寄ると体が通路の大半を占め、空くのは壁際0.05mと真ん中0.1mだけになります。半径0.2mの人はどこにも入れません。寄る判断が、ロボットの通れる幅だけを見て、人が通れるかを見ていませんでした。
もう1つ、入で545秒続いた行き詰まりは、狙いの間0.1mより詰まりすぎて(0.064m)、両方が止まったまま離れる動きがなかったものでした。
「向かい合って止まった」の数え方も確かめました。切で数えた28回のうち26回は、受け渡し口のそばでした。受け渡し口は止まる点が1つしかないので、2台が同じ点へ向かうと向かい合って止まります。切でいちばん長かった559秒は、体が重なっていました(間 −0.041m)。これは今の標準(切)の作りの問題なので、直さずに既知として残しました。実際の店で受け渡し口の前にロボットがどう並ぶかを決めてから直します。
直した3つと、最初の夜の70回
| 直し | 中身 |
|---|---|
| ① 人の通る分を見てから寄る | 要る幅を 0.5×2+0.1+人0.4=1.5m にした。③の1.2m・⑦の0.95mの通路ではすれ違わず、今の決まりに戻る |
| ② 詰まりすぎたら離れる | 残りの間に合わせて速さを抑え、間を割ったら0.6mまで下がってから今の決まりに渡す |
| ③ 数え方を分ける | 通路でのふさぎ合い・受け渡し口・待機場所・体が重なった、を別々に数える |
①②は、すれ違い「入」のときだけ効く枝に入れ、「切」のときは新しい枝に1つも入らず、ロボットに書き込む所もないことを、コードを数えて確かめました(38項目・cs:10)。動かしての確かめは、最初の夜の「切」の60回で見ます。基準(cs:7)が「切」で回したものなので、切が変わると基準が使えなくなるためです。
すれ違いは手で1回ずつ比べず、夜の条件に入れて乱数10個で比べます。最初の夜は、③⑦ × ロボット0・1・2台 × 種0〜9 の60回(すれ違い切)に、③2台・すれ違い入 × 種0〜9 の10回を足した70回にしました。
作業ログ ― 画面なしの実行ファイルができた
店の時計と倍率の画面(SimHud)
実物の動画と秒数を比べられるように、画面の左上に店の時計(経過 時:分:秒)と、実際の倍率(直近2秒の、店の中の時間÷実時間)を出す部品を入れました(cs:12)。1倍で回す切り替えは、1コマ0.05秒の進め方を変えずに、1コマの実時間が0.05秒になるまで待つだけです。1倍で回した回は見る専用で、台帳に書かず、出力フォルダも作りません。画面なしで回すときは描かず、待ちません。
作る途中で落とし穴が1つありました。1コマの時間を0.05秒に固定すると、Unity の「実時間の経過」も0.05秒に固定されるので、それで倍率を測ると常に1.0倍に見えます。実時間は別の時計(起動からの実際の秒数)で測っています。
実行ファイル・1回ずつ回す入口・台帳の鍵
| 部品 | 中身 |
|---|---|
BuildHeadless.cs | メニューからも、コマンドからも、macOS(Apple Silicon)の実行ファイルを作る。入れるシーンはコードの中で指定する。そばに build_info.json(版・作った日時) |
| HeadlessRun.cs | 実行ファイルの入口。条件・乱数の種・名札などの引数を受け取り、段階Bと同じ回し方で1回だけ回して終わる。KIOXIA がつながっていなければ何も書かずに終わる。終わり方を終了コード 0(最後まで)・2(止めた)・1(失敗)で返す |
LedgerRow.cs・ServiceSimLedger.cs | 台帳の1行を作る所を1つにまとめ、書く所に鍵を付けた。ヘッダの確認と「同じフォルダの行がもうあるか」も鍵の中で行う |
tools/make_queue.py | 回す一覧(条件 × 種)を作る。条件は手で写さず、試算の値のファイルから引く |
tools/night_runner.py | 何本も同時に実行ファイルを起動し、終わった回は飛ばし、時間切れは止め、落ちた回は1度だけやり直し、全部終わったら判定を呼ぶ |
tools/ledger.py | 実行係が、止めた回・落ちた回の行を、同じ鍵で書く |
Claude Code の確かめでは、8本同時に台帳へ書いても8行がきちんと入り、59列のヘッダは壊れませんでした。C# の実行ファイルと Python の実行係が、同じ鍵で互いに待ち合えることも確かめています。
実物で動かして見つけた2つの不具合
最初に作った実行ファイルを実際に動かすと、2つの不具合が出ました。
- 実行ファイルの中では、試算の値を読み込む処理を誰も呼んでいなかった。どの条件を渡しても「知らない条件です」で失敗した。エディタの段階Bと同じ読み込みを足した
- 値が合わずに止まる道では、180秒待ってからしか失敗にならなかった。すぐ失敗で終わるようにした
直したあと(cs:17)、実行ファイルを作り直しました。版は cs:17・保留0で固まり、実行ファイルの記録と台帳の版が食い違わないようにしています。実行ファイルの大きさは57.3MBでした。
本物の台帳で2本同時・画面なしでも同じ帯か・何本同時に回せるか
本物の台帳に書く前に、台帳を archive/unity_ledger_v1_preacheck_20261026/ にコピーで退避しました(ヘッダを含めて87行)。そのうえで、3つを確かめました。
A. 2本同時に、本物の台帳へ書く(③1台・種1と種2)
| 回 | 終わり方 | 店の中の時間(分) | 実時間(秒) | 入店待ち(分) |
|---|---|---|---|---|
| acheck 種1 | completed | 183.3 | 148.9 | 2.59 |
| acheck 種2 | completed | 208.7 | 174.8 | 11.62 |
2行とも台帳に入り、列はずれず、ヘッダも59列のままでした。
B. 画面なしでも、エディタと同じ帯に入るか(③1台・種1)
| 回 | 回し方 | 入店待ち(分) | 席は空いているのに待った(分) | 往復 |
|---|---|---|---|---|
| bcheck | 画面なし・cs:17 | 1.71 | 0.09 | 74 |
| split_check 1回目 | エディタ・cs:2 | 1.55 | 0.00 | 64 |
| split_check 2回目 | エディタ・cs:2 | 1.70 | 0.06 | 72 |
| 基準 cs:7 | エディタ・cs:7 | 3.00 | 1.45 | 66 |
同じ乱数でも揺れる前提なので、数字の一致ではなく、エディタの回と同じ帯に入るかを見ました。入っています。
C. 何本同時に回せるか(③2台・種0〜2)
1本ずつ回した結果:
| 種 | 画面なし 実時間(秒) | エディタ(基準 cs:7)実時間(秒) | 画面なし 入店待ち(分) | 基準 cs:7 入店待ち(分) |
|---|---|---|---|---|
| 0 | 114.2 | 687.1 | 1.42 | 1.57 |
| 1 | 138.7 | 645.2 | 3.95 | 2.41 |
| 2 | 197.6 | 636.9 | 11.38 | 11.95 |
画面なしの実行ファイルは、店の中の約3時間(来客の2時間と、全員が帰るまで)を、1回およそ2〜3分(114〜198秒)で回しました。3回の平均は150秒で、エディタで回した同じ3回(平均656秒)の約4.4倍の速さです。 画面を描かないこととエディタの重さがないことが効いていると見ていますが、どちらがどれだけ効いたかは測っていません。
同時に回す本数を変えた結果(Claude Code の報告。CPU とメモリは回している間の値):
| 同時に回す本数 | 1回の平均 | 1時間に終わる回数 | 70回にかかる見込み | CPU | メモリ |
|---|---|---|---|---|---|
| 1本 | 151秒 | 23.8回 | 177分 | 1.5コア | 100MB |
| 2本 | 187秒 | 38.6回 | 109分 | 2.7コア | 195MB |
| 3本 | 220秒 | 43.5回 | 96分 | 3.8コア | 290MB |
| 4本 | 262秒 | 49.5回 | 85分 | 4.6コア | 400MB |
メモリは4本でも16GBの2.5%で、足りなくなる心配はありません。1回の最長は291秒で、実行係の時間切れ(40分)には遠く届きません。70回は1本ずつでも3時間で終わるので、4本と2本の差は24分だけです。
ただ、気になる気配が1つ出ました。③1台・種1を、1本だけで回すと「動けなくなった」0回・人のあきらめ26人、2本同時だと12回・57人、エディタだと9回・63人でした。空いているほど詰まりが少なく見えます。同じ乱数でずれる元として最後まで残っている疑い(人の道を動かす部品が、裏で並べて動いている)と筋は合いますが、それぞれ1回ずつなので、もともとの揺れと見分けがつきません。
判定は、夜の回をエディタで1本ずつ回した基準(cs:7)と比べます。同時に回すほど詰まりが増えるなら、夜の回にだけ印が付きやすくなります。そこで、同時に回す本数は、同じ種を1本×5回と4本×5回で回して分布を比べてから決めることにしました(約15分)。決めた本数は、夜のあいだ途中で変えません。
最初の夜の前の codex レビュー
台帳は壊すと戻せないので、台帳に書く所だけを別の AI(codex)にレビューしてもらいます。依頼文 codex_review_request_v12_ledger.md を作りました。見てもらうのは、C# と Python の鍵が外付けSSDの上でも同じ鍵として効くか、鍵を持ったまま落ちたときに鍵が残って次の回が永久に待たないか、時間切れで止めた回を実行係と実行ファイルが二重に書かないか、などです。レビューが通り、同時に回す本数が決まったら、最初の夜(70回)を回します。
コードと記録の全量
この記事で使った分析・判定・設計・依頼文・Claude Code の報告・台帳の行・Unity のコード(ServiceSim/cs:17)の全文です。
判定の線を決めた分析(KIOXIA の service_sim/unity/stageB_cs144/)
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(33本)
01_c3_judge_lines.py.txt ― c3_judge_lines.py・4,532字
02_c3_judge_lines_output.txt ― c3_judge_lines_output.txt・4,629字
03_tools_judge_night.py.txt ― tools/judge_night.py(ServiceSim・cs:16 で入れた版)・14,214字
04_night_runs_design_v0.md ― night_runs_design_v0.md(夜の仕組みの設計)・3,472字
05_claude_code_request_v12_night_runner.md ― claude_code_request_v12_night_runner.md(画面なしの実行ファイルと夜の実行係の依頼)・4,006字
06_20261025_1545_v11_project_split.txt ― 20261025_1545_v11_project_split.txt・24,963字
07_20261025_1745_v11_nondeterminism.txt ― 20261025_1745_v11_nondeterminism.txt・15,999字
08_20261025_1804_v11_det_check_prep.txt ― 20261025_1804_v11_det_check_prep.txt・8,984字
09_sec11.txt ― 20261025_1945_v12_tools.txt・10,512字
10_20261026_0725_path_iterations_leak.txt ― 20261026_0725_path_iterations_leak.txt・6,320字
11_20261026_1202_v13_passby_check.txt ― 20261026_1202_v13_passby_check.txt・12,063字
12_sec11.txt ― 20261026_1241_v13_simhud.txt・8,195字
13_20261026_1300_v12_headless_build.txt ― 20261026_1300_v12_headless_build.txt・14,561字
14_sec11.txt ― 20261026_1420_v12_check_abc.txt・11,981字
15_sec12.csv ― 台帳の行(unity_ledger_v1.csv・この記事で回した回)・18,231字
16_Assets_ServiceSim_Editor_ServiceSimSetup.cs.txt ― Assets/ServiceSim/Editor/ServiceSimSetup.cs・57,218字
17_Assets_ServiceSim_Editor_ServiceSimStageB.cs.txt ― Assets/ServiceSim/Editor/ServiceSimStageB.cs・45,155字
18_Assets_ServiceSim_Editor_BuildHeadless.cs.txt ― Assets/ServiceSim/Editor/BuildHeadless.cs・11,595字
19_Assets_ServiceSim_Experiment_ExperimentPlan.cs.txt ― Assets/ServiceSim/Experiment/ExperimentPlan.cs・7,716字
20_Assets_ServiceSim_Experiment_ExperimentRunner.cs.txt ― Assets/ServiceSim/Experiment/ExperimentRunner.cs・67,314字
21_Assets_ServiceSim_Experiment_TripLogger.cs.txt ― Assets/ServiceSim/Experiment/TripLogger.cs・87,951字
22_Assets_ServiceSim_Experiment_HeadlessRun.cs.txt ― Assets/ServiceSim/Experiment/HeadlessRun.cs・19,250字
23_Assets_ServiceSim_Experiment_LedgerRow.cs.txt ― Assets/ServiceSim/Experiment/LedgerRow.cs・10,701字
24_Assets_ServiceSim_Experiment_ServiceSimLedger.cs.txt ― Assets/ServiceSim/Experiment/ServiceSimLedger.cs・20,138字
25_Assets_ServiceSim_People_PeopleNav.cs.txt ― Assets/ServiceSim/People/PeopleNav.cs・4,894字
26_Assets_ServiceSim_Robot_FrontSensor.cs.txt ― Assets/ServiceSim/Robot/FrontSensor.cs・5,815字
27_Assets_ServiceSim_Robot_RobotSpec.cs.txt ― Assets/ServiceSim/Robot/RobotSpec.cs・14,035字
28_Assets_ServiceSim_Robot_ServingRobotController.cs.txt ― Assets/ServiceSim/Robot/ServingRobotController.cs・114,775字
29_Assets_ServiceSim_Robot_RobotPassBy.cs.txt ― Assets/ServiceSim/Robot/RobotPassBy.cs・16,005字
30_Assets_ServiceSim_Store_SimHud.cs.txt ― Assets/ServiceSim/Store/SimHud.cs・7,153字
31_tools_make_queue.py.txt ― tools/make_queue.py・6,389字
32_tools_night_runner.py.txt ― tools/night_runner.py・18,746字
33_tools_ledger.py.txt ― tools/ledger.py・6,406字
c3_judge_lines.py
# c3_judge_lines.py — 基準データ v2(段階B・cs:144 の18回)で、自動の判定の線のたたき台を確かめる
# 読むだけ。出力は標準出力(c3_judge_lines_output.txt に保存する)
# 使い方: cd /Volumes/KIOXIA/r2r2r-data/service_sim/unity && python3 stageB_cs144/c3_judge_lines.py
import csv, glob, json, statistics as st, collections
RUNS = sorted(glob.glob('20261025_stageB_cs144_*'))
LEDGER = 'unity_ledger_v1.csv'
c3_judge_lines_output.txt
回数: 18
## 1. ロボットの止まり(1回の長さ・秒)
件数 10783 p50 0.5 p90 4.0 p99 60.0 最大 60.0
10秒以上: 443 件
20秒以上: 349 件
30秒以上: 304 件
45秒以上: 249 件夜の結果の判定
tools/judge_night.py(ServiceSim・cs:16 で入れた版)
#!/usr/bin/env python3
"""judge_night.py — 夜に回した Unity の結果を自動で振り分ける(読むだけ。Unity も台帳も変えない)
振り分け(2026-10-25 エイイチ決定)
回の失敗 : 最後まで回っていない・台帳に行がない・ロボットが1コマで0.05m超え動いた
Unity の作り : 立ち往生(ロボットが30秒以上止まった)などが、基準データと比べて外れた
試算を見直す候補 : ロボットを増やしたときの向きが、種の過半数で試算と逆
または Unity ÷ 試算 の大きさが、基準データの同じ条件の範囲から外れたnight/split_check_cs7/judge.md(新しい基準の18回を自分自身にかけた結果)
# 夜の結果の振り分け(20261025_stageB_cs7_*)
基準データ: 20261025_stageB_cs144_*(18回)/振り分けた回: 18回
| 振り分け | 回数 |
|---|---|
| 正常 | 12 |
| 試算を見直す候補 | 6 |
| Unity の作り | 0 |
| 回の失敗 | 0 |
| 基準なし | 0 |
## 回の失敗
- なし
## Unity の作り(種の中央値が、基準の同じ条件の最大を超えた)
- なし
## 試算を見直す候補
### ロボットを増やしたときの向きが、種の過半数で試算と逆
- なし
### Unity÷試算 の大きさが、基準の同じ条件の範囲から外れた
- fam_p5 スタッフ4 ロボット0台: 料理の待ち(Unity÷試算) 2.07倍(基準 2.31〜2.6倍)
- fam_p5 スタッフ4 ロボット2台: 入店待ち(Unity÷試算) 0.83倍(基準 1.06〜8.24倍)
- fam_p5 スタッフ4 ロボット2台: 席は空いているのに待った(Unity÷試算) 0.89倍(基準 1.82〜21.99倍)
## 記録(印にしない):試算との差の大きさ(条件ごとの種の中央値・Unity÷試算)
| 条件 | 種の数 | 入店待ち | 料理の待ち | 席は空いているのに待った |
|---|---|---|---|---|
| fam_p1 スタッフ4 ロボット0台 | 3 | 1.15 | 2.09 | 2.72 |
| fam_p1 スタッフ4 ロボット1台 | 3 | 1.16 | 1.20 | 3.07 |
| fam_p1 スタッフ4 ロボット2台 | 3 | 2.04 | 1.53 | 3.03 |
| fam_p5 スタッフ4 ロボット0台 | 3 | 1.52 | 2.07 | 3.33 |
| fam_p5 スタッフ4 ロボット1台 | 3 | 1.13 | 1.20 | 1.65 |
| fam_p5 スタッフ4 ロボット2台 | 3 | 0.83 | 1.54 | 0.89 |
線: 立ち往生 30秒以上の止まり/向きは 5%・0.2分より小さい変化を数えない/外れは基準の同じ条件の最小〜最大
設計と依頼文
night_runs_design_v0.md(夜の仕組みの設計)
# 夜も回せる仕組み 設計 v0(2026-10-25)
サービスロボット導入シミュレーションの Unity を、人が見ていない夜のあいだも回し続け、朝には結果が振り分けられている状態にする。
## 1. 決めたこと(2026-10-25・エイイチ)
| 項目 | 決めたこと |
|---|---|claude_code_request_v11_project_split.md(プロジェクトを分ける依頼)
# 依頼 v11:ServiceSim を新しい Unity プロジェクトに分け、同じ結果が出るか確かめる(2026-10-25)
夜も回せる仕組みの最初の一歩。ServiceSim は今、mechArm の Robotics_UX_New に同居していて、「Assets/ServiceSim/ の外を変えない」用心のせいで、ビルド設定・時間・物理などの設定をサービスロボット導入シミュレーションに合わせられない。新しいプロジェクトに分ける。全体の設計は同じフォルダの `night_runs_design_v0.md`。
今回は移すだけで、店の回し方・ロボットの動き・記録は1つも変えない。
## 変えないもの
- **Robotics_UX_New は一切変えない。** ServiceSim はコピーで持っていく。Robotics_UX_New 側の ServiceSim は、新しいプロジェクトで同じ結果が出たのを確かめてから、消すかどうかをエイイチが決める
- ServiceSim の中身(cs:144 の状態):店の回し方・ロボット・人・記録・段階Bの18回の中身と順番・出力フォルダの名前の付け方
- 台帳 unity_ledger_v1.csv の列と、今までの行
- `git clean` は使わない。Unity Version Control の check-in は区切りごとに行う
## 1. 先に洗い出す(報告に書く)
Assets/ServiceSim/ の外にあって、ServiceSim が頼っているものを全部挙げる。
- Unity のエディタのバージョン
- パッケージ(Packages/manifest.json のうち ServiceSim が使うもの。AI Navigation など)
- ProjectSettings のうち ServiceSim の結果に効くもの:NavMesh のエージェントの種類と大きさ・エリア、タグとレイヤー、Time(Fixed Timestep など)、Physics、Quality、描画の設定(URP などのパイプラインのアセット)
- Assets/ServiceSim/ の外にあるアセット(マテリアル・シェーダー・フォントなど)
- 読みに行くファイルの場所(サイトの写し site_copy_*・serving-robot-params.json・layouts)と、書き出す場所(KIOXIA service_sim/unity/)
洗い出して、移せないもの・結果が変わりそうなものがあれば、移す前に書いて止める。
## 2. 新しいプロジェクトを作る
- 場所:`/Users/shimazueiichi/Robotics_UX/ServiceSim/`
- エディタのバージョンは今と同じ
- Assets/ServiceSim/ と、1で挙げたパッケージ・設定・アセットを写す。設定は値をそろえる(今の値と同じになっていることを報告に並べる)
- Unity Version Control に新しいリポジトリを作り、最初の check-in をする
- `Builds/` と `Library/` などは VCS に入れない(次の v12 で `Builds/headless/` を使う)
- 台帳とrun_info.json の `unity_cs` は、新しいプロジェクトでは `ServiceSim/cs:N` の形で書く(番号が1から振り直されるため、今までの `cs:144` などと混ざらないように)
- ServiceSimSetup の説明にある「新しいシーンはビルド設定に足さない」は、新しいプロジェクトでは外してよい。ビルド設定に ServiceSim_Family.unity を入れてよい(このプロジェクトには ServiceSim しかない)
## 3. 確かめ
**A. Claude Code が見る**
- コンパイルが通る。ServiceSim のメニューが今と同じに出る
- 1で挙げた設定の値が、Robotics_UX_New と新しいプロジェクトで同じ(並べて報告)
**B. 同じ結果が出るか(エイイチが押す)**
1. 新しいプロジェクトで check-in して番号を報告
2. ServiceSim → Stage B → 押す前の確かめ(回さない)で、版が v2.8・店の形 8a5b2f6a016a・レジ1つで、18回とも「まだ」になっていること
3. 段階Bの18回のうち **③ ロボット1台・種1**(基準データ v2 では `20261025_stageB_cs144_fam_p1_r1_s1`)だけを、**2回**回す。出力フォルダは段階Bと区別できる名前にする(例:ラベル `split_check`)
見ること:
- 2回の結果が同じか(同じ種で同じ数字が出るか)。台帳の数字を、実時間(wall_seconds)と timestamp を除いて全部並べる
- 基準データ v2 の同じ回と同じか
結果で次を分ける:
- **2回とも同じで、基準データ v2 とも同じ** → 移せた。ここで終わり
- **2回は同じだが、基準データ v2 と違う** → 何が違うか(設定・パッケージ・読んだファイル)を調べて報告して止める
- **2回が違う**(同じ種でも数字が揺れる)→ 揺れる所(どの記録の何列から違い始めるか)を報告して止める。この場合は、18回を回して判定のスクリプトで比べる形に切り替えるかを相談する
## 報告
- 1の洗い出しの一覧
- 写したもの・そろえた設定の値(Robotics_UX_New と並べて)
- 確かめ A・B の結果
- check-in の番号
- この依頼どおりにすると困る所があれば、直す前に書いて止める
報告は `unity/claude_code_reports/` に、今までと同じ形の名前で置く。
claude_code_request_v12_night_runner.md(画面なしの実行ファイルと夜の実行係の依頼)
# 依頼 v12:画面なしの実行ファイルと夜の実行係を作り、最初の夜(60回)を回せるようにする(2026-10-25)
v11 で ServiceSim を新しいプロジェクト(`/Users/shimazueiichi/Robotics_UX/ServiceSim/`)に分け、同じ結果が出るのを確かめたあとに進める。全体の設計は同じフォルダの `night_runs_design_v0.md`。
目的:エディタを開かずに、段階Bと同じ回し方の1回を何本も同時に走らせ、夜のあいだに並べた回を全部回し、朝には判定まで済んでいる状態にする。
## 変えないもの
claude_code_request_v13_pass_by_and_clock.md(すれ違いと店の時計の依頼)
# 依頼 v13:ロボットどうしのすれ違いを実物に合わせる(cs:4)と、実物の動画と秒数を比べられる画面(cs:5)(2026-10-25)
cs:3(det_check の仕掛け)のあとに進める。依頼1 を cs:4、依頼2 を cs:5 として、別々に check-in する。
## きっかけ
実店舗の配膳ロボットの動画を見た。空のロボット2台が、台車の横の狭い所で、2台とも速さを落とし、止まらずに体どうしの間を詰めてすれ違っていた。Unity で起きている「ロボットどうしが60秒向かい合って止まる」は実物では起きていない。エイイチの決定:すれ違いは実物に合わせてよい。録画は実物の動画と秒数を比べられるように調整してよい。
## 変えないもの
- 最高速 0.6m/秒、1コマ0.05秒の時間の進め方
- 人とロボットのよけ方、店の形、条件の値(サイトから読む値)
- 台帳 unity_ledger_v1.csv の列
- cs:3 の det_check の切り替え。ExperimentPlan.asset は今のまま(切は C# の初期値のままでよい。.asset に書き足さない)
- 既存の trips.csv の「ロボット同士が向かい合ったか」の列(そのまま残す)
## 依頼1(cs:4):すれ違い
### 切り替えと値の置き場所
- RobotSpec に1か所にまとめる(check-in する)
- passByEnabled:初期値は切(切のときは cs:3 と同じ動き)
- passByDistanceM = 2.0、passBySpeedMps = 0.3、passBySeparationM = 0.1
- 入を標準にするかは、下の「確かめ」の結果を見てエイイチが決める
### 動き(入のとき)
- 進む先 passByDistanceM 以内に、こちらへ向かってくるロボット(進む向きの差が135度以上)がいたら「すれ違い中」に入る
- すれ違い中は、2台とも速さの上限を passBySpeedMps にする。止まらない
- 譲り合いの順位は付けない。2台とも進む向きの右側へ寄り、体どうしの間を passBySeparationM まで詰めて通る(前方センサーは、相手がロボットのときだけ、この間まで全停止しない)
- 寄った位置で通れる幅が「ロボットの幅×2 + passBySeparationM」に足りないときだけ、今の決まりを使う(料理を載せたロボットが先に行き、空のロボットがよける/3秒空かなければ回り込む道を探す)
- すれ違い終わったら、元の速さと通路の真ん中寄りの走り方に戻す
### 数の定義
- すれ違い1回:上の条件で「すれ違い中」に入ってから、相手が自分の後ろ側に回るか、2台の距離が passByDistanceM を超えるまで。同じ2台の1回は1回と数える(2台で2回にしない)
- 減速していた秒数:ロボットごとに「すれ違い中」だった時間の合計(速さの値では数えない)
- 向かい合って止まった:2台が passByDistanceM 以内・進む向きの差135度以上で、2台とも速さ 0.05m/秒以下が1秒以上続いたら始まり、どちらかが 0.05m/秒を超えたら終わり。回数と最長の秒数。入でも切でも数える(切の回と比べるため)
### 書き出し(台帳の列は足さない)
- summary.json に足す:pass_count、pass_slow_s(全ロボットの合計)、face_stop_count、face_stop_max_s
- 回ごとに passes.csv(すれ違い1回 = 1行):始まりと終わりの時刻・2台のID・場所・一番近づいたときの体どうしの間・一番遅かった速さ・終わり方(すれ違えた/幅が足りず今の決まりへ/向かい合って止まった)
- run_info.json に足す:pass_by の入切と3つの値
### 確かめ
- 切のときに cs:3 から動きが変わる行がないことを、差分で確かめて報告する
- ③(fam_p1)ロボット2台・スタッフ4・種1 で、入と切を1回ずつ回す(ロボット1台の条件ではすれ違いが起きない)。エディタのメニューで押す形でよい。押す順番を1行で出せばエイイチが押す
- 2回の pass_count・pass_slow_s・face_stop_count・face_stop_max_s と、入店待ち・ロボットが運んだ割合を並べて報告する
## 依頼2(cs:5):実物の動画と秒数を比べられる画面
- 録画はエイイチが Mac の画面録画で撮る。Unity Recorder は入れない
- 画面の左上に出す:店の時計(回し始めからのシミュレーションの中の経過 時:分:秒)と、実際の倍率(直近数秒の、シミュレーションの時間 ÷ 実時間)
- 1倍で回す切り替え:1コマ0.05秒のまま、実時間に合わせて待つ形(中身の進み方は変えない)
- 置き場所:新しい SimHud(シーンに置くコンポーネント)の Inspector の項目にする。表示の入切と1倍の入切の2つ。check-in する
- 1倍で回した回は見る専用。台帳に書かず、出力フォルダも作らない
- 画面なしの実行(Application.isBatchMode・graphicsDeviceType が Null)では描かない。測る回は表示の初期値を切にして、数字に影響させない
## 順番
- v12(画面なしの実行ファイルと夜の実行係)はこのあと。先に作らない
- 作業の区切りごとに VCS の check-in をする。git clean は使わない
codex_review_request_v12_ledger.md(台帳に書く所の codex レビュー依頼)
# コードレビュー依頼:夜の実行で台帳に書く所(サービスロボット導入シミュレーション・v12)
対象(読むだけ。書き換えない):Unity プロジェクト `/Users/shimazueiichi/Robotics_UX/ServiceSim/`(ServiceSim/cs:17)
- `Assets/ServiceSim/` の中の `ServiceSimLedger.cs`(台帳に1行足す。Editor の外へ移した版)
- `Assets/ServiceSim/Experiment/LedgerRow.cs`(1行の中身を作る)
- `Assets/ServiceSim/Experiment/HeadlessRun.cs`(画面なしの実行ファイルで1回回す入口)
- `tools/ledger.py`(夜の実行係が、止めた回・落ちた回の行を書く)
- `tools/night_runner.py`(何本も同時に起動し、やり直し・止める・判定を呼ぶ)
---
## このコードがやろうとしていること
Unity で配膳ロボットの店を回すシミュレーションを、画面なしの実行ファイルで夜のあいだ何本も同時に回す。1回が終わるたびに、KIOXIA(外付けSSD)の台帳 `/Volumes/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv` に1行足す。台帳は唯一の正本で、壊すと戻せない。このレビューでは**台帳に書く所だけ**を見てほしい(店の回し方・ロボットの動きは対象外)。
## 設計仕様(台帳の決まり:data_manifest_rules.md 10節)
1. 1回 = 1行・追記のみ。既存の行の上書き・移動・削除をしない
2. 追記ガード:実体のヘッダとコードの列の並び(59列)が違えば書かない
3. 同じ出力フォルダ名の行を2度書かない(出力フォルダ名が照合キー)。やり直しは名前の後ろに `_try2` を付ける
4. 何本も同時に書くので、鍵ファイル `service_sim/unity/unity_ledger_v1.lock` を排他で開けてから書く。開けなければ待って試し直す。C#(実行ファイル)と Python(実行係)が同じ鍵を使う
5. 実行係が止めた回(時間切れ)・落ちた回は、実行係が status = stopped / failed の行を書く(鍵をかけて)
6. 書く前に KIOXIA がつながっているか確かめる。つながっていなければ何も書かない(Mac の中に fallback しない)
7. `unity_cs` は `ServiceSim/cs:N` の形
## レビューしてほしいチェック項目
### A. ロジックの正しさ
A1. C# と Python の鍵は、本当に同じ鍵として待ち合えるか(使っている仕組み:ファイルの排他オープン/flock/ロックファイルの作成と削除 など。macOS の外付けSSD(exFAT か APFS)で同じように効くか)
A2. 鍵を持ったまま落ちた場合(実行ファイルが落ちる・実行係が強制終了される)、鍵が残って次の回が永久に待たないか。古い鍵の扱い
A3. 「ヘッダの確認」「もう同じフォルダの行があるか」「1行足す」が、すべて鍵の中で行われているか
A4. 1行を書く途中で落ちたとき、半端な行が残らないか(1回の write で書いているか・改行の扱い)
A5. 実行係が stopped / failed の行を書いたあと、遅れて実行ファイル自身も同じフォルダの行を書く、という二重書きが起きないか(時間切れで止めた回を SIGTERM したのに、終了処理で台帳に書いてしまう など)
A6. `_try2` の名前の付け方と、「completed は飛ばす」の照合が、C# と Python で同じ規則か
### B. 副作用・破壊チェック
B1. 既存の行(87行)を書き換える経路が1つもないか(ファイルを開くモード:追記のみか)
B2. CSV のクオート・カンマ・改行を含む値(日本語の pending_changes など)で列がずれないか
B3. ヘッダが違うときに、黙って書かないだけでなく、失敗として記録・終了コードに出るか
### C. 暴走・安全リスク
C1. 鍵が取れないまま待ち続けて、夜じゅう止まる道はないか(待つ上限と、その後の扱い)
C2. 実行係が同じ回を何度も起動し続ける道はないか(やり直しは1度だけ)
C3. KIOXIA が途中で外れたとき、新しい回を始めず、Mac の中に書かないか
### D. 制約ルールの遵守
D5. 台帳への追記処理を持たない「通し完走」の経路がないか(回の終わり方が completed / stopped / failed のどれでも1行残るか)
D6. KIOXIA へ書き込む所すべてに、マウントの確かめが入っているか(未マウント時にローカルへ fallback しない)
(D1〜D4 は実機のアーム用の項目なので対象外)
## レビュー結果のフォーマット
各項目について、✅ OK/⚠️ 要注意(何が懸念か)/❌ NG(該当行番号と修正案)で答えてほしい。
最後にサマリとして:最初の夜(70回・2〜3本同時)に進んで良いか、進む前に直すべき項目があるか。
## 補足情報
- 本物の台帳で2本同時の確かめ(名札 acheck)を 2026-10-26 に行った。結果はレビューの参考にしてよい(台帳の acheck の行)
- 台帳は確かめの前に `archive/unity_ledger_v1_preacheck_20261026/` にコピーで退避済み
- `git clean` 禁止・`git add .` 禁止(個別ファイル指定)
Claude Code の報告
20261025_1545_v11_project_split.txt
====================================================================
依頼 v11 の報告:ServiceSim を新しい Unity プロジェクトに分けた
2026-10-25 15:45
====================================================================
結論:新しいプロジェクトを作りました。組み立ては通っています(54 本・エラー 0)。
Robotics_UX_New は一切変えていません(cs:144 のまま・保留は前からの2件だけ)。
20261025_1745_v11_nondeterminism.txt
====================================================================
依頼 v11 の確かめ B:同じ種で2回の数字がずれる元を調べた(直していません)
2026-10-25 17:45
====================================================================
比べた回:KIOXIA service_sim/unity/
20261025_split_check_cs2_fam_p1_r1_s1 (1回め・実時間 654.5 秒)
20261025_split_check_cs2_fam_p1_r1_s1_2 (2回め・実時間 601.1 秒)20261025_1804_v11_det_check_prep.txt
====================================================================
依頼 v11 の 5 章:ずれの切り分けの仕掛けを作った(回すのはエイイチ)
2026-10-25 18:04
====================================================================
結論
・試し1〜3 を押せる形にしました。名札は **det_check** で、20261025_1945_v12_tools.txt
====================================================================
依頼 v12 の 4 章:夜の実行係の道具(tools/)を作った
2026-10-25 19:45
====================================================================
結論
・tools/ に4本作り、**Unity 抜きで通しの試験まで通しました**。20261026_0725_path_iterations_leak.txt
====================================================================
道探しの枠(pathfindingIterationsPerFrame)が残る穴を直した
2026-10-26 07:25
====================================================================
結論
・エイイチの疑いは **当たっている可能性が高い**です。20261026_1202_v13_passby_check.txt
====================================================================
依頼 v13 の 依頼1 の確かめ:すれ違い 入/切 を調べた(まだ直していません)
2026-10-26 12:02
====================================================================
比べた回(③ fam_p1・スタッフ4・ロボット2台・種1・ServiceSim/cs:9・枠 100)
20261026_pass_on_cs9_fam_p1_r2_s1 すれ違い 入
20261026_pass_off_cs9_fam_p1_r2_s1 すれ違い 切20261026_1241_v13_simhud.txt
====================================================================
依頼 v13 の 依頼2:店の時計と倍率の画面(SimHud)+1倍で回す
2026-10-26 12:41 check-in:ServiceSim/cs:12(保留 0)
====================================================================
結論
・画面の左上に「店の時計」と「**測った倍率**」を出す部品を作りました。20261026_1300_v12_headless_build.txt
====================================================================
依頼 v12 の 1〜3 章:画面なしの実行ファイル・1回の回し方・台帳の鍵
2026-10-26 13:00 check-in:ServiceSim/cs:13・cs:14(保留 0)
====================================================================
結論
・1〜3 章を作りました。組み立ては通っています(59 本・エラー 0)。20261026_1420_v12_check_abc.txt
====================================================================
依頼 v12 の 5 章 A・B・C:画面なしの実行ファイルの確かめ
2026-10-26 14:20 check-in:ServiceSim/cs:15・cs:16・cs:17(保留 0)
====================================================================
結論
・**A(台帳)OK**。2本同時で台帳にちょうど2行入り、行は混ざらず、night/20261027/runner_log.txt(夜の実行係の空回し)
2026-10-26 12:16:32 === 夜の実行係を始めます(night 20261027・同時 1 本・上限 90.0 分)===
2026-10-26 12:16:32 並べた回: /private/tmp/claude-501/-Users-shimazueiichi/d0d60c2a-d756-4c07-a05b-13221e3d700f/scratchpad/q4.json(4 回)
2026-10-26 12:16:33 (から回しなので通します)実行ファイルがありません(または実行できません): /Users/shimazueiichi/Robotics_UX/ServiceSim/Builds/headless/ServiceSim.app/Contents/MacOS/ServiceSim
2026-10-26 12:16:33 台帳: /Volumes/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv(59 列)
2026-10-26 12:16:33 版: ServiceSim/cs:10(cm status)→ 出力フォルダの字 cs10
2026-10-26 12:16:33 並べた回の試算の版: v2.8 / 店の形の版: 8a5b2f6a016a
2026-10-26 12:16:33 並べた回 4 / もう completed の回を飛ばす 0 / 回す 4
2026-10-26 12:16:33 (から回し)1 回め fam_p1_s4_r2_a42 種0 すれ違い切 → 20261027_night_cs10_fam_p1_r2_s0
2026-10-26 12:16:33 /Users/shimazueiichi/Robotics_UX/ServiceSim/Builds/headless/ServiceSim.app/Contents/MacOS/ServiceSim -batchmode -nographics -logFile /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261027/logs/20261027_night_cs10_fam_p1_r2_s0.log -ssCondition fam_p1_s4_r2_a42 -ssSeed 0 -ssLabel night -ssNight 20261027 -ssParallel 1 -ssPassBy off
2026-10-26 12:16:33 (から回し)2 回め fam_p1_s4_r2_a42 種1 すれ違い切 → 20261027_night_cs10_fam_p1_r2_s1
2026-10-26 12:16:33 /Users/shimazueiichi/Robotics_UX/ServiceSim/Builds/headless/ServiceSim.app/Contents/MacOS/ServiceSim -batchmode -nographics -logFile /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261027/logs/20261027_night_cs10_fam_p1_r2_s1.log -ssCondition fam_p1_s4_r2_a42 -ssSeed 1 -ssLabel night -ssNight 20261027 -ssParallel 1 -ssPassBy off
2026-10-26 12:16:33 (から回し)3 回め fam_p1_s4_r2_a42 種0 すれ違い入 → 20261027_night_cs10_fam_p1_r2_s0_passon
2026-10-26 12:16:33 /Users/shimazueiichi/Robotics_UX/ServiceSim/Builds/headless/ServiceSim.app/Contents/MacOS/ServiceSim -batchmode -nographics -logFile /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261027/logs/20261027_night_cs10_fam_p1_r2_s0_passon.log -ssCondition fam_p1_s4_r2_a42 -ssSeed 0 -ssLabel night -ssNight 20261027 -ssParallel 1 -ssPassBy on
2026-10-26 12:16:33 (から回し)4 回め fam_p1_s4_r2_a42 種1 すれ違い入 → 20261027_night_cs10_fam_p1_r2_s1_passon
2026-10-26 12:16:33 /Users/shimazueiichi/Robotics_UX/ServiceSim/Builds/headless/ServiceSim.app/Contents/MacOS/ServiceSim -batchmode -nographics -logFile /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261027/logs/20261027_night_cs10_fam_p1_r2_s1_passon.log -ssCondition fam_p1_s4_r2_a42 -ssSeed 1 -ssLabel night -ssNight 20261027 -ssParallel 1 -ssPassBy on
2026-10-26 12:16:33 --- まとめ ---
2026-10-26 12:16:33 dry-run: 4 回
2026-10-26 12:16:33 === 夜の実行係を終わります(終了コード 0)===
台帳の行(unity_ledger_v1.csv・この記事で回した回)
49行(ヘッダ1行と、2026-10-25 15時以降の行)。
timestamp,run_folder,status,unity_cs,layout_generation,params_model,store,staff,robots,arrivals_per_h,mode,trays,fragile_by,seed,staff_first_yield,yield_order_enabled,one_robot_per_aisle,robot_first_wait_s,everyone_left,total_minutes,wall_seconds,entry_wait_mean,staff_wait_mean,dish_wait_mean,cold_share,robot_share,staff_util,robot_util,walk_km_per_staff,site_entry_wait_mean,site_staff_wait_mean,site_dish_wait_mean,site_robot_share,robot_speed_mps,pause_rate,pause_s_mean,stuck_rate,trips,timeouts,stuck_count,stop_s_total,corner_stop_time_share,gave_up,warped,table_freed,rescues,late_staff_dishes,staff_yield_share_of_staff_time,ledger_schema_version,pay_wait_mean,site_pay_wait_mean,blocked_wait_mean,site_blocked_wait_mean,turn_mean,site_turn_mean,clear_wait_mean_s,clear_wait_max_s,clear_wait_over_count,pay_job_wait_mean_s
2026-10-25T15:03:33,20261025_stageB_cs144_fam_p5_r2_s2,completed,cs:144,8a5b2f6a016a,v2.8,fam_p5,4,2,42,serve,3,any,2,1,1,1,120,1,223.7393,933.7357,16.2146,9.8482,1.2676,0.0669,0.9646,0.8141,0.6812,3.0099,1.9669,0.4479,0.9839,0.991,0.5648,,1.3246,,166,1,15,3867.828,0,141,105,4,15,9,0.064,2,6.734,7.9555,9.4085,0.3816,14.0696,2.0967,739.1896,1635.237,85,156.016
2026-10-25T17:23:47,20261025_split_check_cs2_fam_p1_r1_s1,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,179.2347,654.4564,1.5452,0.3161,2.611,0.3155,0.6602,0.7719,0.7395,2.5836,2.5992,0.572,1.9487,0.7204,0.5768,,2.3906,,64,1,11,1117.142,0,53,45,1,11,70,0.0433,2,5.4686,7.9893,0.0023,0.4827,5.7867,2.1338,228.7283,938.5195,9,158.4242
2026-10-25T17:37:41,20261025_split_check_cs2_fam_p1_r1_s1_2,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,182.042,601.1398,1.702,0.4713,2.2184,0.267,0.7039,0.7169,0.6899,2.6179,2.5992,0.572,1.9487,0.7204,0.58,,3.1523,,72,0,0,545.3484,0,28,35,0,0,61,0.0396,2,6.0809,7.9893,0.0636,0.4827,3.5919,2.1338,76.5789,378.5654,0,165.8392
2026-10-25T18:28:06,20261025_det_check_cs2_fam_p1_r1_s1,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,190.5296,809.6896,3.326,2.0819,2.7463,0.3204,0.6748,0.7593,0.7249,2.6241,2.5992,0.572,1.9487,0.7204,0.5763,,2.7702,,68,1,12,1288.491,0,59,36,0,12,67,0.0505,2,5.0516,7.9893,1.7869,0.4827,10.1562,2.1338,455.614,1279.482,30,145.1615
2026-10-25T18:46:33,20261025_det_check_cs2_fam_p1_r1_s1_2,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,183.312,745.9092,2.4759,1.2355,2.3798,0.267,0.6942,0.7242,0.7037,2.6493,2.5992,0.572,1.9487,0.7204,0.5745,,2.6825,,70,0,3,799.7974,0,34,31,0,3,63,0.0391,2,5.9814,7.9893,0.9287,0.4827,5.4044,2.1338,182.7099,777.5508,1,168.0557
2026-10-25T19:02:16,20261025_det_check_cs2_fam_p1_r1_s1_3,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,184.592,688.7477,1.4077,0.205,2.1738,0.199,0.699,0.6795,0.6797,2.6869,2.5992,0.572,1.9487,0.7204,0.5767,,2.5806,,71,0,0,544.4995,0,34,40,0,0,62,0.0254,2,7.2586,7.9893,0,0.4827,2.6641,2.1338,26.331,206.1914,0,169.4946
2026-10-25T19:14:45,20261025_det_check_cs2_fam_p1_r1_s1_4,completed,ServiceSim/cs:2,8a5b2f6a016a,v2.8,fam_p1,4,1,42,serve,3,any,1,1,1,1,120,1,182.0968,746.5142,1.824,0.6458,2.2958,0.2282,0.699,0.7057,0.7039,2.6114,2.5992,0.572,1.9487,0.7204,0.5772,,3.1182,,70,0,0,657.9477,0,38,48,0,0,62,0.0375,2,5.6444,7.9893,0.3357,0.4827,4.8269,2.1338,153.8569,522.4512,0,165.6561Unity のコード(ServiceSim/cs:17)
前のプロジェクト(cs:144)から変えたファイルと、新しく足したファイルの全文です。
Assets/ServiceSim/Editor/ServiceSimSetup.cs
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;Assets/ServiceSim/Editor/ServiceSimStageB.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;Assets/ServiceSim/Editor/BuildHeadless.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;Assets/ServiceSim/Experiment/ExperimentPlan.cs
using System.Collections.Generic;
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// 回す条件と、書き出す場所。実験に関する数字と場所はすべてこの .asset に置く。
/// 条件を順に回すのは ExperimentRunner(段階2で作る)。Assets/ServiceSim/Experiment/ExperimentRunner.cs
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// 条件を回して記録する。1回の Play の中で、条件を順に通せる(段階3の Run All)。Assets/ServiceSim/Experiment/TripLogger.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEngine;
namespace ServiceSimAssets/ServiceSim/Experiment/HeadlessRun.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine;
namespace ServiceSim
{Assets/ServiceSim/Experiment/LedgerRow.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine;
namespace ServiceSim
{Assets/ServiceSim/Experiment/ServiceSimLedger.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEngine;
namespace ServiceSimAssets/ServiceSim/People/PeopleNav.cs
using UnityEngine;
using UnityEngine.AI;
namespace ServiceSim
{
/// <summary>
/// 人の NavMeshAgent を、安全に使えるようにする小さな道具。
///Assets/ServiceSim/Robot/FrontSensor.cs
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// ロボットの前に人・ロボット・椅子があるかを見る。
/// 見るだけで、止まる・動き出すの判断はしない(それは ServingRobotController)。
/// 止まった原因を分けられるように、いちばん近いものの種類も返す。Assets/ServiceSim/Robot/RobotSpec.cs
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// 道の決め方(依頼 v9 の 2 章)。
/// MapPlanner … ロボットが地図(サイトの {名前}_map.json)の上で自分で道を引く。NavMesh は使わない
/// SiteRoutes … サイトの routes の点を順にたどる(v5b〜v8b と同じ。比べるために残す)Assets/ServiceSim/Robot/ServingRobotController.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
namespace ServiceSim
{
/// <summary>Assets/ServiceSim/Robot/RobotPassBy.cs
using System.Collections.Generic;
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// すれ違い1回ぶん(passes.csv に1行。依頼 v13 の 依頼1)。
/// 同じ2台の1回は1行(2台で2行にしない)。Assets/ServiceSim/Store/SimHud.cs
using System.Globalization;
using UnityEngine;
namespace ServiceSim
{
/// <summary>
/// 実物の動画と秒数を比べられる画面(依頼 v13 の 依頼2。2026-10-26)。
///夜の実行係(ServiceSim の tools/)
tools/make_queue.py
#!/usr/bin/env python3
"""make_queue.py — 夜に回す「条件 × 種」を queue.json に並べる(依頼 v12 の 4 章)
条件は Unity と同じ所から引く(手で写さない):
Assets/ServiceSim/Experiment/serving-robot-params.json の unity_conditions
最初の夜:6条件(③ fam_p1・⑦ fam_p5 × ロボット 0・1・2 台)× 種 0〜9 = 60 回
+ ③2台・すれ違い「入」× 種 0〜9 = 10 回 … 合わせて 70 回tools/night_runner.py
#!/usr/bin/env python3
"""night_runner.py — 夜のあいだ、並べた回を全部回す(依頼 v12 の 4 章)
python3 tools/night_runner.py --queue queue.json --parallel 2 --night 20261026
やること
・始める前に、KIOXIA がつながっているか・実行ファイルがあるかを確かめる(無ければ始めない)
・caffeinate で Mac をスリープさせない(終わったら必ず解く)tools/ledger.py
#!/usr/bin/env python3
"""ledger.py — 台帳 unity_ledger_v1.csv に鍵をかけて1行足す(依頼 v12 の 3 章)
夜は実行ファイルを何本も同時に走らせるので、台帳に同時に書かないよう鍵をかける。
ここは **台帳を壊すと戻しにくい所** なので、決まりを狭くしてある。
決まり(C# の ServiceSimLedger と同じ)
・**追記だけ**。前の行は読むだけで、書き換えない・消さない