astra/nema17-stepper-motor-controller-spring-clamp-rp2040

A 4-layer RP2040 controller board that negotiates USB‑C PD motor power and drives a NEMA17 stepper via a DRV8825, with current sensing, thermal shutdown, RGB status LED, buzzer alarm, optional AS5600 encoder, protection/filtering, and test points.

Version
1.4.0
License
unset
Stars
0

routing/ground-pour-selection.ts

import selection from './ground-pour-selection.json';

/** Frozen pour selection for the validated fixed route plan.
 * The pinned pour generator leaves floating fragments. The independent copper
 * audit identifies those fragments; this finalization step removes their actual
 * copper before normal DRC, preview and export. No error record is filtered.
 * A geometry change fails closed and requires regenerating the selection/audit.
 */
export function canonicalPour(pour: any): string {
  return JSON.stringify({layer:pour.layer,source_net_id:pour.source_net_id,shape:pour.brep_shape}, (_key,value)=>
    typeof value==='number'?Math.round(value*1e7)/1e7:value);
}

export function selectConnectedGroundPours(json: any[], regions: Array<{geometry:any;keep:boolean}>) {
  const pours=json.filter(e=>e.type==='pcb_copper_pour');
  const expected=new Map(regions.map(r=>[canonicalPour(r.geometry),r.keep]));
  if (pours.length!==regions.length || pours.some(p=>!expected.has(canonicalPour(p)))) {
    throw new Error('Ground pour geometry changed. Regenerate and audit routing/ground-pour-selection.json.');
  }
  return pours.filter(p=>!expected.get(canonicalPour(p))).map(p=>p.pcb_copper_pour_id);
}

export function installGroundPourFinalization(board: any) {
  if(!board || board.__groundPourSelectionInstalled)return;
  board.__groundPourSelectionInstalled=true;
  const original=board.doInitialPcbDesignRuleChecks.bind(board);
  board.doInitialPcbDesignRuleChecks=()=>{
    const db=board.root?.db;
    // Placement-only CLI renders intentionally have no routed copper.
    if(db && !board.root.pcbDisabled && !board.root.pcbRoutingDisabled) {
      const remove=selectConnectedGroundPours(db.toArray(),selection.regions);
      for(const id of remove)db.pcb_copper_pour.delete(id);
      // Remove annotations that referred to removed geometry, not checks.
      const deleted=new Set(remove);
      for(const trace of db.pcb_trace.list()) {
        if(trace.route.some((p:any)=>deleted.has(p.copper_pour_id))) {
          db.pcb_trace.update(trace.pcb_trace_id,{route:trace.route.map((p:any)=>{
            if(!deleted.has(p.copper_pour_id))return p;
            const {copper_pour_id,is_inside_copper_pour,...point}=p;return point;
          })});
        }
      }
    }
    return original();
  };
}