建立方向盘项目初始版本
This commit is contained in:
99
scripts/build_kfl_3030_concept.py
Normal file
99
scripts/build_kfl_3030_concept.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from pathlib import Path
|
||||
import os, time, traceback
|
||||
import FreeCAD as A, FreeCADGui as G, Part, Import
|
||||
from pivy import coin
|
||||
V=A.Vector
|
||||
R=Path(r'C:\projects\wheel'); O=R/'models'/'kfl_3030_concept'; O.mkdir(parents=True,exist_ok=True)
|
||||
def box(x,y,z,dx,dy,dz): return Part.makeBox(dx,dy,dz,V(x,y,z))
|
||||
def cy(r,h,x,y,z,d=V(0,0,1)): return Part.makeCylinder(r,h,V(x,y,z),d)
|
||||
def sx(x,y,z,r,h): return box(x-2,y-r,z,4,2*r,h).fuse(cy(r,h,x-2,y,z)).fuse(cy(r,h,x+2,y,z))
|
||||
def sy(x,lo,hi,z,r,h): return box(x-r,lo,z,2*r,hi-lo,h).fuse(cy(r,h,x,lo,z)).fuse(cy(r,h,x,hi,z))
|
||||
def sz(x,y,lo,hi,r,h): return box(x-r,y,lo,2*r,h,hi-lo).fuse(cy(r,h,x,y,lo,V(0,1,0))).fuse(cy(r,h,x,y,hi,V(0,1,0)))
|
||||
def add(d,n,s,c):
|
||||
o=d.addObject('PartDesign::Feature',n);o.Shape=s.removeSplitter();o.Label=n;o.ViewObject.ShapeColor=c;o.ViewObject.LineColor=(.15,.15,.15);return o
|
||||
def cv(a,b): return a.common(b).Volume if a.BoundBox.intersect(b.BoundBox) else 0.
|
||||
ok=False
|
||||
try:
|
||||
d=A.openDocument(str(R/'models'/'kfl_double_crossbar_concept'/'Assembly.FCStd'));d.Label='3030 base and purchased long-slotted angles (concept)'
|
||||
for o in list(d.Objects):
|
||||
if o.Name.startswith(('CompactPlate','LongAngle','CrossAngle','Crossbeam','BoardM5_','FootM5_','CrossTopM5_','CrossSideM5_')):d.removeObject(o.Name)
|
||||
d.recompute()
|
||||
for i,x in enumerate((-50.6200577,50.6200577)):
|
||||
q=d.getObject('NewRail%d'%i);q.Shape=box(x-15,-85,-215,30,30,235);q.Label='3030 longitudinal base rail - solid envelope, groove omitted'
|
||||
parts=[];plates=[];cross=[];angles=[];fast=[]
|
||||
for i,z in enumerate((-84.,-187.)):
|
||||
face=z if i==0 else z+8; sign=-1 if i==0 else 1
|
||||
# Crossbeams butt between longitudinal members at the same height, centreline +/-35.6200577.
|
||||
z0=face-30 if i==0 else face
|
||||
cb=add(d,'Crossbeam%d'%i,box(-35.6200577,-87,z0,71.2401154,30,30),(.46,.49,.53));cross.append(cb)
|
||||
p=box(-38,-51,z,76,80,8).cut(cy(19.5,8.04,0,0,z-.02))
|
||||
for x in (-24.,24.):p=p.cut(cy(3.5,8.04,x,0,z-.02))
|
||||
for x in (-23.5,23.5):p=p.cut(sx(x,-42,z-.02,2.75,8.04))
|
||||
plates.append(add(d,'CompactPlate%d'%i,p,(.72,.74,.78)))
|
||||
for j,side in enumerate((-1,1)):
|
||||
x=side*23.5
|
||||
# Overall 50 mm upright includes 3 mm foot; 33mm long slot 6 mm from inside bend.
|
||||
vz=face-3 if i==0 else face
|
||||
upright=box(x-9.5,-54,vz,19,47,3).cut(sy(x,-44.75,-18.25,vz-.02,3.25,3.04))
|
||||
fz=face-31 if i==0 else face
|
||||
# Short leg 31, 16 mm slot position assumed centered; T slot at 15 mm.
|
||||
if i==0: lo,hi=face-20.25,face-10.75
|
||||
else: lo,hi=face+10.75,face+20.25
|
||||
foot=box(x-9.5,-57,fz,19,3,31).cut(sz(x,-57.02,lo,hi,3.25,3.04))
|
||||
a=add(d,'PurchasedAngle%d%d'%(i,j),upright.fuse(foot),(.95,.5,.12));angles.append(a)
|
||||
if i==1: stem=cy(2.45,18,x,-42,z-4);head=cy(4.25,3,x,-42,face+4);nut=cy(4.25,3,x,-42,z-3);wz=face+3
|
||||
else: stem=cy(2.45,18,x,-42,z-5);head=cy(4.25,3,x,-42,face-7);nut=cy(4.25,3,x,-42,z+8);wz=face-4
|
||||
washer=cy(5.5,1,x,-42,wz).cut(cy(2.75,1.02,x,-42,wz-.01))
|
||||
fast.append(add(d,'BoardM5_%d%d'%(i,j),stem.fuse(head).fuse(nut).fuse(washer),(.14,.15,.17)))
|
||||
cz=face+sign*15
|
||||
# Shank intentionally omitted within solid extrusion; actual T slot is not modelled.
|
||||
fast.append(add(d,'FootHead%d%d'%(i,j),cy(5.5,1,x,-54,cz,V(0,1,0)).cut(cy(2.75,1.02,x,-54.01,cz,V(0,1,0))).fuse(cy(4.25,3,x,-53,cz,V(0,1,0))),(.14,.15,.17)))
|
||||
# Side connector concept: to rail inward vertical face and crossbeam top. 20 mm angle, one per end.
|
||||
# Top leg occupies outside edge, held clear of bearing-plate long angles.
|
||||
inner=side*35.6200577
|
||||
if side<0: xa=inner; vx=inner; xb=inner+10
|
||||
else: xa=inner-20; vx=inner-3; xb=inner-10
|
||||
sidez=z0+30 if i==0 else z0-3
|
||||
vz0=z0+30 if i==0 else z0-20
|
||||
cz2=(vz0+10)
|
||||
top=box(xa,-80,sidez,20,18,3).cut(cy(2.75,3.04,xb,-72,sidez-.02))
|
||||
vert=box(vx,-80,vz0,3,18,20).cut(cy(2.75,3.04,vx-.02,-70,cz2,V(1,0,0)))
|
||||
angles.append(add(d,'BaseJoint%d%d'%(i,j),top.fuse(vert),(.78,.38,.08)))
|
||||
d.recompute()
|
||||
# Full independent shape-pair screening for relevant structural parts. Suppressed solid T-slot
|
||||
# screw shanks; inherited switch shape represents only an assumed block around its central opening.
|
||||
new=[o for o in d.Objects if o.Name.startswith(('CompactPlate','PurchasedAngle','Crossbeam','BaseJoint','NewRail','BoardM5_','FootHead'))]
|
||||
contextual=[o for o in d.Objects if hasattr(o,'Shape') and not o.Shape.isNull() and o not in new and o.ViewObject.Visibility]
|
||||
lines=[];bad=[]
|
||||
for i,a in enumerate(new):
|
||||
for b in new[i+1:]+contextual:
|
||||
try:
|
||||
if not a.Shape.BoundBox.intersect(b.Shape.BoundBox):
|
||||
lines.append('%s / %s = 0.0000 mm^3 (bounding boxes disjoint)'%(a.Name,b.Name));continue
|
||||
v=cv(a.Shape,b.Shape)
|
||||
if v>0.001:bad.append((a.Name,b.Name,v))
|
||||
lines.append('%s / %s = %.4f mm^3'%(a.Name,b.Name,v))
|
||||
except Exception as e: lines.append('ERROR '+a.Name+'/'+b.Name+': '+str(e))
|
||||
(O/'all_checks.txt').write_text('\n'.join(lines)+'\n',encoding='utf8')
|
||||
(O/'positive_intersections.txt').write_text('\n'.join('%s / %s = %.4f mm^3'%x for x in bad) or 'none',encoding='utf8')
|
||||
(O/'visible_parts.txt').write_text('\n'.join('%s %s %s'%(o.Name,o.Label,str(o.Shape.BoundBox)) for o in contextual),encoding='utf8')
|
||||
d.saveAs(str(O/'Assembly.FCStd'));Import.export([o for o in d.Objects if hasattr(o,'Shape')],str(O/'Assembly.step'))
|
||||
view=G.activeDocument().activeView();G.activateWorkbench('PartWorkbench')
|
||||
def save(name,mode):
|
||||
if mode=='side':view.viewFront()
|
||||
elif mode=='plate':view.viewBottom()
|
||||
else:view.viewAxonometric();G.updateGui();view.getCameraNode().orientation.setValue(coin.SbRotation(.880476,.115917,-.279848,-.364705))
|
||||
G.updateGui();time.sleep(.3);view.fitAll();G.updateGui();time.sleep(.4);view.saveImage(str(O/name),1800,1250,'White')
|
||||
save('assembly.png','axon');save('side.png','side')
|
||||
vis={o.Name:o.ViewObject.Visibility for o in d.Objects if hasattr(o,'Shape')}
|
||||
show=set([o.Name for o in plates+angles+cross+fast]+['NewRail0','NewRail1','KFLHousing0','KFLHousing1','KFLInner0','KFLInner1','CamShaft'])
|
||||
for o in d.Objects:
|
||||
if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in show
|
||||
save('frame.png','axon');save('plate.png','plate')
|
||||
for o in d.Objects:
|
||||
if hasattr(o,'Shape'):o.ViewObject.Visibility=vis.get(o.Name,True)
|
||||
d.recompute();d.saveAs(str(O/'Assembly.FCStd'));A.closeDocument(d.Name)
|
||||
(O/'DONE.txt').write_text('ok',encoding='utf8');ok=True
|
||||
except Exception:
|
||||
(O/'ERROR.txt').write_text(traceback.format_exc(),encoding='utf8')
|
||||
finally:os._exit(0 if ok else 1)
|
||||
Reference in New Issue
Block a user