imrishabh18/rp2040-motor-controller
The circuit implements a powered USB interface with a W25Q16 flash memory chip, a RP2040 microcontroller, and AO3400A MOSFETs for switch control, enabling USB communication, memory storage, and device power management.
- Version
- 1.0.19
- License
- unset
- Stars
- 0
firmware/main.py
"""Reference USB temperature monitor. Copy all firmware/*.py onto MicroPython.
Commands: arm, stop, status, zero. Position is single-turn, with a volatile zero. This monitor never generates motion commands.
Integrate the existing motor/PWM code only while guard.policy.enabled is true.
The main loop must call guard.poll() and feed the watchdog at least every 100 ms.
"""
from machine import Pin, WDT, PWM, I2C
from time import ticks_ms, ticks_diff, sleep_ms
import sys
import select
from thermal_guard import ThermalGuard
from audible_alarm import AudibleAlarm
from as5600 import AS5600
Pin(22, Pin.OUT, value=0)
watchdog = WDT(timeout=1000)
guard = None
alarm = AudibleAlarm(PWM(Pin(16)))
encoder = AS5600(I2C(0, sda=Pin(0), scl=Pin(1), freq=400_000))
encoder_ok = False
try:
guard = ThermalGuard()
console = select.poll()
console.register(sys.stdin, select.POLLIN)
command = ""
last_sample = ticks_ms()
last_report = last_sample
last_encoder = last_sample
while True:
now = ticks_ms()
if ticks_diff(now, last_encoder) >= 10:
try:
encoder.sample()
encoder_ok = True
except (OSError, ValueError):
encoder_ok = False
guard.stop("encoder unavailable or invalid magnet")
last_encoder = now
if ticks_diff(now, last_sample) >= 100:
guard.poll()
alarm.update(guard.policy.temperature_c, bool(guard.alert.value()), now)
last_sample = now
# Bound the input workload; an incomplete line cannot block monitoring.
for _ in range(16):
if not console.poll(0):
break
char = sys.stdin.read(1)
if char in ("\n", "\r"):
if command == "arm":
print("ARMED" if encoder_ok and guard.arm() else "ARM DENIED")
elif command == "stop":
guard.stop()
elif command == "zero" and not guard.policy.enabled:
try:
encoder.zero()
except (OSError, ValueError):
encoder_ok = False
guard.stop("encoder zero failed")
elif command == "status":
print(guard.policy.temperature_c, guard.policy.status(), "angle_deg=", encoder.angle_degrees)
command = ""
elif len(command) < 32:
command += char
if ticks_diff(now, last_report) >= 1000:
print("temperature_C=", guard.policy.temperature_c, guard.policy.status(), "angle_deg=", encoder.angle_degrees)
last_report = now
# Feed only in this loop, never in an interrupt or unrelated timer.
watchdog.feed()
sleep_ms(10)
finally:
alarm.close()
Pin(22, Pin.OUT, value=0)
if guard is not None:
guard.stop("monitor exited")