molecule
AFS_Adom flight computer molecule
Public Unreviewedby ae007
Active fin stabilization flight computer for a sounding rocket, a clean-room AI redesign of the Rice Eclipse AFS board: RP2350B, ICM-45686, KX134-1211, MMC5983MA, MS5611, TMP117, INA219A, 8 servos, 2S LiPo, USB-C; 4-layer Adom molecule, designed end to end by Claude through KiCad and adom-aiflow
main
ae007
Project page: AFS_Adom rev A (Rice Eclipse AFS clean-room AI redesign): highlight reel and narrated process video with…
cbe460e
7d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
"""Replay the offline routing plan on the live KiCad board through the bridge (kicad_route_net), one net per commit."""
import sys, json, subprocess, time
PLAN = '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad/AFS_Adom/outputs/route_plan.json'
BOARD = 'C:/Users/angus/Documents/aiflow/AFS_Adom/AFS_Adom.kicad_pcb'
AB = ['adom-bridge', '--ai-thread', 'AFS_Adom-flight-computer']
def call(verb, args, timeout=180):
r = subprocess.run(AB + [verb, json.dumps(args)], capture_output=True, text=True, timeout=timeout)
try:
return json.loads(r.stdout)
except Exception:
return {'success': False, 'error': r.stdout[:500] + r.stderr[:300]}
def polylines(entry):
"""Rebuild polylines [(x,y,layer_out)] from ordered segments + vias."""
segs = [tuple(s) for s in entry['segs']]
vias = set((round(x, 3), round(y, 3)) for x, y in entry['vias'])
paths = []
cur = []
for seg in segs:
layer, x0, y0, x1, y1 = seg[:5]
a = (round(x0, 3), round(y0, 3)); b = (round(x1, 3), round(y1, 3))
if cur and (cur[-1][0], cur[-1][1]) == a:
cur[-1] = (a[0], a[1], layer) # outgoing layer at this point
cur.append((b[0], b[1], layer))
else:
if cur:
paths.append(cur)
cur = [(a[0], a[1], layer), (b[0], b[1], layer)]
if cur:
paths.append(cur)
# a stub ends with a via into the plane: mark the final point with the other layer
if entry['kind'] == 'stub' and paths:
last = paths[-1][-1]
other = 'B.Cu' if last[2] == 'F.Cu' else 'F.Cu'
paths[-1][-1] = (last[0], last[1], other)
return paths
def main(start=0, limit=None, dry=False):
plan = json.load(open(PLAN))['plan']
st = call('kicad_routing_state', {'filePath': BOARD})
rev = st.get('revision')
print('revision', rev, 'nets remaining', st.get('netsRemaining'))
done = fail = 0
for i, e in enumerate(plan[start:(start + limit) if limit else None], start):
if e['kind'] == 'epvias':
continue
paths = polylines(e)
if not paths:
continue
args = {'filePath': BOARD, 'expectedRevision': rev, 'net': e['net'], 'width': e['width'], 'viaSize': e['via'][0], 'viaDrill': e['via'][1],
'paths': [[{'x': x, 'y': y, 'layer': l} for (x, y, l) in p] for p in paths]}
if dry:
args['dryRun'] = True
r = call('kicad_route_net', args)
if r.get('success'):
rev = r.get('revision', rev); done += 1
else:
fail += 1
print('FAIL', i, e['net'], e.get('ref', ''), (r.get('error') or '')[:200], (r.get('errorCode') or ''), json.dumps(r.get('drc', ''))[:300])
if r.get('errorCode') == 'stale_board':
st = call('kicad_routing_state', {'filePath': BOARD}); rev = st.get('revision')
if i % 20 == 0:
print('progress', i, 'ok', done, 'fail', fail, 'rev', rev, flush=True)
print('done', done, 'fail', fail)
if __name__ == '__main__':
a = sys.argv[1:]
main(int(a[0]) if a else 0, int(a[1]) if len(a) > 1 else None, '--dry' in a)