DATRON SimPL Programming

DATRON SimPL is a programming language developed by DATRON for users to create their own milling programs on the DATRON next control. If you come from Fanuc-style work, the mental shift is this: SimPL is not a macro layer bolted onto G-code — it replaces both. One readable, English-based, strongly typed language covers everything from “move the axis” to “mill this thread” to “probe this corner and set the work offset,” with real variables, real loops, and named parameters instead of #-numbers and letter arguments. SimPL programs control all work sequences that involve moving the machine axes, and SimPL can also be used within a block editor to edit programs created by CAD/CAM systems. This page maps the language for a programmer who already writes G-code and Macro B; for the control itself see the Datron Control Guide.

What Kind of Language Is This?

SimPL files are pure text files, and the language reads like a lightweight Pascal or C# rather than like NC code. Three properties do most of the work:

  • Strongly typed. Like Pascal, Delphi, Java, C, C++, or C#, every value has a data type fixed when the program is analysed. The great majority of invalid operations are caught when the program is read in and the program is rejected (a loading error) — before the spindle ever turns. Compare that to a Macro B typo that only fails at runtime, mid-cut.
  • Statement-per-line, case sensitive. Statements end at the end of a line (line breaks inside (), [], {} brackets and string literals are ignored). Identifiers are strictly case sensitive; all keywords are written entirely in lower case. Comments start with # to end of line, or use <-- … --> for in-line and multi-line comments.
  • G-code is still available inside it. To ease the transition, some G-code commands per DIN 66025 (linear and circular interpolation, tool change words) are supported, and G-code lines can be mixed with genuine SimPL statements such as loops and conditions. Numeric parameters in those G-code lines must be literals — no expressions or variables. A user-editable G-code wrapper lets you map non-standard or custom G-codes to SimPL commands of your choice.

One more expectation to reset: there is no O-number word-address soup here. You write in an editor with syntax structure, the control validates the whole module on load, and execution starts from program Main.

Structure of a SimPL Program

Modules are the top structural level in SimPL. A module is represented on a storage medium by a single file with the .simpl extension, has a unique name, and contains its elements in a fixed order: module properties, references (import, using, sequence, usermodule), definitions of data types, declarations of module variables, and then the programs. One module contains exactly one main program program Main and any number of sub-programs. Here is a minimal module, assembled from the manual’s own header and library examples and commented:

module Using_SampleLibrary          # module name = first line of the file
@ MeasuringSystem = "Metric" @      # module property: metric units
using Base                          # Base system library = all milling commands
using SampleLibrary                 # reference a user library module

export program Main                 # exactly one Main per module
# call an exported program from the library by name
MyLibraryProgram name="Milling with DATRON next"
endprogram
end                                 # closes the module

The pieces, in the order the manual defines them:

ElementSyntaxRole
Module headermodule NameendWraps the whole file. A SimPL module corresponds to an HSCpro .mcr macroproject.
Module properties@ MeasuringSystem = "Metric" @Metadata such as the measurement system; annotations like @ ToolDescription : … @ and @ WorkpieceGeometry : … @ describe tools and blank size for validation and simulation.
Referencesusing Base, import Math, sequence s1, usermodule n = "…"using makes exported names usable directly; import requires the qualified Module::name form; sequence declares CAM sequence files; usermodule pulls in a stored SimPL program as a subprogram.
Programsprogram Name … endprogramOne Main plus any number of sub-programs; prefix with export to make one callable from other modules.
Functionsfunction f (x:number) returns number … endfunctionSide-effect-free calculations, called as f(x) inside expressions; must have a return value and at least one parameter.

Programs take named, typed call parameters — each declared as name:datatype, passed in any order, optionally marked optional, with a returns clause for a return value:

program tasche breite:number länge:number tiefe:number    # a pocket program (manual's example)
# Anweisungen (statements)
endprogram

# called from another program - parameters by NAME, any order:
tasche breite=10.5 länge=33.3 tiefe=5.4
tasche länge=33.3 tiefe=5.4 breite=10.5   # same effect

That call syntax is the Datron answer to G65 P9101 A1.5 B-0.5 — except the arguments have names and types instead of letters, and forgetting a required one is a load-time error, not a silently null #1. Inside a program, parameter hasvalue tests whether an optional parameter was actually passed before you touch it (touching an unset one is a runtime error). Boolean switches have an abbreviated form (manualFeed alone means manualFeed=true), and so do enumeration parameters.

The Command Families

The manual’s own command overview (ch. 3.2) groups the Base module’s commands into families. Command spellings below are verbatim; this is the map to keep at hand:

FamilyExample commandsWhat it covers
ToolsTool, ProvideTool, GetTool, MeasureToolLength, ToolCompensationTool changing, pre-staging the next tool, reading/writing tool data, length measurement, radius compensation.
Process cyclesDrill, DrillMilling, Thread, RectangleCavity, CircleCavity, RectangleFace, StandardTextEngraveComplete machining operations: drilling, bore milling, thread milling, contours, pockets, face milling, engraving.
Measuring cyclesCornerMeasure, SurfaceMeasure, EdgeMeasure, CircleMeasure, SymmetryAxisMeasureProbing with the XYZ sensor: corner, Z-height, edge, rectangle/circle centre, symmetry, plane.
Position modesAbsolute, Incremental, Rapid, Line, Arc, Helix, SafeRapid, PrePositioningRaw axis motion plus “safe movements” that retract to a safe Z-height first; MoveToParkPosition parks and unlocks the door.
TechnologyFeed, Rpm, Spindle, SpraySystem, Coolant, Rtcp, SmoothingFeed rate, spindle speed and on/off, spray cooling, vacuum, rotary-axis settings, RTCP/multi-axis, dynamics, contour smoothing.
TransformationsSetWcs, ShiftWcsAbs, RotateWcsInc, MirrorWcs, ShiftLcsAbs, WorkPlaneWork piece coordinate systems (Wcs, always based on the machine coordinate system Mcs), local coordinate systems (Lcs) with mirroring and scaling, plane selection.
Program flow & interactionBeginBlock/EndBlock, Dialog, InputDialog, StatusMessage, SleepProgram structure blocks, operator dialogues and notifications, dwell/wait, plus PathCorrection/ZAxisOffset path corrections.
Inputs/outputsGetUserInput, SetUserOutput, WaitForAutomationInput, SetAutomationOutputsUser I/O and automation I/O for fixtures, pallet systems, and cell integration.
Extended modulesMathematics, String, File, DateTime, Pattern, Socket API, Serial port APILibrary modules beyond Base: math functions, string and file handling, circle/rectangle hole patterns, even TCP-socket and serial-port communication from part programs.
Surface profile / camera / visionSurfaceCompensationZGridMeasure, RunExternalProgram, CameraScanCode, VisionMeasureSinglePositionZ-measuring fields for surface compensation, calling external programs and sequences, optional camera code detection and vision measurement.

Notice what that list implies: things that need a DPRNT hack, a ladder edit, or an option board on a Fanuc — writing files, talking to a socket, popping an operator dialogue, scanning a barcode — are ordinary documented commands here. Commands can be typed directly or picked from buttons in the editor; selecting a command and pressing Ctrl + T opens a graphical input mask for its parameters.

Variables, Types & Expressions

SimPL’s simple data types are number (a 64-bit floating-point value; whole numbers exact to about ±1.1×1015), string (Unicode, in double quotes), and boolean (true/false). On top of those you can define enumerations, structures (nested to any depth, even recursive via lists), sets, and lists (dynamic arrays), plus reference/action types that pass one program to another as a parameter. Declaration is either explicit (name:datatype) or implicit — assign to a new name and the variable is created with the value’s type, fixed from then on:

depth:number                        # explicit declaration - no value yet
depth = 5.0                         # assignment
count = 8                           # implicit declaration: count is a number now, forever

structure coordinate ( x:number, y:number)          # user-defined type (manual's example)
StartingPoint:coordinate = { 100, 200 }             # initialiser list
startx = StartingPoint.x                            # component access with "."

Primzahlen:number[]= { 2, 3, 5, 7, 11, 13, 17, 19 } # a list (dynamic array)
append 29 to Primzahlen                             # lists grow with append/insert/remove
Länge = sizeof Primzahlen                           # sizeof = current length

Enumerations deserve a special mention because the built-in commands lean on them everywhere (CircularDirection.CCW, CsType.Wcs, SpraySystemModes.Automatic are all enumeration constants). Defining your own turns magic numbers into checked, self-documenting states:

enumeration SpraySystemMode ( On, Off, Automatic )       # manual's example
currentMode SpraySystemMode = SpraySystemMode.Off
# assigning a value from a DIFFERENT enumeration is a loading error -
# the program is rejected before it runs

Arithmetic uses + - * / % with normal precedence and parentheses; comparisons are ==, <>, <, >, <=, >=; logic is and, or, xor, not. Two details worth knowing: number comparisons build in a tolerance (values whose difference is under 1×10-12 of the larger magnitude compare equal, so ten additions of 0.1 still == 1.0), and a variable read before it has a value is a runtime error — the hasvalue operator is the guard. Variable values can even be made persistent: savevalueof stores a variable’s value in a database so it survives program end, reboot, and software updates. The one-sentence contrast with Fanuc: where Macro B gives you numbered, untyped boxes (#100, #500) whose meaning lives in comments, SimPL gives you named, typed, scope-checked variables whose misuse is rejected before the program runs.

Where variables live. Module variables are declared at the beginning of the module (before the programs), are readable and writable by every program in the module, and are re-initialised at every program start. Local variables and call parameters exist per program call — SimPL programs are reentrant, so recursion is possible (the manual demonstrates a recursive tree-walking function, and also demonstrates the crash you get from mutual recursion with no exit condition). Scopes are hierarchical: module scope, then program/function scope, then block scope inside if/for/while/foreach blocks, and one identifier spelling can exist only once per scope chain. Module variables cannot be exported directly; the manual’s pattern is to expose them through an exported program with an assignable parameter, which callers then read and write as if it were a variable.

Control Flow

All the structured forms are here, each closed by its own end… keyword: if..else..endif, a multi-way case..is..else..endcase (selectors may be enumeration, string, or number), while..endwhile, a counted for..from..to..step..endfor, and foreach..in..endforeach over lists and sets, with break to leave the innermost loop and return/exit/abort to leave the program, all processing, or trigger a PLC stop respectively. A hole grid — the classic Macro B WHILE exercise — comes out like this (drilling command verbatim from the manual’s Drill example, loop adapted):

# 5 x 3 hole grid, 10 mm pitch - no counters to reset, no GOTO labels
for ix from 0 to 4
for iy from 0 to 2
PrePositioning X=(ix * 10) Y=(iy * 10)     # safe move via safe Z-height
Drill depth=10 infeedZ=3 strokeRapidZ=14 strokeCuttingZ=1
endfor
endfor

The for loop computes each pass as start + index × increment internally, so accumulated floating-point error never changes the trip count — the manual notes a loop from 0 to 1 in steps of 0.0000001 executes exactly 1,000,001 times. Subprograms are just the named-parameter program calls shown above; reference and action parameters go further and let you pass a whole program into a generic executor. The manual’s own example is worth seeing, because there is no Macro B analog at all — a program that mills any feature at a list of positions:

structure position (x:number, y:number)

program Executor todo:action places:position[]     # manual's example
foreach point in places
Line X=point.x Y=point.y
todo                                           # run whatever program was passed in
endforeach
endprogram

program main
kreisPositionen:position[]= { { 100,100 }, {100,200} }
Executor todo=(Kreis radius=30) places=kreisPositionen        # mill 2 circles
endprogram

A goto with string labels (: Label1) also exists, but the manual is blunt that it was implemented exclusively to enable automatic conversion of old MCR programs into SimPL and should never be necessary in manually written code — it even prints a spaghetti example labelled as what not to do.

Machining Commands vs Raw Moves

This is the language’s distinguishing trait against G-code. SimPL has the low-level layer — Rapid X=100 Y=20 Z=5, Line X=100, Arc X=20 Y=20 radius=20 direction=CircularDirection.CCW, Helix diameter=20 deltaZ=20 pitch=1 — but you reach for it far less often, because the process cycles express whole features. Milling a 15 mm bore 10 mm deep with an end mill, by hand, is a helix plus finishing passes plus approach and retract; in SimPL it is one documented command:

# G-code way: G0 position, G1 plunge ramp, G2/G3 helix per pass,
# spring pass at final diameter, retract... 20+ blocks you must get right.

# SimPL way - one command, from the manual:
DrillMilling diameter=15 depth=10 infeedZ=3 strokeRapidZ=14 strokeCuttingZ=1 finishingXY=0.1 finishingZ=0.1 infeedFinishingZ=0.1

The cycle owns the whole feature: infeedZ divides the depth into cuts, strokeRapidZ/strokeCuttingZ define where positioning feed hands over to cutting feed (dwelling until the spindle reaches speed), and the finishing… parameters add finish passes that automatically account for the roughing stock. The manual also guarantees that in all machining cycles the tool tip returns to the start position at the end — so cycles compose cleanly inside loops. Thread milling is the same idea at a higher level still: Thread threadStandard=ThreadStandards.Metric threadName="M6" depth=10 pulls the geometry of an M6 from the thread standard table. Tool changes and technology settings are one-liners in the same style: Tool toolNumber=1 newRpm=30000, Rpm value=10000, Feed value=1500, Spindle mode=Activation.On, SpraySystem mode=SpraySystemModes.On.

CAM Programs: Sequences

Long, automatically generated CAM programs get their own vehicle: sequences. A sequence can be any length (up to many gigabytes — many times larger than the control’s RAM) and is executed line by line without being loaded and analysed first, which makes loading fast. The trade-offs: sequences cannot contain arithmetic expressions, loop constructs, or strongly typed variables (a postprocessor doesn’t need them), and a syntax error is not detected until execution reaches it. Sequence lines can hold standard DIN 66025 G-code, simple untyped variable assignments (X = 500), and calls to any SimPL program known in the calling module. A hand-written module declares each sequence in its header and calls it like a program, passing parameters in:

module Bauteil                       # manual's example: calling a CAM sequence
sequence Ausbruch_Form_A             # declare the sequence in the module header
program main
Fläche = 15
Tiefe = 5
Ausbruch_Form_A X = Tiefe Y = Fläche / Tiefe    # call it like a program
return
end

Sequences live either in separate .seq files (module property @ EmbeddedSequences = false @) or embedded after the module’s closing end, each introduced by a $$$ Sequenzname line — so a program plus its CAM toolpaths can travel as one machine-readable text file. Inside a sequence, comments may start with ;, #, or ( — friendly to what postprocessors already emit.

Probing from SimPL

The measuring cycles drive the machine’s XYZ sensor and feed their result straight into the coordinate-system machinery — no G31 skip-and-arithmetic dance. Every measuring cycle automatically activates the probe and resets it afterwards (fold it out manually with PrepareXyzSensor only when chaining many measurements). The cycles are CornerMeasure, RectangleMeasure, CircleMeasure, SurfaceMeasure (Z-height), EdgeMeasure, SymmetryAxisMeasure, and the optional PlaneOrientationMeasure. The common resultCs parameter decides what happens with the result: CsType.Wcs sets the active work piece coordinate system, CsType.Lcs generates an origin offset, and CsType.None just hands the result back as a return value for your own logic.

# touch off the top of the stock and make it the active Wcs Z-origin (manual's example)
SurfaceMeasure resultCs=CsType.Wcs originZShift=0 stockOffset=1 retractDistance=15

One behavior to plan around: measured values set during a program are reset after the program ends, back to the coordinate system that was active at the start — deliberate, so a re-fixtured vacuum-plate job can recalibrate on every run. If the measured origin should survive the program, it must be set to “Initial” before the end.

Coming from Macro B: a Translation Table

Fanuc / Macro B habitSimPL equivalent
#100 = 2.5 (numbered, untyped)depth = 2.5 — named, typed number; or explicit depth:number
#500#999 (survive power-off)savevalueof persistent values (survive reboot and software updates)
WHILE […] DO1 … END1while … endwhile; counted loops: for i from 0 to 9 step 1 … endfor
IF […] GOTO nif … else … endif, case … is … endcase (a string-label goto exists, only for converted MCR programs)
G65 P9101 A1.5 B2. letter argsProgram call with named parameters: tasche breite=10.5 tiefe=5.4; optional + hasvalue replace null-checks on #1#33
G0 / G1 / G2 G3Rapid / Line / Arc (plus Helix, SafeRapid, PrePositioning)
G90 / G91Absolute / Incremental
G54… work offsetsWcs commands: SetWcs, ShiftWcsAbs X= Y= Z=, SaveWcs/LoadWcs, named systems via WcsExisting name="abc"
G41 / G42 cutter compToolCompensation mode=CompensationMode.Left (or .Right, .Off)
T1 M6, S10000 M3, M8Tool toolNumber=1, Rpm value=10000 + Spindle mode=Activation.On, SpraySystem mode=SpraySystemModes.On
G31 skip + system-variable mathMeasuring cycles: CornerMeasure, SurfaceMeasure, EdgeMeasure … with resultCs setting the Wcs directly
G81/G84 canned cyclesProcess cycles: Drill, DrillMilling, Thread, RectangleCavity, CircleFace
DPRNT output tricksValueToString plus the String and File extended modules; operator messages via Dialog, InputDialog, StatusMessage

Putting It Together

Here is what the pieces look like as one small part program — probe the stock height, then bore-mill a 5×3 grid of 6.5 mm holes. Every command’s syntax is verbatim from the manual’s per-command examples; the composition is adapted for this page:

module BoltPlate
@ MeasuringSystem = "Metric" @
using Base

export program Main
Tool toolNumber=3 newRpm=24000    # load the end mill; rpm set on the way from the magazine
Feed value=1500                   # cutting feed, mm/min

# touch off the stock top and set it as the active Wcs Z-origin
SurfaceMeasure resultCs=CsType.Wcs stockOffset=1 retractDistance=15

for ix from 0 to 4                # 5 columns, 12 mm pitch
for iy from 0 to 2              # 3 rows
PrePositioning X=(ix * 12) Y=(iy * 12)     # safe move via safe Z-height
DrillMilling diameter=6.5 depth=8 infeedZ=2 strokeRapidZ=10 strokeCuttingZ=1
endfor
endfor

MoveToParkPosition                # park; the safety door unlocks automatically
endprogram
end

Read it against the Macro B version in your head: no #-variables, no WHILE…DO1 counters to advance, no G43 H3, no hand-rolled helix. Fifteen working lines cover tool change, technology, probing, safe positioning, and fifteen fully finished bores.

The Editor and Running from a Label

SimPL is written in the on-control editor, which pairs the text view with command buttons and the Ctrl + T graphical input masks, alongside Execute and Simulate. Two execution features matter on the shop floor. Multiple execution (optional) mills multiple components from one program start — either in a fixed matrix pattern (offset and count in X and Y, with the minimum required stock size calculated for you) or at a list of individual origins for multiple clamped work pieces; optimised mode can keep the spindle on and skip redundant tool changes between components. Run from label is the recovery tool: after an interruption — a broken tool, an abort, or bumping a hot job in front of this one — milling can be continued from a specific marked program line. You put the cursor on the line, switch on Start from cursor, and a dialogue asks for the conditions: the number of cycles (which pass of a loop or subprogram to resume in), which component (under multiple execution), and the mode — Restart continues the whole program from that line onward, while Reposition executes only the marked operations for the selected components, e.g. to repeat one machining step.

Note that the Macro Playground does not execute SimPL — it runs Fanuc/Haas Macro B, Heidenhain, Siemens, and Okuma programs — but the variable and loop concepts you can experiment with there carry over directly.

Gotchas

  • Case matters, everywhere. Identifiers are strictly case sensitive — Depth and depth are different names — and all keywords must be lower case. Fanuc habits of shouting in caps will produce loading errors.
  • An implicit declaration fixes the type forever. count = 8 creates a number; assigning a string to count later is a loading error. Convenient, but it means a typo in a variable name silently declares a new variable instead of failing.
  • Unset values are errors, not zeros. Reading an explicitly declared variable before its first assignment, or an optional parameter the caller skipped, is a runtime error — SimPL’s stricter cousin of Macro B’s null-vs-zero trap. Guard optional parameters with hasvalue before touching them.
  • No expressions inside G-code lines. Mixed-in G-code accepts only numeric literals per DIN 66025 — G01 X#100-style variable moves don’t exist. If you want computed motion, use the SimPL commands (Line X=(ix * 10)); complex parameter expressions should be enclosed in brackets.
  • Sequences are unchecked until they run. A syntax error in a CAM sequence is not detected until execution reaches it, and execution then aborts. The manual’s advice for a new, previously unknown sequence: run it in simulation mode first to verify it.
  • = copies lists and structures, <- shares them. Assigning or passing a list/structure with = makes an independent copy; <- passes the reference, so changes inside the callee reach the caller’s data. Passing to functions is always by reference. Pick deliberately — the manual shows the same call producing 42 or 42² depending on the operator.
  • Probed origins vanish at program end. Measurement results set during a program reset to the coordinate system active at program start unless set to “Initial” before the end (see the probing section above).

See Also

References

  • DATRON AG, DATRON next SimPL Programming Manual, Version 2.18.1, Document 2181 (EN).

Have a question or want to contribute?

Contact us with corrections, additions, or topics you'd like covered.

Get in Touch