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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
"""AI-created placeholder bodies as valid STEP AP214 solids (axis-aligned boxes, Z up, seated on z=0, centred on the
footprint origin). Labelled AI-generated; dimensions from the datasheet drawings cited in the provenance JSON written beside
each file. Used only for parts with no manufacturer or KiCad packages3D model."""
import json, hashlib, os, sys
sys.path.insert(0, '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad/gen')
def box_step(name, lx, ly, lz, x0=0.0, y0=0.0, z0=0.0, color=(0.2, 0.2, 0.2)):
"""Return STEP text for one box solid from (x0,y0,z0) to (x0+lx, y0+ly, z0+lz) in mm."""
e = [] # entity lines
def add(s):
e.append(s); return len(e)
# geometry context
n_len = add("LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.)")
n_ang = add("NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.)")
n_sol = add("NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT()")
n_unc = add(f"UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-06),#{n_len},'distance_accuracy_value','')")
n_ctx = add(f"GEOMETRIC_REPRESENTATION_CONTEXT(3) GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#{n_unc})) GLOBAL_UNIT_ASSIGNED_CONTEXT((#{n_len},#{n_ang},#{n_sol})) REPRESENTATION_CONTEXT('','')")
x1, y1, z1 = x0 + lx, y0 + ly, z0 + lz
P = [(x0, y0, z0), (x1, y0, z0), (x1, y1, z0), (x0, y1, z0), (x0, y0, z1), (x1, y0, z1), (x1, y1, z1), (x0, y1, z1)]
vp = [add(f"CARTESIAN_POINT('',({p[0]:.4f},{p[1]:.4f},{p[2]:.4f}))") for p in P]
vx = [add(f"VERTEX_POINT('',#{cp})") for cp in vp]
# edges: bottom 0-1,1-2,2-3,3-0 ; top 4-5,5-6,6-7,7-4 ; verticals 0-4,1-5,2-6,3-7
E = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)]
ed = []
for a, b in E:
pa, pb = P[a], P[b]
d = (pb[0] - pa[0], pb[1] - pa[1], pb[2] - pa[2])
L = (d[0] ** 2 + d[1] ** 2 + d[2] ** 2) ** 0.5
dirn = add(f"DIRECTION('',({d[0]/L:.4f},{d[1]/L:.4f},{d[2]/L:.4f}))")
vec = add(f"VECTOR('',#{dirn},1.)")
line = add(f"LINE('',#{vp[a]},#{vec})")
ed.append(add(f"EDGE_CURVE('',#{vx[a]},#{vx[b]},#{line},.T.)"))
# faces: (edge indices with orientation), plane origin point, normal, ref dir
F = [([(0, False), (3, False), (2, False), (1, False)], 0, (0, 0, -1), (1, 0, 0)), # bottom (z0), outward -z
([(4, True), (5, True), (6, True), (7, True)], 4, (0, 0, 1), (1, 0, 0)), # top
([(0, True), (9, True), (4, False), (8, False)], 0, (0, -1, 0), (1, 0, 0)), # front y0
([(2, False), (10, True), (6, True), (11, False)], 2, (0, 1, 0), (-1, 0, 0)), # back y1
([(3, True), (8, True), (7, False), (11, False)], 3, (-1, 0, 0), (0, -1, 0)), # left x0
([(1, True), (10, True), (5, False), (9, False)], 1, (1, 0, 0), (0, 1, 0))] # right x1
faces = []
for loop, pidx, nrm, ref in F:
oes = [add(f"ORIENTED_EDGE('',*,*,#{ed[i]},{'.T.' if o else '.F.'})") for i, o in loop]
el = add(f"EDGE_LOOP('',({','.join('#%d' % o for o in oes)}))")
fb = add(f"FACE_OUTER_BOUND('',#{el},.T.)")
nd = add(f"DIRECTION('',({nrm[0]:.1f},{nrm[1]:.1f},{nrm[2]:.1f}))")
rd = add(f"DIRECTION('',({ref[0]:.1f},{ref[1]:.1f},{ref[2]:.1f}))")
ax = add(f"AXIS2_PLACEMENT_3D('',#{vp[pidx]},#{nd},#{rd})")
pl = add(f"PLANE('',#{ax})")
faces.append(add(f"ADVANCED_FACE('',(#{fb}),#{pl},.T.)"))
shell = add(f"CLOSED_SHELL('',({','.join('#%d' % f for f in faces)}))")
solid = add(f"MANIFOLD_SOLID_BREP('{name}',#{shell})")
# colour
rgb = add(f"COLOUR_RGB('',{color[0]:.3f},{color[1]:.3f},{color[2]:.3f})")
fsa = add(f"FILL_AREA_STYLE_COLOUR('',#{rgb})")
fas = add(f"FILL_AREA_STYLE('',(#{fsa}))")
sfs = add(f"SURFACE_STYLE_FILL_AREA(#{fas})")
sss = add(f"SURFACE_SIDE_STYLE('',(#{sfs}))")
ssu = add(f"SURFACE_STYLE_USAGE(.BOTH.,#{sss})")
pst = add(f"PRESENTATION_STYLE_ASSIGNMENT((#{ssu}))")
sti = add(f"STYLED_ITEM('',(#{pst}),#{solid})")
o = add("CARTESIAN_POINT('',(0.,0.,0.))"); dz = add("DIRECTION('',(0.,0.,1.))"); dx = add("DIRECTION('',(1.,0.,0.))")
ax0 = add(f"AXIS2_PLACEMENT_3D('',#{o},#{dz},#{dx})")
sr = add(f"ADVANCED_BREP_SHAPE_REPRESENTATION('{name}',(#{ax0},#{solid}),#{n_ctx})")
mdi = add(f"MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#{sti}),#{n_ctx})")
app = add("APPLICATION_CONTEXT('core data for automotive mechanical design processes')")
apd = add(f"APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#{app})")
pc = add(f"PRODUCT_CONTEXT('',#{app},'mechanical')")
prod = add(f"PRODUCT('{name}','{name}','AI-created placeholder body',(#{pc}))")
pdc = add(f"PRODUCT_DEFINITION_CONTEXT('part definition',#{app},'design')")
pdf = add(f"PRODUCT_DEFINITION_FORMATION('','',#{prod})")
pd = add(f"PRODUCT_DEFINITION('design','',#{pdf},#{pdc})")
pds = add(f"PRODUCT_DEFINITION_SHAPE('','',#{pd})")
add(f"SHAPE_DEFINITION_REPRESENTATION(#{pds},#{sr})")
prpc = add("PRODUCT_RELATED_PRODUCT_CATEGORY('part','',(#%d))" % prod)
body = '\n'.join(f"#{i+1}={s};" for i, s in enumerate(e))
return f"""ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('AI-created placeholder body {name}'),'2;1');
FILE_NAME('{name}.step','2026-10-15T00:00:00',('AFS_Adom generator'),('Adom'),'mkstep.py','mkstep.py','');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN {{ 1 0 10303 214 1 1 1 1 }}'));
ENDSEC;
DATA;
{body}
ENDSEC;
END-ISO-10303-21;
"""
OUT = '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad/AFS_Adom/3d'
parts = [
# name, lx, ly, lz, x0, y0, color, provenance
('QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm', 10.0, 10.0, 0.9, -5.0, -5.0, (0.15, 0.15, 0.15),
dict(source='RP2350 datasheet, QFN-80 package drawing (10.0 x 10.0 mm body, 0.9 mm max height), via the KiCad footprint Package_DFN_QFN:QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm',
dims_mm=dict(body=[10.0, 10.0], height=0.9), simplifications='single box, no leads, no pin-1 chamfer', used_for='RP2350B (U1) body envelope on the board only')),
('Kionix_LGA-12_2x2mm_P0.5mm_LayoutBorder2x4y', 2.0, 2.0, 0.9, -1.0, -1.0, (0.2, 0.2, 0.2),
dict(source='KX134-1211 specification rev 4.0, Package Dimensions: 2 x 2 x 0.9 mm LGA 12-pin',
dims_mm=dict(body=[2.0, 2.0], height=0.9), simplifications='single box, no pads, no pin-1 dot', used_for='KX134-1211 (U9) body envelope')),
('AMASS_XT30PW-M_1x02_P2.50mm_Horizontal', 13.3, 9.0, 8.3, -9.15, -13.1, (0.85, 0.75, 0.1),
dict(source='KiCad footprint Connector_AMASS:AMASS_XT30PW-M_1x02_P2.50mm_Horizontal F.Fab outline (x -9.15..4.15, y -13.1..-4.1) and the Amass XT30PW-M drawing height (8.3 mm, approximate)',
dims_mm=dict(body=[13.3, 9.0], height=8.3), simplifications='single box over the fab outline; the real part has a mating shroud and two pins', used_for='XT30PW-M (J1) body envelope')),
]
os.makedirs(OUT, exist_ok=True)
for name, lx, ly, lz, x0, y0, color, prov in parts:
txt = box_step(name, lx, ly, lz, x0, y0, 0.0, color)
path = os.path.join(OUT, name + '.step')
open(path, 'w').write(txt)
sha = hashlib.sha256(txt.encode()).hexdigest()
json.dump(dict(file=name + '.step', authoring='AI-created placeholder body (axis-aligned box), not a manufacturer model', generator='gen/mkstep.py (AFS_Adom)',
sha256=sha, units='mm', frame='Z up, seated on z=0, centred on the footprint origin', **prov), open(os.path.join(OUT, name + '.provenance.json'), 'w'), indent=1)
print('wrote', path, len(txt), 'bytes')