MustafaMulla29/rp2040-bldc-motor-controller-new

73×72 mm 4-layer USB‑C PD (5/9/15/20 V) RP2040 controller PCB with protected power switching, MCT8329A sensorless BLDC three-phase MOSFET bridge, USB data/programming, onboard controls, and three motor outputs feeding a 2212 motor through rigid bullet adapters.

Version
0.3.100
License
unset
Stars
0

assembly/build.tsx

import React from "react"
import { Circuit } from "@tscircuit/core"
import { convertCircuitJsonToGltf } from "circuit-json-to-gltf"
import { createHash } from "node:crypto"
import { mkdir, readFile, writeFile } from "node:fs/promises"
import { resolve } from "node:path"
import Study from "./full-assembly"
import { usbConnections } from "./usb-connections"
import { dimensions, geometryNotes } from "./dimensions"
import { selectSocketCad, assemblyParts, matingPoint, phases } from "./attachments"

const base = import.meta.dir
process.chdir(base)
await mkdir("dist/assets", { recursive: true })
await mkdir("dist/results", { recursive: true })
const input = resolve(base, "../dist/index/circuit.json")
const bytes = await readFile(input)
const pcbJson = JSON.parse(bytes.toString())
const board = pcbJson.find((x: any) => x.type === "pcb_board")
if (!board) throw new Error("PCB build has no board geometry")
const boardSizeMm = [board.width, board.height]
const socketCad = selectSocketCad(pcbJson)
const pcbErrors = pcbJson.filter((x: any) => x.type.endsWith("_error"))
if (pcbErrors.length) throw new Error("PCB has native errors; cannot present a validated routed assembly")
const pcbValidation = JSON.parse(await readFile("dist/results/pcb-validation.json", "utf8"))
const sourceHash = createHash("sha256").update(bytes).digest("hex")
if (pcbValidation.sha256 !== sourceHash || pcbValidation.nativeDrcErrors !== 0) throw new Error("PCB validation must match the current generated board")
let prior: any
try { prior = JSON.parse(await readFile("dist/assets/compact-board.provenance.json", "utf8")) } catch {}
if (prior?.input !== input || prior?.sha256 !== sourceHash || !await Bun.file("dist/assets/compact-board.glb").exists()) {
  console.log("Exporting validated routed power-switch PCB to GLB")
  const glb = await convertCircuitJsonToGltf(JSON.parse(bytes.toString()), {
    format: "glb", boardTextureResolution: 1024, includeModels: true,
    boardDrillQuality: "fast", showErrors: true, projectBaseUrl: new URL("../", import.meta.url).href,
  })
  await writeFile("dist/assets/compact-board.glb", Buffer.from(glb as ArrayBuffer))
  await writeFile("dist/assets/compact-board.provenance.json", JSON.stringify({
    input, sha256: sourceHash, description: `${board.width} x ${board.height} mm main PCB; all components top, PCB power switch, onboard controls and copper test pads, side-entry sockets; routed and native DRC checked`,
  }, null, 2) + "\n")
}
console.log("Rendering native custom-CAD assembly")
const c = new Circuit()
c.add(<Study socketCad={socketCad} pcb={pcbJson} />)
await c.renderUntilSettled()
const json = c.getCircuitJson()
const errors = json.filter((x: any) => x.type.endsWith("_error"))
if (errors.length) throw new Error(JSON.stringify(errors))
await writeFile("dist/results/assembly.circuit.json", JSON.stringify(json, null, 2))
console.log("Exporting assembly GLB")
const glb = await convertCircuitJsonToGltf(json, {
  format: "glb", drawFauxBoard: false, includeModels: true,
})
await writeFile("dist/results/assembly.glb", Buffer.from(glb as ArrayBuffer))
// Also export the mechanical objects independently. The browser composes this
// with the original PCB GLB to retain PCB textures lost by nested GLB re-export.
// Both inputs are native exports; no board/net/DRC records are edited.
const mechanical = new Circuit()
mechanical.add(<Study includeBoard={false} socketCad={socketCad} pcb={pcbJson} />)
await mechanical.renderUntilSettled()
const mechanicalGlb = await convertCircuitJsonToGltf(mechanical.getCircuitJson(), {
  format: "glb", drawFauxBoard: false, includeModels: true,
})
await writeFile("dist/results/mechanical.glb", Buffer.from(mechanicalGlb as ArrayBuffer))
const leadLengths = json.filter(x => x.type === "cad_cable").map(cable =>
  cable.path.slice(1).reduce((sum, p, j) => sum + Math.hypot(p.x-cable.path[j].x,p.y-cable.path[j].y,p.z-cable.path[j].z),0))
await writeFile("dist/results/assembly-report.json", JSON.stringify({
  status: "5/9/15/20 V USB-PD controller, separate USB DATA cable, motor and three rigid adapters. External USB enclosures are representative; adapter dimensions remain unverified.",
  pcbSourceSha256: sourceHash,
  nativeCadModels: json.filter(x => x.type === "cad_component").length,
  nativeCables: json.filter(x => x.type === "cad_cable").length,
  nativeMotorLeads: json.filter(x => x.type === "cad_cable" && x.name.startsWith("MOTOR_LEAD_")).length,
  usbConnections: usbConnections(pcbJson),
  operatingMode: "J19 USB-PD power and J1 computer USB DATA connected. SW4 motor POWER, SW3 ARM and RV1 speed. Motor tuning firmware and hardware tests remain required.",
  rigidAdapters: json.filter(x => x.type === "source_component" && x.name?.startsWith("RIGID_ADAPTER_")).length,
  cableModels: json.filter(x => x.type === "cad_cable").map(x=>x.cableprinter_string),
  assemblyRuntime: "@tscircuit/core 0.0.2110-bldc.4; released 0.0.2110 base with custom-CAD mating, validated wire paths and fixed-wire ends; cableprinter 0.0.6-bldc.2 adds single-wire colours",
  attachments: assemblyParts(socketCad).adapters.map((adapter, phase) => ({
    phase: phases[phase], socket: `J${10 + phase}`, pose: adapter.pose,
    motorSocket: matingPoint(adapter, "motor"), boardPlugTip: matingPoint(adapter, "board"),
  })),
  sourceExtensions: ["vendor/core-mating-points.patch","vendor/core-wire-path.patch","vendor/cableprinter-wire-end.patch","vendor/cableprinter-wire-colour.patch","vendor/jscad-electronics-wire-end.patch"],
  nativeRenderErrors: errors.length,
  dimensions, geometryNotes,
  cableCentrelineLengthsMm: json.filter(x=>x.type==="cad_cable").map((x,i)=>({name:x.name,length:leadLengths[i],supplierLengthMm:null})),
  pcbValidation,
  project: "rp2040-bldc-motor-controller-new",
  boardSizeMm, routingStatus: "Routed; saved-routing input guard retained; native and independent checks passed",
  missing: ["Exact BDHI rigid-adapter body dimensions and current rating", "Original motor lead / heat-shrink / plug dimensions", "USB cables and source/host enclosures use representative dimensions", "Physical mating/retention check and motor-control firmware qualification"],
}, null, 2) + "\n")
console.log("Written dist/results/assembly.glb, assembly.circuit.json and assembly-report.json")