Very nice worked example. A couple of other answers are still bothering me:
Would it hurt to go belt and braces and try
float tr = (float) micros();
This literally does nothing. Conversion of arithmetic types is always automatic in assignments.
Similarly, I believe sqrt() expects doubles and returns a double, use sqrtf to return a float.
This is true (about the return type). But it isn't required that double be of any greater precision than float: on small MCUs this could be a compiler option. The compiler can also infer from the destination of the expression (initializer to
float velocity) that greater precision isn't needed, in some cases (not this one).
Whenever I see code that uses floating point and I don't see NAN--well there is always a problem. Pretty much any code that needs to work in a non-hobby environment needs to check validity of inputs and outputs using NAN (look it up).
Silent exceptions are only one possible way to manage exceptional conditions in arithmetic. It is usually better to set the mode register to trap them, and use a SIGFPE handler or equivalent.
Time is often an issue and sure enough you have: "float t1=micros(); float td=micros()-t1;" So, here, td can be either zero or negative (on some platforms, maybe not yours). So any division by td is now suspect (NAN!).
You cannot expect to divide by a time variable in any program when the length of time may be zero units. This is a logic error (which should be found at the flowchart stage), not a coding issue. If your calculation was with integer types then you do not get notice of overflow (NaNs or otherwise): the program is just undefined.
Just took another look at micros() definition; it's EVIL!. " This number will overflow (go back to zero), after approximately 70 minutes." So, yeah, that's a totally unreliable number--what if you catch it at a transition. OMG. Useless.
Time counters are defined and intended to be used with unsigned arithmetic, where no such problems occur. If the program is
unsigned long tr = micros(); unsigned long td = micros()-tr;, then
td will always be the period of time between the two statements, and cannot underflow.