This is what makes this software great.
Someone can download it, make criticisms, and because of it the software
gets some expert help, and it is improved. Thank you for your
insights into the code, I find it really interesting.
Lamar Davidge
PS this guys email that the virus is sending the list is really
boring stuff. I wish he had an affair, or something really good to send
:(
-------Original Message-------
Date: Wednesday,
January 30, 2002 08:30:19 PM
Subject: RESOLVED: EMC
is poorly designed and implemented.
RESOLVED: EMC is poorly designed and
implemented.
I'm an old gray haired assembly hacker and cycle
counter with some experience in closed-loop motion control. I have been
investigating EMC, principally emcmot.c and have come to the conclusion
that EMC is poorly designed and implemented. I don't mean to be
discourteous, but you do not have a good solid product, nor will you
without a major redesign. I will support this conclusion in the
following.
What I see in the implementation is wasteful, redundant
access to I/O ports, lack of insight into floating point speed
considerations, poor factorization into subroutines and far too many
scattered ifdefs for reliable code.
Modern motion control should
be adaptive, using Kalman filters, and state-space or observer
predictor methods. EMC by design uses PIDs, which are from old 1930s
analog computers. PIDs tuned via Ziegler Nichols methods are inherently
prone to oscillation and instability. (The zeros don't cover poles, or
drift into right hand plane, etc as the dynamics of the plant change
with temperature and load.)
A 8-bit 6502 or 8051 running at 1 MHz
could do a nice job of running stepper motors in 1978. Without double
precision, 32-bit integers or 800MHz clock rates. Servos were harder,
but still possible. Today yoy can go to http://www.jrkerr.com/ and buy a
PIC-STEP or PIC-SERVO with software for a reasonable price with
software that'll get you up and running twenty times faster than
EMC.
Look at the source code (30-Jan-2002 sourceforge emcmot.c),
lines 2422ff the polling of the max and min limit switches, home and
axis fault bits. This is within the for loop on line 2373
L2373
for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
This is very
poorly done, the exact same bits are read repeated, (for extsmmot.c)
with over one microsecond per pptDioRead inportb call. That's (3
axes)*(4 switches)=12 microseconds, with 16 us listed as the max. Only
one 1 us read is required. The situation is worse in stgmod.c, where 4
bytes are read, so it takes 48 us. Folks - i/o port access always takes
over a microsecond, regardless of the speed of your i86 processors.
Reading the same bits repeatedly in critical code is foolish and
wasteful.
I believe the choice to poll and debounce these switches
within the motion loop (rather than, say, using a hardware interrupt
or a slower emcio task read and debounce), is a very unwise
design decision. Furthermore, American and European safety
standards REQUIRE that hard limit switches bring the machine down even
if the processor is non-functional. Meaning the limit switches,
through a dumb relay, should drop main power to the motors. So on
commercial machines, you don't need to check the limit switches, you'll
E-stop if you hit them. As implemented here, EMC is likely to be
HAZARDEOUS to the health of its users.
And there's this
over-dependence upon double precision numbers when single or integers
will suffice. For example, in the external interface to stgmod.c,
passing the raw encoders and dacs as double arrays, when they're
integers on all hardware, doubles the subroutine call time, and then
the subroutine itself has to convert it to an integer.
Floating
point is very fast these days, but it still takes time. Even on
Pentiums, double precision floating point is about half as fast as
single or integer arithmetic. Divides take about twice as long
as multiples. A subroutine call takes about as long as an integer
add for each 32-bit parameter. These are ballpark figures, much
affected by caching, out-of-order and speculative execution.
So
code like on emcmot.c line 2397, L2397 if
(fabs(emcmotStatus->input[axis] - emcmotDebug->oldInput[axis])
/ L2398 emcmotConfig->servoCycleTime >
emcmotDebug->bigVel[axis]) { Would be 50% faster if expressed
as M2397 if (fabs(emcmotStatus->input[axis] -
emcmotDebug->oldInput[axis]) M2398 >
emcmotConfig->servoCycleTime * emcmotDebug->bigVel[axis]) { But
both servoCycleTime and bigVel are infrequently changed - on a explicit
command, dump bigVel for bigLeap=bigVel*cycleTime and have N2397 if
(fabs(emcmotStatus->input[axis] -
emcmotDebug->oldInput[axis]) N2398 >
emcmotDebug->bigLeap[axis]) { which by my tests on 233 and 800MHz
machines, would take about a third as long. I see the "debounce bad
feedback" has been changed, it indicates a very serious hardware error
which still is not logged or reported.
You may consider this the
ranting of a dinosaur or as constructive critism - as you
choose.
God Bless America, President Bush and our fighting men and
women. --krb
. |