# GCode Meta Commands

RepRapFirmware 3.01 introduced the concept of basic programming constructs (conditionals, loops and parameters) to Gcode. This combined with the rich object model in RRF3 provides a powerful new layer of control customisation.

RepRapFirmware 3.01 and later provide GCode programming constructs to allow conditional execution and iteration, and allow parameter values in GCode commands to be expressions instead of literals.

## Programming constructs

### Abort command

abort <opt-expression>

This causes all nested macros and the current print file (if any) to be terminated. The expression (if present) is converted to a string, which is included in the message presented to the user and written to the log file.

### Echo command

echo <expression>, <expression>, ...

At least one expression must be provided. The expressions are converted to strings and written to the console, with a space character between each pair. This command is intended for debugging. Example:

echo move.axes[0].homed, move.axes[1].homed, move.axes[2].homed

### Conditional construct

The general form of the conditional block is:

if <boolean-expression> ... elif <boolean-expression> ... else ...

where as usual the “elif” part can be omitted or repeated, and the “else” part can be omitted. The bodies of the if, elif and else parts may contain ordinary GCode commands and/or program elements. Each line in the body must be indented from the corresponding keyword to indicate the extent of the body. The body ends just before the first line that is not indented.

### Loop

while <boolean-expression> ...

The body must be indented from the while keyword. The body ends just before the first line that is not indented.

A loop may contain one or more break statements, which would normally be inside if-constructs:

while <boolean-expression> ... if <boolean-expression> break ...

The break statement transfers control to the line following the end of the loop body.

A loop may also contain one or more continue statements, which would normally be inside if-constructs:

while <boolean-expression> ... if <boolean-expression> continue ...

The continue statement increments the iteration counter and transfers control back to the start of the loop, ready to evaluate the while-condition again.

### Variable declaration

*Not yet implemented*

var <new-variable-name> = <expression>

This creates a new variable and initializes it to *expression*. The name must not already be in use. Names of the form global.identifier are global names, and names of the form local.identifier or just identifier are local names. The scope of a local name is the remainder of the block in which it is declared.

### Variable assignment

*Not yet implemented*

set <existing-variable-name> = <expression>

This re-assigns an existing variable to have value expression. The type of expression (float, int, string, bool) must be the same as when the variable was declared, except that an expression of integer type can be assigned to a variable of floating point type.

## Use of expressions within GCode commands

This form:

{ <expression> }

may be used in place of any numeric or quoted string within a GCode command. Example:

G1 X{move.axes[0].max-10} Y{move.axes[1].min+10}

## Expressions

### General

Tabs and space characters may be used freely between variable names, keywords, literals and other lexical elements to improve readability.

Sub-expressions may be enclosed in { } or in ( ). The outermost level must always be { } because standard CNC GCode uses ( ) to enclose comments. RepRapFirmware treats ( ) as enclosing subexpressions if they appear inside { }, and as enclosing comments when they do not.

### Types

The available types of expressions and variables are: **bool**, **int**, **float**, **string**, **object** and **array**. The only operations available on values of type **object** are comparison with **null** and taking a member. The only operations available on values of type **array** are taking the length (unary prefix operator #) and indexing (operator [ ] ).

### Type conversions

The following implicit type conversions will be performed when necessary:

- from type
**int**to type**float** - from any type to
**string**

### Named constants

The following names constants are provided:

Name | Type | Meaning |
---|---|---|

false | bool | Boolean false |

iterations | int | The number of completed iterations of the innermost loop |

line | int | The current line number in the file being executed |

null | object | The null object |

pi | float | Pi (3.14159265...) |

result | int | 0 if the last G-, M- or T-command on this input channel was successful, 1 if it returned a warning, 2 if it returned an error. Meta commands do not change 'result'. |

true | bool | Boolean true |

### Literals

Decimal integer, floating point, and string literals may be used.

### Object model properties

Expressions may use the values of any properties in the RepRapFirmware Object Model (OM). See Object Model of RepRapFirmware to see what is available. An object model property selector must evaluate to a single string, numeric or Boolean value, unless it is the operand of the unary # operator in which case it must evaluate to an array or a string.

### Variables

[TODO]

### Unary prefix operators

Operator | Signature | Meaning |
---|---|---|

! | bool->bool | Boolean not |

+ | int->int, float->float | Unary + |

- | int->int, float->float | Unary - |

# | X[]->int, string->int | Number of elements in array, or number of characters in string |

### Binary infix operators

Where an expression has multiple binary operators of the same precedence and parentheses are not used to specify the order of evaluation, the operators are evaluated from left to right.

Operator | Precedence | Signature | Meaning |
---|---|---|---|

* | 6 | (int,int)->int, (float,float)->float | Multiplication : See CAUTION note below |

/ | 6 | (float,float)->float | Division |

+ | 5 | (int,int)->int, (float,float)->float | Addition |

- | 5 | (int,int)->int, (float,float)->float | Subtraction |

= or == | 4 | (int,int)->bool, (float,float)->bool, (string,string)->bool | Equality |

!= | 4 | (int,int)->bool, (float,float)->bool, (string,string)->bool | Inequality |

< | 4 | (int,int)->bool, (float,float->bool | Less than |

<= | 4 | (int,int)->bool, (float,float)->bool | Less than or equal |

> | 4 | (int,int)->bool, (float,float)->bool | Greater than |

>= | 4 | (int,int)->bool, (float,float)->bool | Greater than or equal |

& or && | 3 | (bool,bool)->bool | Boolean and |

| or || | 3 | (bool,bool)->bool | Boolean or |

^ | 2 | (string,string)->string | String concatenation |

**Caution!** The multiplication operator * will work when it is used anywhere inside an expression or subexpression enclosed in { } but not otherwise. This is because the * character in a line of GCode normally introduces an end-of-line checksum.

### Ternary operator

The expression <expr1> ? <expr2> : <expr3> evaluates <expr2> if <expr1> is true, otherwise <expr3>. <expr1> must be Boolean. <expr3> may be another ternary expression. The ternary operator has precedence 1.

### Functions

The following functions are supported, with their conventional meanings:

Function name | Signature | Notes |
---|---|---|

abs | float->float or int->int | |

acos | float->float | Result is in radians |

asin | float->float | Result is in radians |

atan | float->float | Result is in radians |

atan2 | (float, float)->float | Result is in radians |

cos | float->float | Argument must be in radians |

degrees | float->float | Converts radians to degrees |

floor | float->int or float->float | Result is int if it fits in a 32-bit signed integer, else float |

isnan | float->bool | |

max | (float, ...)->float or (int, ...)->int | Accepts 1 or more arguments. If any argument is NaN then the result is NaN. |

min | (float, ...)->float or (int, ...)->int | Accepts 1 or more arguments. If any argument is NaN then the result is NaN. |

mod | (int, int)->int or (float, float)->float | |

radians | float->float | Converts degrees to radians |

sin | float->float | Argument must be in radians |

sqrt | float->float | |

tan | float->float | Argument must be in radians |

## Examples of use

### Using conditional GCode commands in bed.g to calibrate a delta printer

Example bed.g file for calibrating a delta printer using conditional GCode. At the start, it homes the printer only if it hasn't already been homed. Then it calibrates the printer by probing a number of points, starting again if probing fails. if calibration yields a standard deviation that is above a limit (set at the end of the loop, in this case >0.03mm), it repeats the calibration process. If calibration fails 5 times for any reason, it quits.

**NOTE:** If you use this method to iterate the levelling of a bed/gantry mounted on leadscrews (eg Cartesian, CoreXY etc), the maximum deviation corrected is still limited by the S parameter of M671 (default 1mm). If the maximum deviation exceeds this limit, the script will exit with "Error: Some computed corrections exceed configured limit of 1.00mm", as it would if G30 bed levelling was called manually.

; Auto calibration routine for large delta printer M561 ; clear any bed transform ; If the printer hasn't been homed, home it if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed G28 ; Probe the bed and do auto calibration G1 X0 Y140 Z10 F10000 ; go to just above the first probe point while true if iterations = 5 abort "Too many auto calibration attempts" G30 P0 X0.00 Y140.00 Z-99999 if result != 0 continue G30 P1 X70.00 Y121.24 Z-99999 if result != 0 continue G30 P2 X121.24 Y70.00 Z-99999 if result != 0 continue G30 P3 X140.00 Y0.00 Z-99999 if result != 0 continue G30 P4 X121.24 Y-70.00 Z-99999 if result != 0 continue G30 P5 X70.00 Y-121.24 Z-99999 if result != 0 continue G30 P6 X0.00 Y-134.85 Z-99999 if result != 0 continue G30 P7 X-65.57 Y-113.57 Z-99999 if result != 0 continue G30 P8 X-112.29 Y-64.83 Z-99999 if result != 0 continue G30 P9 X-130.59 Y-0.00 Z-99999 if result != 0 continue G30 P10 X-115.90 Y66.91 Z-99999 if result != 0 continue G30 P11 X-69.45 Y120.29 Z-99999 if result != 0 continue G30 P12 X0.00 Y70.00 Z-99999 if result != 0 continue G30 P13 X60.62 Y-35.00 Z-99999 if result != 0 continue G30 P14 X-52.28 Y-30.19 Z-99999 if result != 0 continue G30 P15 X0 Y0 Z-99999 S8 if result != 0 continue if move.calibration.initial.deviation <= 0.03 break echo "Repeating calibration because deviation is too high (" ^ move.calibration.initial.deviation ^ "mm)" ; end loop echo "Auto calibration successful, deviation", move.calibration.final.deviation ^ "mm" G1 X0 Y0 Z150 F10000 ; get the head out of the way

## 11 Comments

Please note that the example will only succeed if your probes are within the limits set by your M671 S parameter. This defaults to 1mm

Tekky Dave - Reply

updated my duet maestro tonight. Very much looking forward to var/set functionality. Also, maybe expose probe offsets in object model? It would bee really nice to calc various coords compensating for the offset

Matthew Giant - Reply

Z probe offsets are already reported in the OM at sensors.probes[0].offsets[]

David Crocker -

“Z probe offsets are already reported in the OM at sensors.probes[0].offsets[ ].” You may be correct, but it is not clear that its documented in the link provided on this page for the OM

egmrudd -

move.calibrationDeviation.deviation

should be

move.calibration.final.deviation

at least according to my object model

Nikolai Schauer - Reply