# ENOMEM with Encoder State Machine

**URL:** <https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192>\
**Category:** Python programming\
**Created:** [December 13, 2023, 1:57pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192 "2023-12-13T13:57:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![k.siegall](https://avatars.discourse-cdn.com/v4/letter/k/ad7895/32.png) [@k.siegall](https://xrp.discourse.group/u/k.siegall)\
**Post date:** [December 13, 2023, 1:57pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/1 "2023-12-13T13:57:13Z")

</div>

Student received an ENOMEM error when trying to run his code.

Stack Trace:

```auto
Traceback (most recent call last):
  File "/lib/XRPLib/imu.py", line 537, in <lambda>
  File "/lib/XRPLib/imu.py", line 544, in _update_imu_readings
  File "/lib/XRPLib/imu.py", line 282, in get_gyro_rates
  File "/lib/XRPLib/imu.py", line 142, in _raw_to_mdps
RuntimeError: maximum recursion depth exceeded
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "grid_pathing.py", line 1, in <module>
  File "xrp.py", line 2, in <module>
  File "drive_code.py", line 1, in <module>
  File "lib/XRPLib/defaults.py", line 17, in <module>
  File "lib/XRPLib/encoded_motor.py", line 27, in get_default_encoded_motor
  File "lib/XRPLib/encoder.py", line 27, in __init__
OSError: [Errno 12] ENOMEM

```

I tried checking the state machines manually, and saw the following message:

```auto
rp2.PIO(0).state_machine(0).active(): False
rp2.PIO(0).state_machine(1).active(): False
rp2.PIO(0).state_machine(2).active(): False
rp2.PIO(0).state_machine(3).active(): False
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "debug.py", line 12, in <module>
  File "debug.py", line 10, in report_state_machines
ValueError: StateMachine claimed by external resource

```

debug.py is as follows:

```auto
def report_state_machines():
    for p in (0, 1):
        for sm_c in range(4):
            fmt = "rp2.PIO(%d).state_machine(%d).active(): %s"
            print( fmt % (p, sm_c, rp2.PIO(p).state_machine(sm_c).active()))
            
report_state_machines()

```

I’ve seen this error pop up before, but I don’t remember how I solved it then.

---

<div class="post-metadata">

**Author:** ![k.siegall](https://avatars.discourse-cdn.com/v4/letter/k/ad7895/32.png) [@k.siegall](https://xrp.discourse.group/u/k.siegall)\
**Post date:** [December 13, 2023, 3:12pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/2 "2023-12-13T15:12:11Z")

</div>

Error persists across robots with his code, but it was solved by putting all user code in one file, so maybe the cause has something to do with importing `XRPLib.defaults` multiple times?

---

<div class="post-metadata">

**Author:** ![SparkFro](https://yyz1.discourse-cdn.com/flex011/user_avatar/xrp.discourse.group/sparkfro/32/12_2.png) [@SparkFro](https://xrp.discourse.group/u/SparkFro)\
**Post date:** [December 13, 2023, 5:18pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/3 "2023-12-13T17:18:20Z")

</div>

I’m having trouble recreating this. Tried chaining multiple files that all `import XRPLib.defaults`, manually created more than 4 Encoders, etc. but can’t recreate it. Are you able to share the student’s code? Looks like it occurs in only the first few lines, so you should be able to strip out the rest of the code. Or perhaps you can find some simpler code to recreate it?

The traceback is confusing to me, since it includes both the IMU and the encoder. Are they at all related to each other, or was it just coincidental timing? Since the IMU runs on a timer, my guess is the main thread happened to be setting up the encoders when the IMU timer triggered, and that’s actually what ran into trouble. I think the encoder stuff is a red herring; running your debug.py after importing `XRPLib.defaults` returns the same `ValueError` despite no other issues existing. So I think we need to look closer at the IMU.

Looking at the traceback, there’s `maximum recursion depth exceeded` and `ENOMEM`, which I believe means the RP2040 ran out of RAM. Does the student’s code import a big file or library or something? Or is the IMU code somehow recursing forever? Can you add some memory logging to the code to maybe figure out what’s eating it up?

---

<div class="post-metadata">

**Author:** ![Fgrossman](https://avatars.discourse-cdn.com/v4/letter/f/b77776/32.png) [@Fgrossman](https://xrp.discourse.group/u/Fgrossman)\
**Post date:** [December 14, 2023, 1:49am UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/4 "2023-12-14T01:49:59Z")

</div>

Is it possible to upload the files, or create a simplified version the recreates the problem for us to debug? It looks like you had 3 files. Where you importing the whole files or just functions within the files?

---

<div class="post-metadata">

**Author:** ![SparkFro](https://yyz1.discourse-cdn.com/flex011/user_avatar/xrp.discourse.group/sparkfro/32/12_2.png) [@SparkFro](https://xrp.discourse.group/u/SparkFro)\
**Post date:** [December 14, 2023, 4:23pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/5 "2023-12-14T16:23:52Z")

</div>

Code was share privately, working through it now.

Found a simple way to recreate the encoder error. Paste the following in the shell:

```auto
from XRPLib.defaults import *
from lib.XRPLib.defaults import *

```

Results in:

```auto
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lib/XRPLib/defaults.py", line 17, in <module>
  File "lib/XRPLib/encoded_motor.py", line 27, in get_default_encoded_motor
  File "lib/XRPLib/encoder.py", line 27, in __init__
OSError: [Errno 12] ENOMEM

```

---

<div class="post-metadata">

**Author:** ![SparkFro](https://yyz1.discourse-cdn.com/flex011/user_avatar/xrp.discourse.group/sparkfro/32/12_2.png) [@SparkFro](https://xrp.discourse.group/u/SparkFro)\
**Post date:** [December 14, 2023, 4:33pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/6 "2023-12-14T16:33:32Z")

</div>

Played around some more, looks like the TLDR is only ever use _either_ `from XRPLib.defaults import *` _or_ `from lib.XRPLib.defaults import *`, but not both. If either is run multiple times, the import is “skipped” on successive imports, so there’s no issue. But if both are run, then it effectively does the import all over again, which in this case attempts to create the IMU and encoders twice, which leads to the error messages above.

---

<div class="post-metadata">

**Author:** ![Fgrossman](https://avatars.discourse-cdn.com/v4/letter/f/b77776/32.png) [@Fgrossman](https://xrp.discourse.group/u/Fgrossman)\
**Post date:** [December 21, 2023, 10:00pm UTC](https://xrp.discourse.group/t/enomem-with-encoder-state-machine/192/7 "2023-12-21T22:00:56Z")

</div>

TLDR - We better understand the problem and will put a fix into the next XRPLib release.

For those that want to under stand it all.  
I did a little research and here is what I learned. The place that acts as the cache lookup is `sys.modules` . This keeps a dictionary of module names and locations. But, when they do a module lookup they look at the module name, not the location. So the implicit name `XRPLib.defaults` is different from the explicit name `lib.XRPLib.defaults` , even though they map to the same location. The second part is that `defaults.py` uses relative imports for importing the different parts of XRPLib. For instance `from .encoder import Encoder` . When the loader loads a relative import it starts with the relative location of the parent. Which is either the implicit or explicit name used to import `defaults.py` . This means when `lib.XRPLib.defaults` is used it tries to load all the relative ones the same way, making for new entries in the `sys.modules` . The quick fix, which I tested, was to make` defaults.py` use the implicit loading of the imports `from XRPLib.encoder import Encoder` . While this will still load two different versions of `defaults.py` all the other imports will be already in the cache and all the local variables in defaults will point to the same objects and none will be reloaded. This does mean that that defaults will only work when in a directory named XRPLib, I do not see it as a problem for this project.
