Author: Mugabi Siro

Category: LinuxCNC


This entry presents a setup for testing the program developed in A LinuxCNC MDI Streaming Interface. The LinuxCNC Off-line programming system for PUMA 560 (a rotary-joint, serial robot manipulator with six degrees of freedom) is used here for the test platform. References to LinuxCNC sources and binaries are with respect to the root of the source tree. LinuxCNC v2.8.0~pre1 git is considered.

Tags: linux linuxcnc realtime

Table Of Contents


The program is a basic UI for LinuxCNC that is meant to serve as a template for an external program that streams MDI commands to a LinuxCNC instance. Initially, this setup was developed as part of a (serious) hobby project (back in the emc2-2.x days) to integrate the LinuxCNC infrastructure for PUMA-type robot manipulator control with an external framework for robotics development. The goal was to develop a prototype Task-level-programming (TLP) system for a robotic checkers player: an external program would issue high-level commands, e.g. pick_from_12( ), according to output of the game engine. This high-level function would then stream a set of pre-tested MDI commands which, in turn, would result in robot manipulator action of picking up a piece from the specified location on the checkers board. Unfortunately, due to constraints of time, I never managed to see the project to completion.

The program is a skeletal port of an earlier version of the program that worked with much older LinuxCNC versions (emc2-2.x). It is written for a PUMA-type setup. PUMA configurations are a 6-R robot manipulator mechanism, i.e. Six degrees of freedom, all Rotational joints. Nevertheless, this UI may also be used to stream MDI commands to any other LinuxCNC supported machine type or robot configuration. A notable and perhaps required modification will be additional support for NML channels for tool commands and status info.

A (standard) LinuxCNC setup for PUMA control is also particularly interesting for a number of reasons:

  • The LinuxCNC code base and part programming language interface can serve as a companion for the engineering student (or even practitioner). For example, there is a version of PUMA kinematics that is virtually a textbook implementation of the equations presented in "Introduction to Robotics: Mechanics and Control", John J. Craig; a standard introductory text on (serial and industrial) robot manipulator mechanics. See src/emc/kinematics/pumakins.c. The part programming language supported by LinuxCNC (see section G Code and Programming PUMA 560) can be considered an alternative to the Robot Programming Languages (RPLs) discussed in that book.

    Nevertheless, the PUMA 560 setup considered in this entry uses a different implementation of kinematics that can be used with any serial manipulator configuration. See src/emc/kinematics/genserkins.c. This implementation is based on The Robotics WEBook: Serial Robots by Herman Bruyninckx. This cached copy is included under the terms of the WEBook's Creative Commons License.

  • Further, LinuxCNC supports an Off-line programming (OLP) system for several machine/robot configurations including PUMA 560. In the most basic terms, an OLP system is an RPL that has been sufficiently extended by means of computer graphics such that development of programs can take place without access to the physical manipulator. The LinuxCNC OLP system supports, among other things, kinematic emulation and path-planning emulation. OLP systems are important both in industrial automation and as platforms for robotics research, e.g. serving as a vehicle during development of task-level-programming systems. Of course, the LinuxCNC OLP system also presents an ideal setup for class/lecture/lab assignments, or for a demo (such as this entry).

OLP systems allow the bulk of robot programming to be accomplished before testing in the physical environment. Nevertheless, a task program developed in an OLP system remains a mathematical idealization: joint measurements of physical manipulators are of finite precision, components suffer from measurement tolerances, the manipulator's accuracy usually varies over its workspace, etc. Thus, the task program will require calibration of its parameters, or some "intelligent" way (e.g. use of sensors), to compensate for these discrepancies in the physical environment. Check Accuracy, Repeatability, and Calibration (cached copy) for a detailed discussion. Besides a few "desktop-sized" models, I don't have experience with a factory-grade industrial robot manipulator.

Both the LinuxCNC Python/OpenGL simulator for the PUMA 560 work cell (bin/puma560gui) and the src/emc/kinematics/genserkins.c implementation are by Alex Joni.

LinuxCNC Setup

A few words:

  • Being a skeletal port of an earlier version, the program may contain some unused code or be quite delicate. In any case, if you find it useful, then by all means take the liberty of making your own enhancements.

  • At the time of this writing (March 2016), the current LinuxCNC version (used here) built sanely on Ubuntu 12.04 -- mainly to match the Linux kernel version supported by RTAI. Newer (Debian/Ubuntu) distros may be supported by the time you read this.

Also note that since only the PUMA 560 OLP system is being considered, this particular build configuration was --with-realtime=uspace on x86_64 and the installation was "run-in-place"1.

Assuming that the run-in-place linuxcnc installation is located in the present working directory:

$ ls -CF


G Code and Programming PUMA 560

G code2 is the generic term used to refer to the most common part programming language. Computer Numerical Control (CNC) platforms such as LinuxCNC support a part programming language to allow decoupling of motion description from any particular machine. In other words, G code can be used to control all LinuxCNC supported machine types or robot manipulator configurations.

G code motion commands allow the operator to specify the destination of a move (position and orientation). G codes also support trajectory control, e.g. specifying straight-line, arc, or spline shaped paths between goal points, giving constraints on the speed or duration of the move (e.g. via F code), etc. A complete listing and description of G codes supported by LinuxCNC can be found in Section 15: G Code Overview and Section 16: G Codes of the LinuxCNC User Manual (available online).

Generally, G code commands that result in motion accept a number of parameters that specify the pose of the machine's tool. In the case of the PUMA 6-R mechanism, a pose is the fully specified position of the tooltip and orientation of the tool. The X, Y, and Z G code parameters will refer directly to the position of the tooltip in 3D Cartesian space, while A, B, and C will determine the orientation of the tool.

Now, in order to properly specify the X, Y, Z, A, B, and C parameters for a move with PUMA 560, and to understand the orientation and position feedback information reported by the LinuxCNC runtime, some background on PUMA spatial descriptions is required.

PUMA 560 Spatial Descriptions

Continuing with the LinuxCNC setup described in section LinuxCNC Setup, fire up an instance of LinuxCNC using the default settings in configs/sim/axis/vismach/puma/puma560.ini.

$ cd linuxcnc
$ . scripts/rip-environment 
$ linuxcnc [-v] configs/sim/axis/vismach/puma/puma560.ini
LINUXCNC - 2.8.0~pre1
Machine configuration directory is '/home/siro/emc2/linuxcnc/configs/sim/axis/vismach/puma'
Machine configuration file is 'puma560.ini'
Starting LinuxCNC...
Found file(REL): ./puma560_sim_6.hal
Note: Using POSIX non-realtime

At this juncture, a LinuxCNC instance should be up and running:



  • Since only SIMulation mode was being considered, execution here was POSIX non-realtime (SCHED_OTHER) and no superuser privilidges were required. Otherwise, if this uspace LinuxCNC execution instance has to be POSIX (firm) realtime (SCHED_FIFO with a PREEMPT RT kernel), ensure:

    $ sudo make setuid

    was performed after the build (i.e. make). This will "setuid root" bin/rtapi_app to allow privileged SCHED_FIFO access without having to sudo(8) to root. Also see src/rtapi/{,uspace_common.h:detect_realtime()}.

  • Upon LinuxCNC start, the Python/OpenGL simulation of the PUMA 560 manipulator work-cell in the tk window may appear oriented in the "top-view". Press the mouse's middle/scroll button and drag to adjust the orientation to a side-view as shown in the screenshot. To adjust perspective view depth, scroll (or press the right button and drag). To adjust the model's position in the tk window, press the left button and drag. Etc, etc.

With this PUMA 560 OpenGL model3, the manipulator's links are arranged such that link1 is the stationary stand (the dark grey link) extending vertically from the green floor to the horizontal link2. The link labelled PUMA 560 is link3. link2 to link7 form the 6 moving parts, in that order, of the robot manipulator. The end-effector is located at the center of the end of link7 (the dark grey cylindrical slab), and is of zero-length. With this model, this is also the location of the tooltip.

From the operator's perspective, the interesting spatial descriptions for a move are the position of the tooltip, and the orientation of the tool; and that these descriptions be relative to an absolute frame of reference. With this simulation model, this fixed frame of reference has its origin at the center of the base of link1. This frame of reference will be refered to here as the Base Frame.

The mathematical representations and terminology used in the following two sub-sections on G Code Parameters and Motion Feedback Information are according to the conventions used in "Introduction to Robotics: Mechanics and Control, 2nd or 3rd Ed.", John J. Craig.

G Code Parameters

The X, Y, Z, A, B, and C G code parameters allow the operator to specify a spatial description (or simply, location) for the destination of a move. These descriptions are relative to the Base Frame, {B}. These six parameters get passed to the manipulator's inverse kinematics which then compute values for its joint-space coordinates at the end of the move4.

With this simulation model:

  • The XB, YB and ZB axes are attached to {B}, while the X0, Y0, and Z0 axes are attached to the link2 frame, {0}. The relative pose of {0} with respect to {B} as described by the homogeneous transform, 0BT, is a constant translation along ZB.

  • The link7 frame is {5}. The relative pose of the end-effector frame, {E}, with respect to the manipulator's wrist is a constant translation along Z5. As noted above, the end-effector is located at the center of the end of link7, and is of zero-length. Also recall that the tool attached to the end-effector is of zero-length, and so specifying the location of the end-effector effectively specifies the location of the tooltip.

Consult configs/sim/axis/vismach/puma/puma560_sim_6.hal for a description of the Denavit-Hartenberg (D-H) parameters used.

Now, the X, Y, and Z G code parameters refer directly to the Cartesian-space coordinates of the 3x1 translation vector of the overall homogeneous transform, EBT. In other words, they allow the operator to directly specify the position of the tooltip relative to the Base Frame.

On the other hand, LinuxCNC will interpret the A, B and C G code parameters as values in degrees. Internally, LinuxCNC will use these parameter values to compute the direction cosines (i.e. the elements) of the 3x3 rotation matrix of the overall homogeneous transform5. In other words, they allow the operator to specify the orientation of the manipulator's end-effector relative to the Base Frame. The LinuxCNC code base adopts the terms roll, pitch, and yaw for the A, B, and C parameters, respectively. The convention followed during the conversion of the roll, pitch and yaw values into the direction cosines is the X-Y-Z fixed angles representation6.

With the X-Y-Z fixed angles convention, rotations occur about the axes of a fixed reference frame. In this case, rotations are applied to the end-effector's frame about the fixed axes of the Base Frame. The direction of a rotation about an axis is according to the Right Hand (grip) Rule. Rotations are performed in the following order: first a rotation about the X-axis, then about the Y-axis, and lastly about the Z-axis of {B}. Mathematically, this order can be represented as EBRXYZ(γ, β, α) = Rz(α) Ry(β) Rx(γ), where R denotes a 3x3 rotation matrix, while γ (gamma), β (beta), and α (alpha) imply the values of roll, pitch, and yaw, respectively. Recall that multiplications involving rotation matrices don't generally commute. The order of rotations is important and, say, Rx(γ) Rz(α)Rz(α) Rx(γ)7.

The simple G code program presented in section Preliminary Test demonstrates these concepts. Note that motion trajectories are highly sensitive to the initial conditions for a move -- particularly the robot's joint-space positions. This is especially true for path generation approaches that follow cubic-spline joint-space schemes8.

Motion Feedback Information

This primarily includes values reported by the forward kinematics (a.k.a direct kinematics) which compute Base Frame coordinates (tooltip position and tool orientation) from the manipulator's current joint-space values. With the interface, the X-Pos, Y-Pos and Z-Pos values report tooltip position feedback info, while the Gamma (or roll), Beta (or pitch), Alpha (or yaw) values reflect the X-Y-Z fixed angles representation in degrees. These six values correspond, respectively, to the X, Y, Z, A, B, and C values on the AXIS GUI plot preview (or DR0) window. After a (series of) successful MDI move(s), these values should generally (but not necessarily) match the last set of G code MDI parameters passed via ne_linuxcnc_ui_puma.

Note that the joint* circular dials on the extreme right of the AXIS GUI yield joint-space values (in degrees). The AXIS GUI also displays extra feedback info which might be of interest including DTG X, ..., DTG C, where DTG means Distance To Go (i.e. the remaining distance to be covered during a move).

Further Reading

The mathematical details that constitute the spatial descriptions and kinematics of the PUMA 560 (and, generally, other robot manipulator configurations) are truly non-trivial; in spite of being "classical concepts". Consult, for example, "Introduction to Robotics: Mechanics and Control, 2nd or 3rd Ed.", John J. Craig, or The Robotics WEBook: Serial Robots (cached copy), for a rigorous mathematical treatment of the subject9. The source files src/libnml/posemath/{_posemath.c,gomath.c} implement some of the concepts on spatial descriptions of a robot manipulator's hand as discussed in Chp.2 of John J. Craig's book. The source file src/emc/kinematics/pumakins.c implements the very same equations presented in Chp.3 and Chp.4 of Craig J.'s book, while src/emc/kinematics/genserkins.c is an implementation of equations derived in The Robotics WEBook: Serial Robots. The LinuxCNC infrastructure also includes support for a number of other common manipulator configurations, e.g. SCARA (serial) and Stewart/hexapod platforms (parallel).

Preliminary Test

For a preliminary test run, the ne_linuxcnc_ui_puma UI program will be executed alongside an instance of bin/axis. So, continuing with the default LinuxCNC configuration for PUMA 560 presented in the previous section, shutdown any current instance of linuxcnc and restart:

$ cd ${WDIR}/linuxcnc
$ linuxcnc [-v] configs/sim/axis/vismach/puma/puma560.ini

Once the LinuxCNC application launches, leave the machine state at ESTOP and OFF. Do not perform any homing of the manipulator's rotary joints yet. These operations will be done later on via ne_linuxcnc_ui_puma.

Now, download, ne_linuxcnc_ui_puma.hh and the ne_linuxcnc_ui_puma_makefile to some directory outside the LinuxCNC-git tree and build, e.g:

$ cd $WDIR
$ ls -CF
linuxcnc/  ne_linuxcnc_ui_puma.hh ne_linuxcnc_ui_puma_makefile
$ make LINUXCNCDIR=${WDIR}/linuxcnc [V=1] -f ne_linuxcnc_ui_puma_makefile

Execute ne_linuxcnc_ui_puma. Note that this program module will have LinuxCNC dependencies:

$ readelf -d ne_linuxcnc_ui_puma | grep NEEDED
0x0000000000000001 (NEEDED)             Shared library: []
0x0000000000000001 (NEEDED)             Shared library: []

So, launch it via:

  • export(P), e.g:

    $ export LD_LIBRARY_PATH=${WDIR}/linuxcnc/lib:$LD_LIBRARY_PATH
    $ ./ne_linuxcnc_ui_puma -ini ${WDIR}/linuxcnc/configs/sim/axis/vismach/puma/puma560.ini
  • or directly:

    $ LD_LIBRARY_PATH=${WDIR}/linuxcnc/lib:$LD_LIBRARY_PATH \
        ./ne_linuxcnc_ui_puma -ini ${WDIR}/linuxcnc/configs/sim/axis/vismach/puma/puma560.ini

In either case, program output similar to the one displayed below should appear on the terminal. Notice how the machine state (ESTOP, ON) and LinuxCNC operation modes (Manual, MDI) change on the AXIS GUI during ne_linuxcnc_ui_puma initialization; and how the motion feedback info on the respective AXIS GUI dials change "in sync" with the motion status output displayed by ne_linuxcnc_ui_puma:

>> Parsing INI file "linuxcnc/configs/sim/axis/vismach/puma/puma560.ini"...
>> Done parsing INI file.
>> Using NML file "linuxcnc/configs/common/linuxcnc.nml"
>> Setting up NML channels...
>> Done setting up NML channels.
>> Manual Mode: Homing axes/joints...
AXIS 0:: inpos:       0.0000, outpos:       0.0000, [HOMED]
AXIS 4:: inpos:      90.0000, outpos:      90.0000, [HOMED]..
AXIS 5:: inpos:       0.0000, outpos:       0.0000, [HOMED]
>> Done homing axes/joints.
>> MDI mode: Ready.
MDIQueue InterpState   Coords   X-Pos   Y-Pos   Z-Pos   Gamma    Beta   Alpha
       0        IDLE  MACHINE   19.20    5.50    9.40   92.88  -90.00   87.12

Enter MDI Command:

At this point, MDI commands may be entered interactively. Consider, for example, the demo G code presented here. The code may first be run as a .ngc file, i.e. in AUTO mode with the AXIS GUI, before testing the commands interactively in MDI mode at the ne_linuxcnc_ui_puma command prompt. Program output should resemble this:

LinuxCNC PUMA G Code Demo

Or check this demo video (sha1sum: 9605f7cbf007b23b093ae3b8afb06198999ea6bb).

A CTRL-C will cause the ne_linuxcnc_ui_puma program to exit after turning OFF and ESTOPing the machine instance. Notice how the respective AXIS GUI controls also get reset.


  • When restarting the ne_linuxcnc_ui_puma program, LinuxCNC will start homing from the current joint/axis settings. Therefore, for a fresh start, always restart the LinuxCNC instance before executing ne_linuxcnc_ui_puma.


    Compile with:

    $ make LINUXCNCDIR=${WDIR}/linuxcnc CFLAGS="-DSTRICT_PUMA_CONFIG" [V=1] -f ne_linuxcnc_ui_puma_makefile

    to detect "non-PUMA" configs (at least, with respect to number of joints) in the INI file during ne_linuxcncn_ui_puma initialization. This option is disabled by default.


    Compile with:

    $ make LINUXCNCDIR=${WDIR}/linuxcnc CFLAGS="-DSTRICT_ERROR_CONFIG" [V=1] -f ne_linuxcnc_ui_puma_makefile

    to exit upon any error condition reported by LinuxCNC. This option is disabled by default. For example, consider the following instance of a G code command entered just after ne_linuxcnc_ui_puma initialization. When the default MIN_LIMIT or MAX_LIMIT joint settings in the INI file are exceeded during a move, an error message similar to the one shown below gets issued:

    >> Done homing axes/joints.
    >> MDI mode: Ready.
    MDIQueue InterpState   Coords   X-Pos   Y-Pos   Z-Pos   Gamma    Beta   Alpha
           0        IDLE  MACHINE   19.20    5.50    9.40   92.88  -90.00   87.12
    Enter MDI Command: g0 x20 y10 z0 a0 b90 c0
    MDIQueue InterpState   Coords   X-Pos   Y-Pos   Z-Pos   Gamma    Beta   Alpha
           1     READING  MACHINE   19.55    7.45    5.33   52.69  -12.12   49.43
    NE_UI_FATAL_ERROR| Exceeded positive soft limit on joint 2
           1        IDLE  MACHINE   19.57    7.61    5.00   49.43   -5.79   46.36

    So, if STRICT_ERROR_CONFIG was defined, ne_linuxcnc_ui_puma will exit at this juncture after toggling machine state to OFF and ESTOP. Otherwise, it will simply prompt for next MDI command.

    Also recall that since error messages are retrieved via NML::read() operations10, only one instance of the message gets retrieved from the (DISPLAY-side) CMS/NML buffer. Therefore, in multi-UI setups such as this one, the error message will either appear on the ne_linuxcnc_ui_puma interface, or on the AXIS GUI; depending on which program first accessed the CMS/NML error buffer.

MDI Streaming Interface as Default UI

At this point, an appropriate IPC mechanism (e.g. sockets, psuedo-terminals, etc) can be added to to allow streaming of MDI commands from some Task-level-programming system. Alternatively, the program could be run as a thread, or part of an event I/O (poll(2), select(2), etc) loop, of the TLP system.

The following simple steps will result in a LinuxCNC instance with ne_linuxcnc_ui_puma as the standalone UI. In this particular case, the LinuxCNC engine will only launch the PUMA 560 OpenGL simulator (i.e. the tk window) alongside ne_linuxcnc_ui_puma; no bin/axis instance will be executed. To simplify illustration, a few modifications to the ${WDIR}/linuxcnc tree are made. If this is unacceptably intrusive (pollution of the pristine ${WDIR}/linuxcnc tree state), and if you know better, then you may apply your own fixes:

  • Shutdown any executing linuxcnc instance.

  • Change the DISPLAY value in the [DISPLAY] section of the PUMA 560 INI file:

    $ cat ${WDIR}/linuxcnc/configs/sim/axis/vismach/puma/puma560.ini
    # Sections for display options 
    #+ Name of display program, e.g., xemc
    DISPLAY = ne_linuxcnc_ui_puma
    # DISPLAY =              axis 
    # DISPLAY =              usrmot
    # DISPLAY =              mini
  • Copy ne_linuxcnc_ui_puma to ${WDIR}/linuxcnc/bin/ so that the launch script, ${WDIR}/linuxcnc/scripts/linuxcnc, will be able to locate it.

    $ cp ne_linuxcnc_ui_puma ${WDIR}/linuxcnc/bin/
  • Re-launch:

    $ cd ${WDIR}/linuxcnc
    $ linuxcnc configs/sim/axis/vismach/puma/puma560.ini

Recall that scripts/linuxcnc will, in this case, run ne_linuxcnc_ui_puma as the foreground process on the launch terminal. So, sending a SIGINT11 to ne_linuxcnc_ui_puma should also result in graceful termination of the LinuxCNC instance.


1. See (brief version), or docs/INSTALL (detailed version), for instructions on building and installing LinuxCNC [go back]

2. There are a number of G code dialects. LinuxCNC supports RS274/NGC. [go back]

3. See Python script bin/puma560gui for the implementation. [go back]

4. Overlooking, of course, the details of trajectory generation. During a move, the trajectory planner computes via points (or, more precisely, via locations or via frames) and also applies the inverse kinematics to each of these intermediate path points between the current location and the operator specified goal point. [go back]

5. Since a rotation matrix is a proper orthonormal matrix ("proper" refering to the fact that the determinant is +1), it can be specified by just three parameters -- a consequence of Cayley's formula for proper orthonormal matrices. [go back]

6. This applies to both src/emc/kinematics/{genserkins.c,pumakins.c}. See src/libnml/posemath/gomath.c:go_rpy_mat_convert() and src/libnml/posemath/_posemath.c:pmRpyMatConvert(), respectively. Internally, LinuxCNC performs further conversions from the 3x3 rotation matrix obtained via the X-Y-Z fixed angles representation into quaternion representation (accompanied by a series of checks) before eventually converting back to 3x3 rotation matrix representation. But these extra details are probably of minor concern to the operator. [go back]

7. If these concepts of specifying orientation of the robot manipulator's hand via the A, B and C G code parameters still seem/prove elusive, then you may consult with the experts on the LinuxCNC mailing lists, or on any other forum for robotics or CNC on the Internet. [go back]

8. Check out src/emc/kinematics/cubic.c and see, for example, "Context sensitivity" in "Chp:12.5 Problems Peculiar To Robot Programming Languages", Introduction to Robotics: Mechanics and Control, 3rd Ed., John J. Craig. [go back]

9. Mainly a background in geometry, trigonometry, linear algebra, and differential/integral calculus is required to follow the mathematical derivations. Note that there is some important errata for "Introduction to Robotics: Mechanics and Control". To cite a few, Eq: 2.57 (the skew symmetric matrix), Eq: 2.77 (the rotation matrix RX(θ)), and a small error (the expression for r11) in Eq: 3.14 (the kinematics of PUMA 560). For example, the document "Errata for Introduction to Robotics: Mechanics and Control, 3rd Edition/ENAE 692 Introduction to Space Robotics" (available online) by "Department of Aerospace Engineering, University of Maryland" contains these and other corrections to the 3rd Edition of the book. In any case, consult the LinuxCNC code base when in doubt. [go back]

10. Unlike NML::peek() operations, NML::read() updates the CMS buffer header(s) -- see libnml/cms/ Subsequent read operations return 0 until new data is available for the CMS/NML buffer. On the other hand, peek operations simply keep returning whatever is currently stored in the CMS/NML buffer. Typically, NML::peek() operations are used for retrieving status info. See A LinuxCNC MDI Streaming Interface. [go back]

11. SIGINT is a CTRL+C interrupt from the keyboard. See signal(7). [go back]