I have three figures: a cube, an octahedron, a dodecahedron.
Inside, each figure has an accelerometer.
The sides of the figures numbered between 1 and n.
Task: determine the current side of the cube, octahedron, dodecahedron.
For the cube, I derived the formula:
side = round((Ax*1/988)+(Ay*2/988)+(Az*3/988));
Variable "side" will give values in interval -3 and 3 (without 0), which means the current side of cube between 1 and 6.
Now I need to do the same for the octahedron and the dodecahedron. Help, how can I do this? Do I need additional sensors or accelerometer is enough?
Using a formula like that is quite clever but it has some undesirable properties. Firstly, when moving from one side to another, it will move through some intermediate values as a result of the formula that are geometrically meaningless. For example, if you are on side -3 and rotate to side -1, it will necessarily move through -2. Secondly it may not be robust to noisy accelerometer data, for example a vector that is part way between sides -3 and -1, but closer to -1 may give -2, when it should give -1.
An alternative approach is to store an array of face normals for the figure, and then take the dot product of the accelerometer reading with each of them. The closest match (the one with the highest dot product) is the closest side.
e.g:
float cube_sides[6][3] = {
{-1, 0, 0},
{0, -1, 0},
{0, 0, -1},
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
};
int closest_cube_side(float Ax, float Ay, float Az)
{
float largest_dot = 0;
int closest_side = -1; // will return -1 in case of a zero A vector
for(int side = 0; side < 6; side++)
{
float dot = (cube_sides[side][0] * Ax) +
(cube_sides[side][1] * Ay) +
(cube_sides[side][2] * Az);
if(dot > largest_dot)
{
largest_dot = dot;
closest_side = side;
}
}
return closest_side;
}
You can extend this for an octahedron and dodecahedron just by using the surface normals for each. No additional sensors should be necessary.