建立方向盘项目初始版本

This commit is contained in:
2026-10-29 22:04:55 +08:00
commit 9962cbfbce
834 changed files with 1519203 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
"""Concept assembly only; run with FreeCAD GUI using rebuild_encoder_concept.FCMacro.
All placements except the explicitly supplied nominal dimensions are provisional.
Do not use this model as a fabrication drawing.
"""
import math
from pathlib import Path
import FreeCAD as App
import FreeCADGui as Gui
import Part
import Import
from pivy import coin
root = Path(__file__).resolve().parent.parent
out = root / 'models'
doc = App.newDocument('M9C12_EncoderConcept')
V = App.Vector
def cyl(r, h, x, y, z):
return Part.makeCylinder(r, h, V(x, y, z))
def item(name, label, shape, color, transparency=0):
obj = doc.addObject('PartDesign::Feature', name)
obj.Label = label
obj.Shape = shape
obj.ViewObject.ShapeColor = color
obj.ViewObject.LineColor = (0.13, 0.13, 0.13)
obj.ViewObject.Transparency = transparency
return obj
gray = (0.32, 0.35, 0.38)
blue = (0.20, 0.48, 0.80)
orange = (0.96, 0.55, 0.12)
green = (0.05, 0.55, 0.25)
silver = (0.78, 0.80, 0.82)
# The supplied existing model has rear at z=0 and front at z=30.
motor = item('Motor', '01 M9C12 original approximate model',
Part.read(str(out / 'MAD_M9C12.step')), gray)
motor.ViewObject.Transparency = 60
# User-supplied 27 mm rear interface is a flat mating face at z=0, not a
# claimed protruding shaft. Seat lies on the rear side (-Z).
# 2.2 mm screw head nests in an assumed 2.6 mm counterbore underneath the magnet.
seat = cyl(13.5, 7.5, 0, 0, -7.5)
seat = seat.cut(cyl(1.65, 7.52, 0, 0, -7.51))
seat = seat.cut(cyl(5.1, 3.0, 0, 0, -7.5)) # magnet pocket
seat = seat.cut(cyl(3.5, 2.6, 0, 0, -4.5)) # assumed M3 head pocket
holder = item('MagnetHolder', '02 Rotating 3D printed magnet holder - concept', seat, orange)
mag = item('Magnet', '03 Magnet 10 x 3 mm - magnetization to verify', cyl(5, 3.0, 0, 0, -7.5), silver)
# Board: 33 mm, 1.6 mm thickness assumed. Three holes as pictured.
boardshape = cyl(16.5, 1.6, 0, 0, -10.9)
board_holes = [(0, 13.49), (-11.71, -6.76), (11.71, -6.76)]
for x, y in board_holes:
boardshape = boardshape.cut(cyl(1.5, 1.62, x, y, -10.91))
board = item('EncoderPCB', '04 MT6826S PCB 33mm - thickness assumed', boardshape, green)
# 1 mm spacing from magnet face z=-7.5 to chip surface z=-8.5. Chip height and
# body size are visual approximations, not package dimensions.
chip = item('SensorChip', '05 Sensor face toward magnet - gap 1mm',
Part.makeBox(4, 5, 0.8, V(-2, -2.5, -9.3)), (0.10, 0.10, 0.11))
# Fixed stand: ring behind the PCB plus four slender uprights and 2 mm
# mounting pads attached to the assumed four 45-degree 50 mm PCD holes.
stand = cyl(20.75, 2.6, 0, 0, -13.5).cut(cyl(11, 2.62, 0, 0, -13.51))
for x, y in board_holes:
stand = stand.cut(cyl(1.65, 2.62, x, y, -13.51))
for i in range(4):
a = math.radians(45 + i * 90)
ux, uy = math.cos(a), math.sin(a)
px, py = 19 * ux, 19 * uy
x, y = 25 * ux, 25 * uy
post = cyl(1.6, 11.5, px, py, -13.5)
pad = cyl(4.8, 2, x, y, -2)
bridge = Part.makeBox(8, 3.2, 2, V(18, -1.6, -2))
bridge.rotate(V(0, 0, 0), V(0, 0, 1), 45 + i * 90)
stand = stand.fuse(post).fuse(pad).fuse(bridge)
stand = stand.cut(cyl(2.15, 2.02, x, y, -2.01))
stand = stand.removeSplitter()
support = item('EncoderBracket', '06 Fixed 3D printed bracket - PCD 50 concept', stand, blue)
# M3 head shown on rear at z=-4.5 and nominal shank through to front;
# actual length, head diameter, nut and hole fit are placeholders.
shaft = cyl(1.48, 45.9, 0, 0, -1.9)
head = cyl(3.0, 2.2, 0, 0, -4.1)
fastener = item('M3Bolt', '07 M3 fastener - head thickness 2.2mm', shaft.fuse(head), silver)
# A nut is a symbolic approximate hex in front of the original model.
points = [V(3.2*math.cos(math.radians(30+i*60)),
3.2*math.sin(math.radians(30+i*60)), 44) for i in range(6)]
points.append(points[0])
nut = Part.Face(Part.Wire(Part.makePolygon(points).Edges)).extrude(V(0,0,2.4))
nut = nut.cut(cyl(1.5, 2.42, 0, 0, 43.99))
nut_obj = item('M3Nut', '08 M3 nut - location indicative', nut, silver)
fasteners=[]
for i in range(4):
a = math.radians(45+i*90)
x,y=25*math.cos(a),25*math.sin(a)
# Nominal 8 mm length extends 2 mm through bracket and 6 into motor.
shank=cyl(1.95,8,x,y,-2)
screwhead=cyl(3.4,2.5,x,y,-4.5)
fasteners.append(item('M4Screw%d'%i, '09 M4x8 mounting screw %d - illustrative'%(i+1), shank.fuse(screwhead), silver))
doc.recompute()
for obj in [motor,holder,mag,board,chip,support,fastener,nut_obj]+fasteners:
if obj.Shape.isNull() or not obj.Shape.isValid():
raise RuntimeError('invalid: '+obj.Name)
view = Gui.activeDocument().activeView()
# Rear three-quarter view; adjust after visual inspection.
view.getCameraNode().orientation.setValue(coin.SbRotation(0.880476, 0.115917, -0.279848, -0.364705))
view.fitAll()
Gui.updateGui()
view.saveImage(str(out / 'M9C12_MT6826S_安装示意.png'), 1600, 1200, 'White')
# Diagram-only exploded view: move pieces outward along the axis, preserving
# their relative orientation. The saved assembly remains assembled.
for obj, dz in [(holder,-8), (mag,-15), (board,-25), (chip,-25), (support,-33)]:
obj.Placement = App.Placement(V(0, 0, dz), App.Rotation())
doc.recompute()
view.fitAll()
Gui.updateGui()
view.saveImage(str(out / 'M9C12_MT6826S_爆炸示意.png'), 1600, 1200, 'White')
for obj in [holder,mag,board,chip,support]:
obj.Placement = App.Placement()
doc.recompute()
view.fitAll()
Gui.updateGui()
# The principal conceptual parts should not physically overlap in this model;
# mere face contacts have zero common volume. Sensor fasteners are omitted.
parts = [motor,holder,mag,board,chip,support,fastener,nut_obj]+fasteners
warnings = []
for i, first in enumerate(parts):
for second in parts[i+1:]:
overlap = first.Shape.common(second.Shape).Volume
if overlap > 0.001:
warnings.append('%s / %s : %.4f mm3' % (first.Name, second.Name, overlap))
(out / 'M9C12_MT6826S_几何检查.txt').write_text(
'Concept only. Assumed dimensions are not production measurements.\n'
'Sensor face to magnet gap: 1.0 mm.\n'
+ ('Positive-volume intersections:\n' + '\n'.join(warnings) if warnings else
'No positive-volume intersections above 0.001 mm3 in simplified model.') + '\n',
encoding='utf-8')
doc.recompute()
doc.saveAs(str(out / 'M9C12_MT6826S_安装示意.FCStd'))
Import.export([motor,holder,mag,board,chip,support,fastener,nut_obj]+fasteners,
str(out / 'M9C12_MT6826S_安装示意.step'))
print('ENCODER_CONCEPT_OK')