Allows connecting to a LinuxCNC installation and executing commands, similar to linuxcncrsh.
The motivation was to allow easier control by OpenPNP. To this end some non-standard (for LinuxCNC) commands will be intercepted and handled either within this server, or translated into something LinuxCNC can understand:
- M115 - firmware version
- M114 - current position
- M105 - read analog sensor
- M400 - wait for completion
- BEGINSUB - start batch
- ENDSUB - send batch
All other g-code commands will be passed through unchanged, and are relayed to LinuxCNC as MDI commands.
These commands are to let OpenPNP fetch some information from the LinuxCNC side, and to help the synchronization between the two systems.
No interaction with LinuxCNC. Returns a string like:
ok FIRMWARE_NAME:linuxcnc-gcode, FIRMWARE_VERSION:0.1
Returns the current position of the machine, eg.
ok X:1.200000 Y:3.400000 Z:5.600000 A:7.800000
Returns the values of the first four analog inputs (motion.analog-in-00 etc)
ok T0:0.147000 T1:0.7890000 T2:0.000000 T3:0.000000
This command will cause all subsequent commands to be deferred until the machine is idle.
See the section below about blending.
In addition to plain g-code, you can use the commands below to carry out some common operator actions. Note that some of these will be ignored if LinuxCNC is currently running a program.
Returns information about estop/machine status, task mode, axis homed, and work position, eg.:
ESTOP MANUAL (0 0 0 0) -97.146500 -14.642751 2.000000 0.000000
ON MDI (1 1 1 1) 100.003510 -0.007745 0.005019 0.000000
Same as clearing estop and then toggling the machine on.
Same as clicking "home all" in Axis GUI. Already homed axes will be ignored. There is currently a ten second timeout, so if your homing takes longer this will incorrectly report a failure. To home an individual axis, add the axis index, eg. "home 0".
Same as hitting ESC or the stop button in Axis GUI.
Attempts to enter manual mode, which is necessary for manual jogging of axes.
Attempts to enter MDI mode. (MDI mode will automatically be entered when giving g-code commands.)
Attempts to open the given gcode file. You must specify the full path for the file.
Same as clicking the run button in Axis GUI.
Same as clicking the pause button in Axis GUI.
Same as resuming after a pause in Axis GUI.
Displays the currently loaded filename
Requires the LinuxCNC headers and libs available. On my system I built LinuxCNC from source which produced the package "linuxcnc-uspace-dev", which I then installed. Not sure how you would get this by other methods...
With the requirements in place, you should be able to just run make
to build.
This server uses NML to interface with LinuxCNC. It expects to find the NML definition file at /usr/share/linuxcnc/linuxcnc.nml which is probably where it will be unless you have really been messing around with things.
First startup LinuxCNC, then run this server. By default it will listen on port 5007, or you can change this with the -p option, eg.
./linuxcnc-gcode-server -p 5050
To check connection to the server, you can use a telnet connection like:
telnet 192.168.1.140 5007
If the machine is enabled and homed, you should be able to move it around with g-code commands.
You can use the -e option to instruct the machine to be enabled and homed when the server starts, eg.
./linuxcnc-gcode-server -e
This is the equivalent of clicking the e-stop button off and the machine power button on, and then homing each axis that is not already homed. This is probably not advisable on a real machine, but it's quite convenient during development when using a dummy machine, to save some repetitive clicking. It also allows you to run a headless LinuxCNC without any traditional user interface, and still enable the machine and run g-code.
You can optionally specify the .ini file of your machine with the -i parameter, eg.:
./linuxcnc-gcode-server -i /path/to/your/machine.ini
If you want to home the machine via this server then this parameter is not really optional because reading the .ini file is how the server obtains some basic information like how many axes your machine has. But if the machine is already homed, you can still use the server to run g-code and most other actions without giving the .ini file parameter.
You can see a video demonstrating basic usage here. Note that this video was made before some of the options mentioned above existed. For best results please specify your machine .ini file with the -i option when starting the server to know basic but important info like how many axes there are :)
See the 'headless' subfolder of this repository for the startup/shutdown scripts used in the video.
Set up a GCodeDriver like this:
In the Driver Settings
tab, clicking on Detect Firmware
should show some output like this:
If the gcode server is stopped and restarted, OpenPNP will lose communication with it. You can let it re-connect by clicking the power button off, then on again.
Note that OpenPNP does not read the current position of the machine when connecting, so if the machine was moved by commands outside OpenPNP, they will not be in sync until OpenPNP issues the next move command.
Some commonly used settings are listed below (see OpenPNP's GcodeDriver Command Reference for more details).
The standard rule as suggested by OpenPNP is fine:
^ok.*
The standard rule as suggested by OpenPNP is fine:
^ok X:(?<x>-?\d+\.\d+) Y:(?<y>-?\d+\.\d+) Z:(?<z>-?\d+\.\d+) A:(?<rotation>-?\d+\.\d+)
The standard rule as suggested by OpenPNP is fine:
^error:.*
You can use LinuxCNC's standard M64 and M65 to switch digital outputs on and off. The value P0, P1 etc maps to motion.digital-out-00, motion.digital-out-01 etc. There are various formats that will work for defining this in OpenPNP, I have found this style works ok:
M{True:64}{False:65} P0
OpenPNP will probably suggest something like this which will work fine:
G1 {X:X%.3f} {Y:Y%.3f} {Z:Z%.3f} {A:A%.4f} {FeedRate:F%.0f}
This should be set to M400:
M400
I have not tested this, but I think it would be just:
M105
This will always return four values, for motion.analog-in-00, motion.analog-in-01 etc.
I have not tested this, but I think it would be like:
^ok T0:(?<Value>-?\d+\.\d+)
That would be ok if you wanted to read motion.analog-in-00. But because M105 always returns multiple values, to read T1, T2 etc. you would need a a little extra .* in the regex to skip any preceding values:
^ok.* T2:(?<Value>-?\d+\.\d+)
To have OpenPNP specify acceleration for moves, the Motion Control Type
option in the Driver Settings
tab must be set to a type that controls acceleration, eg. EuclideanAxisLimits, ConstantAcceleration. Then in the MOVE_TO_COMMAND definition you can prepend a rule to output an acceleration setting, for example:
This will produce a g-code command like M171 P125
. The M171 is not a standard g-code, it is a user defined command that you must create on the LinuxCNC machine. The exact number 171 is not really important, it just needs to be from 100 to 199.
To create the user defined command, you need to make a bash script with the same name, no extension, upper-case M. For this example the file name would be "M171". This script must be placed in the directory specified by PROGRAM_PREFIX in your LinuxCNC .ini file:
The contents of this bash script should be:
#!/bin/bash
acceleration=$1
halcmd setp ini.x.max_acceleration $acceleration
halcmd setp ini.y.max_acceleration $acceleration
halcmd setp ini.z.max_acceleration $acceleration
exit 0
LinuxCNC is capable of blending consecutive segments together when G64 is in effect, but unfortunately sending commands via the MDI interface does not always allow this to happen. In my experiments, blending typically occurs in only 70-80% of cases where it would normally be expected. This is due to the lack of synchronization between the timing of commands entering the queue, and when those commands are allowed to start execution. For example if you issue two MDI commands and the machine starts executing the first one before the second has been received, blending cannot occur.
To work around this problem, multiple commands can be grouped into a batch for processing as a cohesive set by enclosing them inside beginsub
and endsub
keywords. This will cause the commands to be stored in a buffer and only sent to LinuxCNC when all commands of the group are known, and full blending can be achieved reliably. For example with this input:
beginsub
g1 x10 y20
g1 x25 y25
g1 x40 y20
endsub
... nothing would happen until the endsub
, at which point all the commands will be sent.
To ensure that the grouped commands are all processed together, a temporary o-code subroutine file is created and executed. This file will be created in the location specified by the RS247NGC:SUBROUTINE_PATH property of your .ini file:
Since the subroutine file is only temporary and will be written and read potentially thousands of times during a pick and place job, it might be preferable to place it in RAM instead of on hard disk. You can find some info about which paths to use in this Stack Overflow discussion. In the screenshot above, the /run/user/1000 path is actually a RAM location, and as such all the 'files' it contains will be lost when the computer is shut down. So if you already have your own subroutine files, you might actually want to use a normal hard disk location, or maybe copy them into the RAM location each time you start LinuxCNC.
Because SUBROUTINE_PATH is defined in your .ini file, to use this feature you must provide the .ini file when starting the server, eg.:
./linuxcnc-gcode-server -i /path/to/your/machine.ini
You can check if these paths are correct when the server starts up:
Finally, to let OpenPNP manage these batches of commands, you can set up your MOVE_TO_COMMAND
and MOVE_TO_COMPLETE_COMMAND
so that a batch will be started before moves are issued, and finalized before the M400 'wait' command :
A beginsub
while a batch is already in progress has no effect.
When using the OpenPNP user interface to jog the machine, the MOVE_TO_COMPLETE_COMMAND is not used, so there will be no endsub
to complete the batch. To workaround this, a timeout is used to automatically send the batch to LinuxCNC if no further commands are given within a certain time. The default timeout is 250ms, you can change this with the -t parameter:
./linuxcnc-gcode-server -t 750
Note: even when using batches to process commands as a group, there are still other factors that can interrupt blending, like the M64/M65 commands or setting the acceleration via bash script as mentioned above.
Note: the commands within a beginsub
/endsub
block are passed to LinuxCNC without any special handling, so you cannot use the 'non-standard' commands (M115, M114, M105, M400). These will be ignored inside a batch.
Although this server is capable of communicating with multiple clients at the same time, that's not really the intended use case. The main issue is that the beginsub
/ endsub
status is tracked globally on the server, not per client. So one client can start the batch and a different client could end it. If you want to switch between using different clients, just make sure there is no ongoing subroutine batch.