shibosoftwaredev/f1c100s-linux-nema17-stepper-controller

A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.

Version
0.4.56
License
unset
Stars
0

scripts/check-assembly-motor-reference.mjs

import fs from "node:fs"
import assert from "node:assert/strict"
import crypto from "node:crypto"
import { parseModelString, getNemaMotorReferencePoints, hexSocketBoltDimensions } from "@tscircuit/modelprinter"
import { Matrix4, Euler, Vector3 } from "three"

const source = fs.readFileSync("index.circuit.tsx", "utf8")
const element = source.match(/<assembly\.motor\s[\s\S]*?\/>/)?.[0]
assert.ok(element, "assembly motor exists")
const prop = name => element.match(new RegExp(`${name}="([^"]+)"`))?.[1]
const modelString = prop("model"), displayName = prop("displayName")
const { fn, ...model } = parseModelString(modelString)
assert.equal(fn, "nema")
const refs = getNemaMotorReferencePoints(model)
const bytes = fs.readFileSync("dist/index/circuit.json"), c = JSON.parse(bytes)
const motor = c.find(e => e.type === "source_component" && e.name === prop("name") && e.ftype === "motor")
const cad = c.find(e => e.type === "cad_component" && e.source_component_id === motor.source_component_id)
assert.ok(cad.model_glb_url.endsWith(encodeURIComponent(modelString)+".glb"))
const matrix = new Matrix4().makeRotationFromEuler(new Euler(...[cad.rotation.x, cad.rotation.y, cad.rotation.z].map(d => d*Math.PI/180), "XYZ"))
const rear = new Vector3(refs.backface.position.x, refs.backface.position.y, refs.backface.position.z)
  .applyMatrix4(matrix).add(new Vector3(cad.position.x, cad.position.y, cad.position.z))
const board = c.find(e => e.type === "pcb_board")
const motorToBoardGap = -board.thickness/2-rear.z
assert.ok(Math.abs(motorToBoardGap-6) < 1e-6, "modeled six millimetre rear gap")
const holeParts = new Set(c.filter(e => e.type === "source_component" && /^MH[1-4]$/.test(e.name)).map(e => e.source_component_id))
const pcbs = new Set(c.filter(e => e.type === "pcb_component" && holeParts.has(e.source_component_id)).map(e => e.pcb_component_id))
const holes = c.filter(e => e.type === "pcb_hole" && pcbs.has(e.pcb_component_id))
assert.equal(holes.length, 4)
const expected = [-1,1].flatMap(x => [-1,1].map(y => [x*model.backFaceHoleSpacing/2,y*model.backFaceHoleSpacing/2]))
assert.ok(expected.every(([x,y]) => holes.some(h => Math.hypot(h.x-x,h.y-y)<1e-6)), "rear-model and board hole patterns match")
const fastener = hexSocketBoltDimensions[model.backFaceScrewSize]
assert.ok(holes.every(h => h.hole_diameter>fastener.diameter), "board holes clear nominal screw shafts")
assert.equal(fastener.headDiameter, 5.5)
const report = {
  checkedAt: new Date().toISOString(), circuitSha256: crypto.createHash("sha256").update(bytes).digest("hex"),
  targetIdentifiedFrom: "index.circuit.tsx assembly.motor; no motor substitution",
  displayName, modelString, modelprinterVersion: JSON.parse(fs.readFileSync("node_modules/@tscircuit/modelprinter/package.json","utf8")).version,
  parsedModel: model, modelReferencePoints: refs,
  defaultRearFastener: fastener,
  modelOnlyFit: { fourHolePatternMatches: true, holeSpacingMm: model.backFaceHoleSpacing, pcbHolesMm: holes.map(h => h.hole_diameter),
    rearFaceWorldZMm: rear.z, motorToBoardGapMm: motorToBoardGap, nominalHeadFitsReserved55MmEnvelope: true },
  limits: {
    manufacturerModel: false,
    rearHoleDepthIsModelDefaultNotMeasured: true,
    suppliedMotorScrewLengthKnown: false,
    motorBodyCapScrewsAreNotDemonstratedBoardMountingBolts: true,
    boardMountingScrewLengthSelected: false,
    originalCableDirectMateProven: false,
    explanation: "displayName identifies the intended StepperOnline motor; the CAD URL is a parametric NEMA model. Its rear M3 holes/depth, round shaft and PH connector are model parameters/defaults, not a certified 17HS13-0404S1 manufacturing drawing. The modeled rear cap screws remain below the PCB; the six millimetre gap does not extend their shanks through the board."
  },
  assemblyApproved: false
}
fs.writeFileSync("reports/assembly-motor-reference.json",JSON.stringify(report,null,2)+"\n")
console.log(JSON.stringify({displayName,modelString,modelOnlyFit:report.modelOnlyFit,assemblyApproved:false}))