Programming for Robotics 1, Chapter 1: Challenge 2 solution (a debounce that never blocks) Idea: the class stores one number, the time at which the condition last BECAME true (None while it is false). Each call does three things and then returns at once: condition false -> forget the start time and return False (any false reading restarts the count) condition true, no start time yet -> remember now as the start return (now - start) >= hold_ms It never sleeps and never loops: the time that passes between calls is the caller's loop. It uses diff_ms (section 3) so that it also works across the tick wrap-around on MicroPython. CODE: class Debounce: """True only after the condition has held on every call for at least hold_ms. Never waits.""" def __init__(self, hold_ms): self.hold_ms = hold_ms self.since_ms = None # when the condition last became true; None if it is false def update(self, now_ms, condition): if not condition: self.since_ms = None # any false reading restarts the count return False if self.since_ms is None: self.since_ms = now_ms return diff_ms(now_ms, self.since_ms) >= self.hold_ms volts = [7.2, 6.5, 6.4, 7.0, 6.5, 6.4, 6.3, 6.2, 6.1] debounce = Debounce(2000) first_true_ms = None for i, volt in enumerate(volts): t_ms = 500 * i low = volt < 6.6 reported = debounce.update(t_ms, low) print("t=%4d ms %.1f V below 6.6 V: %-5s reported: %s" % (t_ms, volt, low, reported)) if reported and first_true_ms is None: first_true_ms = t_ms print("first True at %d ms" % first_true_ms) END CODE OUTPUT: t= 0 ms 7.2 V below 6.6 V: False reported: False t= 500 ms 6.5 V below 6.6 V: True reported: False t=1000 ms 6.4 V below 6.6 V: True reported: False t=1500 ms 7.0 V below 6.6 V: False reported: False t=2000 ms 6.5 V below 6.6 V: True reported: False t=2500 ms 6.4 V below 6.6 V: True reported: False t=3000 ms 6.3 V below 6.6 V: True reported: False t=3500 ms 6.2 V below 6.6 V: True reported: False t=4000 ms 6.1 V below 6.6 V: True reported: True first True at 4000 ms END OUTPUT Reading the output: the voltage was low at 500 ms and 1000 ms, but only for 500 ms (a count that reached 500 ms of the 2000 ms) before the 7.0 V reading at 1500 ms reset it. That dip is exactly what the debounce is for (a motor start briefly sagging the pack: Robotics Fundamentals 10 section 2). The count then restarted at 2000 ms, and the elapsed time reached 4000 - 2000 = 2000 ms at the reading at 4000 ms, so that is the first time it reports True. Note on resolution: the answer can only be one of the call times, so it is accurate to one sampling period (500 ms here). A condition that has held for 2000 ms is first reported on the first call at or after that. Check on method: a common slip is to test elapsed time without resetting the start when the condition goes false, which makes the debounce fire after 2000 ms of the whole run instead of 2000 ms in a row. Another is to write time.sleep(hold) inside the check, which freezes the robot for the whole wait: see section 5.