Saturday, 23 October 2021

Back to Axis - and finally installing Andy Pugh's macros

Full circle?

Given the current state of flux of the various lathe GUIs (Probe Basic, gmoccapy, Qtvcp etc), I'm going to revert to something reasonably stable for the time being. I'm now gravitating towards the AxisGUI which has a lathe version and is the default GUI most people see when they try out the LinuxCNC SIM.

How to install a functional version of Axis lathe:

From what I recall, the process is pretty simple - once you've figured it out. That's pretty much the score with LinuxCNC anyway, so not a great surprise. You start at the "configuration selector" and choose the "sim.axis" group, then select the "lathe" option. This creates an Axis configuration for a lathe. This can be run as a standalone simulation but obviously that's not a whole lot of use here.


The next step is to replace the SIM components with real world equivalents. So for starters, we need the INI and HAL files from before, as they connect the virtual machine to the real world. The INI file needs to have the same name as you'd like to appear in the config selector - and the title bar of the GUI itself. So I went for axis_lathe. I copied my previous INI file across from gmoccapy and renamed it appropriately.

In the subdirectory hallib, I copied over the Bantam_v1.hal and xhc-whb04b-6.hal which seems to have done the trick.

Tool table:

Slight problemette here. I can see there's no sensible way to run programs without a means of editing the tool library. For this, a file named tool.tbl would need to be present in the axis_lathe folder if it were a milling machine - or lathe.tbl if indeed it's a lathe.

Sounds simple enough but when I selected File > Edit tool table... I couldn't get anything to happen. It's supposed to launch a tool editor in Gladevcp. Turns out the file lathe.tbl was corrupted. It wasn't enormously difficult to figure out that the file was corrupted.

The columns shown can be customised: the default is to list every possible axis and all manner of offset, regardless of the application. Here's a little guide to how the tool table works and how to edit it.

Andy Pugh's macros:

One of the drivers for the choice of Axis was to be able to use Andy's macros so that I have the option to use conversational operations. I've see this being described on the forum. So now, let's see if this works out.

Oooof. That doesn't look so nice. It appears that the recent changes to Python have screwed this up too. Bollocks.

Finally (after not much messing about in the end), I have it working. However:

  • For threading, the spindle speed seems to be limited to 20rpm (min) and 200rpm (max). Chamfering is limited to 250rpm (max, with no min). I can see the benefit of limiting the spindle speed in some situations but is it simple to change those limits? I can't see them but perhaps I don't know where to look.
  • The scroll buttons in the dimension boxes don't work for me - is there a fix for that? I can select the digits with the mouse or by tabbing through the boxes then use the popup box to clear and edit the values. If I double click (or accidentally reclick) the dimension, the popup gets hidden behind the main window which was confusing to start with and best avoided.
  • The tool / speed boxes at the top right seem to be incorrectly scaled. Is there a simple fix for this? It may be related to the above scroll button issue perhaps.


Apart from the fact I can't see what to do next, that's close to a result, as I seem to have got Andy's macros installed to some degree. Actually getting them to generate some machining moves is just a detail of course....

Try and fail to install Qtvcp GUI

What is Qtvcp and why bother?

I've so far found that Probe Basic Lathe isn't finished and doesn't (yet?) support add-ins such as Andy Pugh's  lathe macros. Looks nice but is a work in progress. A large update is apparently in the pipeline but there's no indication of timing or any update on progress, assuming it's happening. I'm not criticising but if I'm looking for a stable lathe GUI that I don't need to keep messing with, it's probably not PB Lathe for now.

Having said all this, I see a user on the LinuxCNC forum (anfänger) has made some progress implementing macros in PB Lathe. I must give this a go, although I now find my PBL installation doesn't work any more, presumably since I updated the RTOS recently.

I've also tried gmoccapy as an alternative. This seems to be more robust and mature but TBH, the GUI is pretty clunky - the sort of appearance you might get from an engineer rather than an artistic designer. Not saying I'd do as well or any better but it's not quite what I am after:

There are other options, so I thought I'd try a couple out and see if they look / feel more suitable. But first I need to install Qtvcp to run many of them.

Installing Qtvcp:

Here's how you go about it. You have to download the install script, save it as (in my case), then make it executable. The script is available here and you can follow this procedure to make it executable.

You mark the file as executable:

chmod +x

Then execute it like this:


Hmm. That didn't go well. And reading the evolving Qtvcp thread on the LinuxCNC forum, it seems that recent changes to Python have broken the implementation that had been developed and honed in previous releases of LinuxCNC. It appears that v2.8 doesn't work with it and there's no way to fix it unless somebody (not me!!) goes in and fixed Qtvcp to work with the current version of Python. So that seems to have cooked the Qtvcp goose for the time bing....

Goodbye Qtvcp - for now

I may come back to this later if it appears the installation is sensibly possible. But that time isn't now.

Friday, 15 October 2021

G28 vs G53 and LinuxCNC lathe vs Fusion 360?!

The bloody Fusion 360 post processor is posting U and W moves instead of X and Z when asking for G28 retracts between tool changes / at the end of the program. Like this:

N10 G7
N20 G18
N30 G90
N40 G21
N50 G28 U0.

N60 T4 M6
N80 G54
N90 M8
N100 G97 S1947 M3
N110 G95
N120 G90 G0 X32.7 Z0.
N130 G96 D2000 S200 M3
N140 G0 Z0.25
N150 X11.7
N160 G1 Z-17.4 F0.1
..... etc

N460 G97 S1947 M3
N470 M9
N480 G28 U0.

N490 M5
N500 M1
N510 T6 M6
.... etc

N800 G33 Z-14. K1.25
N810 X7.866 Z-15. K1.768
N820 G0 X18.7
N830 Z0.

N840 M9
N850 M5
N860 G28 U0.
N870 M30

This isn't recognised as legal tender by LinuxCNC which won't run the file. It seems the Fusion team have fucked up the post processor. If LinuxCNC sees a reference to a U or W move, it assumes this refers to a rotational axis, whereas the Fusion team expect it be to seen as a relative move in X or Z, as used by some machines (not LinuxCNC though).

Alkabal raised this on the Fusion forum and Andy Pugh also piled in. Alkabal also posted on the LinuxCNC forum at the same time. I'd also previously posted about this myself not long before.

Looking at the post processor code, it looks pretty messy and, for the sake of avoiding this relatively simple issue, I can't be arsed to edit my post, as the content is sprayed all over this lump of Javascript:

/** Output block to do safe retract and/or move to home position. */
var XZ = 4;
function writeRetract() {
  var words = []; // store all retracted axes in an array
  var singleLineRetract = false;
  var retractAxes = []; // axes to retract
  var method = getProperty("safePositionMethod");
  // define home positions
  var _xHome;
  var _yHome;
  var _zHome;
  if (method == "G28") {
    _xHome = toPreciseUnit(0, MM);
    _yHome = toPreciseUnit(0, MM);
    _zHome = toPreciseUnit(0, MM);
  } else {
    _xHome = machineConfiguration.hasHomePositionX() ? machineConfiguration.getHomePositionX() : getProperty("g53HomePositionX");
    _yHome = machineConfiguration.hasHomePositionY() ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM);
    _zHome = machineConfiguration.getRetractPlane() != 0 ? machineConfiguration.getRetractPlane() : getProperty("g53HomePositionZ");
  if (arguments.length > 0) {
    for (var i in arguments) {
      singleLineRetract = arguments[i] == XZ ? true : singleLineRetract;
  } else {
    switch (getProperty("safePositionStyle")) {
    case "X":
    case "Z":
    case "XZ":
      retractAxes.push(X, Z);
    case "ZX":
      retractAxes.push(Z, X);
    case "singleLineXZ":
      singleLineRetract = true;
      retractAxes.push(X, Z);
  // format home positions
  for (var i = 0; i < retractAxes.length; ++i) {
    switch (retractAxes[i]) {
    case X:
      words.push((method == "G28" ? "U" : "X") + xFormat.format(_xHome));
      retracted[X] = true;
    case Y:
      if (yOutput.isEnabled()) {
        words.push((method == "G28" ? "V" : "Y") + yFormat.format(_yHome));
    case Z:
      words.push((method == "G28" ? "W" : "Z") + zFormat.format(_zHome));
      retracted[Z] = true;
    case XZ:
      words.push((method == "G28" ? "U" : "X") + xFormat.format(_xHome));
      words.push((method == "G28" ? "W" : "Z") + zFormat.format(_zHome));
      retracted[X] = true;
      retracted[Z] = true;
      error(localize("Unsupported axis specified for writeRetract()."));
  for (var i = 0; i < words.length; ++i) {
    switch (method) {
    case "G28":
      writeBlock(gFormat.format(28), singleLineRetract ? words : words[i]);
    case "G53":
      writeBlock(gFormat.format(53), gMotionModal.format(0), singleLineRetract ? words : words[i]);
      error(localize("Unsupported safe position method."));
    if (singleLineRetract) {
  singleLineRetract = false; // singleLineRetract reset
function onClose() {
  optionalSection = false;
  // we might want to retract in Z before X
  // writeBlock(gFormat.format(30), "Z#5422"); // retract/park
  writeRetract();// change this to writeRetract(XZ) to force retract in XZ at the end of the program as a default
  writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off

The answer is quite simple:

  1. Don't select G28
  2. If you want to retract in X (retract the cross slide), choose the "G53 / X only" option in the post processor
  3. If you want to also retract in Z (retract toward the tailstock end), choose the "G53 X and Y" option.

If it weren't for this fuckup, you'd define the required G28 position by positioning the tool where you want the G28 to end up and issue a G28.1 command in MDI. This saves the current coords as system variables 5161 (for X) and 5163 (for Z). Next time you issue G28, it will retract to those coords. But I won't be needing that...

Wednesday, 13 October 2021

Threading trials - G33 in Fusion 360 and LinuxCC

Threading with G33 - spindle synchronised motion

Let's give threading a go now. This should be considerably simpler on a CNC lathe than hitherto, with all the buggerage involving change gears, gearboxes, leadscrew engagement and cross slide movements at the start and end of the threads. Then there's the issue of cutting my preferred metric threads on an imperial machine ie not disengaging the leadscrew between passes.

The spindle encoder feedback is a key part of the process, although it seems the index signal is the default trigger to the movement. Beyond that, the VFD "spindle at speed" input is used to determine the angular position, on the assumption that the spindle movement is as expected, rather than implement an "electronic gear" coupling between the spindle and Z axis movement. 

There's an absolute position signal available from the encoder but it appears I'd need to do more work to implement electronic gearing. One step at a time, fatty. We can get on to that later, once we have the default implementation working. 

How G33 works in LinuxCNC:

From the LinuxCNC documentation:

21. G33 Spindle Synchronized Motion

G33 X- Y- Z- K- $-

K - distance per revolution

For spindle-synchronized motion in one direction, code G33 X- Y- Z- K- where K gives the distance moved in XYZ for each revolution of the spindle. For instance, if starting at Z=0, G33 Z-1 K.0625 produces a 1 inch motion in Z over 16 revolutions of the spindle. This command might be part of a program to produce a 16TPI thread. Another example in metric, G33 Z-15 K1.5 produces a movement of 15mm while the spindle rotates 10 times for a thread of 1.5mm.

The (optional) $ argument sets which spindle the motion is synchronised to (default is zero). For example G33 Z10 K1 $1 will move the spindle in synchrony with the spindle.N.revs HAL pin value.

Spindle-synchronized motion waits for the spindle index and spindle at speed pins, so multiple passes line up. G33 moves end at the programmed endpoint. G33 could be used to cut tapered threads or a fusee.

All the axis words are optional, except that at least one must be used.

Note: K follows the drive line described by X- Y- Z-. K is not parallel to the Z axis if X or Y endpoints are used for example when cutting tapered threads.

Technical Info

At the beginning of each G33 pass, LinuxCNC uses the spindle speed and the machine acceleration limits to calculate how long it will take Z to accelerate after the index pulse, and determines how many degrees the spindle will rotate during that time. It then adds that angle to the index position and computes the Z position using the corrected spindle angle. That means that Z will reach the correct position just as it finishes accelerating to the proper speed, and can immediately begin cutting a good thread.

HAL Connections

The pin must be set or driven true for the motion to start. Additionally spindle.N.revs must increase by 1 for each revolution of the spindle and the spindle.N.index-enable pin must be connected to an encoder (or resolver) counter which resets index-enable once per rev.

See the Integrators Manual for more information on spindle synchronized motion.

G33 Example

G90 (absolute distance mode) 
G0 X1 Z0.1 (rapid to position) 
S100 M3 (start spindle turning) 
G33 Z-2 K0.125 (move Z axis to -2 at a rate to equal 0.125 per revolution) 
G0 X1.25 (rapid move tool away from work) 
Z0.1 (rapid move to starting Z position) 
M2 (end program)

See G90 & G0 & M2 sections for more information.

It is an error if:
  • All axis words are omitted.
  • The spindle is not turning when this command is executed
  • The requested linear motion exceeds machine velocity limits due to the spindle speed

Let's give it a go:
Seems fairly straightforward - and Fusion 360 uses the G33 cycle for threading, so hopefully it will be fairly plain sailing.

Firstly, let's create a test piece. I have several lengths of 0.5" / 12.7mm mystery loominum stock that can be the sacrificial pig here. So I will turn it down to 12mm and create an M12 thread.

And I'll need to create a suitable tool. The only RH threading tool in the default samples library uses a different insert style. It's simple enough though:

As for the lathe threading toolpath, there are some settings to select such as the infeed angle, which I will set to 29 degrees for a 60 degree thread. The default is 0 degrees, which can increase the risk of chatter with deep and coarse threads. It's also possible to select variable feed depths, which compensates for the fact that the material removal rate would otherwise increase as the tool cuts deeper into the stock, due to the triangular profile.

Here we are, with 5 passes:

Which generates the following code. Seems to be generating the expected G33 content:

N10 G7
N11 G18
N12 G90
N13 G21
N14 G53 G0 X0.
N15 G53 G0 Z0.

N16 T0 M6
N18 G54
N19 G97 S500 M3
N20 G95
N21 G90 G0 X22.7 Z10.306
N22 G0 X10.939
N23 G33 Z-19.246 K2.
N24 X11.833 Z-19.694 K2.828
N25 G0 X22.7
N26 Z10.204
N27 X10.569
N28 G33 Z-19.164 K2.
N29 X11.833 Z-19.796 K2.828
N30 G0 X22.7
N31 Z10.125
N32 X10.284
N33 G33 Z-19.1 K2.
N34 X11.833 Z-19.875 K2.828
N35 G0 X22.7
N36 Z10.059
N37 X10.045
N38 G33 Z-19.047 K2.
N39 X11.833 Z-19.941 K2.828
N40 G0 X22.7
N41 Z10.
N42 X9.833
N43 G33 Z-19. K2.
N44 X11.833 Z-20. K2.828
N45 G0 X22.7
N46 Z10.
N47 X9.833
N48 G33 Z-19. K2.
N49 X11.833 Z-20. K2.828
N50 G0 X22.7

N51 M5
N52 G53 G0 X0.
N53 G53 G0 Z0.
N54 M30

I'm guessing the incremental Z moves between passes are the result of the 29 degree entry angle, while the incremental moves in X are the actual infeed between passes. Between passes, the tool is retracted to X22.7 and returned to the start at a faster pitch of 2.828mm.

Clearly it's not attempting to implement any "electronic gear" function. I'm assuming I'd need to modify the Fusion post to make this happen. But that may not be worth the hassle of course...

Good. So let's give that a go, firstly with "air tools". The biggest question in my mind is whether or not the spindle encoder index signal is correctly connected and functioning. That should be easy enough to find out.

Air cutting trial:

And real chips:


Only slight fly in the ointment is the thread pitch. Originally I planned an M12 x 2.0 thread, then changed my mind and changed the model to M10 x 1.50. I seem to have found a buglet in Fusion lathe CAM, as the pitch didn't change when I reprogrammed the toolpaths. I was able to reproduce this consistently so it appears to be a hard coded fuckup. So I ended up with an M10 x 2.0 thread. Oddly enough I don't have such a nut on the shelf. One to bear in mind when I next change the pitch of a thread in Fusion....

Monday, 4 October 2021

Curly fries? Lathe porn.

Well, lathe chips at any rate. And I've done the childish pawn joke ad nauseam before.

In order to reduce the pucker factor and familiarise myself with CNC lathe operation, I need to get my hands dirty - as opposed to getting my underwear dirty. No substitute for experience etc. So back to the pawn test piece. 

Here's the CAM for the pawn test piece. Adaptive roughing, followed by a finishing pass:

This imported into cmoccapy OK. The blue path shows the movement from the machine home (G53 X0 Z0) to the stock origin (G54 X0 Z0) after I told it where the stock origin was (G92 X0 Z0). Perhaps not surprisingly, it remembers these positions between power cycles.

In closer detail, it looks half decent and I previously addressed the issue of the toolpath smoothing.

Let's go:
Firstly, do some homing moves and tell the machine where my stock origin is. That's the G54 X0 Z0 position. I'd like to get that right, otherwise I could have my very first CNC lathe crash - which I'm happy to delay as long as possible. This is the air cut:

Looks OK, so abort, load the tool and brace myself to make real chips. Rubber pants on! Here we go. 

For some reason that may be obvious to a seasoned user, it pauses between operations. Presumably some setting in the CAM or post. I can get past it by forcing the next line of g-code in gmoccapy but that's something to look into. 

Finally, part off manually (I haven't figured out how to set up tool offsets yet with any confidence).

I seem to have the tool height set up nicely at least

And here it is. Better than the last (first) one but still some jerkiness in the movement, resulting in annoying ridges in the surfaces. The Z axis seems to be jerky, so I'll need to look into that. I can use HALscope to observe the following error, which is the difference between the commanded position and the reported position from the encoder. I'm expecting that to resemble a series of jerks.

But that's good news for now.

Sunday, 3 October 2021

e-stop pendant, wiring and HAL connections


Currently, there's an e-stop switch on the cabinet but it's not actually connected up. It's also nowhere near accessible, least of all if I were shitting myself and needing to shut stuff down toot sweet. Time to do something about that - if commissioning time isn't a time for a functioning e-stop, I don't know when is.

Obvs I have loads of spare inputs left on the 7i76 - I've only used 7 of the available 32 inputs. All that is required is for me to get off my fat arse and wire it up. And figure out how to modify the HAL file to make the correct logical connections.

The preferred arrangement is to have a loop of normally closed e-stop switches holding an input in the high state. That way, if the e-stop switch is opened or if the e-stop loop is damaged open circuit or short to ground, the system will be inhibited. It's not completely failsafe but this gets you a long way towards it.

Not surprisingly, there's a page on the website: the e-stop latch page along with some examples on the forum. Looks pretty simple.


My input #7 (it's the 8th, as numbering starts at zero) is hm2_5i25.0.7i76.0.0.input-07 and in this instance I need to invert it so that it's only active when the input goes low. So I need to use hm2_5i25.0.7i76.0.0.input-07-not which is the inverted version of the signal.

First, some related comments from the documentation page:
# ---digital in / out signals---

# ---estop signals---
# from
# iocontrol.0.user-enable-out (Bit, Out) FALSE when an internal estop condition exists
# iocontrol.0.emc-enable-in (Bit, In) Should be driven FALSE when an external estop condition exists.
# iocontrol.0.user-request-enable (Bit, Out) TRUE when the user has requested that estop be cleared

Then make the changes:
# comment out these legacy net connections:
# net estop-out <= iocontrol.0.user-enable-out
# net estop-out => iocontrol.0.emc-enable-in

# ---estop signals---
# config from BigJohn#:

loadrt estop_latch
addf estop-latch.0 servo-thread
net estop-loopout iocontrol.0.emc-enable-in <= estop-latch.0.ok-out
net estop-loopin iocontrol.0.user-enable-out => estop-latch.0.ok-in
net estop-reset iocontrol.0.user-request-enable => estop-latch.0.reset
net remote-estop estop-latch.0.fault-in <= hm2_5i25.0.7i76.0.0.input-07-not

Finally, actually wire up the damned things and test with HAL meter, then check it actually trips the e-stop in gmoccapy (top right of screen.

This works, so now I have a couple of e-stop switches - one on the cabinet and one on a pendant. That should avoid buttock strain when testing out new moves for real. Good result.

Friday, 1 October 2021

It's freezing here (new kernel for Linux Mint) - and G61/G64 path smoothing in LinuxCNC

Cold, fatty?
True, it's cold now but I'm more bothered by the fact that the LinuxCNC PC is still freezing up sporadically. F***ing annoying in fact, as I've tried all sorts to cure it now, including a new SSD, new PSU, new Linux Mint install, new LinuxCNC install etc. And the bastard thing still it locks up.

Latest suggestion is to try a newer kernel. Linux runs a "kernel" (nothing specific to LinuxCNC), which seems to be the core of the OS. Take your pick:

Then there's an "RT patch" so that you can schedule operations in  real time.

I won't pretend I know much about it (yet) or even that I've learned much about it (yet) but it seems that the default for the current version of Mint is 5.4. There are various versions available currently, all the way up to 5.15 for the adventurous. 5.10 seems to be the last "longterm" version although 5.13 and 5.14 are also described as "stable", whatever that means, given that 5.4 is presumably described thuswise too.

Upgrading(?) to 5.10:

Well that went OK as far as I can tell and we are now around 30h in without a freeze - yet. Let's keep everything crossed and hope this one finally sticks.....

Trajectory planner??

A little miffed to discover that the actual path followed by the tool in LinuxCNC doesn't seem to be quite what was anticipated when I generated the toolpath in Fusion 360. What's going on here, then?

Here's what I'd imagined would be happening, as seen from within Fusion 360:

And here's what I'm seeing within gmoccapy:

The sharp corners on the edges of my pawn test piece are not entirely, The controller (LinuxCNC) is clearly being clever here. Presumably it's aware of its own shortcomings, viz the need to slow down ahead of changes in direction. Clearly this must be controllable in the config. IIRC, there are such controls within both Fusion (milling) and Centroid CNC12, so almost certainly there will be similar content in LinuxCNC.

G61 / G64:

Time to dig into the smoothing functions perhaps? Indeed, it's not difficult to find the answers. Here's the crux of it documented within the G code documentation - the G61 and G64 commands and their associated parameters.

Indeed, if you require the tool to faithfully follow the profile with minimal deviation, you need to allow the feedrate to reduce to zero or thereabouts in sharp corners. So here's the effect of specifying G64 P0.01 ie requiring the following error to be no more than 10um:

Sure enough, as the tool enters the corners, the feed rate slows right down. Also pleasing to see that the spindle speed slows down as the radius increases - I've specified constant surface speed (CSS) up to a maximum of 2000rpm and that is attained once the diameter exceeds around 20mm.

That's better! Perhaps time to cut some metal again?

Rust eater?

What? I've had to do some derusting on a variety of components recently and it seems to be an expensive and/or hazardous and/or labour i...