KmotionCNC Conditional Logic

The GCode Interpreter included with KmotionCNC is more bare-bones than the extended on in LinuxCNC, and some people were discussing how to work-around this perceived lack. I found a link on CNCZone that outlined a method (albeit on Mach3) of performing conditionals (as Mach3 also does not support the higher-functions in LinuxCNC). At one point, Tom Kerekes also weighed in:


The same approach should work with KMotionCNC as with Mach3.  Both support variable numeric subroutine labels. With Mach3 the Interpreter should work the same regardless of what motion plugin is performing the motion. KMotionCNC also supports a Variable loop count (L word) which includes zero calls.  To me that is a simpler form of conditional. See the example: SubroutineWithConditionals.ngc I’m not sure why Eon feels that the Loop Count must be less than 100.  Any value up to ~2 billion should be allowed

The reason for the bold statement is apparently Mach3 (which Dynomotion has a plug-in to interface to) claims a limit of 99 iterations Limit on Loops. Others state there is no such limit to Kmotion, and using the Gcode window in Kmotion, I have easily proven this. Instantly I can have huge loops amounts (tested to 20 Million). Another claims to use M47, which in MACH3 repeats program from first line. This Mcode does not exist by default in Kmotion.



KMotionCNC doesn’t support if/while statements.  You can conditionally call subroutines and repeat subroutines.


Regarding KMotionCNC Subroutines: unfortunately calls to other files are not supported. The subroutine must be within the same file.

Comment #4:

If you don’t like using a subroutine with an infinite loop count you should be able to add an action to M30 to automatically re-cycle start.
Configure the M30 (stop rewind) with an additional action to execute:

#include “KMotionDef.h”
#define TMP 10
#include “KflopToKMotionCNCFunctions.c”

while (JOB_ACTIVE) ;  // wait until GCode Finishes
DoPC(PC_COMM_EXECUTE);  // Cycle Start again

The source code for the Interpreter is there if you wish to add a new command.

This last statement is something I spent some time looking for: where exactly is the defined commands.  More on that later.

I have copied below the example Tom cited: SubroutineWithConditionals (Github link)


#100 = 5

(examples of logical operations)
(result is 1 if condition is true)
(result is 0 if condition is false)

#101 = [#100 >  5]
#102 = [#100 >= 5]
#103 = [#100 <  5]
#104 = [#100 <= 5]
#105 = [#100 =  5]
#106 = [#100 <> 5]

(subroutine call can be looped a number of times)
(the L or Q word may be used to specify the count)
(if neither L or Q is specified a count of 1 is used)
(if the count is 0 the subroutine will not be called at all)

M98 P1 L3  (example using L to specify the loop count)
M98 P1 Q3  (example using Q to specify the loop count)

M98 P1 L#100  (example using a variable loop count)

M98 P1 L[5 > 4]  (example using a conditional as a loop count)

#200 = [#200+1]

Although this was new to me (using a third party CAM package, I rarely do more than tweak the resulting G-code; I know, but too many other priorities), but apparently the question was not new. May 2014 Post CNCZone:

Is there a G code supported that will allow a line jump? An M99 P12 will jump to line 12 for example on a Fanuc and some others . I have also seen GOTO used in the G code.


KMotionCNC supports Jumps to Subroutines which is similar to a Jump if you simply never return. M98 Pxxx can be used to Jump to the GCode Line with the Label: Oxxx The Jump can be conditional as well by specifying a Subroutine Loop Count of either 0 or 1. See the included example SubroutineWithConditionals.ngc

A further example refining the code was given

Still a bit clumsy but here is a way to eliminate your list of repeated conditional subroutine calls by using a looped surbroutine:


M98 P2 L100 (Do up to 100 tools)
(MSG,Tool Setting Complete)

O2 (Sub to conditionally call another sub)
M98 P1 L[#101=1]

(Change Tool)
M6 T#100
(Set Fixture Offset)
(Set Height Offset & Save XY Offset to G59.3)
(Go Home)
G00 G53 G90 Z0.
G00 G53 G90 X0. Y0.
(Send Message and pause)
(MSG,Change to next Tool!)
M00 (Uncheck "Block Delete" To End)
G00 G59.3 G90 X0. Y0.
#100=[#100 + 1]
M00 (Move Z to desired Offset Height)

And more: Aug 2015 – Yahoo GroupsKflopWebNC Sub Programs


Now, on to finding the place to modify the interpreter

I found where the G-Code words are referenced to internal numbered functions (Definitions are in rs274ngc.h), but not where the internal functions are defined. As an example: #define G_93   930. Great. Now where is 930… According to Windows Search, that term only occurs in the aforementioned file (searched the entire directory). RS274ngc.cpp DOES have an occurrance of 300 in it as well, so looking through it.

They are not in either of the above header or program file. I have found DMRS274 Interpreter file in the KMotion Dot Net directories (all C#).

At this point, I surfaced and did a Google search for adding a custom G-code into the linuxCNC compiler. Since that, Mach3 and Kmotion all are derived from the same source, I could find some hints that way.

Stand Alone Interpreter for LinuxCNC

The interpreter is really just a library of related functions that work together to read RS274 files and output canonical commands, it does not
have a main() function(...) nor does it have a "user interface". 

Well. That was helpful. Off to RS274NGC_3.pdf – 2000.

1.3.1 How it Runs

When the Interpreter starts up, before accepting any input, it sets up a world model that includes data about itself, parameter data, and data about the machining center being controlled (including data about the tools in the tool carousel of the machine).

Once initialized, the Interpreter runs using a two-step process: 1. Get a line of RS274/NGC code and read it into memory, building an internal representation of the meaning of the entire line. We will call this stage “reading.” 2. Change internal state and/or call one or more canonical machining functions (see Section 4) in order to do what the line says to do. We will call this “executing” the line.

So, as far as I can see, I might have been right to look in the canonical section, despite not seeing anything before (it is to be included in RS274ngc.h). Well, that was somewhat useful; most of the items in there state references to external code… Let us search keyword: DWELL. It appears in several places, and corresponds to a GCode.


That showed me enough to convince me that I was correct; there is no one file with definitions for each Gcode; it is spread all over the place.


Appendix D. Interpreter Software

D.1 Interpreter Interfaces

The Interpreter has four interfaces, as shown in Figure 9. These are all function call interfaces. The direction of function calling is indicated by arrows. The flow of information in the reverse direction from the arrows differs in the different interfaces. The Interpreter-do-it functions tell the Interpreter to do something, such as read a line of NC code or execute the line last read. These functions all return an integer status code as described in Appendix A.1. The functions themselves are described in Appendix D.4. They are declared in rs274ngc.hh and defined in The names of these functions all begin with “rs274ngc_”.

So, off to look at _pre. Annnd there is no file in Kmotion labeled that. Reading through NGC…

The file may be pre-preprocessed

into "" by "prepre" (a lex-based pre-processor). All

fifteen executables may be compiled from the file.

Fair enough; was not pre-processed. Well, back to Google:

Also, after asking a few questions on the developer”s list, I found out that the EMC2 version of the interpreter is encapsulated in a C++ class. Not too long ago, all the functions in the rs274ngc intepreter were named rs274ngc_functionxxx(), but Paul Corner was kind enough to drop the “rs274ngc_” prefix from all the sources, which was a great first step towards generalizing the interpreter function call interface. Here”s how to find out what interpreter functions are being called: 1. The rs274ngc interpreter in EMC2 (and presumably any future
interpreter) encapsulates its functions into a C++ class named Interp.