建立方向盘项目初始版本
This commit is contained in:
118
scripts/build_kfl_plate_b38_concept.py
Normal file
118
scripts/build_kfl_plate_b38_concept.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from pathlib import Path
|
||||
import math, time, traceback
|
||||
import FreeCAD as A, FreeCADGui as G, Part, Import
|
||||
from pivy import coin
|
||||
|
||||
R=Path(r'C:\projects\wheel'); O=R/'models'/'kfl_plate_b38_concept'; O.mkdir(parents=True,exist_ok=True)
|
||||
V=A.Vector
|
||||
def cyl(r,h,x,y,z):return Part.makeCylinder(r,h,V(x,y,z))
|
||||
def add(doc,name,label,s,color,trans=0):
|
||||
o=doc.addObject('PartDesign::Feature',name);o.Label=label;o.Shape=s;o.ViewObject.ShapeColor=color;o.ViewObject.LineColor=(.1,.1,.1);o.ViewObject.Transparency=trans;return o
|
||||
def intersection(a,b):
|
||||
return a.common(b).Volume if a.BoundBox.intersect(b.BoundBox) else 0.0
|
||||
try:
|
||||
doc=A.openDocument(str(R/'models'/'kfl_plate_adjust_concept'/'Assembly.FCStd'))
|
||||
doc.Label='KFL b38 - 39 mm bore conceptual assembly'
|
||||
for i,z in enumerate((-84.,-187.)):
|
||||
p=doc.getObject('AdjustPlate%d'%i)
|
||||
p.Shape=p.Shape.cut(cyl(19.5,8.04,0,0,z-.02)).removeSplitter()
|
||||
p.Label='8 mm plate, central through-bore Ø39 assumption'
|
||||
# Enlarge only the portion assumed to penetrate the plate; leave mounting ears intact.
|
||||
# KMT catalog axial section: static housing protrudes 6 mm from ear seating plane.
|
||||
# A circular Ø38 bounding section is a conservative stand-in for the unmeasured
|
||||
# actual penetrating profile, not a manufacturer's individual diameter callout.
|
||||
for i,z in enumerate((-82.,-187.)):
|
||||
h=doc.getObject('KFLHousing%d'%i)
|
||||
outer=cyl(19,6,0,0,z).cut(cyl(9.5,6.02,0,0,z-.01))
|
||||
h.Shape=h.Shape.fuse(outer).removeSplitter()
|
||||
h.Label='KFL seat Ø38 circular envelope assumed; 6mm inside plate'
|
||||
# Replace previous simplified M6 heads/nuts with individually selectable shank,
|
||||
# head, nut, and two washers. OD12 ID6.6 washers are nominal placeholders.
|
||||
for i,z in enumerate((-84.,-187.)):
|
||||
for j,x in enumerate((-24.,24.)):
|
||||
name='KFLFastEnd%d%d'%(i,j)
|
||||
if doc.getObject(name):doc.removeObject(name)
|
||||
old='KFLBolt%d_%d'%(i,j)
|
||||
if doc.getObject(old):doc.removeObject(old)
|
||||
if i==0:
|
||||
# flange ear z=-76..-70.5; plate z=-84..-76
|
||||
wplatez=-85.; wearz=-70.5; nutz=-88.; headz=-69.5
|
||||
else:
|
||||
# ear z=-192.5..-187; plate z=-187..-179
|
||||
wplatez=-179.; wearz=-193.5; nutz=-178.; headz=-196.5
|
||||
# Each washer is hollow to avoid its shaft being a spurious positive overlap.
|
||||
ring=lambda zz: cyl(6,1,x,0,zz).cut(cyl(3.3,1.02,x,0,zz-.01))
|
||||
add(doc,'BearingWasherPlate%d%d'%(i,j),'M6 washer Ø12 on plate, schematic',ring(wplatez),(.42,.44,.47))
|
||||
add(doc,'BearingWasherEar%d%d'%(i,j),'M6 washer Ø12 on bearing ear, schematic',ring(wearz),(.42,.44,.47))
|
||||
add(doc,'BearingHead%d%d'%(i,j),'M6 head envelope Ø10',cyl(5,3,x,0,headz),(.13,.14,.16))
|
||||
add(doc,'BearingNut%d%d'%(i,j),'M6 nut envelope Ø10',cyl(5,3,x,0,nutz),(.13,.14,.16))
|
||||
add(doc,'KFLBolt%d_%d'%(i,j),'M6 bolt shank engagement schematic Ø5.8',cyl(2.9,18.5,x,0,nutz if i==0 else wearz),(.13,.14,.16))
|
||||
doc.recompute()
|
||||
tests=[]
|
||||
def chk(label,sa,sb):tests.append((label,intersection(sa,sb)))
|
||||
for i in range(2):
|
||||
p=doc.getObject('AdjustPlate%d'%i).Shape
|
||||
for n in ('KFLHousing%d'%i,'KFLInner%d'%i):chk('plate%d/%s'%(i,n),p,doc.getObject(n).Shape)
|
||||
for j in range(2):
|
||||
for k in ('BearingWasherPlate','BearingWasherEar','BearingHead','BearingNut'):
|
||||
v=doc.getObject('%s%d%d'%(k,i,j)).Shape
|
||||
for other in ('MotorFlange','WheelHub','SwitchEnvelope'):
|
||||
o=doc.getObject(other)
|
||||
if o:chk('%s%d%d/%s'%(k,i,j,other),v,o.Shape)
|
||||
for n in ('KFLHousing%d'%i,'KFLInner%d'%i):
|
||||
other=doc.getObject('MotorFlange' if i==0 else 'WheelHub')
|
||||
chk(n+'/hub',doc.getObject(n).Shape,other.Shape)
|
||||
# Contact support: intersect planar annulus with plate surface only; washer radius 6, hole radius 3.3.
|
||||
# The single-bore-to-plate-hole line edges are 24 - 19.5 - 3.5 = 1 mm.
|
||||
# Use a thin prism intersection for total plate contact footprint (normal separation < modelling epsilon).
|
||||
contact=[]
|
||||
for i,z in enumerate((-84.,-187.)):
|
||||
p=doc.getObject('AdjustPlate%d'%i).Shape
|
||||
platevolume=0
|
||||
for j,x in enumerate((-24.,24.)):
|
||||
v=(cyl(6,.1,x,0,z if i==0 else z+7.9).cut(cyl(3.3,.12,x,0,z-.01 if i==0 else z+7.89))).common(p).Volume/.1
|
||||
contact.append((i,j,v))
|
||||
# Two-bore nearest metal/nominal washer footprint purely geometric; not strength.
|
||||
b=doc.getObject('KFLHousing0').Shape.BoundBox
|
||||
lines=['CONCEPT ONLY; DO NOT USE FOR CNC OR SAFE-FIT APPROVAL.',
|
||||
'Plate central bore nominal OD39, 8mm thick. 48mm KFL mounting pitch, nominal OD7 holes.',
|
||||
'KFL protrusion given b=38 as conservative circular OD38 bounding assumption, not confirmed round nor actual profile; 0.5mm radial nominal bore clearance.',
|
||||
'KFL ear thickness5.5, stationary central protrusion depth6, inner ring width14.5 and projects 10.5 past mating plane (KMT interpretation).',
|
||||
'Centre-hole to each fastening-hole nominal edge gap = 24 - 19.5 - 3.5 = 1.0mm.',
|
||||
'M6 plate-face washer assumed OD12, ID6.6, thickness1: towards centre hole it extends 1.5mm over nominal opening.',
|
||||
'Plate-face washer nominal contact area mm^2 (face-intersection):']+[f'plate{i} washer{j}: {a:.6f}' for i,j,a in contact]+[
|
||||
'These are static contact footprints, not load/fastener/tear-out calculations. Bearing ear footprint and flush contact require real KFL shape.',
|
||||
'Axial clearance must not be inferred from standard b width. Encoder screw, wires, set-screw access and rotational clearances not fully modelled.',
|
||||
'M6 heads/nuts/washer geometry is illustrative and no tool access is verified; M5 standard angles and crossing slots inherit prior notes.',
|
||||
'Diameter 39 is proposed initial 1mm diametral allowance and is not a fit/tolerance guarantee. No FEA, validation or testing.',
|
||||
'Checked positive-volume intersections (mm^3):']+[f'{n}: {v:.6f}' for n,v in tests]
|
||||
(O/'geometry_check.txt').write_text('\n'.join(lines)+'\n',encoding='utf-8')
|
||||
doc.recompute();doc.saveAs(str(O/'Assembly.FCStd'))
|
||||
Import.export([o for o in doc.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=='top':view.viewBottom()
|
||||
else:view.viewAxonometric()
|
||||
G.updateGui();time.sleep(.6);view.fitAll();G.updateGui();time.sleep(.6)
|
||||
camera=view.getCameraNode();camera.nearDistance.setValue(.01);camera.farDistance.setValue(10000)
|
||||
G.updateGui();view.saveImage(str(O/name),1800,1300,'White')
|
||||
save('assembly.png','axon');save('side.png','side')
|
||||
vis={o.Name:o.ViewObject.Visibility for o in doc.Objects if hasattr(o,'Shape')}
|
||||
show={'AdjustPlate0','KFLHousing0','KFLInner0','KFLBolt0_0','KFLBolt0_1','BearingWasherPlate00','BearingWasherPlate01','BearingWasherEar00','BearingWasherEar01','BearingHead00','BearingHead01','BearingNut00','BearingNut01'}
|
||||
for o in doc.Objects:
|
||||
if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in show
|
||||
save('bearing_detail.png','axon')
|
||||
# Plate + plate-face washers, as seen straight along axis; making relationship visible.
|
||||
show={'AdjustPlate0','BearingWasherPlate00','BearingWasherPlate01'}
|
||||
for o in doc.Objects:
|
||||
if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in show
|
||||
save('plate_detail.png','top')
|
||||
for o in doc.Objects:
|
||||
if hasattr(o,'Shape'):o.ViewObject.Visibility=vis.get(o.Name,True)
|
||||
doc.recompute();doc.saveAs(str(O/'Assembly.FCStd'))
|
||||
if (O/'ERROR.txt').exists(): (O/'ERROR.txt').unlink()
|
||||
(O/'DONE.txt').write_text('ok',encoding='utf8')
|
||||
except Exception:
|
||||
(O/'ERROR.txt').write_text(traceback.format_exc(),encoding='utf8')
|
||||
raise
|
||||
Reference in New Issue
Block a user