Motorized knee" on the mill works great now!

It took a lot of work, but everything is great now.
First, tuning was complicated because everything is "different". The
knee has to move over 1,000 lbs of metal, using a high friction mechanism, and a "springy" transmission.
Finally, I realized that I need to greatly increase P and I terms and that took the following error way down -- it is always well under 0.001".
I also reduced max acceleration big time, as I realized that I was stressing the machine comlpetely unnecessarily.
The next issue was that in steady state, when not really moving it, the servo motor was heating up from residual current. This is because the PID loop in EMC2 was obsessively trying to move the motor that "last hair", against friction, not really strongly enough to actually move it.
I am sure that, if not fixed, it would fry the little motor one day. It was completely unnecessary, since the ACME screw is self locking.
Andy Pugh on EMC-Users list suggested a "timeout" component that would, after 10 seconds of inactivity, turn off the current to the knee servo motor. After 1.5 more hours of chasing a weird FPU comparison issue, the component is now working. So, the motor turns off completely after 10 seconds of inactivity.
To sum it:
1) The knee moves at a perfectly acceptable speed (1cm per second or so) 2) It moves smoothly, with low acceleration (which reduces stresses on everything) 3) The following error is always under 0.001 4) After 10 seconds following completion of a move, the motor turns off and uses zero current.
There is a couple of things still to be done.
a) Install limit and home switches for the knee b) Investigate a mechanical issue with the setup, whereby the gearmotor is somehow not perfectly coaxial and wobbles aruond its axis of rotation. It is as if the crank handle shaft is bent slightly or something.
i
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

CLIP
Photos, video? Would love to see a video...
--


Regards,
Joe Agro, Jr.
  Click to see the full signature.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

I will try. Good idea. I want to restore functioning of the rotary table first. I had to use the output that I used for rotary table, for the knee, because I was waiting to get an additional digital to analog converter card from Jon. I have it now and I need to restore. Then I will do a grand finale type of video, demonstrating all capabilities of the mill -- X, Y, Z, rigid tapping, 4th axis, and W axis (motorized knee).
i
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Ignoramus20691 wrote: <snip>

The only sure way to do floating point comparisons, that I know of is:     if( fabs(a - b) < epsilon )
I usually pick epsilon, at least 100 X smaller than the tolerable error.
This problem has been causing headaches for 50 years, and will probably continue to do so for another 50. After that I won't care. :-) 1.5 hours is pretty good. I've seen people spend days, and never find it.
<snip>

--
Gary A. Gorgen | "From ideas to PRODUCTS"
snipped-for-privacy@comcast.net | Tunxis Design Inc.
  Click to see the full signature.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Gary A. Gorgen wrote:

With Microsoft C epsilon is defined in float.h for both float and double data types.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
David Billington wrote:

I don't use anything Microsoft, so I don't know. What does Microsoft C do about the comparison ? What is epsilon #define as, or it a variable.
--
Gary A. Gorgen | "From ideas to PRODUCTS"
snipped-for-privacy@comcast.net | Tunxis Design Inc.
  Click to see the full signature.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Gary A. Gorgen wrote:

Currently from visual studio 2008 float.h
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */ #define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */ #define LDBL_EPSILON DBL_EPSILON /* smallest such that 1.0+LDBL_EPSILON != 1.0 */
It's a standard header file, see http://en.wikipedia.org/wiki/Float.h , GCC has it also but the #defines above refer to other defines not in float.h on my Linux system and I haven't gone looking for where they are.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Sat, 05 Mar 2011 14:51:31 +0000, David Billington wrote:

...
Using a fixed epsilon works if the numbers being compared are in some narrow range, eg 1e-6 to 1e6, but for wide-ranging numbers, epsilon needs to depend on the size of the numbers. In place of " < epsilon" one could substitute " < epsilon*(fabs(a)+fabs(b))", with epsilon~1e-9. Less-cumbersome forms apply in specific cases, eg if a and b have the same sign, or the magnitude of a always exceeds that of b, etc
If you want to test if b differs from a by no more than 1 bit of roundoff error, the following will work: if (a==b || b==nextafter(a,b) || a==nextafter(b,a)) ...
The nextafter() series of functions is defined in the C99 standard and available on linux.

--
jiw

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

I do not use Microsoft either!
i
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Ignoramus1280 wrote:

I use Linux for virtually all my personal computing but I make most of my living writing software that runs in MS Windows, must be I sinned badly in a past life.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

I feel blessed, because my entire digital life, including personal, work, and making money from websites, is based on Linux.
i
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

It is slightly worse than this because essentially, we are comparing
"a == a"
and it still fails as inequal. This is called "GCC bug 323" and is not a GCC bug, but a very insiduous FPU register issue.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id23
Anyway, I ended up modifying the component proposed by Andy and what I have now, works really great. The motor reliably shuts off 10 seconds after cessation of movement.
Here it is ====================================================================component timeout """Reduces motor command to a predetermied value after a certain number of seconds of no axis motion""";
pin in float position-command-in "link to motor-pos-cmd"; pin in float current-in "link to the PID output"; pin out float current-out "link to the DAC"; pin out float debug-t-out "Watch t"; pin out float debug-old-pos "Watch old-pos"; pin out float debug-pos-in "Watch position-command-in"; pin out float debug-pos-diff "Watch position diff"; param rw float timeout = 10 "timeout in seconds"; param rw float default-current = 0 "current output after timeout"; variable float old_pos; variable float t = 0; function _; license "GPL"; author "Andy Pugh";
;;
#include <rtapi_math.h>
FUNCTION(_){
debug_old_pos = old_pos; debug_pos_in = position_command_in; debug_pos_diff = position_command_in - old_pos;
if( fabs( position_command_in - old_pos ) > 1E-7 ){ t = timeout; old_pos = position_command_in; } else { t -= fperiod; }
debug_t_out = t;
if( t < 0 ){ current_out = default_current * current_in; t = -1; } else { current_out = current_in; }
}
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

No, it's fundamental, as some others have noted.
Floating point numbers are inherently fuzzy, especially after a sequence of computations, so in practice tests of equality of floating-point variables always fail, even if one is using quad precision.

That's the correct approach, but the 1e-7 tolerance is not really coarse enough to be bulletproof.
The issue is the width in bits of the mantissa of the floating-point word. According to IEEE Std 754 (which is the formal definition of the universally used "IEEE float"), the mantissa of a 32-bit single float is 24 bits (binary32 format in the "Digits" column) supports 7.22 decimal digits, so a tolerance of 10e-7 is right on the edge, which will cause random-seeming failures.
To be specific, the "epsilon" is 1/(2^24)= 5.9605e-8, which is within a factor of two of 10e-7; this is far too tight a tolerance to be reliable. I would change the tolerance to 10e-6, so the code would read "if( fabs( position_command_in - old_pos ) > 1E-6 ){"
For the record, the width in decimal digits is calculated as follows: Log10[2^24]= 7.2247
<http://en.wikipedia.org/wiki/IEEE_754-2008
Joe Gwinn

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

Except that it does not apply here Joe.
I had the same issue at work once. a == a fails even though both numbers are equal and come from the same source. But one is in a CPU register and one is in memory.
Read that bug discussion, it is a fountain of knowledge.
i

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

My point is more general, that a==a is not reliable with floating point, even if the Gnu bug is fixed.

It sounds like a no-see-um of a problem. But a==a would is a problem regardless of that bug.
You need to make the tolerance larger, as discussed below.
Speaking of founts of knowledge, reading IEEE-754 has much to recommend itself. It may be arcane, but it lays out the foundations of floating point arithmetic, which in turn underlays essentially all of computer math.
There are many war stories.
Joe Gwinn

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Ignoramus1280 wrote:

Ah, HA! Now I know what it is!
In a number of CPUs, especially the X86, they hold extra mantissa bits in the floating point hardware registers. When you save the register to a memory location, these extra bits of precision are truncated to the standard IEEE floating point representation. So, when you compare them again, they do not match!
I'm sure this is documented somewhere in the X86 hardware documentation. The reason for this is to allow repetitive calculations to maintain the full accuracy up to the external representation.
Jon
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

I consider it (extra precision in registers) a bug, by the way. It is wrong on many levels.
i
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Sun, 06 Mar 2011 00:07:42 -0600, the renowned Ignoramus1280

Comparisons on FP numbers are always fraught with potential difficulties. IME, you should always look for |x - y| < e where e is a small number, rather than x == y.
Best regards, Spehro Pefhany
--
"it's the network..." "The Journey is the reward"
snipped-for-privacy@interlog.com Info for manufacturers: http://www.trexon.com
  Click to see the full signature.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Spehro Pefhany wrote:

This is the sort of thing that separates the Real Programmers from the scriptkiddies. ;-)
Cheers! Rich
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Sun, 06 Mar 2011 01:50:23 -0500, Spehro Pefhany

When I was programming process control systems, I avoided using "=" as a condition for any action. Much more reliable to use "<" or ">". Like "close tank filling valve 1 when level > x". Make the test "=" and the tank's going to run over. Probably same reason as above.
Pete Keillor
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

Polytechforum.com is a website by engineers for engineers. It is not affiliated with any of manufacturers or vendors discussed here. All logos and trade names are the property of their respective owners.