Persistence-of-vision projects like our SpokePOV kit use a magnetic Hall effect sensor to gauge both time and position — a magnet on the bike frame or fork provides an absolute point of reference as the wheel spins.
At least once a week we’re asked whether it’s possible to do this sort of “cyclical” persistence-of-vision freestanding without a frame — perhaps on a staff or spinning poi — could it be done with data from an accelerometer or gyro?
In theory, yes, even a basic accelerometer should provide sufficient data to do this…but it’s like finding a whisper in a sandstorm of noise. Those with the know-how are probably (I hope) off earning good money designing consumer products like fitness trackers and game controllers, using signal processing and higher math to pull the subtlest gestures from the cheapest possible sensors.
For those of us less enlightened, I’d been wondering if the BNO055 9-DOF absolute orientation sensor might provide us a crutch. This chip combines accelerometer, gyro and compass along with some math to provide more “meaningful” numbers — for example, it can distinguish between gravity and the device’s own acceleration vector separately. Could this get us muggles where we want to be?
The gyro should give a pretty good indication of current rotation rate, but we need an absolute frame of reference — an up or a down — to create steady, repeating images. Maybe we could poll for the device’s absolute orientation, or alternately the gravity vector, watching for changes where we’re pointing “up-ish” or “down-ish” to establish a horizon line.
I threw together a “napkin sketch” with the sensor, an Arduino board, battery and some NeoPixels for visual feedback, and the requisite cable ties (they’re cleaner than duct tape), plus a little code:
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BNO055.h> #include <Adafruit_NeoPixel.h> Adafruit_BNO055 bno = Adafruit_BNO055(); Adafruit_NeoPixel strip = Adafruit_NeoPixel(15, 4); void setup(void) { bno.begin(); bno.setExtCrystalUse(true); strip.begin(); } boolean prev; void loop(void) { imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_GRAVITY); boolean plusx = (euler.x() >= 0); if(!prev && plusx) fill(0xFF0000); // RED = Change from -x to +x else if(prev && !plusx) fill(0x00FF00); // GREEN = Change from +x to -x delay(10); fill(0); prev = plusx; } void fill(uint32_t color) { for(uint8_t i=0; i<15; i++) strip.setPixelColor(i, color); strip.show(); }
The result:
Does it work? No, not quite. Could it work? I suspect so. Biggest issues are lag (a delay from when a measurement is taken and when the Arduino reads it, which can be compensated for), and temporal aliasing (“time jaggies” resulting from the different interval at which the BNO055 performs its “sensor fusion” math — about 100 Hz — and the speed of rotation (which might not be an even multiple of that interval), and how often we’re polling the device.
In the video, notice the red and green flashes, which should indicate when the device crosses the horizon as it’s moving up or down. It’s not just that they’re off (lag), but that they drift (not seen in the short video: it doesn’t continually drift, but jumps back periodically). Our makeshift poi is spinning at about 2 Hz, meaning only 50 distinct samples per loop…rather coarse resolution.
So the bad news: no, there’s no quick and easy solution to the freestanding POV problem, yet.
The good news: with the BNO055 I suspect we’re halfway there, that a little more work could produce a steady image. Maybe not perfect, but good enough is my suspicion.
This was a few minutes’ kludge. One could surely do better…maybe using the gyro as a primary data source, and one of the other readouts as a sanity check, that our gyro-derived position estimate is getting ahead or behind? Maybe the gravity vector is a bad choice? There are countless things that could be done with a little more thought and testing.
Hi,
with a rotating "rope" like in the picture, there is still a fixed pivoting point in the hand, so a rotary encoder could be put there, that’s what I am experimenting with for version 2 of my JMP-rope http://ao2.it/103
However it is true indeed that a freestand solution is more general and would work better for poi balls and even for for something like a bo staff or a devilstick.
Keep up the good work.
Ciao ciao,
Antonio