Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Counter get stuck on "schedule queue full" error #14

Open
willbelr opened this issue Aug 28, 2021 · 1 comment
Open

Counter get stuck on "schedule queue full" error #14

willbelr opened this issue Aug 28, 2021 · 1 comment

Comments

@willbelr
Copy link

With a "binary" bounded range (-1 or 1), when the "schedule queue full" RuntimeError is encountered in rotary.py, it blocks all future inputs occuring in the same direction. Thus, the rotary encoder must be rotated in the opposite direction to change self._value.

For my use case, the solution was to reverse the saved value on error instead of silencing it :

        try:
            if old_value != self._value and len(self._listener) != 0:
                micropython.schedule(_trigger, self)
        except RuntimeError:
            self._value = 1 if not self.value else 0

However this will break other range modes such as RotaryIRQ.RANGE_UNBOUNDED.

Below is a sample code derived from the async class example:

import uasyncio as asyncio
from rotary_irq_rp2 import RotaryIRQ


class RotaryEncoder():
    def __init__(self, rotary_encoder, callback):
        self.cb = callback
        self.re = rotary_encoder
        self.re.add_listener(self._callback)
        self.re.reset()
        self.event = asyncio.Event()
        asyncio.create_task(self._activate())

    async def _activate(self):
        while True:
            await self.event.wait()
            value = self.re.value()
            if value:
                self.cb(value)
                self.re.reset()
            self.event.clear()

    def _callback(self):
        self.event.set()


async def main():
    def re_callback(value):
        print("$", value)

    RotaryEncoder(RotaryIRQ(pin_num_clk=16,
                            pin_num_dt=17,
                            min_val=-1,
                            max_val=1,
                            range_mode=RotaryIRQ.RANGE_BOUNDED),
                  re_callback)

    while True:
        await asyncio.sleep_ms(10)

try:
    asyncio.run(main())
except (KeyboardInterrupt, Exception) as e:
    print('Exception {} {}\n'.format(type(e).__name__, e))
finally:
    ret = asyncio.new_event_loop()  # Clear retained uasyncio state
@dmccreary
Copy link

n micropython, we get the following error in the rotary class:

line 30: micropython.schedule(self.call_handlers, Rotary.ROT_CW)

Traceback (most recent call last):
File "rotary.py", line 30, in rotary_change
RuntimeError: schedule queue full

In MicroPython, the micropython.schedule() function is used to schedule a function to be called later in the context of the MicroPython scheduler. It's especially useful when you need to call a function in response to an interrupt, but the function might not be safe to call directly from an interrupt context (for example, it may allocate memory).

The error "RuntimeError: schedule queue full" indicates that the internal queue MicroPython uses to keep track of scheduled functions is full. There's only a limited number of slots in this queue.

Here are some reasons why you might be encountering this error:

High Interrupt Rate: If the rotary_change function is getting called very frequently (because of rapid changes in the rotary encoder), it might be trying to schedule more functions than the queue can handle.

Scheduled Function Duration: If the scheduled function (self.call_handlers) takes a long time to execute, it can prevent the queue from being emptied in a timely manner, which means new functions can't be scheduled until the old ones are executed.

Other Scheduled Functions: If other parts of your code are also scheduling functions using micropython.schedule(), they could be filling up the queue, leaving no space for the rotary_change function to schedule its handler.

To solve the problem:

Debounce: If the interrupt from the rotary encoder isn't debounced, you might get multiple interrupts for a single "event". Consider adding a debounce mechanism.

Optimize the Handler: Ensure that the function you're scheduling (self.call_handlers) is as fast as possible. If you can optimize it, you'll free up the queue more quickly.

Check for Other Schedulers: Look through your code to see if other parts of your application are also scheduling functions frequently, and optimize or reduce their frequency if possible.

Direct Handling: If the operation in the scheduled function is simple and doesn't require memory allocation or other operations that aren't safe in an interrupt context, you might consider handling it directly in the interrupt handler rather than scheduling it.

Increase the Queue Size (Advanced): If you're building your own MicroPython firmware, you might be able to increase the size of the schedule queue, though this will consume more RAM.

Remember, the goal is to balance the rate at which functions are added to the schedule queue with the rate at which they're removed (executed). If you can achieve this balance, you won't run into the "schedule queue full" error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants