|
| 1 | + |
| 2 | +# Implementing an IMU/accelerometer/gyro driver? Use the FIFO! |
| 3 | + |
| 4 | +Hi everyone, |
| 5 | +my name is Jon and I work on machine learning for sensor systems, |
| 6 | +including condition monitoring of machines (at [Soundsensing](https://www.soundsensing.no/)), |
| 7 | +and an open-source TinyML library called [emlearn](https://github.com/emlearn/emlearn-micropython). |
| 8 | + |
| 9 | +The usecases we care about often require high quality data and low-power. |
| 10 | +While trying to use MicroPython in this area, I have noticed one limitation in the ecosystem: |
| 11 | +The lack of FIFO support in IMU drivers. |
| 12 | + |
| 13 | +So here is my attempt at raising this concern, and how we could address it :) |
| 14 | + |
| 15 | +## Current state of IMU drivers |
| 16 | + |
| 17 | +Most of the IMU drivers out there today have functions to read the current values |
| 18 | +of the accelerometer/gyro/magnetometer data. |
| 19 | + |
| 20 | +EXAMPLE CODE |
| 21 | + |
| 22 | +When one only does a single readings of the data, this works rather OK. |
| 23 | +For example to check the current orientation of a rarely moving object, say for asset tracking. |
| 24 | + |
| 25 | +However when doing continious sampling, doing this by looping over. |
| 26 | + |
| 27 | +Such continious sampling is needed for example when one tracks a moving object, |
| 28 | +detect gestures, implement a regulation loop (PID), measure vibrations etc. |
| 29 | + |
| 30 | +## Problems with continious sampling using repeated polling |
| 31 | + |
| 32 | +This is less-than-ideal for several reasons: |
| 33 | + |
| 34 | +1. Any variation/delay in time of reading causes uneven sampling of data. Jitter/noise. |
| 35 | +2. Application processor must be constantly running. High power consumption. |
| 36 | +3. Hard for the program to do other work concurrently, while ensuring 1) |
| 37 | + |
| 38 | +These problems become particualy painful at high samplerates, |
| 39 | +or in low-power / battery-powered scenarios, |
| 40 | +or when trying to do multiple things at the same time (concurrency). |
| 41 | + |
| 42 | +These concerns are generally independent of the programming language (more of a system design issue). |
| 43 | +However - there are a couple of reasons why it can easily be more problematic in MicroPython: |
| 44 | + |
| 45 | +1. Variable delays in execution time due to **garbage collection**. |
| 46 | +When MicroPython code executes, there will at some point be a need to do some garbage collection. |
| 47 | +The likelihood increases with how much allocations the code does, |
| 48 | +but can generally happen at any point in time. |
| 49 | +One garbage collection run may take many milliseconds, and will cause the data to be sampled at the wrong time. |
| 50 | +This can mess up the results of most types of analysis, |
| 51 | +be it Digital Signal Processing, control theory, or Machine Learning - because they rely on regularly sampled data. |
| 52 | + |
| 53 | +2. Execution time might be too slow for high samplerates. |
| 54 | +To read at 1kHz+, code would need to spend under 1 ms per iteration, |
| 55 | +which can be hard to achieve in MicroPython. |
| 56 | + |
| 57 | +## The solution: Use the FIFO buffer of the sensor |
| 58 | + |
| 59 | +Any recent digital MEMS IMU will have a buffer that it can collect measurements into. |
| 60 | +Typically this is referred to as a FIFO, since it is a First In First Out type of buffer/queue. |
| 61 | + |
| 62 | +For example the LIS2dh/LIS3dh acceleometers have a 32 samples deep FIFO for its 3 axes. |
| 63 | +The BMA421 can store up to 1024 bytes, allowing to store 170 samples. |
| 64 | + |
| 65 | +When enabling FIFO mode, the sensor itself is responsible for timing the sampling. |
| 66 | +This means that. |
| 67 | +And our application code can then . |
| 68 | +As long as one reads the FIFO before it overflows, one gets perfectly sampled data - with minimum effort. |
| 69 | + |
| 70 | +## How to implement |
| 71 | + |
| 72 | +To support this kind of usage, the IMU driver should have: |
| 73 | + |
| 74 | +- A function to enable FIFO sampling mode |
| 75 | +- A function to read the FIFO fill level |
| 76 | +- A function to read data from the FIFO. A) |
| 77 | +- Optionally: A function to enable interrupts. B) |
| 78 | + |
| 79 | +A) I recommend that the data reading returns the raw bytes. |
| 80 | +This enables the application to decide when/if to convert to a physical unit such as gravity. |
| 81 | + |
| 82 | +B) Most IMUs also support triggering an interrupt |
| 83 | +when the FIFO fill level has reached a certain threshold (watermark). |
| 84 | +This can be useful to get absolutely the most out of, but is not critical. |
| 85 | +One can still get most of the benefits still by polling the FIFO level |
| 86 | +and triggering readout based on that. |
| 87 | +It might also be that the interrupt pin is not connected, only I2C/SPI pins, |
| 88 | +so one should still support usage without interrupts. |
| 89 | + |
| 90 | +## Application pseudo code |
| 91 | + |
| 92 | +Here is some illustrative code for how such a driver could be used |
| 93 | +to implement low-power continious data analysis of short time-windows of IMU data. |
| 94 | +This could for example be human activity detection on a smartwatch, |
| 95 | +gesture detection for a "magic wand", |
| 96 | +animal activity detection on a LoRa tracker, et.c. |
| 97 | + |
| 98 | +``` |
| 99 | + SAMPLERATE = 25 |
| 100 | + THRESHOLD = 25 |
| 101 | + imu = SuperIMU2k(i2c=machine.I2C(...), odr=SAMPLERATE) |
| 102 | +
|
| 103 | + while True: |
| 104 | + level = imu.get_fifo_level() |
| 105 | + if level < THRESHOLD: |
| 106 | + samples = imu.read_fifo_data(THRESHOLD) |
| 107 | +
|
| 108 | + # should take 100 ms or less. Otherwise compensate the sleep time |
| 109 | + process_samples(samples) |
| 110 | +
|
| 111 | + machine.lightsleep(900) |
| 112 | +``` |
| 113 | + |
| 114 | +## Call to Action: Use the FIFO! |
| 115 | + |
| 116 | +So next time you are implementing a driver for an IMU, please consider supporting using the FIFO! |
| 117 | +It will make the driver much more powerful and useable for a wider range of scenarios, |
| 118 | +enabling people to get higher data quality and lower power consumption. |
| 119 | + |
| 120 | + |
| 121 | +## Drivers with FIFO support |
| 122 | + |
| 123 | +Here is an initial start of divers that support FIFO. |
| 124 | +Please let us know if you have made, or found more, and we can link them here! |
| 125 | + |
| 126 | +- [BMA423](https://github.com/antirez/bma423-pure-mp/pull/5) |
| 127 | +- [LIS2DH/LIS3DH](). FIXME: publish a gist |
| 128 | + |
| 129 | + |
0 commit comments