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
"""Offline fallback for the reference/value field moves: KiCad 10.0.6's IPC refuses PCB_FIELD updates through
kicad_silk_fields_batch (ISC_INVALID_TYPE: PCB_FIELD_T unhandled). Edits the saved board file: for every update in
apply_fields.json (field UUID -> board x/y, layer, height, stroke) rewrite that property's (at ...), (layer ...),
(effects (font (size) (thickness))) and drop (hide yes). Positions go into the footprint's local frame (inverse of the
pcb.py rotation convention); the text angle is written relative to the footprint. The board is reloaded in KiCad with
File > Revert afterwards and re-validated natively."""
import json, re, math, sys
S = '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad'
src, dst = sys.argv[1], sys.argv[2]
upd = {u['id']: u for u in json.load(open(S + '/AFS_Adom/aiflow/silk/apply_fields.json'))['update']}
board = json.load(open(S + '/AFS_Adom/aiflow/silk/board.json'))
fp_of = {}
for fp in board['footprints']:
for name, pr in fp['props'].items(): fp_of[pr['uuid']] = (fp, name)
txt = open(src, encoding='utf-8').read()
done = 0; missing = []
for uuid, u in upd.items():
if uuid not in fp_of: missing.append(uuid); continue
fp, name = fp_of[uuid]
i = txt.find('(uuid "%s")' % uuid)
if i < 0: missing.append(uuid); continue
start = txt.rfind('(property "%s"' % name, 0, i)
# end of this property block: match parens from start
d = 0; k = start
while True:
c = txt[k]
if c == '(': d += 1
elif c == ')':
d -= 1
if d == 0: break
k += 1
block = txt[start:k + 1]
r = math.radians(fp['rot']); bx, by = u['x'] - fp['x'], u['y'] - fp['y']
px = bx * math.cos(r) - by * math.sin(r); py = bx * math.sin(r) + by * math.cos(r)
ang = (u.get('rotation', 0) - fp['rot']) % 360
nb = re.sub(r'\(at [-\d.]+ [-\d.]+( [-\d.]+)?\)', '(at %.3f %.3f %g)' % (px, py, ang), block, count=1)
nb = re.sub(r'\(layer "[^"]+"\)', '(layer "%s")' % u['layer'], nb, count=1)
nb = re.sub(r'\(size [-\d.]+ [-\d.]+\)', '(size %g %g)' % (u['height'], u['width']), nb, count=1)
if '(thickness' in nb: nb = re.sub(r'\(thickness [-\d.]+\)', '(thickness %g)' % u['stroke'], nb, count=1)
else: nb = nb.replace('(size %g %g)' % (u['height'], u['width']), '(size %g %g)\n\t\t\t\t(thickness %g)' % (u['height'], u['width'], u['stroke']), 1)
nb = re.sub(r'\n\s*\(hide yes\)', '', nb)
txt = txt[:start] + nb + txt[k + 1:]; done += 1
open(dst, 'w', encoding='utf-8').write(txt)
print('fields rewritten', done, 'missing', len(missing))