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"))