component
Adom Machine Pins, Fusion Library + Sample Board
Public Made by Adomby adom
One Fusion 360 .lbr with all four Adom press-fit machine pins (working 3D), plus a sample board (2D/3D/silkscreen) ganging all four together. Fully documented and rebuildable.
← Commit history
Revert silkscreen/callouts to 3D extruded text: rotates with the assembly so labels match pins AND read correctly at default camera (texture UV kept desyncing). Fixed arrow apex-on-target.
3 files changed
+41−44
AdomMachinePins-4pin-animated.glb⋯ 1 unchanged line ⋯
AdomMachinePins-complete.zip⋯ 1 unchanged line ⋯
scripts/build_board_glb.py+41−44@@ -165,61 +165,58 @@ for k,(c,barrel_r) in pin_info.items(): add_mesh(s.vertices,s.faces,[0.62,0.63,0.66,1.0],f"ball_{k}_{j}",metal=True) print(f" balls PIN_{k}: {n} hemispheres x {BALL_D*1000:.2f}mm on ring r={ring_r*1000:.2f}mm") -# --- SILKSCREEN + CALLOUTS as a flat PRINTED TEXTURE on the board top (zero geometry => no-# shadow-casting text). Arrows drawn in 2D so the head lands EXACTLY on its target. ----from PIL import Image, ImageDraw, ImageFont-import math-TEX=3000 # px across the 50mm board => 60 px/mm (crisp)-BW=(bx1-bx0)*1000; BH=(by1-by0)*1000 # board size in mm-img=Image.new("RGBA",(TEX,TEX),(13,107,31,120)) # transparent green soldermask-dr=ImageDraw.Draw(img)-def A(xmm,ymm): # board mm -> texture px (flip y so +y reads up)- return (xmm/BW*TEX, (1.0-ymm/BH)*TEX)-def T(s,cx,cy,h_mm,rgba):- f=ImageFont.truetype(FONT_PATH,int(round(h_mm/BW*TEX)))- dr.text(A(cx,cy),s,font=f,fill=rgba,anchor="mm")-def ARR(sx,sy,tx,ty,rgba,w_mm=0.34,head_mm=1.3):- p0=A(sx,sy); p1=A(tx,ty); ang=math.atan2(p1[1]-p0[1],p1[0]-p0[0])- dr.line([p0,p1],fill=rgba,width=max(2,int(w_mm/BW*TEX)))- hl=head_mm/BW*TEX; hw=0.6*head_mm/BW*TEX- ax=p1[0]-hl*math.cos(ang); ay=p1[1]-hl*math.sin(ang)- dr.polygon([p1,(ax-hw*math.sin(ang),ay+hw*math.cos(ang)),- (ax+hw*math.sin(ang),ay-hw*math.cos(ang))],fill=rgba)-WHITE=(247,247,247,255); AMBER=(250,189,26,255); STEEL=(150,205,250,255)+# --- SILKSCREEN + CALLOUTS as 3D extruded text on the board top. These go through add_mesh, so+# they get the SAME 180 rotation as the pins -> labels stay matched to pins AND read left-to-right+# at the default camera. (Solid geometry, unlike the flat-texture attempt whose UV kept desyncing.)+WHITE=[0.97,0.97,0.97,1.0]; AMBER=[0.98,0.74,0.10,1.0]; STEEL=[0.60,0.80,0.97,1.0]+def place_text(txt, cx_mm, cy_mm, h_mm, color, name):+ t=text_mesh(txt, h_mm); t.apply_scale(0.001)+ t.apply_translation([cx_mm/1000.0, cy_mm/1000.0, board_top+0.00006])+ add_mesh(t.vertices, t.faces, color, name)+def arrow(sx,sy,tx,ty,color,name):+ z=board_top+0.00006+ lead=trimesh.creation.cylinder(radius=0.00016,+ segment=[[sx/1000.0,sy/1000.0,z],[tx/1000.0,ty/1000.0,z]])+ add_mesh(lead.vertices,lead.faces,color,name+"_lead")+ d=np.array([tx-sx,ty-sy],float); d/=np.linalg.norm(d); HH=0.0012+ head=trimesh.creation.cone(radius=0.00048,height=HH,sections=16) # apex at +Z*HH+ zc=np.array([0,0,1.]); axd=np.array([d[0],d[1],0.]); axd/=np.linalg.norm(axd)+ v=np.cross(zc,axd); s_=np.linalg.norm(v); cth=np.dot(zc,axd)+ if s_>1e-6:+ vx=np.array([[0,-v[2],v[1]],[v[2],0,-v[0]],[-v[1],v[0],0]])+ head.apply_transform(np.block([[np.eye(3)+vx+vx@vx*((1-cth)/(s_*s_)),np.zeros((3,1))],[np.zeros(3),1]]))+ # place the APEX exactly on the tip (base sits back toward the callout)+ head.apply_translation([tx/1000.0-HH*d[0], ty/1000.0-HH*d[1], z])+ add_mesh(head.vertices,head.faces,color,name+"_arrow") LABELS={0:("MP-MED-STD","hole Ø1.1 pin Ø1.2"), 1:("MP-MED-SHORT","hole Ø1.1 pin Ø1.2"), 2:("MP-LRG-STD","hole Ø3.45 pin Ø3.6"), 3:("MP-LRG-SHORT","hole Ø3.45 pin Ø3.6")} for k,(c,barrel_r) in pin_info.items(): nm,sp=LABELS[k]; cx,cy=c[0]*1000,c[1]*1000; y0=cy-barrel_r*1000-2.8- T(nm,cx,y0,1.35,WHITE); T(sp,cx,y0-1.9,1.15,WHITE)+ place_text(nm, cx, y0, 1.35, WHITE, f"silk_{k}_0")+ place_text(sp, cx, y0-1.9, 1.15, WHITE, f"silk_{k}_1") -# PRESS-FIT callouts (amber), arrow tip AT the pin/hole-T("PRESS-FIT",21.5,20.2,2.3,AMBER); T("hole Ø1.1 pin Ø1.2",21.5,18.0,1.5,AMBER)-T("pin 0.1mm wider = gas-tight",21.5,16.0,1.4,AMBER); ARR(30.0,14.0,39.2,10.7,AMBER)-T("PRESS-FIT",27.0,32.2,2.3,AMBER); T("hole Ø3.45 pin Ø3.6",27.0,30.0,1.5,AMBER)-T("pin 0.15mm wider = gas-tight",27.0,28.0,1.4,AMBER); ARR(19.5,34.0,12.6,38.4,AMBER)--# SOLDER PASTE callout (steel), arrow tip snapped to the nearest ball center @ (40,40)+def callout(title, ax, ay, spec, why, tx, ty, sx, sy, prefix, color):+ place_text(title, ax, ay+2.2, 2.3, color, prefix+"_t")+ place_text(spec, ax, ay, 1.5, color, prefix+"_s")+ place_text(why, ax, ay-2.0, 1.4, color, prefix+"_w")+ arrow(sx,sy,tx,ty,color,prefix)+# PRESS-FIT: medium -> pin @ (40,10); large -> pin @ (10,40)+callout("PRESS-FIT",21.5,18.0,"hole Ø1.1 pin Ø1.2","pin 0.1mm wider = gas-tight",+ 39.2,10.7, 30.0,14.0, "cmed", AMBER)+callout("PRESS-FIT",27.0,30.0,"hole Ø3.45 pin Ø3.6","pin 0.15mm wider = gas-tight",+ 12.6,38.4, 19.5,34.0, "clrg", AMBER)+# SOLDER PASTE -> nearest ball center on the large pad @ (40,40) _pc=np.array([40.0,40.0]); _ca=np.array([24.0,45.5]); _u=(_ca-_pc)/np.linalg.norm(_ca-_pc) _ringmm=(FP[3][0]+FP[3][1])/2.0*1000; _n=max(6,int(round(2*np.pi*(FP[3][0]+FP[3][1])/2.0/PITCH))) _ang=round(np.arctan2(_u[1],_u[0])/(2*np.pi/_n))*(2*np.pi/_n) _ball=_pc+_ringmm*np.array([np.cos(_ang),np.sin(_ang)])-T("SOLDER PASTE",24.0,47.7,2.3,STEEL); T("300µm (0.3mm)",24.0,45.5,1.5,STEEL)-T("jet-dispensed paste balls",24.0,43.5,1.4,STEEL); ARR(30.0,45.0,_ball[0],_ball[1],STEEL)-print(f" silkscreen texture {TEX}px: 4 labels + 3 callouts; solder arrow -> ball ({_ball[0]:.1f},{_ball[1]:.1f})")-img.save("/tmp/v7_texture.png")-img=img.transpose(Image.FLIP_LEFT_RIGHT) # GLB export mirrors this face in X; pre-flip so print + arrows read correct+callout("SOLDER PASTE",24.0,45.5,"300µm (0.3mm)","jet-dispensed paste balls",+ _ball[0],_ball[1], 30.0,45.0, "csol", STEEL)+print(f" 3D silk: 4 labels + 3 callouts; solder arrow -> ball ({_ball[0]:.1f},{_ball[1]:.1f})") -# add the board with the silkscreen texture (planar UVs; single-sided transparent print)-# UV from ORIGINAL vertex positions (planar), then rotate the board verts with the rest of the-# assembly so the printed silkscreen faces the viewer's default camera. UV stays per-vertex, so the-# texture rotates with the board. Node transform stays identity -> the pin lift animation is unaffected.-uv=np.column_stack([(slab.vertices[:,0]-bx0)/(bx1-bx0), 1.0-(slab.vertices[:,1]-by0)/(by1-by0)])-bmesh=trimesh.Trimesh(vertices=_rot(slab.vertices), faces=slab.faces, process=False)-bmesh.visual=trimesh.visual.TextureVisuals(uv=uv, material=trimesh.visual.material.PBRMaterial(- baseColorFactor=[255,255,255,255], baseColorTexture=img, metallicFactor=0.2, roughnessFactor=0.55,- alphaMode="BLEND", doubleSided=False))-scene.add_geometry(bmesh, node_name="board_fr4", geom_name="board_fr4")+# transparent FR4 board (solid colour; the 3D text above carries the print)+add_mesh(slab.vertices, slab.faces, [0.05,0.42,0.12,0.46], "board_fr4", double=False) scene.export(OUT) print("exported",OUT)