After some debugging and head banging I have narrowed an issue to a few lines of code. All I'm trying to do is to normalize the 4 element global array q so that its L2 norm is 1. The relevant code, including debugging output, looks like:
PrintMatrix(q, 1, 4); //prints the array q as a 1x4 matrix
int i;
float c2 = 0.0;
//calculate the norm
for(i = 0; i < 4; i++){
c2 += q[i]*q[i];
Serial.print(c2); Serial.print("\n");
}
//perform a single division first to save time; only multiplies will be needed.
c2 = 1/sqrt(c2);
for(int i = 0; i < 4; i++){
q[i] = c2*q[i];
}
PrintMatrix(q, 1, 4); //prints the array q as a 1x4 matrix
This code appears at the end of an attitude propagation function and gets executed every 20 ms. In general, the code works as expected and everything is happy. However, between 0.1% and 0.2% of the time, the coefficient c2 is set to zero. This proceeds to clobber all attitude information and I have to restart the algorithm. The issue typically occurs in the 2nd, 3rd, or 4th pass through the first for loop. If the issue occurs, c2 changes from a value which is displayed as 1.00 to 0.00 after executing c2 += q[ i ]*q[ i ];.
I can't see a bug in my code so I have tried a number of other equivalent solutions in the hope that I've just been staring at this too long:
-
I replaced the for loop (or rather started with) the function normalize(q, 4) which, as the name implies, normalizes an array of length 4 to a norm of 1. I have used this function in other places of the code where it works as expected.
-
I replaced the for loop and the statement c2 = 1/sqrt(c2); with
float c2 = 1.0/sqrt(sq(q[0]) + sq(q[1]) + sq(q[2]) + sq(q[3]));
- The quaternion q tends to stay close to a norm of 1 for several hundred iterations without renormalization so I added the test
if(c2 < 0.5 || c2 > 2){
c2 = 1.0;
Serial.print("if was true");
}
before and after c2 = 1/sqrt(c2) to try an preserve the attitude information.
As you may have guessed, none of these solutions worked; c2 still occasionally gets set to zero. I find it especially disturbing that the inequality never gets evaluated as true. Here is a sample output:
1.00 -0.06 -0.04 0.00
0.99
1.00
1.00
0.00
0.00 0.00 0.00 0.00
The reason I think it's an addition problem is that inserting Serial.print(q[ i ]*q[ i ]) before or after c2 += q[ i ]*q[ i ]; correctly displays the square of q[ i ]. I am using an Arduino UNO with IDE version 1.0.1 and am completely out of ideas.
As a complete side note, how would you prevent the text from becoming italicized after the statement c2 += q[ i ]*q[ i ]; without adding spaces between the 'i' and the brackets?