建立方向盘项目初始版本
This commit is contained in:
89
scripts/build_washer_grid_4x4.py
Normal file
89
scripts/build_washer_grid_4x4.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""Build mixed-thickness 4x4 sprue; run with FreeCAD bundled Python."""
|
||||
from pathlib import Path
|
||||
import json, math, zipfile, shutil, hashlib
|
||||
import FreeCAD as App
|
||||
import Part, Mesh, MeshPart
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SRC = ROOT/'models'/'pcd50_open_pillar_v1'
|
||||
OUT = ROOT/'models'/'washer_grid_4x4'
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
V=App.Vector
|
||||
|
||||
def load(name, thickness):
|
||||
s=Part.read(str(SRC/name))
|
||||
s.translate(V(-10,-10,0))
|
||||
if s.isNull() or not s.isValid() or len(s.Solids)!=1 or abs(s.BoundBox.ZLength-thickness)>1e-6:
|
||||
raise RuntimeError('Invalid source '+name)
|
||||
# The original 90-degree opening is centered 22.5 degrees above +X.
|
||||
# Rotate to the NE quadrant so bar attachments on the SW side miss it.
|
||||
s.rotate(V(),V(0,0,1),22.5)
|
||||
return s
|
||||
|
||||
source05=load('Shim05.step',.5)
|
||||
source10=load('Shim10.step',1.0)
|
||||
# Bars are 2x2 across their width/height. Offset attachment centerlines by
|
||||
# 1.5mm away from the open quadrant. At that line, the nominal free length
|
||||
# between the circular outer edges is 2.0mm; rod ends overlap by 0.8mm each.
|
||||
offset=1.5
|
||||
edge=math.sqrt(6.0**2-offset**2)
|
||||
pitch=2*edge+2.0
|
||||
rod_start=edge-.8
|
||||
rod_length=pitch-2*rod_start
|
||||
pads=[]
|
||||
for row in range(4):
|
||||
for col in range(4):
|
||||
p=(source05 if row<2 else source10).copy()
|
||||
p.translate(V(col*pitch,row*pitch,0))
|
||||
pads.append(p)
|
||||
rods=[]
|
||||
endpoints=[]
|
||||
for row in range(4):
|
||||
for col in range(3):
|
||||
rods.append(Part.makeBox(rod_length,2,2,V(col*pitch+rod_start,row*pitch-offset-1,0)))
|
||||
endpoints.append((row*4+col,row*4+col+1,'H'))
|
||||
for row in range(3):
|
||||
for col in range(4):
|
||||
rods.append(Part.makeBox(2,rod_length,2,V(col*pitch-offset-1,row*pitch+rod_start,0)))
|
||||
endpoints.append((row*4+col,(row+1)*4+col,'V'))
|
||||
if len(rods)!=24 or abs(rod_length-3.6)>1e-7: raise RuntimeError('Incorrect rods')
|
||||
contacts=[]
|
||||
for k,(a,b,d) in enumerate(endpoints):
|
||||
va=rods[k].common(pads[a]).Volume; vb=rods[k].common(pads[b]).Volume
|
||||
if min(va,vb)<0.2: raise RuntimeError('Weak or absent rod overlap %d: %.4f %.4f'%(k,va,vb))
|
||||
contacts.append([round(va,5),round(vb,5)])
|
||||
# Do not allow any bars into the 4.4mm bore. Bars are on the SW sides, so
|
||||
# they also avoid the NE open quadrant; test that region on each pad.
|
||||
for i,p in enumerate(pads):
|
||||
x=(i%4)*pitch; y=(i//4)*pitch
|
||||
bore=Part.makeCylinder(2.2,2,V(x,y,0))
|
||||
opening=Part.makeBox(6.1,6.1,2,V(x,y,0))
|
||||
for rod in rods:
|
||||
if rod.common(bore).Volume>1e-6: raise RuntimeError('Rod blocks bore %d'%i)
|
||||
if rod.common(opening).Volume>1e-6: raise RuntimeError('Rod blocks open quadrant %d'%i)
|
||||
shape=pads[0].multiFuse(pads[1:]+rods).removeSplitter()
|
||||
if shape.isNull() or not shape.isValid() or len(shape.Solids)!=1: raise RuntimeError('Not one valid solid')
|
||||
if any(p.cut(shape).Volume>1e-5 for p in pads): raise RuntimeError('Washer removed')
|
||||
doc=App.newDocument('Washers4x4')
|
||||
obj=doc.addObject('Part::Feature','Grid');obj.Label='4x4 washers - 2mm links';obj.Shape=shape
|
||||
doc.recompute()
|
||||
doc.saveAs(str(OUT/'4x4_混合垫片.FCStd'))
|
||||
Part.export([obj],str(OUT/'4x4_混合垫片.step'))
|
||||
mesh=MeshPart.meshFromShape(Shape=shape,LinearDeflection=.03,AngularDeflection=.2,Relative=False)
|
||||
mesh.write(str(OUT/'4x4_混合垫片.stl'))
|
||||
App.closeDocument(doc.Name)
|
||||
check=Mesh.Mesh(str(OUT/'4x4_混合垫片.stl'))
|
||||
parts=check.getSeparateComponents()
|
||||
if len(parts)!=1 or not parts[0].isSolid(): raise RuntimeError('STL is not one closed component')
|
||||
shutil.copyfile(SRC/'EncoderBracket.stl',OUT/'编码器支架_单件.stl')
|
||||
if hashlib.sha256((SRC/'EncoderBracket.stl').read_bytes()).digest()!=hashlib.sha256((OUT/'编码器支架_单件.stl').read_bytes()).digest():
|
||||
raise RuntimeError('Bracket copy changed')
|
||||
b=shape.BoundBox
|
||||
data={'count':16,'washers_05':8,'washers_10':8,'rod_count':24,
|
||||
'rod_width_mm':2.0,'rod_height_mm':2.0,'rod_total_length_mm':round(rod_length,6),
|
||||
'rod_centerline_free_span_mm':2.0,'rod_nominal_end_overlap_mm':.8,
|
||||
'rod_contact_volumes_mm3':contacts,'hole_opening_check':'passed',
|
||||
'was_original_washer_geometry_retained':True,'closed_components':len(parts),
|
||||
'bounds_mm':[b.XMin,b.XMax,b.YMin,b.YMax,b.ZMin,b.ZMax]}
|
||||
(OUT/'几何检查.json').write_text(json.dumps(data,ensure_ascii=False,indent=2)+'\n',encoding='utf8')
|
||||
print(json.dumps(data,ensure_ascii=False,indent=2))
|
||||
Reference in New Issue
Block a user