サービスロボット導入シミュレーション Log#29 | 狭いファミレスでは、配膳ロボットは1台まで
この記事の素材(コード・ログ・データ 12ファイル・まとめてダウンロードあり)arrow_downwardAIで読む ChatGPT・Claude などで、この記事に質問できます expand_more
通路の狭いファミレスでは、配膳ロボットは1台が上限だった。Unity(ゲームや3Dの映像を作るソフト)でファミレスを再現したシミュレーションで、28卓・スタッフ2人の店に配膳ロボットを2台入れると、入店待ちは1台のときの約2倍(13.8分 → 25.1分)に延び、動けなくなったロボットをスタッフが動かしに行く回数は、昼のピーク2時間で13回から54回に増えた。狭い店で2台目が足を引っぱる原因は、ロボットどうしが1本道で向かい合ってふさぎ合うことで、「1本道には1台ずつ入る」という決まりにすると不利は半分ほどに縮むが、それでも1台には届かなかった。
この結果で、配膳ロボットの台数を決める前に言えることが増えました。
- これから入れる店は、台数を「店の通路」で決められる。 卓の数や混み具合だけでなく、1本道の通路が多い店では2台目を足しても待ちは縮まず、スタッフの手間が増える。ロボットが止まった場所を店の平面図に重ねると、どの通路で詰まるかが見える
- もう2台入れている狭い店には、席を減らさずにできる直し方がある。 「1本道に向かいからロボットが来ていたら、手前で待つ」という決まりにすると、ロボットの世話(動かしに行く回数)は3〜4割減り、料理は1〜2分早く届いた(どちらもシミュレーションの値)
- シミュレーションの比べ方を変えるだけで、言えることが3組から37組に増えた。 同じ条件・同じ客の来方どうしで差を取る比べ方に変えると、夜に回す数(1条件10回)を増やさずに、ロボットを1台足した効果のある・なしがはっきりした。4つのやり方 × 2つの混み具合 × 10回=80回の比べは、Mac が夜のうちに約2時間で回した
きっかけは、同じ条件で回しても Unity の数字が毎回少し違うことでした。乱数の種(客がいつ来るか・何人組かを決める数字の出発点。同じ種なら同じ客の来方になる)をそろえても、ロボットが動けなくなった回数が20回の時もあれば35回の時もあります。これでは「ロボットを2台にしたら待ちが延びた」と出ても、本当の差なのか、たまたまなのかが言えません。調べると、ずれは種を変えたときの差の約10分の1で、同じ種どうしで比べれば十分に見分けられると分かりました。そこで、店の人が知りたいこと(ロボットの煩わしさ・スタッフの負担・お客さんの待ち・回転・安定)の順に、6つの店の夜の結果を並べ直し、いちばん結果の悪かった④の店で、ロボットどうしが向かい合わないための3つの案を試しました。
| やったこと | なぜ | 結果 |
|---|---|---|
同じ条件・同じ種でくり返した回を集め、ずれの大きさを測った | 夜の結果の差が本当の差か、ずれかを見分けるため | ずれは種を変えたときの約10分の1。同じ種どうしで比べると、はっきり言える組が76組中3組 → 37組 |
店で測る観察シートに、10回測ったら「早いとき・遅いとき」も出す表示を足した | 実際の店の作業時間のばらつきを、あとで試算に入れられるようにするため | 試算には入れず、記録として残す形で公開 |
ロボットが止まった場所を、店の平面図に重ねた | どこで・なぜ詰まるかを店の人に見せるため | ④では島の下の狭い通路と1本道に集中。相手の半分はもう1台のロボット |
スタッフの負担と待ち時間を、6店 × 0〜2台で並べた | 店が望むこと(負担・煩わしさ・待ち)を1つの表で見るため | 1台目は歩く距離を2〜3割減らす。2台目は、動かしに行く回数を一気に増やす |
④で、一方通行・1本道は1台ずつ・席を外したよけ場所の3案を、夜に80回回した | 2台を入れてしまった店がとれる打ち手を確かめるため | 1本道は1台ずつが最もよく効く。一方通行は混むと逆に悪くなる。どの案も1台には届かない |
下の図で、④の店の0台・1台・2台と3つの案を切り替えると、入店待ち・ロボットを動かしに行った回数・料理が届くまでの時間が変わります。
配膳ロボットを自分の店に入れたらどうなるかは、このシリーズの試算をもとにした別のページで試せます。
作業ログ ― Unity の夜の結果のずれを、同じ種どうしで比べ直した
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(12本)
01_var2.py.txt ― 種を変えたときのずれと比べた var2.py(種の中央値どうしの比べ)・9,166字
02_var3.py.txt ― 同じ種どうしの差で比べ直した var3.py・6,028字
03_sec02.txt ― 観察シートの画面と送る文を直した差分(コミット 8d70549)・4,734字
04_field_import.py.txt ― 届いた記録を取り込む field_import.py(全文)・10,720字
05_stopmap.py.txt ― 止まった場所を描く stopmap.py(全文)・4,049字
06_burden.py.txt ― 負担と待ち時間を並べる burden.py(全文)・17,959字
07_sec05.json ― サイトの回し方の決まりに、2つの決まりを「切」で足した(params の unity_rules)・3,544字
08_sec05.txt ― 依頼59の結果(依頼箱の報告)・3,306字
09_20261101_traffic_p2_impl.txt ― Claude Code の報告 20261101_traffic_p2_impl.txt(全文)・10,068字
10_sec06.txt ― 依頼60bの結果(依頼箱の報告)と、Claude Code の報告 20261108_night_traffic_p2_b.txt(全文)・7,782字
11_traffic_compare.py.txt ― 1台と比べると、どの案でも2台は1台に届かなかった traffic_compare.py・3,503字
12_traffic_compare.py.txt ― 1台と比べると、どの案でも2台は1台に届かなかった traffic_compare.py・4,278字
ここから下は作業ログです。コード・依頼文・報告・出力は全量で載せます。効果の数字は、断りがない限りすべて Unity のシミュレーションで測った値で、実際の店で測った値ではありません。
このシリーズで使う Unity・乱数の種・依頼箱
| 言葉 | 何か | このシリーズでの使い方 |
|---|---|---|
| Unity | ゲームや3Dの映像を作るソフト | ファミレスを3Dで建て、客・スタッフ・配膳ロボットを歩かせて、待ち時間や止まった回数を測る |
| サイトの試算 | 計算だけで待ち時間を出すシミュレーション(試算のページ) | 店の形・人数・決まりの正。Unity はこれを読んで店を建てる |
| 乱数の種 | 乱数(でたらめに見える数)の出発点の数 | 種が同じなら、客がいつ来るか・何人組かが同じになる。1つの条件を種0〜9の10回で回す |
| 夜の回し | Mac が夜のうちに、画面なしで Unity を何十回も回す仕組み | 4本ずつ同時に回し、1回ごとに台帳(unity_ledger_v1.csv)へ1行書く |
| 依頼箱 | Claude が書いた依頼を、Mac の見張り係が Claude Code に渡して実行させるフォルダ | Unity のコードを変える作業と夜の回しは、ここから Claude Code が行う |
| Claude Code | Anthropic のプログラミング用の AI | Mac の上で Unity のコードを書き、回し、報告を書く |
同じ種でも Unity の数字が毎回少し違うことは、10月25日に一度調べていた
LOG418 で、道の線を消すだけの撮り直しなのに、ロボットが動けなくなった回数が20回から35回に変わりました。原因は10月25日に Claude Code が調べていて、人の位置が0.1mm違うくらいの小数の最後の桁からずれが始まること、人の道の計算の遅れや人どうしのよけ方の計算を止めてもずれが残ることまで分かっていました。そのとき「同じ種なら必ず同じ、は今は追わない。ずれとして扱い、種10個の中央値で比べる」と決めています。
今回は原因を追うのではなく、ずれの大きさを測りました。いちばん疑わしいのは、Unity が中で複数の計算を同時に進めるとき、その順番が毎回少し変わることです。Mac で同時に回す本数を増やすとずれが大きくなるのも、その見方と合います。ただし確かめてはいません。
同じ条件・同じ種でくり返した回を、台帳から集めた var1.py
台帳1,533行のうち、条件も種も同じでくり返した回は、10月26日の「1本ずつ5回・4本同時8回」(③・ロボット1台・種1)と、10月31日の「1本ずつ3回・4本同時3回」(④・ロボット2台・種0)、それに LOG418 の道の線あり・なしの4組でした。
import csv,re,collections,statistics as st,random
L='/sessions/'+__import__('os').environ['HOME'].split('/sessions/')[1]+'/mnt/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv' if False else __import__('os').path.expanduser('~/mnt/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv')
R=list(csv.DictReader(open(L)))
M=['entry_wait_mean','staff_wait_mean','stuck_count','robot_share','turn_mean']
f=lambda r,m: float(r[m]) if r[m] not in('','nan') else None
# 1) within-seed repeats
def sd(x): return st.pstdev(x) if len(x)>1 else 0
print('== 同じ条件・同じ種のくり返し')
groups={'repeat1(1本ずつ3回)':'20261031_repeat1','repeat4(4本同時3回)':'20261031_repeat4','busy1(1本ずつ5回)':'20261026_busy1','busy4(4本同時8回)':'20261026_busy4'}
for n,p in groups.items():
rs=[r for r in R if r['run_folder'].startswith(p)]
print(n, rs[0]['store'],'staff',rs[0]['staff'],'robots',rs[0]['robots'],'seed',rs[0]['seed'])
for m in M:
x=[f(r,m) for r in rs]; print(' %-16s'%m, ['%.2f'%v for v in x], 'sd %.2f'%sd(x))
# rec(線あり) vs nopath(線なし) same seed same condition
print('== 線あり(cs52) と 線なし(cs53):同じ条件・同じ種7')
A={re.sub(r'^20261031_rec_|_cs52','',r['run_folder']):r for r in R if r['run_folder'].startswith('20261031_rec') }
B={re.sub(r'^20261101_rec_nopath_|_cs53','',r['run_folder']):r for r in R if r['run_folder'].startswith('20261101_rec_nopath')}
for k in sorted(set(A)&set(B)):
print(' ',k[:40], 'entry %.2f / %.2f'%(f(A[k],'entry_wait_mean'),f(B[k],'entry_wait_mean')),'stuck %s / %s'%(A[k]['stuck_count'],B[k]['stuck_count']))
== 同じ条件・同じ種のくり返し
repeat1(1本ずつ3回) fam_p2 staff 2 robots 2 seed 0
entry_wait_mean ['18.51', '19.85', '18.41'] sd 0.65
staff_wait_mean ['16.74', '18.50', '16.83'] sd 0.81
stuck_count ['73.00', '63.00', '76.00'] sd 5.56
robot_share ['0.82', '0.83', '0.88'] sd 0.02
turn_mean ['32.97', '43.32', '36.17'] sd 4.33
repeat4(4本同時3回) fam_p2 staff 2 robots 2 seed 0
entry_wait_mean ['19.22', '14.59', '21.39'] sd 2.84
staff_wait_mean ['17.89', '13.27', '20.06'] sd 2.83
stuck_count ['73.00', '74.00', '92.00'] sd 8.73
robot_share ['0.86', '0.83', '0.81'] sd 0.02
turn_mean ['36.56', '32.21', '41.81'] sd 3.93
busy1(1本ずつ5回) fam_p1 staff 4 robots 1 seed 1
entry_wait_mean ['2.33', '2.29', '1.58', '2.31', '2.19'] sd 0.28
staff_wait_mean ['1.10', '1.06', '0.34', '1.08', '0.95'] sd 0.29
stuck_count ['5.00', '3.00', '1.00', '1.00', '1.00'] sd 1.60
robot_share ['0.68', '0.67', '0.70', '0.70', '0.71'] sd 0.01
turn_mean ['5.50', '5.08', '3.33', '6.04', '5.29'] sd 0.91
busy4(4本同時8回) fam_p1 staff 4 robots 1 seed 1
entry_wait_mean ['1.93', '1.65', '1.64', '2.00', '3.05', '2.82', '1.57', '1.62'] sd 0.54
staff_wait_mean ['0.68', '0.43', '0.39', '0.76', '1.81', '1.60', '0.36', '0.39'] sd 0.54
stuck_count ['5.00', '3.00', '8.00', '6.00', '11.00', '9.00', '2.00', '8.00'] sd 2.87
robot_share ['0.69', '0.68', '0.66', '0.66', '0.64', '0.66', '0.69', '0.65'] sd 0.02
turn_mean ['4.49', '3.49', '5.40', '4.56', '8.54', '6.85', '3.18', '4.80'] sd 1.66
== 線あり(cs52) と 線なし(cs53):同じ条件・同じ種7
a30_fam_p1_r2_s7_passon_sbret_ek_post entry 1.30 / 1.35 stuck 3 / 6
a54_fam_p1_r2_s7_passon_sbret_ek_post entry 14.11 / 14.02 stuck 11 / 6
st3_fam_p1_r2_s7_passon_sbret_ek_post entry 12.41 / 13.23 stuck 34 / 31
st5_fam_p1_r2_s7_passon_sbret_ek_post entry 2.98 / 2.72 stuck 23 / 19
同じ種でくり返したときの入店待ちのずれ(標準偏差)は、③の1本ずつで0.28分、④の1本ずつで0.65分でした。4本同時に回すと0.54分・2.84分に広がります。
種を変えたときのずれと比べた var2.py(種の中央値どうしの比べ)
夜に回した6つの店の結果から、ロボットを1台足す前と後を、種10個の中央値どうしで比べました。今の夜の判定と同じ比べ方です。
import csv,re,collections,statistics as st,random,os,json
L=os.path.expanduser('~/mnt/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv')
R=list(csv.DictReader(open(L)))
random.seed(0)
NAME={'fam_p0':'②','fam_p1':'③','fam_p2':'④','fam_p3':'⑤','fam_p4':'⑥','fam_p5':'⑦'}
G=collections.defaultdict(list)
for r in R:
if '_night' not in r['run_folder']: continue
k=re.sub(r'_s\d+(_|$)',r'_s*\1',r['run_folder'])
k=re.sub(r'_r\d_','_r#_',k)
G[(k,int(r['robots']))].append(r)
def med(x): return st.median(x)
def boot(a,b,n=4000):
d=[med(random.choices(b,k=len(b)))-med(random.choices(a,k=len(a))) for _ in range(n)]
d.sort(); return d[int(.025*n)],d[int(.975*n)]
rows=[]
for (k,rb),rs in sorted(G.items()):
if rb==0: continue
base=G.get((k,rb-1))
if not base or len(rs)<8 or len(base)<8: continue
for m in ['entry_wait_mean']:
a=[float(r[m]) for r in base]; b=[float(r[m]) for r in rs]
lo,hi=boot(a,b)
rows.append(dict(cond=k,store=NAME.get(rs[0]['store'],rs[0]['store']),staff=rs[0]['staff'],arr=rs[0]['arrivals_per_h'],step=f'{rb-1}→{rb}',n=f'{len(a)}/{len(b)}',med_a=med(a),med_b=med(b),diff=med(b)-med(a),lo=lo,hi=hi,
sd_seed=st.pstdev(b),verdict=('縮む' if hi<0 else '延びる' if lo>0 else 'ぶれの範囲')))
json.dump(rows,open('robot_effect.json','w'),ensure_ascii=False,indent=1)
c=collections.Counter(r['verdict'] for r in rows); print(len(rows),c)
for r in rows: print('%-55s %s 人%s 客%s %s 中央 %.2f→%.2f 差%+.2f [%+.2f,%+.2f] %s 種sd %.2f'%(r['cond'][:55],r['store'],r['staff'],r['arr'],r['step'],r['med_a'],r['med_b'],r['diff'],r['lo'],r['hi'],r['verdict'],r['sd_seed']))
76 Counter({'ぶれの範囲': 73, '延びる': 3})
20261027_night_cs21_fam_p1_r#_s* ③ 人4 客42 0→1 中央 4.08→4.56 差+0.48 [-6.87,+4.36] ぶれの範囲 種sd 4.22
20261027_night_cs21_fam_p1_r#_s* ③ 人4 客42 1→2 中央 4.56→3.04 差-1.53 [-4.64,+4.91] ぶれの範囲 種sd 4.62
20261027_night_cs21_fam_p5_r#_s* ⑦ 人4 客42 0→1 中央 4.22→4.98 差+0.76 [-6.71,+5.86] ぶれの範囲 種sd 3.91
20261027_night_cs21_fam_p5_r#_s* ⑦ 人4 客42 1→2 中央 4.98→2.89 差-2.09 [-7.19,+5.43] ぶれの範囲 種sd 3.82
20261028_night_cs25_fam_p1_r#_s* ③ 人4 客42 0→1 中央 4.19→3.04 差-1.15 [-7.14,+6.59] ぶれの範囲 種sd 4.32
20261028_night_cs25_fam_p1_r#_s* ③ 人4 客42 1→2 中央 3.04→2.98 差-0.06 [-7.28,+5.52] ぶれの範囲 種sd 3.97
20261028_night_cs25_fam_p5_r#_s* ⑦ 人4 客42 0→1 中央 4.49→3.60 差-0.89 [-7.11,+4.51] ぶれの範囲 種sd 3.68種を変えたときの入店待ちのずれ(種sd)は、③の普通で約4〜5分、④では8〜16分あります。同じ種でくり返したときのずれは、その約10分の1以下です。中央値どうしの比べでは、76組のうち「縮む」「延びる」とはっきり言えたのは3組だけで、残りは「ぶれの範囲」でした。
同じ種どうしの差で比べ直した var3.py
同じ種は同じ客の来方なので、ロボット0台と1台を同じ種どうしで引き算すれば、客の来方の違いを消して、ロボットの効きだけを見られます。差の中央値に、くり返し引き直し(ブートストラップ)で95%の幅を付けました。
import csv,re,collections,statistics as st,random,os,json
L=os.path.expanduser('~/mnt/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv')
R=list(csv.DictReader(open(L))); random.seed(0)
NAME={'fam_p0':'②','fam_p1':'③','fam_p2':'④','fam_p3':'⑤','fam_p4':'⑥','fam_p5':'⑦'}
G=collections.defaultdict(dict)
for r in R:
if '_night' not in r['run_folder']: continue
k=re.sub(r'_s\d+(_|$)',r'_s*\1',r['run_folder']); k=re.sub(r'_r\d_','_r#_',k)
G[(k,int(r['robots']))][int(r['seed'])]=r
out=[];m='entry_wait_mean'
for (k,rb),d in sorted(G.items()):
if rb==0 or (k,rb-1) not in G: continue
a=G[(k,rb-1)]; seeds=sorted(set(a)&set(d))
if len(seeds)<8: continue
diffs=[float(d[s][m])-float(a[s][m]) for s in seeds]
bs=sorted(st.median(random.choices(diffs,k=len(diffs))) for _ in range(4000))
lo,hi=bs[100],bs[3899]
up=sum(x>0 for x in diffs); dn=sum(x<0 for x in diffs)
v='縮む' if hi<0 else '延びる' if lo>0 else 'ぶれの範囲'
r0=d[seeds[0]]
out.append(dict(night=k.split('_cs')[0],store=NAME[r0['store']],staff=int(r0['staff']),arr=int(r0['arrivals_per_h']),step=f'{rb-1}→{rb}',n=len(seeds),med=st.median(diffs),lo=lo,hi=hi,up=up,down=dn,verdict=v))
json.dump(out,open('robot_effect_paired.json','w'),ensure_ascii=False,indent=1)
print(collections.Counter(o['verdict'] for o in out), len(out))
for o in out: print('%-22s %s 人%d 客%2d %s 種%2d 差の中央%+6.2f [%+6.2f,%+6.2f] 延%2d縮%2d %s'%(o['night'],o['store'],o['staff'],o['arr'],o['step'],o['n'],o['med'],o['lo'],o['hi'],o['up'],o['down'],o['verdict']))
Counter({'ぶれの範囲': 39, '縮む': 24, '延びる': 13}) 76
20261027_night ③ 人4 客42 0→1 種10 差の中央 -0.50 [ -1.96, -0.03] 延 2縮 8 縮む
20261027_night ③ 人4 客42 1→2 種10 差の中央 -0.22 [ -1.25, +1.23] 延 4縮 6 ぶれの範囲
20261027_night ⑦ 人4 客42 0→1 種10 差の中央 -0.28 [ -1.88, +0.25] 延 3縮 7 ぶれの範囲
20261027_night ⑦ 人4 客42 1→2 種10 差の中央 -0.39 [ -2.01, -0.03] 延 2縮 8 縮む
20261028_night ③ 人4 客42 0→1 種10 差の中央 -0.12 [ -2.01, +0.35] 延 4縮 6 ぶれの範囲
20261028_night ③ 人4 客42 1→2 種10 差の中央 +0.03 [ -1.63, +1.18] 延 5縮 5 ぶれの範囲
20261028_night ⑦ 人4 客42 0→1 種10 差の中央 -1.19 [ -2.27, +0.00] 延 3縮 7 ぶれの範囲- ねらい:夜の結果の差が、ロボットのせいなのか、ずれなのかを見分ける
- 変わったこと:Unity も回す数もそのままで、はっきり言えた組が76組中3組から37組(縮む24・延びる13)に増えた
- 見込める効果:夜の回す数(1条件10回)は足りていると分かった。「2台目はほとんど効かない」「スタッフが多い店ではロボットが少し邪魔になる」を、根拠つきで言える
見えてきたことは3つです。1台目は、スタッフが少なく混んでいる店でよく効きます(⑥スタッフ2人で −12.5分、②スタッフ1人で −6.9分。どちらも10種すべてで縮んだ)。2台目は、はっきり縮んだのが⑥の客49組/時と⑦スタッフ3人ぐらいです。④の「ロボットを足すと入店待ちが延びる」は、4回の夜すべてで10種中9〜10種が延びていて、ずれではありませんでした。
夜の判定の仕組み(judge_night.py)に、この比べ方を足すかは決めていません。
動きにばらつきがあること自体は、実際の店に近い
同じ条件でも、人やロボットの動きが毎回同じにならないのは、実際の店も同じです。そこで、必ず同じ数字にするのではなく、どこに・どれくらいのばらつきがあるのが実際の店に近いかを決めるのが本来の形だ、という話になりました。
前提の表(104行)を見直すと、会計90秒・卓を拭く40秒・案内45秒のようなスタッフの作業の時間は、すべて1つの値で固定でした。ばらつきがあるのは客の来方と、一時停止の長さ(3〜10秒)、デザートができるまで(2〜7分)だけです。実際には、会計が60秒の組も150秒の組もあります。
ただし、作業の時間にばらつきを入れると試算の版が変わり、試算のページの数字も変わります。幅の根拠もまだありません。そこで、今は試算には入れず、店で測ったばらつきを記録として残すところまでにしました。
作業ログ ― 観察シートに「早いとき・遅いとき」を足した
観察シートは、店のスタッフがスマホで作業の時間を測るページです(観察シート)。測った記録は LINE かメールで店長やロボットの担当に送り、届いた記録から、試算の前提を置き換える候補を作ります(LOG414・LOG415)。
決めたこと:試算に入れず、10回測ったら幅を出す
| 決めたこと | 中身 |
|---|---|
| 店の値で試算を回すか | 回さない(10月31日の決めごとのまま)。届いた記録は標準の値を直す候補にするだけ |
作業の時間のばらつきを試算に入れるか | 入れない。記録が10回以上たまって幅が分かってから決める |
| 幅を出す回数 | 1つの作業を10回測ったら |
入口で待った時間を測る作業を足すか | 足さない |
幅は「早いとき・遅いとき」と書き、中身は、測った値を並べて速い方の4分の1と遅い方の4分の1を外した範囲です(四分位)。店の人に分かる言い方にしました。
観察シートの画面と送る文を直した差分(コミット 8d70549)
commit 8d70549f4025f9877762ea0137302f5c7424b3b7
Author: PixelstoMotors <studio@adaptdesign.jp>
Date: Sun Nov 1 19:21:23 2026 +0900
観察シート:1つの作業を10回測ったら早いとき・遅いときも出す(画面・送る文・取り込みの値の案)
- 速い方の4分の1と遅い方の4分の1を外した幅。シートと field_import.py で同じ計算
- 試算・前提の表には入れない。記録として残すだけ届いた記録を取り込む field_import.py(全文)
表の右に「店ごとの早いとき・遅いとき」の列を足しました。シートと同じ計算なので、同じ数字になります。
"""観察シートの記録(LINE・メールで届いた文)を取り込み、試算の前提の表に入れる値の案を出す(2026-10-31)
使い方:
python3 field_import.py <field のフォルダ> <届いた文.txt> [<届いた文.txt> ...] # 取り込んで、案を作り直す
python3 field_import.py <field のフォルダ> # 案だけ作り直す
field のフォルダは iCloud の サービスロボット導入シミュレーション/field/(店のデータは GitHub に入れない)。
- raw/ 届いた文の原文(取り込んだときに写す。直さない)偽の記録で、画面・送る文・取り込みの3か所が同じ幅になるかを確かめた
会計12回・テーブルを拭く3回の偽の記録を入れて、画面・送る文・proposal.md を見ました。確かめに使ったスクリプトと出力です。
const { chromium } = require('playwright');
(async()=>{const b=await chromium.launch();const p=await b.newPage({viewport:{width:375,height:900},deviceScaleFactor:2});
const errs=[];p.on('pageerror',e=>errs.push(e.message));
await p.goto('file:///home/claude/p2m-site/public/sim/serving-robot-observation.html');
const t0=Date.parse('2026-11-01T12:00:00');
const pay=[62,75,80,88,90,95,101,110,120,150,85,70].map((s,i)=>({id:'p'+i,k:'pay',sec:s+0.3,at:t0+i*60000}));
const wipe=[30,35,41].map((s,i)=>({id:'w'+i,k:'wipe',sec:s,at:t0+i*61000}));
await p.evaluate(([r])=>{localStorage.setItem('p2m-obs-sheet-v2',JSON.stringify({purpose:'post',store:{name:'',staff:3,robots:2,time:'',tags:[],note:'',tables:'',occ0:''},recs:r,arrivals:[],leaves:[]}));},[pay.concat(wipe)]);
await p.reload();
require("fs").writeFileSync("/tmp/claude-0/sheet.txt",await p.evaluate(()=>summaryText()));
await p.evaluate(()=>show('sList'));
await p.waitForTimeout(300);
const el=await p.$('#sum'); await el.screenshot({path:'/tmp/claude-0/sum.png'});
console.log('errors',errs);await b.close();})();
送る文(sheet_test.txt):
観察シートの記録
日付:2026/11/1
目的:ロボットを入れていて、改善したい
お店:(未入力) スタッフ3人 ロボット2台
時間帯:夜(ディナー)
会計:だいたい1分29秒・早いとき1分19秒・遅いとき1分44秒(12回)
テーブルを拭く:だいたい35秒(3回)
--- 1回ずつの記録 ---
12:00:00 会計 62.3秒
12:00:00 テーブルを拭く 30秒
12:01:00 会計 75.3秒
12:01:01 テーブルを拭く 35秒
12:02:00 会計 80.3秒
12:02:02 テーブルを拭く 41秒
12:03:00 会計 88.3秒
12:04:00 会計 90.3秒
12:05:00 会計 95.3秒
12:06:00 会計 101.3秒
12:07:00 会計 110.3秒
12:08:00 会計 120.3秒
12:09:00 会計 150.3秒
12:10:00 会計 85.3秒
12:11:00 会計 70.3秒
取り込みの値の案(proposal_test.md):
# 前提の表に入れる値の案(観察シートの記録から)
作った日:2026-11-01 記録 15 回
- 店ごとに 15 回に届くまでは「参考」。標準の値の候補は、2店以上・合わせて 15 回以上
- 表はまだ書き換えていない。候補を表に入れるかはエイイチが決める(basis を「現場」、n に回数、source に店の数と期間。店の名前は書かない)
- 早いとき・遅いときは、1つの店で 10 回以上測った作業だけ出す(速い方の4分の1と遅い方の4分の1を外した幅)。試算には入れず、記録として残す
- 中央値で比べる。席へ案内は 2026-10-31 16:08 より前の記録を使わない(歩く時間を含む前の区切り)
## 作業の時間(秒)
| 行 | シートの作業 | 今の値(根拠) | 全体の中央値 | 店の数 | 回数 | 判定 | 店ごと(中央値・回数) | 店ごとの早いとき・遅いとき |
|---|---|---|---|---|---|---|---|---|
| `pay_s` | 会計 | 90(実感) | 89.3 | 1 | 12 | 参考 | 名前なし_2026-11-01 89.3秒・12回(参考) | 名前なし_2026-11-01 79〜103.5秒 |
| `clear_s` | 片付け | 40(仮置き) | — | 0 | 0 | 記録なし | — | — |
| `wipe_s` | テーブルを拭く | 40(仮置き) | 35 | 1 | 3 | 参考 | 名前なし_2026-11-01 35秒・3回(参考) | — |
| `guide_s` | 席へ案内 | 45(仮置き) | — | 0 | 0 | 記録なし | — | — |
| `call_s` | 呼び出し | 30(仮置き) | — | 0 | 0 | 記録なし | — | — |
| `staff_place_s` | 料理を置く | 10(仮置き) | — | 0 | 0 | 記録なし | — | — |
## ロボット(往復のうち、起きた往復の割合)
| 行 | 数え方 | 今の値(根拠) | 全体 | 店の数 | 往復の回数 | 判定 | 店ごと |
|---|---|---|---|---|---|---|---|
| `pause_rate` | 1回以上止まった往復 | 0.3(仮置き) | — | 0 | 0 | 記録なし | — |
| `stuck_rate` | 人が動かした往復 | 0.01(仮置き) | — | 0 | 0 | 記録なし | — |
ロボットの往復の時間(答え合わせ用・表には入れない):中央値 — 秒・0 往復
## 店の条件(今は記録だけ。店ごとの値で試算は回さない)
| 店 | 日付 | 時間帯・ようす | スタッフ | ロボット | 卓 | 来店/時 | 回転率/時 | 滞在の目安(分) |
|---|---|---|---|---|---|---|---|---|
| 名前なし_2026-11-01 | 2026-11-01 | 夜(ディナー) | 3 | 2 | — | — | — | — |

会計の幅は、画面・送る文が1分19秒〜1分44秒、取り込みが79〜103.5秒で、同じ値でした。公開したページに新しい表示が入っていることも確かめました。
- ねらい:店で測った作業時間のばらつきを、捨てずに残す
- 変わったこと:10回測った作業に「早いとき・遅いとき」が出る。送る文と値の案にも入る
- 見込める効果:記録が集まれば、作業の時間を1つの値ではなく幅として試算に入れるかを、店の数字で決められる。まだ記録は届いていない
作業ログ ― 配膳ロボットが止まった場所を、店の平面図に重ねた
ここからは、店の人がシミュレーションに求めることを先に決めてから進めました。ロボットを入れた店が望むのは、ロボットの煩わしさが減ること、忙しくてもスタッフの負担が減ること、お客さんの満足度が高いこと、回転が良くなり売上が上がるか安定すること、です。これを、どこで・なぜ止まるのか/何を変えれば良くなるのか/変えたらどれくらい良くなるのか/スタッフは楽になっているのか、の4つの材料にして順に作りました。
混んでいるとき、④は⑥の約3倍の時間ロボットが止まっていた
夜に回した10回(2026-10-29 の「混み具合を広げた夜」・cs:44)の stops.csv から、ロボットが止まった場所・時間・相手を取り出し、店の平面図の上に0.5mのマスで止まっていた時間を足し上げました。赤い点は、ロボットが動けなくなり、スタッフが動かしに行った場所です。

混んでいるとき・ロボット2台(ピーク2時間あたり・10回の平均) | ④ 効率重視・小さめ | ⑥ ゆったり・入口が横 |
|---|---|---|
| 動けなくなった回数 | 68回 | 10回 |
| 止まっていた時間の合計 | 114分 | 34分 |
| 動けなくなった相手 | もう1台のロボット 354・人が立ち止まっていた 159・スタッフとすれ違った 81・お客さんとすれ違った 40・椅子や荷物 30・分からない 14・通路の幅が足りない 1 | もう1台のロボット 75・スタッフ 8・お客さん 6・人が立ち止まっていた 5・分からない 2・椅子や荷物 2 |
(相手の数は10回分の合計)
④で詰まっていたのは、島の下の横の通路(幅約1.1m)と、島の左の縦の通路、パントリー横の縦の通路でした。どれも1本道で、すれ違う場所がありません。卓に向かう道がこの下の通路に集まるので、2台が向かい合って動けなくなります。


止まった場所を描く stopmap.py(全文)
Mac で夜の stops.csv から必要な列だけを stops_extract.csv(35,653行)に書き出し、クラウドの作業環境で描きました。店の形は、サイトの公開している店の形(public/sim/layouts/)をそのまま読んでいます。
# 配膳ロボットが止まった場所を、店の平面図の上に重ねる(Unity の夜の種10個ぶん)
import sys, csv, json, collections
sys.path.insert(0, '/home/claude/p2m-site/tools/sim_layouts')
import matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.patches import Rectangle
for f in font_manager.findSystemFonts():$ python3 stopmap.py ".../unity/stop_map_20261101/stops_extract.csv"
stopmap_p2_crowded.png
stopmap_p4_crowded.png
stopmap_p2_vs_p4_crowded_r2.png
fam_p2 [('もう1台のロボット', 354), ('人が立ち止まっていた', 159), ('スタッフとすれ違った', 81), ('お客さんとすれ違った', 40), ('椅子・荷物・ベビーカー', 30), ('分からない', 14), ('通路の幅が足りない', 1)]
fam_p4 [('もう1台のロボット', 75), ('スタッフとすれ違った', 8), ('お客さんとすれ違った', 6), ('人が立ち止まっていた', 5), ('分からない', 2), ('椅子・荷物・ベビーカー', 2)]
作業ログ ― スタッフの負担と待ち時間を、6店 × 0〜2台で並べた
1台目は歩く距離を2〜3割減らし、2台目は動かしに行く回数を一気に増やす
店ごとに一番新しい夜の結果(10回の中央値)を、空いている・普通・混んでいるの3つで並べました。下の表は普通の混み具合で、0台→1台→2台の順です。
| 店(スタッフ) | 入店待ち(分) | 料理が届くまで(分) | 歩く距離(km/人) | 手がふさがる割合 | ロボットを動かしに行った回数 |
|---|---|---|---|---|---|
| ②(2人) | 2.0→1.7→2.1 | 0.9→1.0→1.0 | 2.3→1.7→1.7 | 66%→56%→58% | 0→0→12 |
| ③(4人) | 4.1→5.0→4.0 | 1.0→2.5→2.0 | 3.4→2.7→2.7 | 77%→73%→72% | 0→4→18 |
| ④(2人) | 13.0→13.8→26.8 | 1.3→2.1→3.5 | 3.4→2.5→3.1 | 84%→81%→89% | 0→13→78 |
| ⑤(4人) | 8.1→6.6→5.5 | 1.1→2.6→2.2 | 4.0→3.2→3.0 | 81%→80%→80% | 0→1→12 |
| ⑥(3人) | 9.6→6.0→4.8 | 1.1→2.1→1.3 | 3.7→2.6→2.4 | 83%→75%→75% | 0→1→8 |
| ⑦(4人) | 4.5→3.2→3.6 | 1.0→2.5→1.6 | 3.4→2.7→2.7 | 77%→74%→69% | 0→6→16 |
混んでいるときも傾向は同じです。
| 店(スタッフ) | 入店待ち(分) | 料理が届くまで(分) | 歩く距離(km/人) | 手がふさがる割合 | ロボットを動かしに行った回数 |
|---|---|---|---|---|---|
| ②(2人) | 11.2→11.4→10.7 | 1.0→2.0→1.4 | 2.8→2.2→2.2 | 75%→67%→66% | 0→13→24 |
| ③(4人) | 19.0→16.4→15.8 | 1.0→2.6→1.8 | 4.3→3.4→3.2 | 84%→79%→79% | 0→6→14 |
| ④(2人) | 32.9→31.6→45.9 | 1.3→2.3→2.9 | 4.5→3.3→3.4 | 87%→85%→87% | 0→21→64 |
| ⑤(4人) | 24.8→23.7→24.4 | 1.1→2.7→1.8 | 5.1→4.1→3.9 | 87%→84%→85% | 0→4→6 |
| ⑥(3人) | 30.1→21.6→19.8 | 1.2→2.1→1.3 | 4.9→3.5→3.2 | 89%→84%→83% | 0→1→12 |
| ⑦(4人) | 19.4→17.7→16.6 | 1.0→2.6→1.8 | 4.4→3.5→3.2 | 84%→79%→78% | 0→4→16 |
- スタッフの負担は、どの店でも1台目で減ります。歩く距離は2〜3割減り、④でも減りました。2台目ではほとんど減りません
- ロボットの煩わしさは、2台目で一気に増えます。1台なら動かしに行く回数は0〜21回、2台だと6〜78回です。④の普通の78回は、2時間で約1.5分に1回です
- お客さんの待ちでは、料理が届くまでが延びます。ほぼ全部の店で約1分から2〜2.5分になります。料理はロボットを優先し、ロボットが来るまで最大2分待ってからスタッフが運ぶ決まりにしているためです
- 入店待ちは店しだいで、⑤⑥は縮み、②③⑦はほぼ変わらず、④の2台は倍になります
通路の幅そのものより、すれ違える場所や回り道があるかが効いているようです。③と、③の細い通路を80cmから95cmに広げた⑦では、2台のときの動かしに行く回数が18回と16.5回で、ほとんど変わりません。④は上に幅約2.1mの広い通路があるのに、2台とも同じ下の狭い道を行き来していました。
負担と待ち時間を並べる burden.py(全文)
import csv,re,collections,statistics as st,os,json
L=os.path.expanduser('~/mnt/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv')
R=list(csv.DictReader(open(L)))
N={'fam_p0':'②','fam_p1':'③','fam_p2':'④','fam_p3':'⑤','fam_p4':'⑥','fam_p5':'⑦'}
# 普通の混み具合の夜(店ごとに一番新しい作り)
NORMAL={'fam_p1':'20261102_night','fam_p5':'20261102_night','fam_p3':'20261103_night','fam_p4':'20261104_night','fam_p0':'20261105_night','fam_p2':'20261030_night'}
LOW={'fam_p0':'a14','fam_p1':'a30','fam_p2':'a20','fam_p3':'a33','fam_p4':'a27','fam_p5':'a30'}
HIGH={'fam_p0':'a24','fam_p1':'a54','fam_p2':'a36','fam_p3':'a59','fam_p4':'a49','fam_p5':'a54'}
def pick(prefix,store):
return [r for r in R if r['run_folder'].startswith(prefix) and r['store']==store and '_ruleb' not in r['run_folder']]
M=[('entry_wait_mean','入店待ち(分)'),('walk_km_per_staff','歩く距離(km/人)'),('staff_util','手がふさがる割合'),('rescues','動かしに行った回数'),('staff_yield_share_of_staff_time','よけていた時間の割合'),('dish_wait_mean','料理が届くまで(分)'),('gave_up','あきらめて帰った組')]
out=[]
for store in N:
for cond,prefix in [('空いている','20261106_night_'+LOW[store]+'_'),('普通',NORMAL[store]+'_'),('混んでいる','20261106_night_'+HIGH[store]+'_')]:
rs=pick(prefix,store)
for rb in '012':
sub=[r for r in rs if r['robots']==rb]
if not sub: continue
d=dict(store=N[store],cond=cond,robots=int(rb),n=len(sub),staff=int(sub[0]['staff']),arr=int(sub[0]['arrivals_per_h']),cs=sub[0]['unity_cs'])
for k,lab in M:
v=[float(r[k]) for r in sub if r[k] not in('','nan')]
d[k]=st.median(v) if v else None
out.append(d)
json.dump(out,open('burden.json','w'),ensure_ascii=False,indent=1)
for d in out: print(d['store'],d['cond'],'人',d['staff'],'台',d['robots'],'n',d['n'],' '.join('%s=%.2f'%(k[:8],d[k]) for k,_ in M if d[k] is not None))
出力の全量(burden.json):
[
{
"store": "②",
"cond": "空いている",
"robots": 0,
"n": 10,
"staff": 2,
"arr": 14,作業ログ ― ④でロボットどうしが向かい合わないための3つの案を作った
下の通路は幅約1.1m、使われていない上の通路は約2.1m
④の平面図の数字を確かめると、島の下の横の通路は約1.1m、島の上の横の通路は約2.1m、左右の縦の通路は約1.2mでした。ロボットが下の通路を通るのは、受け渡し口から左の卓まで一番近いからです。Unity のロボットは、店の地図の上で一番近い道を自分で引くので、2台とも同じ狭い道を行き来します。
すれ違うときに片方が少しよけられる場所が1つあるだけで、「向かい合って2台とも動けない」が「片方が待って、すぐ通れる」に変わります。そこで、向かい合いを起こさない案と、向かい合ったら片方が待つ案を作りました。

| 案 | 中身 | 席 | 代わりに起きること |
|---|---|---|---|
| 案A 一方通行 | 店の中を1周する向きを決め、その通路では逆向きに進まない | 減らさない | 遠回りになる卓が出る(パントリー横の T21〜T23 は、受け渡し口から約4m → 1周して約19m) |
| 案B 1本道は1台ずつ | 下・左・パントリー横の3本を1本道として扱い、向かいからロボットが来ていたら手前の待つ点で待つ | 減らさない | 待つ時間が出る |
| 案B’ よけ場所 | 下の段の2人席 T26 を外し、下の通路の真ん中に1台分のよけ場所を作る(案Bと組み合わせる) | 2席減る(27卓・86席) | 待つ時間が出る。席が減るぶん、同じ来客では待ちが延びやすい |
図面を見ると、④は通路の途中に隙間がなく、通路の途中によけ場所を作るには席を外す必要がありました。案Bの待つ点は、席を減らさずに使える角の空き(4か所)にしています。待つ点は、ロボットの地図でどれもふだんの道(幅1.0m)が通れるマスで、障害物から0.59m以上離れていることを確かめました。
案を描いた plan_p2.py(全文)
import sys, json
sys.path.insert(0, '/home/claude/p2m-site/tools/sim_layouts')
import matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.patches import Rectangle, FancyArrowPatch, Circle
for f in font_manager.findSystemFonts():
if 'NotoSansCJK-Regular' in f: font_manager.fontManager.addfont(f)
plt.rcParams['font.family'] = 'Noto Sans CJK JP'
import famires_v3 as F
L = json.load(open('/home/claude/p2m-site/public/sim/layouts/p2_efficient_narrow.json'))['layout']
def base(ax):
try: F.draw(ax, L, [], {}, {})
except Exception: pass
for t in L['tables']:
x0,y0,x1,y1 = F.fp(t); ax.add_patch(Rectangle((x0,y0),x1-x0,y1-y0,fc='#e9ecef',ec='#868e96',lw=0.6,zorder=3))
ax.text((x0+x1)/2,(y0+y1)/2,t['id'],ha='center',va='center',fontsize=6,color='#868e96',zorder=4)
def arrow(ax,a,b,c='#1c7ed6'):
ax.add_patch(FancyArrowPatch(a,b,arrowstyle='-|>',mutation_scale=22,lw=3,color=c,zorder=8))
f, axs = plt.subplots(1,2,figsize=(14,6.6))
# A 一方通行
ax=axs[0]; base(ax)
Z=[('下の通路 ←',[1.4,1.8,8.8,2.9]),('左の通路 ↑',[1.4,2.9,2.6,8.45]),('真ん中の細い通路 ↑',[5.1,2.9,6.3,8.45]),('上の通路 →',[1.4,8.45,10.0,10.0]),('パントリー横 ↓',[8.8,2.9,10.0,8.45])]
for n,(x0,y0,x1,y1) in Z: ax.add_patch(Rectangle((x0,y0),x1-x0,y1-y0,fc='#a5d8ff',alpha=0.35,ec='none',zorder=5))
arrow(ax,(8.4,2.35),(2.2,2.35)); arrow(ax,(2.0,3.2),(2.0,8.0)); arrow(ax,(5.7,3.2),(5.7,8.0)); arrow(ax,(2.6,9.3),(9.2,9.3)); arrow(ax,(9.4,8.2),(9.4,3.2))
arrow(ax,(10.9,4.3),(9.6,2.7),'#2f9e44')
ax.set_title('案A 一方通行:店の中を1周する向きを決める\n(青=向きを決める通路、緑=受け渡し口から出る向き)',fontsize=11)
# B 待つ場所
ax=axs[1]; base(ax)
S=[('下の通路',[1.4,1.8,8.8,2.9]),('左の通路',[1.4,2.9,2.6,8.45]),('パントリー横',[8.8,2.9,10.0,8.45])]
for n,(x0,y0,x1,y1) in S: ax.add_patch(Rectangle((x0,y0),x1-x0,y1-y0,fc='#ffd8a8',alpha=0.45,ec='none',zorder=5))
P=[('①',0.75,1.6),('②',9.4,1.1),('③',2.0,9.3),('④',9.4,9.3)]
for n,x,y in P:
ax.add_patch(Circle((x,y),0.4,fc='#e8590c',ec='white',lw=1.5,zorder=8)); ax.text(x,y,n,ha='center',va='center',color='white',fontsize=10,weight='bold',zorder=9)
ax.set_title('案B 1本道は1台ずつ:向かいから来ていたら、端の待つ場所で待つ\n(だいだい=1本道、①〜④=待つ場所。席は減らさない)',fontsize=11)
f.suptitle('④ 効率重視・小さめの店:ロボットどうしが向かい合わないための2つの案',fontsize=13,weight='bold')
f.tight_layout(rect=(0,0,1,0.95)); f.savefig('plan_p2_traffic.png',dpi=130)
サイトの回し方の決まりに、2つの決まりを「切」で足した(params の unity_rules)
決まりの正はサイトです。サイトの params(public/sim/serving-robot-params.json)の unity_rules に、案Aと案B・B’の決まりを、既定は切で足しました。試算の数字は変えていません。
{
"traffic_one_way": {
"value": false,
"role": "site_rule",
"stores_only": [
"p2_efficient_narrow"
],
"note": "(切)案A 一方通行(2026-11-01 エイイチと決めた。④で試す)。ロボットは zones の中では dir の向きにしか進まない(逆向きに進むマスは通れない扱い。横切るのはよい)。受け渡し口から出るときは下の通路へ向かう。店の中を1周する向き:下の通路は左へ、左と真ん中の細い通路は上へ、上の通路は右へ、パントリー横は下へ。遠回りになる卓(パントリー横の T21〜T23 など)が出るのは承知の上。zones の外(受け渡し口のまわり・下の段の卓の前など)は向きを決めない。試算の数字(卓までの距離)は変えない",公開している④は変えず、T26 を外した店を別のフォルダに作った trial_p2_traffic.py(全文)
公開している店の形は基本変えない決まりなので、案B’の店は public/sim/layouts/trials/p2_noT26/ に別に作りました。作り方・決まりの確かめ・Unity 用の細かい形と地図は、6つの店と同じ規則です。卓の番号は④と同じまま(T26 だけ抜ける)にしました。
"""④ 効率重視・小さめの店で、ロボットどうしが向かい合わないための試し(2026-11-01 エイイチと決めた)
案B'(席を1つ外して、下の通路の途中によけ場所を作る)の店の形を、公開している ④ とは別のフォルダに作る。
公開している店の形のデータ(public/sim/layouts/ の p2_efficient_narrow*)は変えない(2026-10-31 の決まり)。
- 下の段の2人席 T26 を外す(席 2 つ減る)。卓の番号は ④ と同じまま(T26 だけ抜ける)
- 外した所(下の通路の真ん中・真ん中の細い通路の下の口の前)を、ロボットのよけ場所にする
- 店の形の作り方・確かめ・Unity の細かい形と地図は famires_v3 と同じ規則で作る
- 出力:public/sim/layouts/trials/p2_noT26/(p2_efficient_narrow_noT26.json・_analysis.json・.png・unity/ の2つ)
使い方: python3 trial_p2_traffic.py
"""
import json, sys
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import famires_v3 as F
HERE = Path(__file__).resolve().parent
OUT = HERE.parent.parent / "public" / "sim" / "layouts" / "trials" / "p2_noT26"
NM = "p2_efficient_narrow_noT26"
REMOVE = "T26"
def main():
L = F.prepare(F.gen.p2_efficient_narrow())
assert any(t["id"] == REMOVE for t in L["tables"])
L["tables"] = [t for t in L["tables"] if t["id"] != REMOVE]
L["name"] = L["name"] + "(試し:T26 を外してよけ場所)"
v = F.check_rules(L)
ctx = {}
res_a, err_a = F.analyze(L, F.SETTINGS["res"], ctx)
res_b, err_b = F.analyze(L, F.SETTINGS["check_res"])
v += err_a + [e for e in err_b if e not in err_a]
if v:
for k, m in v:
print("NG", k, m)
sys.exit(1)
OUT.mkdir(parents=True, exist_ok=True)
gen_id = "trial-p2-noT26-" + F.generation_id()
conv = [a["id"] for a, b in zip(res_a, res_b) if a["category"] != b["category"]]
summ = F.summarize(L, res_a)
fig, ax = plt.subplots(figsize=(14, 11), dpi=120)
F.draw(ax, L, res_a, summ, conv)
fig.savefig(OUT / f"{NM}.png", bbox_inches="tight", facecolor="white")
F.export(L, res_a, summ, conv, NM, OUT, gen_id)
U = F.export_unity(L, res_a, ctx, NM, OUT, gen_id)
vr = F.check_register_clear(U)
if vr:
print("NG", vr); sys.exit(1)
print("OK", gen_id, summ, "マス目の差", conv)
if __name__ == "__main__":
main()
$ python3 trial_p2_traffic.py
OK trial-p2-noT26-e578507fff7d {'name': '④ 効率重視型・狭い店・入口が右の壁(試し:T26 を外してよけ場所)', 'seats': 86, 'tables': 27, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 27, 'robot_seats': 86, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.6, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None} マス目の差 []
④(28卓)の卓までの平均距離は8.5m・最長13.92mで、T26 を外した店は8.6m・13.92mでした。
commit f3a3888210d95f8c6e5be6d420dcb61636cd004d
Author: PixelstoMotors <studio@adaptdesign.jp>
Date: Sun Nov 1 20:08:46 2026 +0900
④でロボットどうしが向かい合わない試し:一方通行(案A)・1本道は1台ずつ(案B)・T26を外したよけ場所(案B')
- params の unity_rules に traffic_one_way・traffic_single_lane を足した(既定は切。試算の数字は変えない)
- 公開している店の形は変えず、案B' の店の形を trials/p2_noT26/ に別に作った
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LevEXTjmDgrBZ74rhCRBtF
diff --git a/tools/sim_layouts/README.md b/tools/sim_layouts/README.md
index c495343..7dd1b31 100644
--- a/tools/sim_layouts/README.md
+++ b/tools/sim_layouts/README.md
@@ -42,6 +42,13 @@
- 卓の数・止まる位置・距離は変わらない(椅子は外形の内側に置くだけ)。版 2e9fc773050a → dffc100b269c(②の部品と説明が増えただけで、6店とも数字は同じ。サイトの試算は計算し直していない)
- まだないもの:人がロボットをよける逃げ場(refuges)
+## 試しの店の形(`public/sim/layouts/trials/`。2026-11-01)
+
+公開している店の形は変えずに、試しのためだけの店の形を別のフォルダに作る。作り方・確かめ・Unity の細かい形と地図は famires_v3 と同じ規則。
+
+- `trials/p2_noT26/`(`trial_p2_traffic.py`):④から下の段の2人席 T26 を外し、下の通路の真ん中にロボットのよけ場所を作った店(案B')。27卓・86席。卓の番号は④と同じまま(T26 だけ抜ける)。版は `trial-p2-noT26-…`
+- 一方通行(案A)と1本道は1台ずつ(案B・B')の決まりは、params の `unity_rules.traffic_one_way`・`traffic_single_lane`(どちらも既定は切)
+
## 動かし方
### 依頼59「店4の一方通行と1本道は1台ずつを切り替えで入れる」の全文
```text
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼59:④で「一方通行(案A)」「1本道は1台ずつ(案B)」「T26 を外したよけ場所(案B')」を切り替えで入れる(2026-11-01)
エイイチの決定(2026-11-01 20:07):④ 効率重視・小さめの店では、混むとロボット2台が下の狭い通路などで向かい合って動けなくなり、スタッフが動かしに行く回数が2時間で60〜80回になる。向かい合わないための3つの案を、夜に種10個で比べる。この依頼は、その切り替えを入れて確かめるところまで。夜に回すのは次の依頼60。
**エイイチは寝ているかもしれない。人に聞かないと進めない所に当たったら、そこで止めて報告に書いて終わる。**
決まりの正はサイト(p2m-site の main、コミット f3a3888 以降)。Unity で決まりの形を変えない。
- `public/sim/serving-robot-params.json` の `unity_rules.traffic_one_way`(案A)と `unity_rules.traffic_single_lane`(案B・B')。中身(通路の矩形・向き・待つ点)と note の文がそのまま決まり
- 案B' の店の形:`public/sim/layouts/trials/p2_noT26/unity/p2_efficient_narrow_noT26.json` と `_map.json`(④から下の段の T26 を外しただけ。卓の番号は④と同じで T26 だけ抜ける。27卓)
- 公開している④の店の形(`public/sim/layouts/unity/p2_efficient_narrow*.json`)は変わっていない
## 始める前に確かめること(1つでも違えば何も変えずに報告して終わる)
1. Unity エディタ・night_runner・rec_runner が動いていない。/Volumes/KIOXIA がマウントされている。unity_ledger_v1.lock がない
2. ServiceSim の保留が 0
3. サイトの params に `traffic_one_way` と `traffic_single_lane` があり、どちらも value が false
## やること
1. **取り込み**:いつもの取り込み方で、params の2つの決まりと、案B' の店の形(unity の2つのファイル)を取り込む。案B' の店は今の6店とは別の店として扱い、条件の値(スタッフ・来客・ロボットの台数)は④と同じものを使う(来客のペースも④のまま。卓が1つ減るぶん待ちが延びるのは承知の上)
2. **案A 一方通行**(切り替え `-ssOneWay`。既定は切):ロボットが地図の上で道を引くとき、zones の中では dir の向きに進むマスだけを通れる扱いにする(逆向きに進むことができない。dir と直角に動くのはよい)。zones の外は今までどおり。回り込みの道を探すときも同じ扱い。行けなくなる卓が出たら、その卓の名前を報告に書く(直さない)
3. **案B 1本道は1台ずつ**(切り替え `-ssSingleLane`。既定は切):lanes の中に向かいの向きに進むロボットがいる(入ろうとしている)あいだは入らず、近い方の待つ点で待つ。同じ向きなら続いて入ってよい。同時なら料理を載せている方が先、同じなら先に待つ点に着いた方。待っていた時間は、今の止まりの記録(stops.csv)とは分けて数えられるようにする(原因の名前を新しく足すなど。やり方は任せる。報告に書く)
4. **案B'**:店を案B' の店にし、`-ssSingleLane` を入れたときに p2_efficient_narrow_noT26 の lanes を使う。店の指定の仕方(引数の名前など)は任せる。出力フォルダ名で④と区別できるようにする
5. 3つの切り替えとも切のときは、今の動きと1つも変わらないこと
6. **確かめ**(画面なし・1本ずつ):④・スタッフ2人・ロボット2台・混んでいる(来客 36組/時)・種0 で、今のまま・案A・案B・案B' の4回を回す。全員が帰ること、行けない卓がないこと、待つ点で待ちっぱなしにならないことを見る。4回の数字(入店待ち・料理の待ち・動けなくなった回数・30秒以上の止まり・案Bの待った時間の合計)を並べる
7. 確かめの4回のうち、案A・案B'の店の 900〜1200 秒の間のコマを1枚ずつ png にして、ロボットの向き・待つ点が決まりどおりかを目で見られるようにする(置き場所は night/20261101_traffic_check/)
8. check-in する。画面なしの実行ファイルを作り直し、build_id と保留なしを記録する
## 変えないもの
- Unity の ArticulationBody の Stiffness・Damping(絶対変更禁止)
- 公開している6店の店の形、ほかの切り替えの既定(すれ違い入・待機場所へ戻る入・案B切・入口番入・持ち場入)
- ロボットの速さ・よけ方の決まり・試算の数字
- 確かめの4回は台帳に追記してよい。ほかの台帳の行は変えない
## 報告
依頼箱の結果に加えて、claude_code_reports に 20261101_traffic_p2_impl.txt として書く(場所:~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity/claude_code_reports/)。
- 始める前の確かめ3つ
- 足した切り替えの名前と使い方、案B' の店の指定の仕方、案Bの待った時間の数え方
- 変えたファイル、cs 番号、build_id
- 確かめの4回の表と png の場所
- 行けなくなった卓・待ちっぱなし・全員が帰らなかった回があればその内容
- 依頼60(夜の80回)にそのまま進めてよい状態か。よくないなら、何が足りないか
- 決めてほしいこと(なければ「なし」)
依頼59の結果(依頼箱の報告)
# 結果:20261101_59_店4の一方通行と1本道は1台ずつを切り替えで入れる
- 状態:完了
- 始めた時刻:2026-11-01 21:38
- 終わった時刻:2026-11-01 22:33(54分)
- 作業フォルダ:/Users/shimazueiichi/Robotics_UX/ServiceSim
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume c7493ad8-d47b-4892-b16a-cefadf9ddc76`
Claude Code の報告 20261101_traffic_p2_impl.txt(全文)
====================================================================
④の一方通行(案A)・1本道は1台ずつ(案B)・T26 を外した店(案B')を切り替えで入れ、4回で確かめた
依頼:20261101_59_店4の一方通行と1本道は1台ずつを切り替えで入れる.md(依頼57)
2026-11-01 21:38 〜 22:45 check-in:cs:54・cs:55 build_id cs55_20261101_2224(保留 0)
====================================================================
結論
確かめの1回ずつ(④・混んでいる・ロボット2台・種0)では、案B’がよさそうに見えました。最初の版では、相手が1本道を離れても「入ってよい」を手放さないコードの誤りと、待つ点が出てくる台の道の上にある問題で、571秒の待ちっぱなしが出ていて、Claude Code が直して回し直しています。


決めた5つ(依頼59の「決めてほしいこと」)
| 決めてほしいこと | 決めたこと |
|---|---|
1本道に横から入るとき、決めた待つ点が通路の向こう側になる | 今の仮の作り「入る手前のその場で待つ」のまま。実際のロボットも入口の手前で止まる |
待つ点が、1本道から出てくる台の道の上にある | 今夜は、待っている台が今のよけ方で道を空ける作りのまま。待つ点の場所は結果を見てから |
| 試しの回が台帳に書いた1行 | 残す(測定データは消さない) |
| 待った回数の数え方 | 待つと決めた回数(lane_holds)で数える |
試しのビルドと途中で止めた回のフォルダ | 今は残す |
作業ログ ― 3つの案を夜に80回回し、1台とも比べた
依頼60は、決めごとが残っていたので回さずに止まった
依頼60は、始める前の確かめに「依頼59の報告に、進めてよいと書いてある」を入れていました。依頼59の報告は「決めてほしいことが決まるまで、そのままは進めない方がよい」だったので、依頼60は80回を回さず、台帳も変えずに止まりました。決めた5つを書き足して、依頼60bとして出し直しています。
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 330
---
# 依頼60:④の「向かい合わない3案」を今のままと並べて80回回す(夜の作業・2026-11-01)
エイイチの決定(2026-11-01 20:07):④で、一方通行(案A)・1本道は1台ずつ(案B)・T26 を外したよけ場所(案B')を、今のままと同じ種で比べる。比べ方は、同じ種どうしの差で見る。
**エイイチは寝ている。人に聞かないと進めない所に当たったら、回さずに報告に書いて終わる。**
## 始める前に確かめること(1つでも違えば回さずに報告して終わる)
1. 依頼59(20261101_59_店4の一方通行と1本道は1台ずつを切り替えで入れる)が「完了」で終わっていて、報告 claude_code_reports/20261101_traffic_p2_impl.txt に「依頼60に進めてよい」と書いてある
2. 画面なしの実行ファイルが依頼59で作り直した版(build_id が報告と同じ)で、保留なし
3. Unity エディタが起動していない。/Volumes/KIOXIA がマウントされている。unity_ledger_v1.lock がない
## 台帳の退避(回す前に自分で行う)
`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv` を
`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_pretraffic_20261101/unity_ledger_v1.csv` にコピーする(コピーだけ。移動・上書きしない。フォルダが既にあれば止めて報告)。行数と md5 を控え、元と同じかを確かめる。
## 回す
夜の名前 20261108_traffic。④(fam_p2)・スタッフ2人・ロボット2台 × 来客2つ(普通 28組/時・混んでいる 36組/時)× 4通り × 種0〜9 = 80回。同時に回す本数は 4。記録は night/20261108_traffic/。
| 4通り | 店 | 切り替え |
|---|---|---|
| 今のまま | ④ | どちらも切 |
| 案A 一方通行 | ④ | `-ssOneWay` |
| 案B 1本道は1台ずつ | ④ | `-ssSingleLane` |
| 案B' よけ場所 | ④から T26 を外した店 | `-ssSingleLane` |
(切り替え・店の指定の名前は、依頼59で決めたものを使う)
- ほかの切り替えは今の標準のまま(すれ違い入・待機場所へ戻る入・案B切・入口番入・持ち場入)
- 「今のまま」も、比べを同じ作りにそろえるためにこの版で回し直す
- 判定(judge_night.py)は回さなくてよい(基準データに同じ条件がないため)
- 回している間はほかの作業をしない。Ctrl+C で止めない。途中で止まっても回し直さない
- 作業フォルダに queue の一時ファイルを残さない
## 報告
依頼箱の結果に加えて、claude_code_reports に 20261108_night_traffic_p2.txt として書く(場所は依頼59と同じ)。
- 始める前の確かめ3つと、台帳の退避(行数・md5)
- runner_log のまとめ(completed・失敗・止まった回・最長の実時間)
- 台帳の行数(退避+80 になるはず)と、先頭の行の md5 が退避と同じか
- 来客 × 4通りごとの種10個の中央値(最小〜最大):入店待ち・料理の待ち・動けなくなった回数(スタッフが動かしに行った回数)・30秒以上の止まり(1往復あたり)・案B/B'で待った時間の合計・往復の数・スタッフ1人の歩く距離・スタッフの手がふさがっている割合・ロボットが運んだ皿の割合
- 全員が帰らなかった回・失敗した回があればその名前(原因の調べはしない)
- 決めてほしいこと(なければ「なし」)
# 結果:20261101_60_店4の向かい合わない3案を夜に80回回す
- 状態:完了
- 始めた時刻:2026-11-01 22:33
- 終わった時刻:2026-11-01 22:35(3分)
- 作業フォルダ:/Users/shimazueiichi/Robotics_UX/ServiceSim
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume 2b3f0b6e-21e6-4563-8575-e15e09c33100`
## Claude Code の報告
**やったこと**
回す前に、始める前の確かめ3つを順に見ました。その結果、確かめ1が合わなかったので、80回は回していません。台帳の退避もしていません。回す前の手順なので、止めた時点で行わないことにしました。台帳・出力フォルダ・プロジェクトは何も変えていません。止めた理由を報告ファイルに書きました。
**結果**
- 確かめ1(合わない):依頼57の報告 `20261101_traffic_p2_impl.txt` には「依頼58に進めてよい」とは書かれていません。6章には逆に「そのままは進めない方がよい」とあり、決めてほしいことが5つ残っています。依頼箱で依頼57が「完了」になっているかは、こちらからは見えませんでした。
- 確かめ2(合う):画面なしの実行ファイルは build_id cs55_20261101_2224(ServiceSim/cs:55)で、依頼57の報告と同じです。保留はありません。
- 確かめ3(合う):Unity エディタと night_runner は動いていません。/Volumes/KIOXIA はマウントされていて、unity_ledger_v1.lock はありません。
- 台帳は今1541行で、依頼57の終わりと同じです。依頼58の退避先 `archive/unity_ledger_v1_pretraffic_20261101` はまだありません。依頼57の控え(pre_traffic)とは名前が別なので、ぶつかりません。
- runner_log・中央値などの数字は、回していないのでありません。
**変えたファイル**
- 新しく作ったもの:`…/サービスロボット導入シミュレーション/unity/claude_code_reports/20261108_night_traffic_p2.txt`(止めた理由の報告)
- そのほかは変えていません。
**決めてほしいこと**
1. 依頼57の報告8章に残っている5つを決めてほしいです。とくに次の2つです。
- 1本道に横から入るときの待ち方。今は仮で「入る手前のその場で待つ」にしています。
- 待った回数を lane_holds(待つと決めた回数)で数えてよいか。
2. 仮の作りのまま80回回してよいなら、その旨を書いて依頼58を出し直してほしいです。確かめ1の条件を外すか、依頼57の報告に「依頼58に進めてよい」を足すかのどちらかが要ります。
====================================================================
依頼58:④の向かい合わない3案を夜に80回回す ― 回さずに終えた
2026-11-01 夜の名前 20261108_traffic(回していない)
====================================================================
結論
始める前の確かめ 1 が合わなかったので、回さずに終えた。
台帳の退避もしていない(回す前の手順のため)。台帳・出力フォルダ・プロジェクトは何も変えていない。
1. 始める前の確かめ
1. 依頼57 の報告 20261101_traffic_p2_impl.txt … 合わない
「依頼58に進めてよい」とは書かれていない。6 章に
「そのままは進めない方がよい」と書かれ、決めてほしいことが5つ残っている
(横から1本道に入るときの待ち方〈今は仮〉・待つ点が出口の道の上にある件・
試しの回の台帳1535行めの扱い・待った回数を lane_holds で数えるか・残った Builds と試しのフォルダ)。
依頼箱で依頼57 が「完了」かどうかは、こちらからは見えなかった。
2. 画面なしの実行ファイル … 合う(参考)
Builds/headless/build_info.json:build_id cs55_20261101_2224・ServiceSim/cs:55・pending_changes 空
(依頼57 の報告と同じ)
3. Unity エディタ・night_runner:動いていない。/Volumes/KIOXIA:マウントされている。
unity_ledger_v1.lock:なし … 合う(参考)
台帳:今 1541 行(依頼57 の報告の終わりと同じ)。退避はしていない。
参考:archive/ には依頼57 の控え unity_ledger_v1_pre_traffic_20261101 があり、
依頼58 の退避先 unity_ledger_v1_pretraffic_20261101 はまだ無い(名前が別なので、ぶつからない)。
2. runner_log・台帳の行数・種ごとの中央値
回していないので、なし。
3. 決めてほしいこと
1. 依頼57 の報告 8 章の5つ(とくに 1 の横から入るときの待ち方と 4 の待った回数の数え方)を決めること。
決まれば、依頼57 の続きで作りを直すか、仮のまま依頼58 を回すかを依頼してほしい。
2. 仮の作りのまま 80 回回してよいなら、そう書いた依頼を出し直してほしい
(確かめの条件「依頼58に進めてよい」を外す、またはその一文を報告に足す)。
依頼60b「店4の向かい合わない3案を夜に80回回す」の全文
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 330
---
# 依頼60b:④の「向かい合わない3案」を今のままと並べて80回回す(夜の作業・2026-11-01)
エイイチの決定(2026-11-01 20:07):④で、一方通行(案A)・1本道は1台ずつ(案B)・T26 を外したよけ場所(案B')を、今のままと同じ種で比べる。比べ方は、同じ種どうしの差で見る。
**エイイチは寝ている。人に聞かないと進めない所に当たったら、回さずに報告に書いて終わる。**
## エイイチが決めたこと(2026-11-01 22:39。依頼59の報告の「決めてほしいこと」5つ)
1. 1本道に横から入るときは、今の仮の作り「入る手前のその場で待つ」のままでよい
2. 待つ点が1本道から出てくる台の道の上にある件は、今夜は依頼59で足した作り(待っている台が今のよけ方で道を空ける)のままでよい。待つ点の場所の見直しは結果を見てから
3. 試しの回が台帳に書いた1行(1535行目)は残す
4. 待った回数は lane_holds(待つと決めた回数)で数えてよい
5. 試しのビルド(Builds/traffic_pre・traffic_pre2)と途中で止めた試しの回のフォルダは、今は残す(消さない)
## 始める前に確かめること(1つでも違えば回さずに報告して終わる)
1. 依頼59(20261101_59_店4の一方通行と1本道は1台ずつを切り替えで入れる)が「完了」で終わっている(報告 claude_code_reports/20261101_traffic_p2_impl.txt がある)。「依頼60に進めてよい」の一文はなくてよい(上の5つで決めたため)
2. 画面なしの実行ファイルが依頼59で作り直した版(build_id cs55_20261101_2224)で、保留なし
3. Unity エディタが起動していない。/Volumes/KIOXIA がマウントされている。unity_ledger_v1.lock がない
## 台帳の退避(回す前に自分で行う)
`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv` を
`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_pretraffic_20261101/unity_ledger_v1.csv` にコピーする(コピーだけ。移動・上書きしない。フォルダが既にあれば止めて報告)。行数と md5 を控え、元と同じかを確かめる。
## 回す
夜の名前 20261108_traffic。④(fam_p2)・スタッフ2人・ロボット2台 × 来客2つ(普通 28組/時・混んでいる 36組/時)× 4通り × 種0〜9 = 80回。同時に回す本数は 4。記録は night/20261108_traffic/。
| 4通り | 店 | 切り替え |
|---|---|---|
| 今のまま | ④ | どちらも切 |
| 案A 一方通行 | ④ | `-ssOneWay` |
| 案B 1本道は1台ずつ | ④ | `-ssSingleLane` |
| 案B' よけ場所 | ④から T26 を外した店 | `-ssSingleLane` |
(切り替え・店の指定の名前は、依頼59で決めたものを使う)
- ほかの切り替えは今の標準のまま(すれ違い入・待機場所へ戻る入・案B切・入口番入・持ち場入)
- 「今のまま」も、比べを同じ作りにそろえるためにこの版で回し直す
- 判定(judge_night.py)は回さなくてよい(基準データに同じ条件がないため)
- 回している間はほかの作業をしない。Ctrl+C で止めない。途中で止まっても回し直さない
- 作業フォルダに queue の一時ファイルを残さない
## 報告
依頼箱の結果に加えて、claude_code_reports に 20261108_night_traffic_p2_b.txt として書く(場所は依頼59と同じ)。
- 始める前の確かめ3つと、台帳の退避(行数・md5)
- runner_log のまとめ(completed・失敗・止まった回・最長の実時間)
- 台帳の行数(退避+80 になるはず)と、先頭の行の md5 が退避と同じか
- 案B・B'の待った回数(lane_holds)と、200秒を超えた待ち・待ったまま往復が打ち切られた回の数
- 来客 × 4通りごとの種10個の中央値(最小〜最大):入店待ち・料理の待ち・動けなくなった回数(スタッフが動かしに行った回数)・30秒以上の止まり(1往復あたり)・案B/B'で待った時間の合計・往復の数・スタッフ1人の歩く距離・スタッフの手がふさがっている割合・ロボットが運んだ皿の割合
- 全員が帰らなかった回・失敗した回があればその名前(原因の調べはしない)
- 決めてほしいこと(なければ「なし」)
依頼60bの結果(依頼箱の報告)と、Claude Code の報告 20261108_night_traffic_p2_b.txt(全文)
80回すべて最後まで回り、全員が帰りました。実時間は1回平均5.7分・最長8.6分で、全体は23:15〜01:10でした。
# 結果:20261101_60b_店4の向かい合わない3案を夜に80回回す
- 状態:完了
- 始めた時刻:2026-11-01 23:11
- 終わった時刻:2026-11-02 01:13(122分)
- 作業フォルダ:/Users/shimazueiichi/Robotics_UX/ServiceSim
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume c4c0baba-91e9-4bec-b5b8-07db8101b8c9`
- 止められた操作:1件(いちばん下に一覧)
## Claude Code の報告
**やったこと**
- 始める前の確かめ3つは、すべて合格でした。
- 依頼59は「済み」で終わっていて、報告もあります。
- 画面なしの実行ファイルは cs55_20261101_2224 で、保留はありません。
- Unity エディタは起動しておらず、KIOXIA はマウントされていて、lock はありませんでした。
- 台帳を archive/unity_ledger_v1_pretraffic_20261101/ にコピーしました。元も控えも 1541行、md5 995542102319d77d1416b7c6abfe0619 で同じです。
- 4通りの並びを作って1つにまとめ、80回を同時4本で回しました。止まっても回し直さない設定にしています。
- 夜の名前に「20261108_traffic」は使えなかったため(8桁の日付しか受け付けない)、夜は 20261108、記録のフォルダ名を night/20261108_traffic/ にしました。
- 判定は回さなくてよいとされていましたが、実行係が終わりに自動で呼ぶ作りのため judge.md が出ています(80回とも「基準なし」)。
- 回す前に、実際には回さず打つコマンドだけを見る確かめをしました。そのとき出た記録は runner_log_dryrun.txt という名前で残しています。
**結果**
- 80回すべて最後まで回りました。失敗・止まった回・回し直しは 0、全員が帰らなかった回も 0 です。
- 1回の実時間は平均 5.7分、最長 8.6分でした。
- 案Aで行けない卓は 0 でした。
- 台帳は 1621行(退避の 1541+80)で、先頭 1541行の md5 は退避と同じです。
- 種10個の中央値、カッコ内は同じ種どうしの差(案−今のまま)の中央値です。
| 来客 | 通り | 入店待ち(分) | 料理の待ち(分) | 動けなくなった(回) | 30秒以上の止まり(1往復あたり) |
|---|---|---|---|---|---|
| 28 | 今のまま | 25.06 | 3.47 | 53.5 | 0.727 |
| 28 | 案A | 24.16(+0.43) | 3.38(+0.10) | 57.5(−0.5) | 0.876 |
| 28 | 案B | 17.58(−7.31) | 1.96(−1.81) | 29.0(−20.5) | 0.472 |
| 28 | 案B' | 20.00(−5.27) | 2.58(−1.06) | 40.0(−13.5) | 0.624 |
| 36 | 今のまま | 43.65 | 3.19 | 74.5 | 0.821 |
| 36 | 案A | 56.49(+11.40) | 4.17(+1.09) | 92.0(+16.0) | 1.152 |
| 36 | 案B | 42.12(−4.45) | 2.48(−0.86) | 55.0(−18.0) | 0.612 |
| 36 | 案B' | 39.88(−6.99) | 2.45(−1.06) | 44.0(−29.5) | 0.493 |
- 案B・B'は、どちらの来客でも、入店待ち・料理の待ち・動けなくなった回数が、10種のうち7〜10種で今のままより減りました。
- 案Aは、普通ではほぼ同じでした。混んでいるときは悪くなり、入店待ちが減った種は 4/10、動けなくなった回数が減った種は 2/10 でした。
- 案B・B'の待ちです。
| 来客 | 通り | 待った回数(lane_holds)の合計 | 200秒を超えた待ち | 待ったまま往復が打ち切られた |
|---|---|---|---|---|
| 28 | 案B | 213 | 8 | 2 |
| 28 | 案B' | 256 | 11 | 2 |
| 36 | 案B | 324 | 17 | 2 |
| 36 | 案B' | 252 | 12 | 3 |
- いちばん長い待ちは 550.9秒でした。
- 200秒を超えた待ちの数は、記録の行が細切れになることがあるため、少なめに出ている見込みです。
- 往復の数・歩く距離・手がふさがっている割合・ロボットが運んだ皿の割合・最小〜最大は、報告ファイルの5章と6章に書きました。
- 差がどこから来たかの調べはしていません。
**変えたファイル**
- プロジェクトのコード・params・ビルドは変えていません(保留 0 のまま)。
- 新しく:claude_code_reports/20261108_night_traffic_p2_b.txt
- KIOXIA:台帳に 80行追記、archive/unity_ledger_v1_pretraffic_20261101/、出力フォルダ 80個、night/20261108_traffic/
**決めてほしいこと**
1. 並びを作るための一時ファイルを /tmp/p2m_work60b.m4vn/ に置きました(作業フォルダの外です)。終わってから消そうとしましたが、消すコマンドが許可されず残っています。消してよいか、決めてください。中の queue.json と同じものは night/20261108_traffic/ に写されています。
## 止められた操作
- {"tool_name": "Bash", "tool_use_id": "toolu_01Vp3MH4Y24ZyAKQtMPgCTgo", "tool_input": {"command": "rm -rf /tmp/p2m_work60b.m4vn; ls /tmp | grep p2m_work60b; ls /Volumes/KIOXIA/r2r2r-data/service_sim/unity/*.lock 2>&1 | head -1", "description": "Remove temp queue work folder"}}
====================================================================
④の「向かい合わない3案」を今のままと並べて80回回した(夜 20261108_traffic)
依頼:20261101_60b_店4の向かい合わない3案を夜に80回回す.md
2026-11-01 23:15 〜 2026-11-02 01:10 build_id cs55_20261101_2224(ServiceSim/cs:55・保留 0)
====================================================================
結論
1本道は1台ずつは効き、一方通行は混むと悪くなった
同じ種どうしの差で比べました(④・スタッフ2人・ロボット2台・10回の真ん中の値。かっこは今のままとの差)。
| 入店待ち | ロボットを動かしに行った回数 | 料理が届くまで | 歩く距離 | |
|---|---|---|---|---|
| 普通(28組/時) | ||||
| 今のまま | 25.1分 | 53.5回 | 3.5分 | 2.63km |
| 案A 一方通行 | 24.2分(+0.4・減った種4/10) | 57.5回(−0.5) | 3.4分(+0.1) | 2.60km |
| 案B 1本道は1台ずつ | 17.6分(−7.3・10/10) | 29.0回(−20.5・8/10) | 2.0分(−1.8・9/10) | 2.42km |
| 案B’ よけ場所 | 20.0分(−5.3・9/10) | 40.0回(−13.5・8/10) | 2.6分(−1.1・9/10) | 2.53km |
| 混んでいる(36組/時) | ||||
| 今のまま | 43.7分 | 74.5回 | 3.2分 | 3.46km |
| 案A 一方通行 | 56.5分(+11.4・4/10) | 92.0回(+16.0・2/10) | 4.2分(+1.1) | 3.77km |
| 案B 1本道は1台ずつ | 42.1分(−4.5・8/10) | 55.0回(−18.0・10/10) | 2.5分(−0.9・8/10) | 3.36km |
| 案B’ よけ場所 | 39.9分(−7.0・8/10) | 44.0回(−29.5・8/10) | 2.5分(−1.1・7/10) | 3.23km |
-
一方通行は、向かい合いは減りますが、遠回りで通路にいる時間が延び、人とぶつかる回数が増えます。混んでいるときは入店待ちも世話も悪くなりました
-
1本道は1台ずつは、どちらの混み具合でもはっきり効きます。世話が3〜4割減り、料理も早く届きます。席は減らしません。代わりに、ロボットが1本道の手前で待つ時間が、2時間で合計11〜13分(中央値)あります
-
よけ場所(席を2つ外す)は、混んでいるときに最もよく効き、動かしに行く回数がほぼ半分になります。普通の混み具合では、案Bの方が上でした
-
ねらい:2台入れてしまった狭い店が、すぐとれる直し方を見つける
-
変わったこと:1本道は1台ずつで、普通の混み具合の入店待ちが25.1分→17.6分、動かしに行く回数が53.5回→29.0回(同じ種どうしの差の中央値は −7.3分・−20.5回)
-
見込める効果:席を減らさずに、ロボットの世話を3〜4割減らせる見込み。実際の店で同じになるかは、店で動かしに行った回数を測って確かめる
1台と比べると、どの案でも2台は1台に届かなかった traffic_compare.py
0台・1台は、前の夜(普通は cs:29、混んでいるは cs:44)の結果です。2台の今のままは、前の版と今の版(cs:55)で入店待ち26.9分と25.1分・45.9分と43.7分と近いので、版の違いは小さいと見ていますが、きっちりそろえてはいません。
# ④ 効率重視・小さめの店:向かい合わない3案(夜 20261108_traffic・80回)を、今のまま・1台・0台と同じ種どうしで比べる
# 使い方: python3 traffic_compare.py (台帳は KIOXIA の unity_ledger_v1.csv を読むだけ)
import csv, json, os, glob, random, statistics as st, collections
U = os.path.expanduser('~/mnt/KIOXIA/r2r2r-data/service_sim/unity')
R = list(csv.DictReader(open(f'{U}/unity_ledger_v1.csv')))
random.seed(0)
def var(f):
==== 来客 28組/時(④・スタッフ2人) ====
-- 0台(前の版)(10回・ServiceSim/cs:29)
入店待ち(分) 12.95
動かしに行った回数 0.00
料理が届くまで(分) 1.26
歩く距離(km/人) 3.42
手がふさがる割合 0.84| ④・スタッフ2人 | 入店待ち(普通) | 入店待ち(混んでいる) | 動かしに行った回数(普通/混む) | 歩く距離(普通) |
|---|---|---|---|---|
| 0台 | 13.0分 | 32.9分 | 0/0回 | 3.42km |
| 1台 | 13.8分 | 31.6分 | 13/21回 | 2.51km |
| 2台 今のまま | 25.1分 | 43.7分 | 53.5/74.5回 | 2.63km |
| 2台 案B 1本道は1台ずつ | 17.6分 | 42.1分 | 29/55回 | 2.42km |
| 2台 案B’ よけ場所 | 20.0分 | 39.9分 | 40/44回 | 2.53km |
同じ種どうしで、2台が1台より入店待ちが短かった種は、案Bでも10個中1〜3個でした。④では、1台なら入店待ちは0台とほぼ同じのまま、スタッフの歩く距離が約3割減り、動かしに行く回数も2時間で13〜21回に収まります。2台目は、決まりを工夫しても1台を超えませんでした。
狭い店の配膳ロボットについて、店に伝えられること
狭い店は1台から始める。もう2台入れているなら、まず「1本道には1台ずつ入る」決まりを入れる。それでも混む時間帯の世話が多ければ、2人席を1つ外してよけ場所を作る。一方通行は遠回りになり、かえって悪くなる。
残っていることを書いておきます。
- 1台・0台の数字は前の版の夜のもの。記事や提案で数字を並べるなら、今の版(cs:55)で1台・0台を回し直してそろえる
- 案B・B’で、1回の待ちが7〜9分になる回がある。中身を見た回は、1本道の中の相手がスタッフにふさがれていた。終わったときに待ったままの回が40回中9回あった
- 料理が届くまでが、ロボットを入れると約1分から2〜2.5分に延びる。「ロボットが来るまで最大2分待つ」決まりから来ているので、この待ちを短くしたらどうなるかは、次に試せる打ち手
- 夜の判定に、同じ種どうしの比べ方を足すかは決めていない
- 作業の時間のばらつきは、店の記録が10回以上たまってから試算に入れるかを決める
置き場所
| もの | 場所 |
|---|---|
ずれの比べ(var1〜3.py と出力) | iCloud のサービスロボット導入シミュレーション/unity/unity_variance_check_20261101/ |
止まった場所の図・負担の表・夜の比べ(stopmap.py・plan_p2.py・burden.py・traffic_compare.py と出力) | 同じ unity/stop_map_20261101/ |
| この記事に載せた材料の写し | 同じ LOG423_sources/ |
| 案B’の店の形 | GitHub の p2m-site の public/sim/layouts/trials/p2_noT26/ |
| 回し方の決まり | GitHub の p2m-site の public/sim/serving-robot-params.json の unity_rules |
| 夜の80回の記録 | KIOXIA の r2r2r-data/service_sim/unity/night/20261108_traffic/ と 20261108_tr_* の80フォルダ・unity_ledger_v1.csv |
| 確かめの4回と画像 | KIOXIA の night/20261101_traffic_check/ |