Look at almost any sensor's datasheet and you'll find that measurements are always given as an increment +/- an amount of error which impact the accuracy. Typically, these inaccuracies are counteracted by a technique called oversampling where several readings are taken in succession and then averaged together to give a value that is more stable. However, this process is destructive as the underlying distribution of values is destroyed in order to create that singular reading, not to mention how it now takes several readings of the sensor to produce one value- much slower!
Signaloid's UxHw technology, on the other hand, allows for these distributions to be natively tracked in the CPU's hardware rather than relying on either the sensor to oversample or the software reading from the sensor to execute expensive statistical operations for greater fidelity. And with the release of their C0-microSD, this tracking functionality is now accessible on an FPGA-based board with a Micro SD card form-factor.
This project uses a combination of a 9-axis inertial measurement unit (IMU), host PC, and a C0-microSD plugged into that host to improve the positional accuracy of the accelerometer over time by using the true, weighted mean of values instead of oversampled ones.
Setting up the hardware and reading valuesThe IMU of choice in this project was the ICM-20948 due to its fast polling rate and scalable output which can range between +/-2g all the way up to +/-16g. Using the QWIIC breakout from SparkFun, I connected it to one of my custom RP2040-based boards and wrote a simple program that continuously checks if the sensor has a new reading available. Once it does, the raw readings from each axis are pulled and written to a CSV file on an attached Micro SD card, as well as a rolling average value for each of the three accelerometer axes.
After transferring the raw values to my PC, I created another two applications. First, there is a Python host script that parses the CSV, sends some of the raw values to the C0-microSD, gets the results, and then outputs them to another CSV file. Note: this project demonstrates how the C0-microSD can be used to compute values via the UxHw API and does not take advantage of its uncertainty-tracking capabilities. A simple application that exercises this feature set can be found here, and a more advanced one which implements a Gaussian Process machine learning algorithm can be seen here on GitHub.
The second program is the actual firmware running on top of the custom RISC-V instruction set architecture that the C0-microSD has been flashed with. To flash it, start by cloning the repository and then plugging in the C0-microSD card.
$ git clone --recursive https://github.com/having11/IMU-Fidelity-with-Signaloid-C0-MicroSD
# To update submodules:
$ git pull --recurse-submodules
$ git submodule update --remote --recursive
The light should be a solid red, and if it's not, run
$ cd submodules/C0-microSD-utilities
# Here, /dev/disk4 is the path to the device; adjust to match what shows on your host
$ sudo python3 C0_microSD_toolkit.py -t /dev/disk4 -s
Then upload the program
$ cd signaloid-soc-application
# Modify the DEVICE flag in Makefile to match the device's path
$ make flash
$ make switch
# LED should be blinking green now
# Power cycle the C0-microSD
Follow the instructions in the README for more information about how to modify this project and flash your own version(s).
About the SoC programAt a high level, there exist several memory locations that act as registers for setting status/commands or as buffers which allow data to be passed between the device and the host over the block device protocol. The C0-microSD exposes a command called kCalculateWindow
wherein the array of values is set inside of the MOSI buffer and processed.
A 1D distribution of floating-point samples is created (the window of accelerometer values for a single axis) before the variance
and mean
are taken using Signaloid's native uncertainty tracking architecture and UxHw library. To get the weighted mean, the function uses the variance to compute the relative weight of each value, and once all values in the distribution have been computed, a call to UxHwFloatDistFromWeightedSamples
quickly returns the weighted mean which is sent back to the host and stored.
With the resulting array of weighted averages now back on the host, the three axes get placed into the existing input data CSV rows which creates a new output CSV. The final step involves reading these weighted values into a program created by GitHub user Anthony Nasr which integrates them using a Kalman filter over time to give the estimated positions of the device as it moves through 3D space. As seen in these graphics, using the weighted mean values instead of the simple sliding window gives a far more accurate picture of the positions:
To get started, you can visit the project's repository here on GitHub.
Comments