I apologize for my lack of posts in the last year. My multicopter projects have taken a back seat to some other interests and to "real life" priorities. I anticipate putting more time into posting about what I am doing over the winter. As part of that, I have started uploading some of my Arduino libraries to my Github account. These are libraries that I have personally written for my quad copter project. I have a couple of disclaimers in relation to these libraries:
- I am an amateur coder. These are written to accomplish things the way I think they should be done. There are probably better ways to do everything I do.
- These are written for the Arduino platform and will work for both 8-bit Atmel processors and the 32-bit SAM. Although the code is basic C++, I will not be adjusting them to work outside of the Arduino platform.
- I would love feedback from anyone who finds these libraries useful. Having said that, I generally will not be adding additional functionality to them unless it benefits me. I know that sounds selfish, but I only have a limited amount of time and coding for others when I could be working on my own projects just isn't in the cards at this time.
- I am working on the documentation for these libraries, but it's probably never going to be perfect. If experimenting and reading the code in my libraries to figure out how things work doesn't sound like fun to you, then these may not be the right libraries for you.
- These are a work in progress.
Ok, now that that's out of the way, here's the fun stuff. I have uploaded the first two libraries and they are used for sensor filtering.
Median Filter:
This is an one dimensional filter that receives data as INT data type and sorts it from highest to lowest value and returns the median result. This type of filter can be very good at rejecting "spikey" noise while not introducing a large filter lag. I use this on my accelerometer readings due to the level of noise I see from motor and propeller vibration.
Usage:
#include
MedianFilter filterObject(window size, filter seed); // Object creation.
...
filteredData = filterObject.in(rawData); // use the "in" method when adding data to the object, it returns the latest result.
...
filteredData = filterObject.out(); // use the "out" method to retrieve the current result without submitting new data.
Average processing time (micro seconds) when submitting new data (given certain window sizes):
3 | 7 | 15 | 31 | 63 | 127 | 255 | |
Due | 2.11 | 3.27 | 5.39 | 9.56 | 17.8 | 34.3 | 67.5 |
328-16 | 18.0 | 29.4 | 50.5 | 92.3 | 176 | 340 | 677 |
Notes:
Avoid using a lot of these with large windows sizes. Although I have tried to keep the memory needs as small as possible, the amount of memory needed to store a lot of numbers adds up quickly.
Low Pass Filter
This is an one dimensional, exponential decay, low pass filter. It accepts data type INT. I prefer this filter over a sliding window filter for a couple of reasons. The first is that is is very fast, even on the 8-bit processors. The second reason is that new data has the highest effect immediately after it is added to the filter, and has diminishing effect as new samples are added. This contrasts to a sliding window where the data has constant effect as long as it exists in the window. Both filter types have equivalent long term effects.
Usage:
#include
LowPassFilter filterObject(filtering power, filter seed); // Object creation.
...
filteredData = filterObject.in(rawData); // use the "in" method when adding data to the object, it returns the latest result.
...
filteredData = filterObject.out(); // use the "out" method to retrieve the current result without submitting new data.
Processing time (micro seconds) when submitting new data (based on filtering power):
1 | 2 | 3 | 4 | |
Due | 0.48 | 0.48 | 0.48 | 0.48 |
328-16 | 2.9 | 3.2 | 3.5 | 3.8 |
Notes:
Each increase in filtering power doubles the effect of this filter. Both the "lag" and the "smoothing" effect are doubled. A filter power of zero has no effect on the data.
I have designed these two filters so that I can "stack" them as follows:
filteredData = LPF_object.in(MF_object.in(rawData));
When I get around to uploading my library for the Invesense MPU-6050, it will be more apparent why I have done this. In addition, you will notice that both of these filters use data type int, this is intentional as it is much faster this way. My final control/orientation computations are done as floats/doubles but avoiding converting to them until as late as possible helps keep my control loops from getting too slow.
Over the next month I intend to release the following libraries:
MPU6050 - my library for the Invesense MPU-6050 (nearly finished, re-verifying it's function)
Math3D - my Quaternion and 3D vector library (re-writing to include operator overloading)
My next post, I will be discussing my experience with my Multicopter I/O Shield (MIOS) and my future plan for it.
That is all for now. Let me know if you have any questions.
Thanks for reading and please sign up on the right if you want to be automatically notified when I post more updates.
~Phillip
No comments:
Post a Comment