Parameters and expressions allow you to use gocde as a programming language. It has a lot of limitations, but should be able to allow you to create more powerful macros and things like simple tool changers. It is based on LinuxCNC and NIST RS274NGC
Note: This is an advanced feature for advanced users. You should be an expert in gcode before you attempt using gcode parameters. Please consider become a project supporter before asking for support on this feature.
There are three kinds of syntactic appearance:
The value of a parameter is a floating point number. A parameter reference can appear in GCode in place of any number. So for example you could say
G0 X#<saved_x>
instead of
G0 X5
The value of a parameter can be assigned with =, as in
#<myparam>=5
The new value can be a number, another parameter value, or an expression
#<saved_wco_x>=#5221
You can put multiple assignments on one line
#<saved_wco_x>=#5221 #<saved_wco_y>=#5222
You can put ordinary GCode on the same line with parameter assignments, but if you do so, the new parameter values will not take effect until after the GCode has been executed. So if you say
#<x>=4
#<x>=5 G0 X#<x>
the target of the G0 is X4, and the value of parameter #<x>
will not change to 5 until after the G0 X4
command has been issued.
You can set named global parameters.
#<_feed>=1500
; or
#<my_feed>=1500 ; set a local parameter
#<_feed>=#<my_feed> ; set the feed rate with a local paramter
These numbers come from the GCode standard and LinuxCNC. Not all are supported yet.
Example
D#5400 ; Get current tool number
[MSG:INFO: Value is 2.000]
ok
#<my_tool_num>=#5400
ok
D#<my_tool_num>
[MSG:INFO: Value is 2.000]
ok
You can use math expressions to calculate the numbered parameter you want
D#5422
[MSG:INFO: Value is 38.987]
ok
D#[5420+2]
[MSG:INFO: Value is 38.987]
ok
Say, for example, you want to know the current coordinate offset of the Z axis. You can get the current coordinate system with 5220. The values of the offsets start at #5221 and are 20 apart.
$#
[G54:48.000,-89.000,-44.577]
[G55:70.000,-10.000,-31.657]
...
[TLO:4.590]
ok
D#[5221 + [#5220 * 20] + 2]
[MSG:INFO: Value is -31.620]
ok
Local named parameters are ones whose names you choose, that do not begin with an underscore (_) character. They have "local scope", which means that they only exist within the context of a single file or macro. A local named parameter that is defined in one file is not visible within another file. That means that you can use the same name within multiple files without conflict, even if one file invokes another.
#<i>=123.4 (create a variable with the name i and give it a value of 123.4
If a parameter name begins with an underscore character (_), it has "global scope". The same parameter can be set or read from any context, and the current value can be "seen" from anywhere. Thus global parameters can be used to pass information between files.
You can define your own named global parameters, and there are also some system-defined global parameters that give information about the operation of FluidNC.
#<_x>
#</axes/x/steps_per_mm>
These are the current work coordinates with all offset applied (like $10=2) for the axes.
#<s>=#<_spindle_m> (set local parameter s to the global parameter _spindle_m
M5 ( turn off spindle
... do something with the spindle off
M#<s> (Restore the spindle to its previous mode, like M3
Returns the current value of F, not the actual feed rate.
Example: Save and restore the distance mode.
#<my_incremental>=#<_incremental> ; save the distance mode
... do something that changes the distance mode, like perhaps G91
G[90+#<my_incremental>] ; restore the distance mode
The D word in GCode can be used show the value of a parameter, for debugging purposes. The number (or parameter value, or expression result) follwing D will be displayed in an INFO message.
D is a standard GCode word that is normally used for cutter diameter in the context of "Dynamic Cutter Compensation" - G41.1 and G42.1 - which FluidNC does not support. We have abused D for this debugging use. If FluidNC ever supports dynamic cutter compensation, the D word might be reassigned its standard meaning, so you should not use this debugging feature in production programs. Use it only for exploration.
#<s>=#<_spindle_m> (set local parameter s to the global parameter _spindle_m
D#<s> (Display the value of local parameter s
[MSG:INFO: Value is 5.000]
More Information
Expressions let you perform computations on numbers and parameter values. As with parameter references, they can appear in place of any GCode number.
Absolute value
Inverse cosine
Inverse sin
Four quadrant inverse tangent
cosine
e raised to the given power
Round down to integer
Round up to integer
Base-e logarithm
Round down to integer
sine
Square root
Return 1 if the parameter exists, 0 if not
#<foo>=5
ok
D[EXISTS[foo]]
[MSG:INFO: Value is 1.000]
ok
Note: SIN, COS, TAN, etc use degrees, not radians
G0 X[#<saved_x> + 5.3] F[#</axes/x/max_rate_mm_per_min * 0.5]
G0 Y[#<saved_y> * 0.9 + 1.2]
G0 A[SIN[30] * #<a_scale_factor>]
In the expressions - and in fact in all of GCode - spaces are ignored, so you can use them for readability or omit them, as you prefer.
Flow control allows branching and looping in gcode.
Currently, this is only fully supported in gcode files stored on an SD card or the LocalFS. This is because FluidNC needs a way to move freely up and down through the file when branching and looping. This is not possible from a gcode sender or a console.
o (the letter, not the number) codes are used to define code blocks. Use matching numbers to define the code block. Based on the LinuxCNC implementation.
Numerical value of 0 is equivalent to logical false. Any nonzero value is considered to be logical true.
; check for probe success
o100 if [#5070]
G53G0Z-1 ; move to top of Z
o100 endif
(if parameter #2 is greater than 5 set F100)
o102 if [#2 GT 5]
F100
o102 elseif [#2 LT 2]
(else if parameter #2 is less than 2 set F200)
F200
(else if parameter #2 is 2 through 5 set F150)
o102 else
F150
o102 endif
repeat example
#<_times>=4
o101 repeat[#<_times>]
G91 G1 X5 F500
(MSG: Repeat)
o101 endrepeat
while example:
G91
F500
#<_x> = 0
o101 while [#<_x> LT 10]
G1 X5
#<_x> = [#<-x>+1]
o101 endwhile
do example
G91
F500
#<_x> = 0
o102 do
G1 X5
#<_x> = [#<-x>+1]
o102 while[#<_x> LT 5]]
Inside a while loop, o<num> break immediately exits the loop, and O<num> continue immediately skips to the next evaluation of the while condition. If it is still true, the loop begins again at the top. If it is false, it exits the loop.
Alarms (such as hard or soft limit violations) that are generated by FluidNC will stop all running jobs and enter the Alarm state.
If you want create your own alarm, you can use the $Alarm/Send-\<alarm_num>
command.
#<my_tool>=1
#<max_tool_num>=4
o101 if [#<my_tool> GT #<my_tool>]
$Alarm/Send=13
o101 endif
Listed in precedence order
Operator | Description | |
---|---|---|
** | Power | |
* | Multiply | |
/ | Divide | |
MOD | Modulus | |
+ | Add | |
- | Subtract | |
EQ | Equal | |
NE | Not equal | |
GT | Greater than | |
GE | Greater than or equal | |
LT | Less than | |
LE | Less than or equal | |
AND | And | |
OR | Or | |
XOR | Exclusive or |
This allows you to print messages from gcode with formatted parameters. There are 2 types
#<foo>=123.456789
ok
#<BAR>=54321
ok
(print,foo is #<foo>, bar is %d#<bar>, fooint is %d#<foo>, bar2 is %.2f#<bar>, foo4 is %f#<foo>)
[MSG:INFO: PRINT,foo is 123.456779 bar is 54321 fooint is 123 bar2 is 54321.00 foo4 is 123.4568]
ok
(debug,foo is #<foo>, bar is %d#<bar>, fooint is %d#<foo>, bar2 is %.2f#<bar>, foo4 is %f#<foo>)
[MSG:DBG: DEBUG,foo is 123.456779 bar is 54321 fooint is 123 bar2 is 54321.00 foo4 is 123.4568]
ok
G91
F500
#<_foo> = 0
o102 do
G1 X5
(print, foo=%d#<_foo>)
#<_foo> = [#<_foo>+1]
o102 while[#<_foo> LT 5]]
Parameters and Flow Control are dependant on scope. There is a global scope (includes the console) and job scopes. Jobs are typically gcode files stored on the SD card or LocalFS.
Parameters that start with a leading underscore #<_myparam>
are global in scope, They can be created, accessed and modified from any scope. Paramters without a leading underscore #<myparam>
have a scope that is local to the job. This means you can have independent parameters with the same name in different scopes.
Flow control should only be used in job scopes. Gcode coming from the console or streamed from gcode senders is executed and forgotten. Looping will not work because the contents of the loop was never saved.
o<numbers> are local in scope. You can safely use the same number in multiple scopes.
; dual speed probe macro
; set parameters
#<fast_rate>=160
#<slow_rate>=80
#<probe_dist>=100
#<probe_offset>=0
#<retract_height>=5
G38.2 G91 Z[-#<probe_dist>] F#<fast_rate> ; probe fast
G0 Z3 ; retract a little
G38.2 G91 Z[-#<probe_dist>] F#<slow_rate> P#<probe_offset> ; probe slowly
G0 Z[#<retract_height>+#<probe_offset>] ; retract
; be careful you are still in G91 mode
; Get the range of the x axis from config values.
o100 if [#</axes/x/homing/positive_direction>]
#<x_max>=#</axes/x/homing/mpos_mm>
#<x_min>=#<x_max> - #</axes/x/max_travel_mm>
o100 else
#<x_min>=#</axes/x/homing/mpos_mm>
#<x_max>=[#<x_min> + #</axes/x/max_travel_mm>]
o100 endif
(print, X Range is %.2f#<x_min>, - %.2f#<x_max>)