@@ -16,20 +16,48 @@ So here is my attempt at raising this concern, and how we could address it :)
16
16
17
17
Most of the IMU drivers out there today have functions to read the current values
18
18
of the accelerometer/gyro/magnetometer data.
19
-
20
- EXAMPLE CODE
19
+ Each call of the function returns a single datapoint in time.
20
+ Example: ` (x, y, z) = get_xyz() ` .
21
21
22
22
When one only does a single readings of the data, this works rather OK.
23
23
For example to check the current orientation of a rarely moving object, say for asset tracking.
24
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.
25
+ However many applications requires continious sampling of several samples.
26
+ Examples includ tracking a moving object, detect gestures,
27
+ implement a regulation loop (PID), measure vibrations etc.
29
28
30
29
## Problems with continious sampling using repeated polling
31
30
32
- This is less-than-ideal for several reasons:
31
+ Here is example code for continious sampling,
32
+ at a slow 25 Hz and processing 1 second time-windows.
33
+ This could for example be human activity detection on a smartwatch,
34
+ gesture detection for a "magic wand",
35
+ animal activity detection on a LoRa tracker, et.c.
36
+
37
+ ```
38
+ SAMPLERATE = 25
39
+ THRESHOLD = 25
40
+ sensor = SomeIMU(i2c=machine.I2C(...))
41
+ samples = []
42
+ while True:
43
+ t = time.ticks_ms()
44
+ xyz = sensor.get_xyz()
45
+ samples.append(xyz)
46
+
47
+ if len(samples) == THRESHOLD:
48
+ process_samples(samples)
49
+ samples = []
50
+
51
+ # Try compensate for execution time causing variation in data sampling time
52
+ # But - if more than 1/SAMPLERATE (4ms for 25 Hz) - will miss the entire timestep...
53
+ time_spent = time.ticks_diff(time.ticks_ms(), t)
54
+
55
+ # Very little benefit from lightsleep on very short durations
56
+ wait_time = max(1000/SAMPLERATE - time_spent, 0)
57
+ time.sleep_ms(wait_time)
58
+ ```
59
+
60
+ Doing continious sampling by fetching single samples is less-than-ideal for several reasons:
33
61
34
62
1 . Any variation/delay in time of reading causes uneven sampling of data. Jitter/noise.
35
63
2 . Application processor must be constantly running. High power consumption.
@@ -47,8 +75,8 @@ When MicroPython code executes, there will at some point be a need to do some ga
47
75
The likelihood increases with how much allocations the code does,
48
76
but can generally happen at any point in time.
49
77
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 .
78
+ This can mess up the results of many types of analysis - because they rely on regularly sampled data.
79
+ Most methods from Digital Signal Processing, control theory, or Machine Learning.
52
80
53
81
2 . Execution time might be too slow for high samplerates.
54
82
To read at 1kHz+, code would need to spend under 1 ms per iteration,
@@ -89,28 +117,30 @@ so one should still support usage without interrupts.
89
117
90
118
## Application pseudo code
91
119
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.
120
+ Here is some illustrative code for how such a driver could be used in the same scenario as above.
121
+
97
122
98
123
```
99
124
SAMPLERATE = 25
100
- THRESHOLD = 25
125
+ THRESHOLD = 25 # NOTE: Should be max 75% of IMU FIFO capacity
101
126
imu = SuperIMU2k(i2c=machine.I2C(...), odr=SAMPLERATE)
102
127
103
128
while True:
104
129
level = imu.get_fifo_level()
105
130
if level < THRESHOLD:
106
131
samples = imu.read_fifo_data(THRESHOLD)
107
132
108
- # should take 100 ms or less. Otherwise compensate the sleep time
133
+ # Can take up to 100 ms without needing to compensate sleep time
134
+ # Or up to 1000ms if one does the compensation
109
135
process_samples(samples)
110
136
111
- machine.lightsleep(900 )
137
+ machine.lightsleep(100 )
112
138
```
113
139
140
+ This code will spend 90-99% of the time in lightsleep, for 10-100x power savings.
141
+ It will also just work if using high samplerates (1000 Hz+).
142
+ And the same approach will work to collect data from multiple sensors at the same time.
143
+
114
144
## Call to Action: Use the FIFO!
115
145
116
146
So next time you are implementing a driver for an IMU, please consider supporting using the FIFO!
0 commit comments