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
firmware/current_monitor.py
"""Signed winding-current telemetry for INA241A1 + 0.1 ohm inline shunts.
Gain is 10 V/V, so sensitivity is 1 V/A. REF1=3V3, REF2=GND.
These readings are short-window signed averages, not RMS or stall detection.
ADC reference is nominally 3.3 V; calibrate against a meter on real hardware.
"""
ADC_FULL_SCALE = 65535
ADC_REFERENCE_V = 3.3
SENSITIVITY_V_PER_A = 10 * 0.1
def current_amperes(raw, zero=ADC_FULL_SCALE / 2, reference_v=ADC_REFERENCE_V):
if not 0 <= raw <= ADC_FULL_SCALE:
raise ValueError("ADC value out of range")
return (raw - zero) * reference_v / ADC_FULL_SCALE / SENSITIVITY_V_PER_A
class CurrentMonitor:
def __init__(self, adc_a, adc_b):
self.adcs = (adc_a, adc_b)
self.zero = [ADC_FULL_SCALE / 2, ADC_FULL_SCALE / 2]
self.amperes = (None, None)
self.clipped = False
def sample(self, count=32):
if count < 1 or count > 256:
raise ValueError("invalid sample count")
totals = [0, 0]
clipped = False
for _ in range(count):
for i, adc in enumerate(self.adcs):
raw = adc.read_u16()
# Flag lost measurement range; don't present saturation as valid current.
clipped = clipped or raw < 1024 or raw > ADC_FULL_SCALE - 1024
totals[i] += raw
self.clipped = clipped
self.amperes = tuple(current_amperes(totals[i] / count, self.zero[i]) for i in range(2))
return self.amperes