Yet another iteration of nothing
Random header image... Refresh for more!

Category — Motion Controller

Brief History of G-Code, Numerical Control, and G-Code Complilers

G-Code (more precisely G and M Code, more formally, RS-274D or other names) is a programming code that dates back circa 1950, and was originally developed to control mechanical machining operations using paper tape.

It shows.

The last ratified standard was in 1980, and the last open source variant in 2000 (RS274NGC_3.pdf – 2000). Most manufacturers extend it in their own directions, making incompatible changes to others doing the same thing. The standardized code has no ability to do any of the commonly done flow control (loops)or logic operations (if, then, else, and, nor). Outrageous, says someone coming from a computing background.

When one examines in detail the actual history, intended operations and uses of these machines, a different picture emerges.

Simple Machines have existed for thousands of years, with compound or complex machines for hundreds, and each generally performed simple, repeated tasks. For example: windmills were used to grind grains to flour continuously, the Archimedes screw was used to lift water. More complex machines, such as the lathe, exist to rotate items, removing material from their diameters. In most cases, the machining progression is a straightforward, beginning-to-end process. 

To illustrate, here is a sample process to produce a wooden candlestick from a raw work-piece on a lathe. It can be broken down into single, discrete steps:

  • load the work-piece into the lathe
  • start the lathe (bow, pedal, water, steam, electricity or other motive power)
  • turn the work-piece cylindrical with a tool
  • carve away material to form the general intended shape
  • carve decorative features if desired
  • drill a hole for the candle
  • stop the lathe
  • unload the machined work-piece

In the above example, there is very little need for any advanced flow control or logic. The workflow is a straightforward progression of isolated steps performed in a procedural manner.

Historically, someone would perform all those steps by hand, and doing so quickly with minimal mistakes became a production bottleneck when industries switched from cottage level craftsmanship to mass production. After all, a Master woodworker can only turn out so many finished pieces in a day. Adding more people and more lathes would speed up production, but costs also rise, since more Master level woodworkers are needed, as is more machines. It is an oversimplification, but it can be said the focus changed to more production at less cost. 

As technology progressed, what used to take a Master level worker with a handheld gouge and pedal powered rotary motion to produce could now be manufactured in a single cycle by an unskilled person placing a work-piece blank into a lathe equipped with multiple cutting knives on a bar and triggering the entire series of operations with a single motion, drastically decreasing machining time. Factories in the 20th century had rows of such machines, each doing a single set of operations on the work-piece, and once completing its process, transferred the work-piece to the next machine to do the following operations. In the generally more complex metalworking world, ways were found of reproducing the actions of the master worker via mechanical means (cams, levers and gears shaped to replicate the same actions). Now that same Master level worker could oversee gangs of lesser skilled personnel overseeing the mechanically automated machines.

Manufacturing continued to move from skilled worker to assembly line worker to automation.

This was acceptable for industry for a time, but setting up each machine mechanically to do only one job and then changing the job performed required expensive and time consuming changes to the mechanisms. A logical extension of the technique was to make a single machine capable of performing the actions of several other machines. Enter the world of Numerical Control (NC); the precursor to Computer Numerical Control.

Machines were constructed that could have their work patterns altered by a punched paper tape, which was fed into a reader, which in turn controlled the machine operation. As technology progressed, the paper tape was replaced with magnetic media, but the basic operations required to produced the same candlestick really did not change; the same operations had to occur, in the same order; only the timeframe for the production of the product had shifted from hours to seconds. The production of G-Code reflected that process; the produced code had little need of more than the ability to loop operations and utilize subroutines. Typical operations were:

  • re-iterate a cutting/drilling/boring/milling procedure until final depth was reached
  • utilize a preexisting movements (subroutine) when a particular point in the main program was reached (move the machine to a specific spot, trigger the drilling subroutine, move to another spot, trigger the drilling routine again)

Very procedural programming.

Enter the 21st century, with vertical machining centers capable of self-feeding in work stock, performing lathe and mill operations simultaneously while interfacing to external automation systems, and now operational complexity has outstripped the original purposes.

Machine control manufactures extended the standard G-Code to include storage variables, more so-called canned cycles, goto, if-then-else flow control, AND,OR,NOR logic, and even so-called conversational programming (select operation, select size, select depth, select direction, speeds and feeds, push go; the machine generates the G-Code), all to the goal of increasing production, decreasing cycle time, improving cost-effectiveness.

But what if you have none of those features built in to the controller? Enter G-Code Compilers.

General purpose computer programming languages have long since needed flow control and conditional operations, and it is entirely possible to interface the two. An example from my own research is using C language to handle the flow and conditionals, and have it produce executable G-Code for each case. Here is an example from the web; someone made a compiler that converts logical arguments in C to LinuxCNC compatible G-Code:

CGCC Gcode CompilerFeatures and Examples

// Constants
const float X_Holes = 10;
const float Y_Holes = 10;
// Loop
for (float y = 0; y < Y_Holes; y++) {
for (float x = 0; x < X_Holes; x++) {
if (x != y) {
G00 Z1
G00 X[x] Y[y]
G01 Z0 F1
G00 Z1
The above code is as follows:
– Want to drill a grid of 100 holes in a 10 x 10 inch grid
– the code is repeated 100 times with different X and Y coordinates.
– The code has to skip a line of holes down the diagonal where X equals Y

The person states that LinuxCNC CAN produce this workflow through the added-on O-codes (extension of the original RS-274D standard) but it is hard to produce good programs quickly. The result is a program that takes C language syntax incorporating G-Code and produces LinuxCNC compatible Gcode.

Others have similar needs:

GCME – G-Code Meta Compiler

January 5, 2016   Comments Off on Brief History of G-Code, Numerical Control, and G-Code Complilers

Dynomotion KFLOP and KSTEP running from Raspberry Pi using patched version for Linux of KMotionCNC

Who might be interested in this.

Anyone that would like to operate their KFlop controlled machine from their phone, tablets or anything with a web browser.

Github Repository of the patched system

GitHub Parhansson

YouTube Link of Operational System

January 5, 2016   Comments Off on Dynomotion KFLOP and KSTEP running from Raspberry Pi using patched version for Linux of KMotionCNC

Motion Controllers (Software and Hardware)

CNC toolchain:

CAD -> CAM -> G-Code PostProcessor -> Motion Controller -> Drives

A Motion Controller is, well, just that. A structure to control the coordinated motion of at least a singular CNC axis. Motion controllers can be software or hardware based. On the hardware side, the continuum runs from as simple as relay logic through small embedded controllers to complex machine controllers such as the Dynomotion KFLOP.


Software controllers have a distinct disadvantage running under Windows, as it is not a real-time operating system (Mach3, Mach 4). Software interrupts (caused by running other programs or a slow machine), or other normal operations run close to the performance envelope can cause buffer failures, wrecking parts. LinuxCNC runs under a real-time kernel, and as such should not experience such issues.


Relay or ladder logic controllers only react to a dedicated set of inputs. For example, controlling the end points of travel. When reached via sensors, simply reverse travel at set speed/rates.

More advanced hardware controllers are dedicated and do all of the trajectory planning onboard with higher speed, optimized hardware. The host PC only passes the G-Code file and operational parameters to the hardware controller to execute. As an example, the KFLOP:

“uses a DSP-based microcontroller with 1.2 GFLOPs of processing power, a 100k Gate FPGA, 16 Mb SDRAM, 8 axes of control, lots of I/O and the ability to program in C and do path planning with G-Code”


Finalists (Hardware)

Ethernet Eding 4 Axis


Dynomotion KFLOP

December 5, 2015   Comments Off on Motion Controllers (Software and Hardware)

KFLOP C Programming Dissection – My Init.c Pendant Code

#include “KMotionDef.h”

// Example Init program that includes “smooth” MPG motion example
// which makes use of the exponential motion command.

// Which Pins were somewhat arbitrary; 11 I/O were needed, so JP4 and JP6 were used. The remainder were wired to level shifting boards and remain unused.
#define SELECTX 24 // KFLOP JP4, Pin 15 (I/O 24):
#define SELECTY 17 // KFLOP JP4, Pin 06 (I/O 17):
#define SELECTZ 19 // KFLOP JP4, Pin 10 (I/O 19):
#define SELECT4 21 // KFLOP JP4, Pin 12 (I/O 21):

#define FACTOR1 23 // KFLOP JP4, Pin 14 (I/O 23):
#define FACTOR10 25 // KFLOP JP4, Pin 16 (I/O 25):
#define FACTOR100 26 // KFLOP JP6, Pin 05 (I/O 26):

#define TAU 0.02 // smoothness factor (Low Pass Time constant seconds)
#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change

#define QA 16 // KFLOP JP4, Pin 5 (I/O 16): define to which IO bits the AB signals are connected; I’ve assumed A+ and B+
#define QB 18 // KFLOP JP4, Pin 7 (I/O 18):
//Note: Dynomotion seems to just use single ended, the pendant is dual/differental; as such, two inputs are not needed, could reduce total to nine from eleven.
//Note: Current assignment of QA and QB results in backwards operation. Swapped lower down in code. Need to verify hardwire assignment correct.

int main()
double T0, LastX=0, LastY=0, LastZ=0, Tau;
int result;
int BitA,Change1=0,Change2=0, DiffX2;
int PosNoWrap, NewPos, Pos=0, wraps;
int InMotion=FALSE,Axis,LastAxis=-1;
double LastChangeTime=0,Target,Factor=0;

// Add a small amount of Coordinated Motion Path smoothing if desired
// Tau = 0.001; // seconds for Low Pass Filter Time Constant
// KLP = exp(-TIMEBASE/Tau);
KLP=0; // force to 0 to disable
// printf(“Tau=%f KLP=%f\n”,Tau,KLP);

// Main program starts here; includes MPGSmooth subroutines
for (;;) //Main program, cycle forever
// Pendant reading code
// convert quadrature to 2 bit binary
//BitA = ReadBit(QA);
//PosNoWrap = (ReadBit(QB) ^ BitA) | (BitA<<1);
BitA = ReadBit(QB);
PosNoWrap = (ReadBit(QA) ^ BitA) | (BitA<<1);

// Diff between expected position based on average of two prev deltas
// and position with no wraps. (Keep as X2 to avoid division by 2)
DiffX2 = 2*(Pos-PosNoWrap) + (Change2+Change1);

// Calc quadrature wraparounds to bring Diff nearest zero
// offset by 128 wraps to avoid requiring floor()
wraps = ((DiffX2+1028)>>3)-128;

// factor in the quadrature wraparounds
NewPos = PosNoWrap + (wraps<<2);

Change2 = Change1;
Change1 = NewPos – Pos;
Pos = NewPos;

// Determine which Axis is selected; Logic tree. If none are selected, disable pendant MPG control, as the unit is in the OFF position
// Pendant purchased did not have a ENABLE switch, no free conductors to install one; this will work fine to function as an erstaz one.

if (ReadBit(SELECTX)) // is x selected?
Axis=0; //X axis in my setup
else if (ReadBit(SELECTY)) // is y selected?
Axis=1; //Y Axis in my setup
else if (ReadBit(SELECTZ)) // is z selected?
Axis=2; //Z axis in my setup
else if (ReadBit(SELECT4)) // is 4th axis selected?
Axis=3; //A axis in my setup
Change1 = 0; // Disable Pendant, since OFF is selected (none of the above resolve to TRUE)
Factor = 0; // Force the change factor off (13 Nov 2015)

// Determine which multiplier is selected; unlike above, must be one of the three positions by hardware design
// Factor numbers by design, how much to move per MPG pulse

if (ReadBit(FACTOR1)) // is X1 selected?
// Factor = 1.5748031496062992125984251968504;
Factor = 1;
else if (ReadBit(FACTOR10)) // is X10 selected?
Factor = 10;
//Factor = 15.748031496062992125984251968504;
else if (ReadBit(FACTOR100)) // is X100 selected?
Factor =15;
//Factor =157.48031496062992125984251968504 ;

return 0;

// Debounce a bit
// return 1 one time when first debounced high
// return 0 one time when first debounced low
// return -1 otherwise
#define DBTIME 300
int Debounce(int n, int *cnt, int *last, int *lastsolid)
int v = -1;

if (n == *last) // same as last time?
if (*cnt == DBTIME-1)
if (n != *lastsolid)
v = *lastsolid = n; // return debounced value
if (*cnt < DBTIME) (*cnt)++;
*cnt = 0; // reset count
*last = n;
return v;

November 17, 2015   Comments Off on KFLOP C Programming Dissection – My Init.c Pendant Code

KFLOP C Programming Dissection – My Init.c E-Stop Code

#include “KMotionDef.h”

int elast=0,elastsolid=-1,ecount=0; // for debouncing estop pushbutton
int Debounce(int n, int *cnt, int *last, int *lastsolid);
int DoPC(int cmd);

#define ESTOP 168 // set to the external estop input bit
#define TMP 10 // which spare persist to use to transfer data
#include “C:\KMotion433\C Programs\KflopToKMotionCNCFunctions.c”

int main()
double T0, LastX=0, LastY=0, LastZ=0, Tau;
int result;
int BitA,Change1=0,Change2=0, DiffX2;
int PosNoWrap, NewPos, Pos=0, wraps;
int InMotion=FALSE,Axis,LastAxis=-1;
double LastChangeTime=0,Target,Factor=0;

// Main program starts here; includes ESTOP, MPGSmooth subroutines
for (;;) //Main program, cycle forever

// Handle ESTOP interrupts
result = Debounce(ReadBit(ESTOP),&ecount,&elast,&elastsolid);
if (result == 0)
printf(“Local ESTOP Active!\n”);

// Debounce a bit
// return 1 one time when first debounced high
// return 0 one time when first debounced low
// return -1 otherwise
#define DBTIME 300
int Debounce(int n, int *cnt, int *last, int *lastsolid)
int v = -1;

if (n == *last) // same as last time?
if (*cnt == DBTIME-1)
if (n != *lastsolid)
v = *lastsolid = n; // return debounced value
if (*cnt < DBTIME) (*cnt)++;
*cnt = 0; // reset count
*last = n;
return v;

November 17, 2015   Comments Off on KFLOP C Programming Dissection – My Init.c E-Stop Code

Dual Closed Loop Control with KFLOP

The Dynomotion KFLOP controller can control 8 motor axis (either as 4 dual/slaved or 8 independent), complete with 8 dedicated hardware encoder channels (while any generic input could be used in theory for encoding,  I understand the general I/O speed is much less than the dedicated lanes).

Placing rotary encoders on stepper or BLDC/BDC/AC motors can feed information on the motor position back to KFLOP, which will then apply corrective action to the drivers to accurately place the motors exactly where they were commanded to be (See Dynomotion – Closed Loop Stepper Control)

Unfortunately, this does nothing to compensate for pitch error in the screws, lash, or other purely linear mechanical elements. The solution to these is to add linear encoders in addition to the rotary; measuring the actual position of the linear elements and sending that feedback to KFLOP.

With a stepper system, one might be able to utilize linear encoders alone, and achieve good results. The stepper motor design itself imparts built in feedback: when the motor is commanded to assume a position, the drive pulse forces the rotor to assume the commanded angle via the two phases. When the motor overcomes the initial frictional opposing forces, the torque is naturally reduced. A stepper motor can be though of as a spring and mass system. The rotor is the mass, and as torque is applied, the magnetic force acts like the spring, storing energy and releasing it (this is also the reason for mid-band resonance in a stepper system). If the load attempts to move the motor out of that position, the increased magnetic field will “push” it back to the commanded position; this force does vary depending on where the motor is (full step and half step are stronger than microstep positions), as the magnetic torque follows a sine pattern.

Having said all that, the “bandwidth” (ability to react in short time frames) with linear encoders alone is said to be rather low/slow.  Enter the Dual Loop setup: using the rotary encoders for velocity control of the motors, and the “outer loop” (linear encoders) for motion/positional control (see Dynomotion – Dual Closed Loop).

Multiplexing Encoders

Unfortunately, encoders #0-4 occupy the same JP connector as that used to connect to a KSTEP (which then uses those pins for multiplexing KSTEP I/O). This is perfectly acceptable for the majority of stepper driven systems (being open loop) and the JP5 connector can be utilized for single loop motor or linear encoders (using the #4-7 encoder channels).

Fortunately, KFLOP can be programmed to multiplex the encoder inputs over to alternative connectors. If the multiplex bit is asserted, the dedicated inputs shift from their normal pin assignments on JP5 and JP7 (respectively) to the first 8 inputs on JP4 and JP6, respectively (4/2012 firmware changesMux’d Encoders Discussion).

The first 8 Inputs on JP4 are Encoders 0-3 A/B signals (when mux’ed). The first 8 Inputs on JP6 are Encoders 4-7 A/B signals (when mux’ed).

Reference MUX program:

 // Mux encoder inputs from KFLOP JP7 & JP5 to JP4 and JP6


Mux = 0                                                              Mux = 1
Signal       I/O Bit  Pin                             I/O Bit    Pin
ENC0A        0                 JP7 – 7                       16             JP4 – 5
ENC0B        1                  JP7 – 8                       17             JP4 – 6
ENC1A         2                 JP7 – 9                       18             JP4 – 7
ENC1B         3                 JP7 – 10                     19             JP4 – 10
ENC2A        4                 JP7 – 11                      20             JP4 – 11
ENC2B        5                 JP7 – 12                      21             JP4 – 12
ENC3A        6                 JP7 – 13                      22            JP4 – 13
ENC3B        7                 JP7 – 14                      23            JP4 – 14

ENC4A        36               JP5 – 1                        26            JP6 – 5
ENC4B        37               JP5 – 2                        27            JP6 – 6
ENC5A        38               JP5 – 3                        28           JP6 – 7
ENC5B        39               JP5 – 4                        29           JP6 – 10
ENC6A        40               JP5 – 5                        30           JP6 – 11
ENC6B        41              JP5 – 6                          31           JP6 – 12
ENC7A        42               JP5 – 7                         32          JP6 – 13
ENC7B        43               JP5 – 8                         33          JP6 – 14

Note that JP6 and JP4 are 3.3V only. Driving them above 3.8V will not do good things to KFLOP’s integrated circuits (JP5 is 5V tolerant by design).


KMOTION Dual Loop Programming

KMotion (the C program loader) must be programmed to join the two servo control loops together, forming an “inner” and “outer” loop. Dynomotion has an example program to do this:

#include "KMotionDef.h"

// Creates dual feeback loops for cases such as rotary motor encoder feedback
// with linear scale encoder feedback.  Two KFLOP Servo Axes are required,
// one for each loop.  Output of the outer loop is applied as a velocity
// to the inner loop 

    for (;;)  // loop forever
        ch0->Dest += ch2->Output;  // move ch0 at speed of ch2 output

This uses two KFLOP Axes channels per set, allowing 4 combined axis. The “FOR” loop can be added to the KFLOP initialization C program as well.

Examples of the settings for KFLOP axes:

Set Inner Loop Axis as:
Input Mode = Encoder
Input Channel = Rotary Encoder
Output Mode = DAC Servo

Set Outer Loop Axis as:
Input Mode = Encoder
Input Channel = Linear Encoder
Output Mode = No Output

Each loop can be tuned separately:

– Tune the inner loop axis for optimal performance based on the rotary encoders

– Tune the outer positional loop for optimal performance based on the linear encoders.

The outer (positional) loop is a higher level control, so it’s output should drive the inner (velocity) loop. example: ch2->Dest +=ch3->Output;


Multiplexing Encoders vs. Input Loss

Multiplexing the encoders to JP4 and JP6 means the previously utilized general I/O connections can only move to JP5 and other connectors (JP7 will still use the I/O pins for multiplexing KSTEP’s inputs). This results in a net loss of available inputs that may be non-trivial to regain.

The Velocity Loop in External Drives

A simpler solution is to fit servo drives that accept encoder feedback and close the velocity/torque loop in the drives, leaving KFLOP to handle the linear encoder inputs, which forms the position loop. The drives will then make certain the motors respond to where they should, and the KFLOP will correct for positional errors via the linear scales. Less control by KFLOP, easier wiring and installation.

Pros and Cons

If the level of mechanical compliance/accuracy of the system is already acceptable, adding the (possibly) significant cost and complexity of closed loop control may not be warranted. Conversely, if the mechanicals are so sloppy a strong wind or quake can shift positions, additional feedback will not make for quality performance.

Closing the control loop around linear scales includes more “bad” mechanical things inside, making the loop more difficult to control. Lash for example, crossing a axis point (think the four quadrants of a circle) will cause considerable havoc as the servo system chases the lash around for that split moment the affected axis is unloaded. Always best to remove lash rather than attempt to correct for it. In addition to Backlash, there is Stiction (static (sticking) vs dynamic friction), and Compliance (elastic modulus). Poor machine design can render expensive zero backlash ballscrews useless. As examples:

  • Inherent design (Box Ways, Dovetail Ways) have relatively large amounts of stiction, which is offset by the proportionally greater load bearing surface area, compared to linear guides.
  • Ballscrew classes can have significant lead error (According to Thompson Ballscrews), a Transport Class 7 rolled Ballscrew can have a permissible variation of 900um in 2500um (0.035 inches in 98), and up to 0.18mm of lash (0.007″).
  • Thermal expansion. On a large machine, the growth of the ballscrew can be significant. (11.7 ppm/° Celsius). As an exaggerated example, a 1219mm long (48 inch) ballscrew, during a 50 degree Celcius rise in temperature, will “grow” 0.73152mm (.0288 inches).
  • Rigidity (stiffness, opposite of compliance) of the unit: floppy drive belts, worn or “sloppy” gearboxes, torsion and bend loads in the structure, flexible couplers

As an example of such from Tom Kerekes of Dynomotion (on a post from CNCZone):


 …So for example say the linear encoder has a small error that the servo wants to correct. This will usually cause the servo to ramp up the motor torque. Eventually the motor will have enough torque to break stiction and begin accelerating. But the linear scales may not yet indicate any thing has moved because of the system’s backlash/compliance. So the Servo will continue to ramp up torque further. Eventually when the backlash/compliance is taken out the Axes will move and the Linear scales will report the motion. But at that point the motor may be at such a velocity that it is difficult to avoid a significant overshoot. Most systems like this can be made to work and be stable but only with very low feedback gains (torque is ramped up very very gradually) resulting in poor dynamic performance (errors are not connected quickly and therefore are allowed to grow to larger values).


February 24, 2015   Comments Off on Dual Closed Loop Control with KFLOP