Simcnc Python Scripts Guide en
Simcnc Python Scripts Guide en
control software
Guide To Python Scripts
simCNC control software supports scripts that automate procedures such as tool change or tool length
measurement. The usability of the scripts does not end with such procedures, however, and it is sometimes
necessary to write scripts that are much more complex. To help the software’s users create their own scripts,
simCNC uses Python as a script language.
Python is a general-purpose high-level programming language with an extensive set of standard libraries, which
mainly features simple and clear source code. Its syntax is also clear and concise.
Python is used by both beginners and professionals. With the language being so popular, many tutorials and
libraries are created that can be found on innumerable websites. With such things in place, the only obstacle on
the way to write your own script is your willingness and imagination.
Page 3
When simCNC is installed on the hard disk, Python is installed as separate software, too. simCNC communicates
with Python via the UDP Internet protocol using a special library called ___COMM.pyc. In addition to this library,
the developers have also prepared a library called ___DEVICE.pyc, which contains a collection of functionalities to
control simCNC using macros.
− use an advanced external programming editor with debugging feature, such as Visual Studio Code.
− control simCNC from another PC across a local network via UDP.
The two solutions will be addressed in more detail in supplementary documentation, whereas this manual
describes the script editor incorporated into simCNC.
Page 4
To run the Python script editor, click on Macro in the upper bar of your simCNC window, and then select Show
Script Editor from the drop-down list.
The Python script editor is provided with a prompt mechanism. To launch it in the editor window, you need only
to press Ctrl + space simultaneously. You can use this combination at any time.
To select a function, highlight it using keyboard cursors and confirm the selection by pressing Enter, or simply
click the selected function with the left mouse button.
ATTENTION!
The list does not include functions that require getting a module and provide direct access to digital and
analog ports.
Page 6
3) If you have found the required function, but you do not know an
argument value.
In such an event, all what you need to do is to delete the argument name and press the key combination Ctrl +
space (if it was not pressed earlier). The prompt window will show you all the variants of the argument value
that match a specific function.
Page 7
1) Getting a Module
To access digital or analog ports of CS-LAB devices, you should first get a module (a module representing a
device, a handle).
FUNCTION ARGUMENTS:
ModuleType type – Type of device
AVAILABLE OPTIONS:
ModuleType.IP – CSMIO/IP-S, CSMIO/IP-A, and CSMIO/IP-M controllers
ModuleType.MPG – CSMIO-MPG manual axis control module
ModuleType.ENC – CSMIO-ENC threading module
ModuleType.IO –CSMIO-IO extra I/O module
ModuleType.DRV – simDrives
AVAILABLE OPTIONS:
CSMIO-IO (ID 0 to 15)
SimDrive (ID 0 to 5)
If more than one CSMIO-IO extra I/O module or simDrive are used, you should enter the appropriate
device number for their identification. This does not apply to the CSMIO/IP controller and the CSMIO-
MPG and CSMIO-ENC modules. Their device number is 0 because they always appear in the control
system one at a time.
FUNCTION RESULT:
Module - Device module
EXAMPLES:
mod_IP, mod_MPG, mod_ENC, mod_IO_0, mod_IO_15, mod_simDrive_0, and mod_simDrive_5 are the
proper names of the modules (handles) created for the purposes of the manual. A module can have any
name, which should clearly state what devices it relates to.
2) Digital Ports
DIOPinVal getDigitalIO( IOPortDir direction, int digitalPin) – Returns the pin value of a digital input or
output (returns the digital input or output value).
FUNCTION ARGUMENTS:
IOPortDir direction – Specifies the port direction
AVAILABLE OPTIONS:
IOPortDir.InputPort - Input port
IOPortDir.OutputPort - Output port
FUNCTION RESULT:
DIOPinVal – Pin value
AVAILABLE OPTIONS:
DIOPinVal.PinReset – Low pin value
DIOPinVal.PinSet – High pin value
EXAMPLES:
void setDigitalIO( int digitalPin, DIOPinVal value) – Sets the pin value of a digital port (sets a digital
output value).
FUNCTION ARGUMENTS:
AVAILABLE OPTIONS:
EXAMPLE:
3) Analog Ports
float getAnalogIO( IOPortDir direction, int analogPin) – Returns the pin voltage of an analog input or
output port (returns the analog input or output voltage).
FUNCTION ARGUMENTS:
AVAILABLE OPTIONS:
FUNCTION RESULT:
void setAnalogIO( int analogPin, float value) – Sets the voltage of an analog port pin.
FUNCTION ARGUMENTS:
ATTENTION!
The pin voltage of analog input and output ports can range from 0 V to 10 V with a resolution of 12 bit.
The pin voltage of the CSMIO-MPG manual axis control module’s analog input port can range from 0 V to
5 V with a resolution of 12 bit.
float getEncoderIOAngle( int channel = 0 ) - Returns the encoder angle as calculated from the index
signal.
FUNCTION ARGUMENTS:
FUNCTION RESULT:
int getEncoderIOPostion( int channel = 0 ) – Returns the encoder position as calculated from the first
index signal.
FUNCTION ARGUMENTS:
FUNCTION RESULT:
EXAMPLE:
float getEncoderIORPM( int channel = 0 ) – Returns the encoder’s rotational speed (RPM).
FUNCTION ARGUMENTS:
FUNCTION RESULT:
ATTENTION!
Threading module channels 0, 2, and 4 are physical channels, whereas channels 1, 3, and 5 are virtual
copies of the physical channels to be used in the future.
Until further notice, physical channels 0, 2, and 4 in simCNC configuration correspond to channels 0, 1,
and 2.
Page 16
1) Reading Coordinates
List<float>(6) getPosition( CoordMode coordMode ) - Returns the current machine or program
coordinates for all the axes.
FUNCTION ARGUMENTS:
AVAILABLE OPTIONS:
CoordMode.Machine – Machine coordinates
CoordMode.Program – Program coordinates
FUNCTION RESULT:
EXAMPLES:
After running the example presented above, the d.getPosition( CoordMode.Machine ) function will read
the machine coordinates of all six axes and put them on a six-item list, which is indexed from 0 through
5. Then use function print( ) to display in the Python console the machine coordinates that are stored in
the list.
Page 17
After running the example presented above, the d.getPosition( CoordMode.Machine ) function will read
the machine coordinates of all six axes and put them on a six-item list, which is indexed from 0 through
5. Then use function print( ) to display in the Python console the machine coordinates that are stored in
the list.
Page 18
void setAxisProgPosition( Axis axis, float value ) – Sets the program coordinates of a selected axis.
FUNCTION ARGUMENTS:
Axis axis – Axis for which the new program coordinates will be saved
AVAILABLE OPTIONS:
Axis.X – Axis X
Axis.Y – Axis Y
Axis.Z – Axis Z
Axis.A – Axis A
Axis.B – Axis B
Axis.C – Axis C
x = 10
y = 20
z = 30
a = 40
b = 50
c = 60
d.setAxisProgPosition( Axis.X, x )
d.setAxisProgPosition( Axis.Y, y )
d.setAxisProgPosition( Axis.Z, z )
d.setAxisProgPosition( Axis.A, a )
d.setAxisProgPosition( Axis.B, b )
d.setAxisProgPosition( Axis.C, c )
d.setAxisProgPosition(Axis.X, pos[0])
d.setAxisProgPosition(Axis.Y, pos[1])
d.setAxisProgPosition(Axis.Z, pos[2])
d.setAxisProgPosition(Axis.A, pos[3])
d.setAxisProgPosition(Axis.B, pos[4])
d.setAxisProgPosition(Axis.C, pos[5])
Page 20
void moveAxisIncremental( Axis axis, float distance, float velocity ) – Moves a selected axis by a set
distance at a preset velocity (incremental movement).
ARGUMENTS:
AVAILABLE OPTIONS:
Axis.X – Axis X
Axis.Y – Axis Y
Axis.Z – Axis Z
Axis.A – Axis A
Axis.B – Axis B
Axis.C – Axis C
EXAMPLES:
After running the example presented above, axes X and Y move from the current position, along the
circumference of a 20 mm or 20” wide square with a velocity of 1000 mm/min or inch/min.
void moveToPosition( CoordMode coordMode, List<float>[6] position, float velocity ) – Moves to the set
position expressed in machine or program coordinates at a preset resultant velocity.
ARGUMENTS:
AVAILABLE OPTIONS:
CoordMode.Machine – Machine coordinates
CoordMode.Program – Program coordinates
List<float>[6] position – A list of the six coordinates (X, Y, Z, A, B, C) of the final position
float velocity – Set resultant velocity
Page 21
X=0
Y=1
pos = d.getPosition(CoordMode.Program)
pos[X] = pos[X] + 20
d.moveToPosition( CoordMode.Program, pos, 1000 )
pos[Y] = pos[Y] + 20
d.moveToPosition( CoordMode.Program, pos, 1000 )
pos[X] = pos[X] - 20
d.moveToPosition( CoordMode.Program, pos, 1000 )
pos[Y] = pos[Y] - 20
d.moveToPosition( CoordMode.Program, pos, 1000 )
After running the example presented above, axes X and Y will use the program coordinates to move from the
current position, along the circumference of a 20 mm or 20” wide square with a velocity of 1000 mm/min or
inch/min.
X=0
Y=1
pos = d.getPosition(CoordMode.Machine)
pos[X] = pos[X] + 20
d.moveToPosition( CoordMode.Machine, pos, 1000 )
pos[Y] = pos[Y] + 20
d.moveToPosition( CoordMode.Machine, pos, 1000 )
pos[X] = pos[X] - 20
d.moveToPosition( CoordMode.Machine, pos, 1000 )
pos[Y] = pos[Y] - 20
d.moveToPosition( CoordMode.Machine, pos, 1000 )
After running the example presented above, axes X and Y will use the machine coordinates to move from the
current position, along the circumference of a 20 mm or 20” wide square with a velocity of 1000 mm/min or
inch/min.
The two examples show how lists can be used to modify coordinates.
You will see such a mode of calculation in scripts available from CS-LAB’s website. Therefore, it is worth
taking a closer look at it already now.
Page 22
ARGUMENTS:
AVAILABLE OPTIONS:
CoordMode.Machine – Machine coordinates
CoordMode.Program – Program coordinates
AVAILABLE OPTIONS:
Axis.X – Axis X
Axis.Y – Axis Y
Axis.Z – Axis Z
Axis.A – Axis A
Axis.B – Axis B
Axis.C – Axis C
EXAMPLES:
X=0
pos = d.getPosition(CoordMode.Program)
After running the example presented above, axis X will use the program coordinates to move to 25 mm or
inches with a velocity of 100 mm/min or inch/min and then return to the starting point with a velocity of 20
mm/min or inches/min.
Z=2
pos = d.getPosition(CoordMode.Program)
After running the example presented above, axis Z will use the program coordinates to move to 78 mm or
inches with a velocity of 350 mm/min or inches /min and then return to the starting point with a velocity of
Page 23
FUNCTION RESULT:
EXAMPLES:
def show():
velocity = d.getCurrentXYZVelocity( )
L2["text"] = str(int(velocity))
window.after(5, show)
window = Tk()
window.geometry("180x80")
window.title( "Example" )
window.after(5, show)
mainloop()
After running the example presented above, the script will cause a
window to appear showing the current resultant velocities of axes X, Y,
and Z. On the right, you can see a picture showing the situation where
none of the axes is moving.
To make sure that the script is running, select the Keyboard control
option or use the combination Alt + j and move an axis or axes with
keyboard cursors.
Page 24
ARGUMENTS:
AVAILABLE OPTIONS:
CoordMode.Machine – Machine coordinates
CoordMode.Program – Program coordinates
List<float>[6] position – A list of the six coordinates (X, Y, Z, A, B, C) of the final position
int probeIndex – Probe number (probe configurations can be found in Settings/Special IO)
float velocity – Resultant velocity
FUNCTION RESULT:
AVAILABLE OPTIONS:
True – If the probe was activated
False – If an axis or axes reached the final position and the probe was not activated
List<float>[6] getProbingPosition( CoordMode coordMode ) - Returns the activation position of the probe or the
final position expressed in machine or program coordinates. The functionality returns the final position only if
the probe is not activated during the probing.
ARGUMENTS:
AVAILABLE OPTIONS:
CoordMode.Machine - Machine coordinates
CoordMode.Program - Program coordinates
FUNCTION RESULT:
List<float>[6] - a list of the six coordinates (X, Y, Z, A, B, C) of the probe activation position or the final
position.
Page 25
Probing_vel = 10
Return_vel = 100
Distance = 20
The script described above shows how to perform probing using axis Z, starting from the current position
across a distance defined by the Distance parameter. Once probing, whatever its result, is completed, axis Z
always returns to its starting position. Probing_vel is a parameter that relates to probing velocity and
Return_vel to the velocity of the probe returning to the starting position. The probing result is shown in a
pop-up window.
Page 26
import sys
try:
File = open(File_path, "a+")
except IOError:
sys.exit("\n No access to file !!!")
Probing_vel = 100
Return_vel = 1000
Distance = 20
Starting_position = d.getPosition( CoordMode.Program )
Maximum_position = Starting_position.copy()
Maximum_position[2] -= Distance
try:
File.write(Saved_text)
except IOError:
File.close()
sys.exit("\n File write error !!!")
Now you only need to save the script shown above e.g. under the name “M40” and execute it from gcode at
some intervals. Upon execution, the script performs probing and save the probe’s activation position and
those of X and Y in the file C:\Program Files\simCNC\digitizing.txt. Below you can see how the macro works
using as an example some simple gcode that creates motion along the circumference of a 10 x 10 large
square.
Page 27
1) Tool Number
int getSelectedToolNumber( ) - Returns the number of a tool selected from Gcode, the MDI line, or a
Python script.
FUNCTION RESULT:
EXAMPLE:
tool = d.getSelectedToolNumber( )
print("You have chosen the tool = " + str(tool))
msg.info( "You have chosen the tool = " + str(tool), "Info" )
Save this script e.g. as M66, and then execute it from Gcode or the MDI line adding the command T + any
tool number (e.g. M66 T10). Then a window should appear informing you which tool number is selected.
For instance, we used the MDI line and tool No. 10. We recommend using the macro M66 on purpose to
show you that the d.getSelectedToolNumber( ) function works with any macro, and not only with M6.
Page 29
ARGUMENTS:
EXAMPLE:
After running the example presented above, the d.setSelectedToolNumber( ) function will set the number
of the selected tool to 10, and the d.getSelectedToolNumber( ) function, which is already known to you,
will return the same tool number.
As you can easily see now, the d.setSelectedToolNumber( 10 ) function makes exactly the same as the T10
command executed from Gcode or the MDI line.
Page 30
ARGUMENTS:
EXAMPLE:
import time
After running the example presented above, every 0.5 seconds the d.setSpindleToolNumber( tool )
function in a for loop will increase the tool number on the simCNC screen until it reaches 9.
Page 31
FUNCTION RESULT:
EXAMPLE:
import time
This script is a continuation of the previous example. This time the for loop comes with the
current_tool = d.getSpindleToolNumber( ) function, which with each run of the for loop returns the current
number of the tool in the spindle. Then the tool number is presented in the Python console using the
"print" function.
Page 32
void setToolLength( int toolNumber, float toolLength ) – Sets a tool length offset.
ARGUMENTS:
EXAMPLE:
tool = 1
length = 1.234
After running the example presented above, the length offset of tool No. 1 will be set to 1.234.
Page 33
ARGUMENTS:
FUNCTION RESULT:
EXAMPLE:
tool = 1
length = d.getToolLength( tool )
After running the example presented above, the length offset of tool No. 1 will be shown in the Python
console.
Page 34
ARGUMENTS:
EXAMPLE:
tool = 1
d.setToolOffsetNumber( tool )
After running the example presented above, the tool length offset number is set to 1.
Page 35
ARGUMENTS:
EXAMPLE:
tool = d.getToolOffsetNumber( )
After running the example presented above, the number of the current length offset tool will be shown in
the Python console.
Page 36
ATTENTION!
At present, SimCNC does not use tool diameters, which means that no tool diameter compensation is
currently supported.
ARGUMENTS:
EXAMPLE:
tool = 1
diameter = 8
After running the example presented above, the diameter of tool No. 1 will be set to 8.
Page 37
ARGUMENTS:
FUNCTION RESULT:
EXAMPLE:
tool = 1
diameter = d.getToolDiameter( tool )
After running the example presented above, the diameter of tool No. 1 will be shown in the Python
console.
Page 38
1) Spindle
void setSpindleSpeed( float spindleSpeed ) – Sets a preset rotational speed (RPM) of the spindle.
ARGUMENTS:
EXAMPLE:
RPM = 500
d.setSpindleSpeed( RPM )
After running the example presented above, the preset rotational speed of the spindle will be set to 500
RPM.
Page 39
FUNCTION RESULT:
EXAMPLE:
RPM = d.getSpindleSpeed( )
print("Set spindle speed = " + str(RPM))
After running the example presented above, the preset rotational speed of the spindle will be shown in the
Python console.
Page 40
ARGUMENTS:
AVAILABLE OPTIONS:
EXAMPLE:
import time
RPM = 500
d.setSpindleSpeed( RPM )
d.setSpindleState( SpindleState.CW_ON )
time.sleep(10)
d.setSpindleState( SpindleState.CCW_ON )
time.sleep(10)
d.setSpindleState( SpindleState.OFF )
After running the example presented above, the spindle rotates clockwise for 10 seconds, then it switches
to counterclockwise rotation, and switches off after 10 seconds.
Please note that the setSpindleState functions suspends the script for the duration of the spindle
acceleration and deceleration ramps.
Page 41
FUNCTION RESULT:
AVAILABLE OPTIONS:
EXAMPLE:
state = d.getSpindleState( )
print( "state = " + str(state))
if state == SpindleState.CW_ON :
print( "Spindle state - ClockWise" )
if state == SpindleState.CCW_ON :
print( "Spindle state - Counter Clockwise" )
if state == SpindleState.OFF :
print( "Spindle state - Stopped")
After running the example presented above, the current state of the spindle resulting from the
d.getSpindleState( ) function will be shown in the first line of the Python console. In the second line, your
own message will be shown to provide a more detailed description of the current spindle state.
The figure below shows how the script works like for all spindle states.
Page 42
ARGUMENTS:
EXAMPLE:
RPM = 500
Delay_for_checking = 5 # sec
d.setSpindleSpeed( RPM )
d.setSpindleState( SpindleState.CW_ON )
try:
d.waitForSpindleSetSpeed(Delay_for_checking)
except SimCncException as ex:
print(str(ex))
sys.exit(0)
After running the example presented above, the spindle starts to rotate clockwise (line 5 – see the figure
below) with a preset rotational speed of 1000 RPM (line 4). Then the waitForSpindleSetSpeed function
suspends the execution of the script until the spindle reaches 80% of its preset rotational speed, i.e. 800
RPM (80% of 1000 RPM = 800 RPM). If the spindle does not reach 800 RPM within 5 seconds, the
waitForSpindleSetSpeed function will report a SimCncException (line 9). This will stop the spindle (line 10),
show the contents of the exception in the Python console (line 11) and terminate the script upon request
(line 12) so that it is not executed anymore. The example described above requires CSMIO-ENC for its
execution because it provides information on the current rotational speed of the spindle.
Page 43
Delay_for_checking = 5 # sec
d.setSpindleState( SpindleState.CW_ON )
try:
d.waitForSpindleSetSpeed( Delay_for_checking )
except SimCncException as ex:
d.setSpindleState( SpindleState.OFF )
print(str(ex))
d.stopTrajectory( )
sys.exit(0)
2) Coolant
ARGUMENTS:
AVAILABLE OPTIONS:
FloodState.ON - Coolant activation
FloodState.OFF - Coolant deactivation
EXAMPLE:
import time
d.setFloodState( FloodState.ON )
time.sleep(10)
d.setFloodState( FloodState.OFF )
After running the example presented above, the coolant will be enabled for 10 seconds.
Page 44
FUNCTION RESULT:
AVAILABLE OPTIONS:
FloodState.ON - Coolant enabled
FloodState.OFF - Coolant disabled
EXAMPLE:
state = d.getFloodState( )
print("state = " + str(state))
if state == FloodState.ON :
print("Flood state - ON")
if state == FloodState.OFF :
print("Flood state - OFF")
After running the example presented above, the coolant state resulting from the d.getFloodState( )
function will be shown in the first line of the Python console. In the second line, your own message will be
shown to provide a more detailed description of the current coolant state.
The figure below shows how the script works like for all coolant states.
Page 45
ARGUMENTS:
AVAILABLE OPTIONS:
MistState.ON - Mist activation
MistState.OFF - Mist deactivation
EXAMPLE:
import time
d. ( MistState.ON )
time.sleep(10)
d.setMistState( MistState.OFF )
After running the example presented above, the mist will be enabled for 10 seconds.
Page 46
FUNCTION RESULT:
AVAILABLE OPTIONS:
MistState.ON - Mist enabled
MistState.OFF - Mist disabled
EXAMPLE:
state = d.getMistState( )
print("state = " + str(state))
if state == MistState.ON :
print("Mist state - ON")
if state == MistState.OFF :
print("Mist state - OFF")
After running the example presented above, the mist state resulting from the getMistState( ) function will
be shown in the first line of the Python console. In the second line, your own message will be shown to
provide a more detailed description of the current mist state.
The figure below shows how the script works like for all mist states.
Page 47
FUNCTION RESULT:
List<float>[6] - a list of the six coordinates (X, Y, Z, A, B, C) of the current work offset
EXAMPLE:
CurrentWorkOffset = d.getCurrentWorkOffset( )
After running the example presented above, the coordinates of the current work offset will be read and
shown in the Python console.
Page 48
ARGUMENTS:
FUNCTION RESULT:
EXAMPLE:
Index = 1
WorkOffset = d.getWorkOffset( Index )
print( "workOffset(" + str( Index ) + ") = " + str( WorkOffset ))
Index = 4
WorkOffset = d.getWorkOffset( Index )
print( "workOffset(" + str( Index ) + ") = " + str( WorkOffset ))
Index = 7
WorkOffset = d.getWorkOffset( Index )
print( "workOffset(" + str( Index ) + ") = " + str( WorkOffset ))
After running the example presented above, the coordinates of work offsets No. 1 (G54), 4 (G57), and 7
(G59.1) will be read and shown in the Python console.
Page 49
FUNCTION RESULT:
EXAMPLE:
Index = d.getWorkOffsetNumber( )
Before running the example described above, enter the G54 command in the MDI line and execute it by
pressing the button on the right of the MDI line. Then run an example script. Once you do it, information on
the index of the current work offset will appear in the Python console. Repeat the same procedures using the
G55 and G56 commands to achieve the same result as in the figure below.
Page 50
ARGUMENTS:
EXAMPLE:
Index = 1
WorkOffset = [30, 26, -44, 55, -50, -70]
d.setWorkOffset( Index, WorkOffset )
Index = 4
WorkOffset = [10, -54, 12, 84, -27, 64]
d.setWorkOffset( Index, WorkOffset )
Index = 7
WorkOffset = [-27, 64, 29, -19, 48, 99]
d.setWorkOffset( Index, WorkOffset )
After running the example presented above, the work offsets indexed as 1 ( G54 ), 4 ( 57 ), and 7 ( G59.1 )
will be set to new coordinates [30, 26, -44, 55, -50, -70], [10, -54, 12, 84, -27, 64] i [-27, 64, 29, -19, 48, 99].
Page 51
ARGUMENTS:
List<float>[6] workOffsetValues - six new coordinates values (X, Y, Z, A, B, C) of the current work offset
EXAMPLE:
d.setCurrentWorkOffset( WorkOffset )
After running the example presented above, the work offset indexed as 1 (G54) will be set to new
coordinates [30, 26, -44, 55, -50, -70].
Page 52
ARGUMENTS:
EXAMPLE:
Index = 2
d.setWorkOffsetNumber( Index )
After running the example presented above, the current work office will be switched to the work offset
indexed as 4 (G57).
Page 53