m-lundberg / simple-pid

A simple and easy to use PID controller in Python
MIT License
801 stars 217 forks source link

MicroPython Port. #64

Open beyonlo opened 2 years ago

beyonlo commented 2 years ago

Hello!

Do you have plans to support the MicroPython?

I think that on the pid.py needs just to change the import warnings to an equivalent in MicroPython, right?

And about the performance, maybe needs change something more to better fit on the MicroPython?

Thank you.

m-lundberg commented 2 years ago

Hi!

I have never used MicroPython or CircuitPython myself so I currently have no idea what would be needed to support those platforms.

The warnings module was removed in #63 , so that should no longer be an obstacle.

Regarding performance, this library was not written with optimal performance in mind. Personally, if performance was important for a project I would not use Python for it usually. But again, I don't know about MicroPython or CircuitPython.

If there are other things which are needed to support MicroPython and/or CircuitPython, please comment! When I have more of a grasp of how much work it would be I will decide if it should be officially supported.

eirinnm commented 2 years ago

With the warnings import removed, this library works perfectly in CircuitPython. Performance on an ESP32 is totally adequate for a PID loop.

beyonlo commented 2 years ago

@eirinnm That's a great news! If works on the CircuitPython, so probably works on the MicroPython as well :)

Thank you all!

m-lundberg commented 2 years ago

Thanks for the feedback, that's good to hear!

According to the MicroPython docs, there is no time.monotonic() available on that platform, and time.time() only returns an integer (as reported in #67). I intend to solve this by introducing PID.time_fn that you can override to specify which time function should be used. In the end it should work in MicroPython by using it like this:

pid = PID()
pid.time_fn = time.ticks_us  # For example, use which time function you want

# Use pid as normal
m-lundberg commented 2 years ago

Another thing that needs to be done if MicroPython and/or CircuitPython should be officially supported is to add some documentation for it.

RedKrieg commented 2 years ago

I ran in to a problem with using time.ticks_us when the ticks wrapped around. I solved this by changing the dt calculation in __call__ to add a test that the result of (now - self._last_time) > 0 and to use self.sample_time instead of the previous 1e-16:

dt = now - self._last_time if (now - self._last_time > 0) else self.sample_time

I chose to use self.sample_time for two reasons, first I am working with integer time values on micropython and second to force an update to self._last_time by running through the rest of the function. This could probably be improved further by adding a test for sys.platform.name == "micropython" and using time.ticks_diff() to calculate now - self._last_time, but I didn't want to add additional platform-specific code inside the "main loop".