Files
wheel/models/encoder_standoff_plate_print/build.FCMacro

71 lines
4.5 KiB
Plaintext

from pathlib import Path
import math, json, os, traceback, time
import FreeCAD as A, FreeCADGui as G, Part, Mesh, MeshPart, Import
V=A.Vector
root=Path(r'C:\projects\wheel')
out=root/'models'/'encoder_standoff_plate_print'
try:
src=A.openDocument(str(root/'models'/'symmetric_corner_18_concept'/'Assembly_对称角码装配_概念.FCStd'))
src.recompute()
plate=src.getObject('EncoderPlateConcept').Shape.copy()
assert plate.isValid() and len(plate.Solids)==1 and plate.Volume>1
# 10mm standoff with 1mm shim -> support face at z=11, rear motor z=0.
plate.translate(V(0,0,0.1))
hit=[]; distances=[]
for o in src.Objects:
if not hasattr(o,'Shape') or o.Shape.isNull() or not o.ViewObject.Visibility or o.Name=='EncoderPlateConcept': continue
if o.Name.startswith(('EncoderHex','EncoderSpacer')): continue
v=plate.common(o.Shape).Volume if plate.BoundBox.intersect(o.Shape.BoundBox) else 0
if v>0.001: hit.append((o.Name,round(v,6)))
if o.Name.startswith(('NewMotorCorner','Rail')):
distances.append((o.Name,round(plate.distToShape(o.Shape)[0],5)))
# Test panel has four complete M4 clear bores, as in the source design.
bore=[]
for k in range(4):
angle=math.radians(45+90*k)
x=25*math.cos(angle);y=10+25*math.sin(angle)
probe=Part.makeCylinder(2.19,3.3,V(x,y,10.95))
bore.append(round(probe.common(plate).Volume,6))
assert max(bore)<1e-5
# The old PCB rests against the lower face of this 3.2 mm slab. Verify
# each 1.8 mm pilot and surrounding pads match the old original panel.
pcb_centres=[(0,13.49),(-11.71,-6.76),(11.71,-6.76)]
pcb_probes=[]; pcb_pad=[]
for x,y in pcb_centres:
y+=10
probe=Part.makeCylinder(.89,3.3,V(x,y,10.95))
pcb_probes.append(round(probe.common(plate).Volume,6))
pad=Part.makeCylinder(3.1,3.2,V(x,y,11))
pcb_pad.append(round(pad.common(plate).Volume,6))
assert max(pcb_probes)<1e-5 and min(pcb_pad)>50
orig=src.getObject('OpenPillarBracket').Shape.common(Part.makeBox(120,120,3.2,V(-60,-60,10.9)))
compare=plate.copy();compare.translate(V(0,0,-.1))
panel_diff=[orig.cut(compare).Volume,compare.cut(orig).Volume]
assert max(panel_diff)<1e-5
# Put support face flat on build plate and centre the source motor axis.
printed=plate.copy();printed.translate(V(0,-10,-11))
assert abs(printed.BoundBox.ZMin)<1e-5
doc=A.newDocument('EncoderStandoffPlate')
obj=doc.addObject('PartDesign::Feature','EncoderPlate')
obj.Label='PCD50 encoder panel - four metal stand-offs'
obj.Shape=printed;obj.ViewObject.ShapeColor=(.15,.4,.85)
doc.recompute();doc.saveAs(str(out/'EncoderPlate.FCStd'))
Import.export([obj],str(out/'EncoderPlate.step'))
mesh=MeshPart.meshFromShape(Shape=printed,LinearDeflection=0.05,AngularDeflection=math.radians(15),Relative=False)
mesh.write(str(out/'EncoderPlate.stl'))
mesh2=Mesh.Mesh(str(out/'EncoderPlate.stl'))
assert mesh2.isSolid() and mesh2.Volume>0
step=Part.read(str(out/'EncoderPlate.step'))
assert step.isValid() and len(step.Solids)==1
G.activateWorkbench('PartWorkbench');G.activeDocument().activeView().viewAxonometric();G.updateGui();time.sleep(.6);view=G.activeDocument().activeView();view.fitAll();G.updateGui();time.sleep(.6);view.saveImage(str(out/'EncoderPlate.png'),1400,1000,'White')
report={'solid_valid':printed.isValid(),'solids':len(printed.Solids),'volume_mm3':printed.Volume,'dimensions_mm':[printed.BoundBox.XLength,printed.BoundBox.YLength,printed.BoundBox.ZLength],'mesh_closed':mesh2.isSolid(),'mesh_volume_mm3':mesh2.Volume,'bore_probe_intersections_mm3':bore,'pcb_pilot_probe_intersections_mm3':pcb_probes,'pcb_pad_material_mm3':pcb_pad,'original_panel_two_way_difference_mm3':panel_diff,'tested_position':'10 mm standoffs + 1 mm shim, panel bottom at z=11 mm','positive_intersections_mm3':hit,'angle_rail_clearances_mm':distances,'warning':'All geometry and PCB dimensions assumed; tool access and physical assembly unverified.'}
(out/'验证.json').write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf8')
A.closeDocument(doc.Name)
reopened=A.openDocument(str(out/'EncoderPlate.FCStd'));reopened.recompute()
assert reopened.getObject('EncoderPlate').Shape.isValid();A.closeDocument(reopened.Name)
A.closeDocument(src.Name)
(out/'完成.txt').write_text('ok',encoding='utf8')
except Exception:
(out/'错误.txt').write_text(traceback.format_exc(),encoding='utf8')
os._exit(0)