I have spent a few days to sort out the Inverse Kinematics formulas. My mathematics skills have been much better in the old days. As I am using an AVR ATmega2560 I did the implementation in fixed point integers. As everyone knows float calculations are much too slow.
It took me days to get atan, acos and sqrt functions working. I need reasonable resolution (<1°) and reasonable sized lookup tables. But generally flash isn’t an issue, the ATmega2560 has 128 kByte of it.
For the automated testing, that I always implement, I did check my integer functions against their double precision counterparts. And as the AVR has timers, I also tracked the execution times. I was surprised.
|min / avg / max|
|min / avg / max
|sqrt||24 / 38 / 56||28 / 31 / 36
|acos||48 / 49 / 52||128 / 160 / 176
|atan||140 / 152 / 160||168 / 184 / 204
|inverse kinematics||544 / 559 / 580||829 / 926 / 976
Ok, double is slower than 16 bit integer. But, the overall difference is only 70%, but accuracy is much higher. The inverse kinematics results calculated with integers differ by 5° maximum, the double results are better than 0.1°. Writing the fixed point functions took about 4 days, the double version 30 minutes. The planning of accuracy and operand length for fixed point integer is a pain.
What do I take from this:
- Never optimize before I have the proof that I need to.
- Double isn’t as bad as I thought. And much much easier to handle.
- I’ll use double for the project. As I am planning to split the control to leg and body control to multiple processors, I should have enough resources to get a reasonable cycle time.
- If not, I can optimize later.
After some debugging here, cutting away code here and there, recovering from frustration, and some other magical moves, I found … a buffer-overflow of an itoa(). I love it. It did garble the stack, resulting in a restart loop. Pure magic, dark magic. I hoped for something honorable, like a compiler bug.
One of my favorite from http://natashenka.ca/posters/ seen at 30c3. There are more!
Microcontroller code is simple. No memory allocation, very few pointers, simple structure. Ok, there are interrupts, but they can be managed.
But why does it always end up in hunting strange bugs? A few weeks ago I started writing the code for a smooth linear motion. I thought that would be a good exercise for more complex motion code I’d begin with soon. Then I also wrote a test for this function. I am now always developing formal tests. The time you spend on the tests is much less then hunting the bugs in the production framework. For the microcontroller I am using AceUnit.
Now a few weeks passed by and I still didn’t get much further. The test produced garbled output and did restart in a never ending loop. Strange. Luckily, that happened with a rather simple test case. I did strip it down. The output did change unpredictably. I stripped it down further, and found a few bugs in the serial output code. I use the serial output for debugging, unfortunately the Arduino doesn’t support the standard connectors for an Atmel debug device. I fixed the code, not understanding why it could have lead to a restart loop, but in good hope. After restoring the test framework, I ran the test case again, and it still looped forever. At least the output looks nicer now. It is a Boojum, for sure.
By the way, ‘The Hunting of the Snark’ by Lewis Carroll is a wonderful poem, worth to read. With brilliant ideas, as you would expect from him. I have a reprint with the original steel engravings, like the one on the left.