Retrofitting 1983 Shizuoka AN-SB CNC milling machine, Bridgeport mill, Colchester Bantam lathe and 1982 Tree UP-1000 CNC lathe with modern controls - and other workshop stuff
Enough buggering about with the Bantam CNClathe. Let's slap this tube bender together finally and see what we've got.
The final piece of the jigsaw to make up was this end cap, intended to prevent the ballnut travelling past the end of the ballscrew, at which point it would liberate most of the contents of the ballnut. Well my balls already dropped some time ago, so there would be no need for that.
Fits on the end of the ballscrew, held on with an M10 bolt. I could probably shear it off by applying large torque and negligible talent but at least it would offer some resistance / protest by way of warning in the process. Here's the ballnut (moving) end of the assembly:
There's actually an optional hydraulic actuator that looks fairly similar to my ballscrew mechanism. Ballscrews don't like bending moments being applied through the ballnut though, hence my ballnut bracket pivots are aligned with the ballscrew axis, unlike this piston which doesn't give a toss:
Obvs I will be substituting my new ballscrew gubbins in place of the original ratchet mechanism. Like this:
A drill driver with a 17mm socket is the means of driving the actuator. Hopefully this will have enough grunt to bend 32mm x 1.5mm tubes, otherwise I'll have to use the beefier impact socket driver.
Bottom line though is - does it actually bend tubing ok? There's only one way to find out. Here's a length of 32mm dia tube, 1.5mm wall thickness loaded up.
And although I have established that a flat 3Ah battery bogs down, a charged 6Ah battery sails through. No need for the larger impact driver at this stage.
Not bad, not bad, although as before this thin walled tubing tends to collapse on the outside of the bend. The thicker walled tubes don't seem to suffer from that. However, I've got a selection of U bends and small radius mandrel bends to work with, so this isn't a massive problem. I will be fabricating the manifold using a series of them welded together.
Well, that was as much an exercise in learning the new conversational controls for the Linuxcnc Probe Basic Lathe GUI as it was fabricating the ballscrew actuator. Job done on that front though. I'm pleasantly surprised that it seems to have gone without any major cockups - as far as I can tell so far, although that can change.
The exhaust manifold can now wait for the next unnecessary tool that will appear in the overcrowded workshop, namely one of those trendy laser cutter / welder / cleaner. Unlike every Youtube influencer and his dog, I'll have to pay for mine but I won't be seeing that for another month or two (slow boat from China etc), so I'll revert to some of the other myriad unfinished "projects" I started but never quite finished, ideally some of them actually in the workshop.
Last time, I'd drilled and bored out the brackets for the bearing and ballnut. To complete these parts and approach the point of assembling this machine, I need to machine the pivots that locate them on the tube bender arms.
To recap, here's what the guts of the tube bender will look like, once I've replaced the original ratchet lever mechanism with a ballscrew actuator. The brackets sit at each end of the ballscrew:
The ballscrew is machined up and is ready to go. The pivots for the brackets will look like this:
Luckily, I have the appropriate tapping drills (7mm for M8 and 8.5mm for M10), a 3/4" end mill for counterboring the bush and a clearance drill for the bushes through holes (10.3mm for 10mm machine screw).
I need to bore out the holes in the arm to suit the 3/4" bushes. Renishaw probe to find the centre, 3/4" end mill to bore through:
I have some 3/4" brass stock which fits nicely, as indeed it should:
Bore it out 10.3mm to clear the 10mm machine screws:
But oof, what is this??? The X axis keeps faulting with "loss of position". With the cross slide stationary, I can feel the servo motor rotating slowly, despite there being no linear movement of the axis. Clearly there's some loss of connection between the motor and the ballscrew.
Ah, the locknut has come loose. The pulley is keyed to the ballscrew but the nut has worked loose, resulting in lost axial movement (hysteresis). No wonder the closed loop controller was struggling. I guess I never got round to final fitting of the nut ie locking the thread.
Tightened it up, this time with some mild nut lock.
Back in business. Pretty close to the required 14mm:
All 4 bushes completed:
And the M10 threads cut:
Time for a quick tidy up, then get the thing assembled!
There's still some work to be done on this homing accuracy business. Let's see if we can crack it finally. The decision to use the Claude Code extension within Visual Studio Code has certainly allowed me to do stuff I'd never have been able to figure out myself, it's true - but the experience is pretty trying at times. If Claude has a personality it's that of an excitable junior engineer - tends to sound very pleased with itself and jumps to conclusions that aren't backed up with evidence. I guess we can hope that Claude will develop over the coming years to the point that it is a lot more dependable and less fallible.
Let's look at the homing moves. It seems to me that the movements are rather jerky, whereas a servo system should be capable of smooth, quiet movement. Let's log some moves and see if there's anything to be learned.
All 10 index-clear events from the final switch position, velocity-derived from the raw position samples and aligned to each cycle's own capture instant (t=0, dashed green). Commanded (blue) is what the trajectory planner is asking for; feedback (orange) is what the axis is actually doing. Faint lines are individual cycles; overlap (or lack of it) at t=0 shows how consistently the capture lands on the velocity profile.
This doesn't look ideal - what's all that sinusoidal wobble about? Looks like marginal stability to me.
Here's the same data plotted as distance rather than velocity. Velocity is simply the derivative of distance.
Let's do some transient testing. Here's the g code for a backlash test. The moves are G91 (relative / incremental, and this is a lathe, remember), which allows me to position the tool anywhere within the machine limits before running the test - that way I can check for backlash at different positions of the ballscrew. The 1mm move each way should be enough to break any stiction - beyond that, there's little to be gained in moving further before reversing back to the starting point.
(X axis backlash check)
(Jogs X +/-1mm from wherever it currently sits, pausing 1s each time it)
(returns to the start point -- alternating which direction it approaches)
(from, so a DTI held at that point shows the gap between a + and - approach.)
(Runs purely relative to current position -- no work offset needed.)
(edit these two to taste)
#<feed> = 200 (mm/min)
#<cycles> = 10 (number of +/- pairs)
G21 (metric)
G94 (feed rate in units/min, not units/rev)
G91 (incremental mode -- all moves relative to current position)
o100 repeat [#<cycles>]
G1 X1 F#<feed> (jog +1mm)
G1 X-1 F#<feed> (return to start, approaching from +)
G4 P1 (dwell 1s -- read DTI now: approach from +)
G1 X-1 F#<feed> (jog -1mm)
G1 X1 F#<feed> (return to start, approaching from -)
G4 P1 (dwell 1s -- read DTI now: approach from -)
o100 endrepeat
G90 (back to absolute mode)
M2
All 10 dwell events from thez_backlash_check.ngc+/-1mm relative-jog test (no switch, no homing, no index involved at all -- a plain commanded stop), aligned to each move's own stop instant (t=0, dashed green). Commanded (blue) is what the trajectory planner is asking for; feedback (orange) is what the axis is actually doing. Faint lines are individual cycles.
Nasty lumpy movement is still visible. Homing in on the transient portions of the +/-1mm backlash test, shows some unauthorised wobbling:
Cruise-phase velocity ripple
Z velocity during the constant-speed middle portion of a single +/-1mm move (200mm/min commanded) -- not the stop/settle transient, the actual translation. Commanded (blue) should be a flat line; feedback (orange) swings from near zero to more than double the commanded speed, cyclically, roughly every 40ms (~24-25Hz).
Fundamental frequency is ~26Hz. Is this caused by the Linuxcnc controller or is it caused by the Lichuan servo driver? That's worth establishing before trying to optimise the wrong PID loop. IIRC, the Lichuan servo driver is actually pretty well set up for the matching motor.
Same +/-1mm cruise-phase window as before, but now including pid.z.output -- the actual velocity command LinuxCNC's PID sends downstream to the stepgen, before it ever reaches the drive. It shows the same ~26Hz ripple as the feedback, and at far larger amplitude than the nominal -3.33mm/s command -- meaning LinuxCNC's own loop output is actively oscillating, not just passing through a clean signal that gets corrupted later.
Setting D=0 in the INI file makes quite a difference:
Same +/-1mm cruise-phase window and signals as the previous capture, but with pid.z.Dgain set to 0 (was 3). pid.z.output now ramps smoothly and holds steady instead of oscillating between roughly -17 and +14mm/s -- suggests that the ~26Hz ripple was mostly the D-term amplifying quantization noise from the 5µm scale, not a real mechanical resonance.
Looks to me like too much Kp term. Reduce Kp to 35 from 50 and Kd to 0 from 3, I unchanged.
PID tuning progress
pid.z.output (the velocity command LinuxCNC sends to the stepgen) across three tuning stages, same +/-1mm cruise window each time. This is the clearest single signal for the whole investigation -- how hard the loop is working to hold a supposedly constant speed.
That is starting to look a lot better - the wobble is almost certainly due to too much Kp and Kd terms, resulting in overshoot and marginal stability.
PID tuning progress - Z axis
pid.z.output (the velocity command LinuxCNC sends to the stepgen) across three tuning stages, same +/-1mm cruise window each time. This is the clearest single signal for the whole investigation -- how hard the loop is working to hold a supposedly constant speed.
pid.x.output across the X-axis tuning sequence -- same diagnostic process as Z, but a different root cause: X's weak feedforward (FF1=0.4) meant Kp was carrying too much of the tracking burden, so raising FF1 (not cutting Kp or Kd) was the fix here.
Good - so we now seem to have a decent transient response on both axes. How has that improved the homing accuracy, if at all?
Servo homing results, Z and X
Each dot is one homing cycle's resting position (raw linear-scale feedback, not the DRO -- unaffected by the homing offset reset), shown as deviation from that group's own mean so spreads are directly comparable across groups measured in different sessions. Same jog-away and settle protocol throughout.
The Z axis is looking pretty good:
But the X axis is still pretty crap, even if it has improved a bit:
Clean before/after: original X gains (P=60 I=40 D=1 FF1=0.4) vs. the final tuned config (P=100 I=40 D=0 FF1=0.85). Mean peak position error went from ~41µm to 5.0µm (one encoder increment) on every single cycle.
And as for the X homing - has that finally improved? I'm close to losing the will to live here but I want to get this thing cracked.
Servo homing results, Z and X
Each dot is one homing cycle's resting position (raw linear-scale feedback, not the DRO -- unaffected by the homing offset reset), shown as deviation from that group's own mean so spreads are directly comparable across groups measured in different sessions. Same jog-away and settle protocol throughout.
Woohoo - finally looking half decent. I need to convince myself the effort was worth it - perhaps that conviction will come with time.
Note that these X distances are radius, not diameter. So the diameter home position error is 4x that of the Z axis ie +/-20um (0.8 thou). Hmm, that's shit. What more can be done?
One key difference is that the Z axis is still using index mark. we don't know how it would behave without that, as many changes happened since we implemented it. Is the x axis just as good as the z would be without index? In other words, has all this messing about with index marks been a waste of time?
Let's compare index mark homing vs the original proximity switch to double check....
Conclusion: using the index mark from the servo driver makes sod all difference. So I had no need to bugger about with connections from the servo driver to the 7i85 interface and all the buggerage that it entailed. Instead, careful setup of the homing and PID parameters delivered the same results.
Final numbers:
X axis homing accuracy - typically +/- 5-10um on radius (+/- 20um on diameter).
Z axis homing accuracy - typically +/- 5-10um.
And here's the proof of the homing accuracy (actually repeatability) for the X axis, typically within 5um after settling (10um on diameter):
And the backlash tests for the X axis (typically 15um variation):
Homing Z axis:
Backlash on Z axis:
Sod it. That may have to do for now unless I can be arsed to repeat the homing and backlash videos for the Z axis. Only time will tell.
And no, I'm not going to be using "index mark" homing on the Z axis. I've removed the relevant code from the HAL and INI files. And I never implemented index mark homing on the X axis, so no change required there.