ShiboSoftwareDev/nema8-20mm-dual-usbc-stepper-controller

A compact 4-layer USB‑C PD stepper-motor controller PCB using a CH32X035 MCU, TMC2209 driver, dual USB‑C ports, power protection/regulation, ESD/TVS diodes, current-sense resistors, and NEMA‑8 motor connector.

Version
1.0.13
License
unset
Stars
0

scripts/score-via-combinations.mjs

import fs from "node:fs"
import { runAllRoutingChecks } from "@tscircuit/checks"

const baseline = JSON.parse(
  fs.readFileSync("frozen-global-router-baseline.json", "utf8"),
).filter((element) => !String(element.type).endsWith("error"))

const candidates = [
  ["source_net_30_0", 0.3165170373, 2.4681926742, 0.1165, 2.3682],
  ["source_net_26_mst1_0", -4.9635288614, 0.8009878988, -5.2635, 0.601],
  ["source_net_26_mst1_0", -1.0149987646, -4.722238758, -1.215, -4.7222],
  ["source_net_22_mst0_0", -5.975494, -3.367, -6.2755, -3.567],
  ["source_net_22_mst1_0", 1.9745212144, 2.375001, 1.6745, 2.875],
  ["source_net_21_0", 1.6, -3.9750010113, 1.6, -3.775],
]

const samePoint = (point, x, y) =>
  Math.abs(point.x - x) < 1e-5 && Math.abs(point.y - y) < 1e-5

const applyMove = (circuit, [traceId, oldX, oldY, newX, newY]) => circuit.map((element) => {
  if (element.type === "pcb_via" && element.pcb_trace_id === traceId &&
      samePoint(element, oldX, oldY)) {
    return { ...element, x: newX, y: newY }
  }
  if (element.type === "pcb_trace" && element.pcb_trace_id === traceId) {
    return {
      ...element,
      route: element.route.map((point) => samePoint(point, oldX, oldY)
        ? { ...point, x: newX, y: newY }
        : point),
    }
  }
  return element
})

let best = { count: Infinity, mask: 0, errors: [] }
for (let mask = 0; mask < 2 ** candidates.length; mask++) {
  let circuit = baseline
  for (let index = 0; index < candidates.length; index++) {
    if (mask & (1 << index)) circuit = applyMove(circuit, candidates[index])
  }
  let errors
  try {
    errors = await runAllRoutingChecks(circuit)
  } catch {
    continue
  }
  if (errors.length < best.count) best = { count: errors.length, mask, errors }
}

console.log(`best\t${best.count}\tmask=${best.mask.toString(2).padStart(candidates.length, "0")}`)
for (let index = 0; index < candidates.length; index++) {
  if (best.mask & (1 << index)) console.log(`use\t${candidates[index].join("\t")}`)
}
console.log(Object.entries(Object.groupBy(best.errors, (error) => error.type))
  .map(([kind, errors]) => `${kind}\t${errors.length}`)
  .join("\n"))
console.log(best.errors.map((error) => error.message).join("\n"))