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/search-via-doglegs.mjs
import fs from "node:fs"
import { runAllRoutingChecks } from "@tscircuit/checks"
let circuit = JSON.parse(fs.readFileSync("dist/index/circuit.json", "utf8"))
.filter((element) => !String(element.type).endsWith("error"))
const targets = ["pcb_via_9", "pcb_via_14", "pcb_via_34", "pcb_via_35", "pcb_via_37", "pcb_via_49"]
const samePoint = (point, x, y) =>
Math.abs(point.x - x) < 1e-5 && Math.abs(point.y - y) < 1e-5
const doglegVia = (input, viaId, newX, newY) => {
const via = input.find((element) => element.type === "pcb_via" && element.pcb_via_id === viaId)
if (!via) return input
const trace = input.find((element) => element.type === "pcb_trace" && element.pcb_trace_id === via.pcb_trace_id)
if (!trace) return input
return input.map((element) => {
if (element.type === "pcb_via" && element.pcb_via_id === viaId) {
return { ...element, x: newX, y: newY }
}
if (element.type !== "pcb_trace" || element.pcb_trace_id !== trace.pcb_trace_id) return element
const route = []
for (let index = 0; index < element.route.length; index += 1) {
const point = element.route[index]
if (point.route_type !== "via" || !samePoint(point, via.x, via.y)) {
route.push(point)
continue
}
const previous = route.at(-1)
const next = element.route[index + 1]
if (!previous || !next || previous.route_type !== "wire" || next.route_type !== "wire") {
route.push({ ...point, x: newX, y: newY })
continue
}
// Preserve the old arrival/departure points and bridge locally to the new via.
route.push({ ...previous, x: newX, y: newY })
route.push({ ...point, x: newX, y: newY })
route.push({ ...next, x: newX, y: newY })
route.push(next)
index += 1
}
return { ...element, route }
})
}
let errors = await runAllRoutingChecks(circuit)
console.log(`start\t${errors.length}`)
for (const viaId of targets) {
const via = circuit.find((element) => element.type === "pcb_via" && element.pcb_via_id === viaId)
if (!via) continue
let best = { count: errors.length, x: via.x, y: via.y, circuit, errors }
const radii = [0.8, 1.4, 2]
for (const radius of radii) {
const step = 0.2
for (let dx = -radius; dx <= radius + 1e-6; dx += step) {
for (let dy = -radius; dy <= radius + 1e-6; dy += step) {
if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) continue
const x = Number((via.x + dx).toFixed(4))
const y = Number((via.y + dy).toFixed(4))
const candidate = doglegVia(circuit, viaId, x, y)
let candidateErrors
try {
candidateErrors = await runAllRoutingChecks(candidate)
} catch {
continue
}
if (candidateErrors.length < best.count) {
best = { count: candidateErrors.length, x, y, circuit: candidate, errors: candidateErrors }
}
}
}
if (best.count < errors.length) break
}
circuit = best.circuit
errors = best.errors
console.log(`${viaId}\t${best.count}\t${via.x},${via.y}\t${best.x},${best.y}`)
}
console.log(Object.entries(Object.groupBy(errors, (error) => error.type))
.map(([kind, group]) => `${kind}\t${group.length}`)
.join("\n"))
console.log(errors.map((error) => error.message).join("\n"))