First cut with servo-mill

Got the XYZ servos mounted and tuned. The first video shows a test program with some drilling G-codes. Rapids are set at 5000mm/min with around 400 mm/s^2 accelerations. Following errors stay below 0.02 mm. The second video shows a 40 mm face-mill at 3000 rpm cutting a 20 mm wide aluminium bar with 1 mm depth of cut and 500 mm/min feed. We think this is pretty good for this size of minimill. The stability and sound will not be as nice as this without linear rails, ballscrews, and a good spindle.

8-channel 4th-order 60 kHz anti-alias low-pass filter

I used this Sallen-Key design to build an 8-channel 4th order low-pass anti-alias filter for a 16-bit 200 kS/s +/- 10 V AD-Converter. I calculated the components for the 60 kHz low-pass Butterworth design with this on-line calculator. Previously I've used the MAX274, but that component is limited to +/- 5 V signals. Here I really need the +/- 10 V voltage swing. The exact design calls for 2872 pF, 2452 pF, 6935 pF, and 1016 pF capacitors, but I looked at the transfer function with what values were available in 1% tolerance from Farnell, and the response looked fine with (R= 1 k, C1=C2= 2700 pF for the first stage and C1=6800 pF, C2=1000 pF for the second stage). Both the resistors and capacitors (~1.5 eur/pcs!) have a tolerance of 1 %, which according to a monte-carlo simulation should not affect the response that much. I'm using OP42 op-amps with a unity-gain bandwidth of 10 MHz, which should be adequate (100x the cut-off frequency was recommended in a guide I read, that would be 6 MHz in this case).

For testing I hooked up a signal generator and an oscilloscope and wrote a LabVIEW program to loop trough around 250 different frequencies while recording the peak-to-peak value of the filter input and output signals. The oscilloscope only has an 8-bit AD converter, but I adjusted the analogue gain between 5 V/div and 2 mV/div to achieve effectively around 16-bit dynamic range.

This is the result of testing all channels with a 20 Vpp sine wave between 100 Hz and 10 MHz. The blue curve shows the design response and the red and green curves show the maximum and minimum expected response from the monte-carlo simulation (I drew all component values from normal distributions with 1 % standard deviations). Pretty nice agreement until ~500 kHz. Here's another view of the data:

This figure shows the deviation of the real filters from the design response, again confirming that everything works as it should up to 500 kHz.

Log-log plots can be confusing, so here's a semilog plot and a linear plot of the same data:

Here are the source files for this design:

The box actually looks like this.

X-axis test

I mounted a servo on the x-axis of the mill today and did some PID tuning. The video shows a ca 300mm rapid move at 5500mm/min (217 IPM). Below some hal-scope views of what's going on in the PID loop during the move.

Here only P-gain is used and the machine needs to lag behind the commanded position (blue) a bit (slightly less than 1 mm, red trace) for the DAC output (green) to reach to reach the required level.

The lagging behind is curable with FF1, 1st order feed-forward. FF1 adds to the DAC output in proportion to the commanded velocity. With too little FF1 (top, note scale for red trace is 20x finer than in the first pic) the machine still lags behind. Wit too much FF1 (middle) the machine leads commanded position, and I figure the bottom trace has about the right amount of FF1 since the error is small and symmetrical around zero during the 'cruise'-phase (constant velocity) of the move.

I found FF2 much more tricky. Note again the scale is finer than before (100x finer compared to the first pic!). FF2 is 2nd order feed-forward and adds DAC output in proportion to the acceleration of the commanded position. In A there is no FF2 and the machine lags during acceleration and leads during deceleration. In B I've added FF2 and the error during acceleration seems to be a bit better. C has more FF2 and both the acceleration- and deceleration-phase errors are better. Then in D it seems I've overdone FF2 since the acceleration-phase error gets much worse (machine is leading commanded position), while the deceleration error improves.

I'm confused. What could be asymmetric so that FF2 acts differently during acceleration and deceleration? I should add that I am using an m5i20 to generate PWM for pico-systems servodrives (basically a H-bridge). There is no motor current, motor voltage, or velocity feedback, only feedback from a 4000 pulse encoder. The ballscrews are 2.5 mm/rev so one count is 0.000625 mm. The peak error during acc./dec. in the FF2 figure above is around 0.01 mm or 16 encoder counts. During cruise-phase the error is smaller, maybe only +/- 8 counts.

I then tested the inverse-deadband component which is supposed to linearise the DAC-motor system. I'm not sure what these results mean yet. The first error-peak is lowered, but there's an opposite effect during deceleration. This is a slower move and shows some periodic error during the cruise-phase, I wonder what that could be?

Finally some traces recorded with different length moves and different feed-rates. In reality 1000 mm/min is about the highest feed-rate used while machining, and everything higher than that is mostly for show only 🙂

Clearly higher feed-rates are more difficult for the PID loop. The acceleration/deceleration phases are still difficult, and there remains an asymmetry where with the current PID-parameters the acceleration phase works a bit better than the deceleration phase. I think with another choice of FF2 that could be reversed so that deceleration is fine but there is more error during acceleration.

I wonder if there is something peculiar to only torque-mode servo PID-loops that I should take into account? Something to do with the asymmetry between acceleration/deceleration...

EMC2 test run

The servos are now almost ready to go on the mill. Some dry-running of EMC2, the servo electronics, and the VFD today. I've made this pyVCP panel for AXIS which displays the commanded and actual spindle RPM, the spindle current (in some uncalibrated unit), the PID outputs and following errors for X/Y/Z. The jog-pendant box shows the mode of the jogwheel (X-jog, Y-jog, Z-jog, Off, Feed-override, Spindle-override), and the jog-increment (0.01 mm above). The four pendant buttons are now wired to turn on/off the coolant (blue button), to start the spindle forward or stop it (yellow button), to step through the program (green button), and to pause/resume the program (red button).

A video of the setup.
0:00 Actors, in order of appearance: EMC2, jog-pendant, electronics box, limit-switch box, X/Y/Z servos, VFD, Spindle motor.
0:30 Running a program. Load-meters. Rotating servos. Rotating spindle. Note professional mount and axis-coupler for spindle-encoder. The encoder will eventually be mounted on the other end of the motor.
1:30 Load-monitor demonstration. Running the machine from (300,300,300) to (0,0,0) with a rapid move (6000mm/min or around 2400 RPM on the servo shaft) and watching the bar-graphs show the commanded PWM to the amps.

It's best to store all the working config files here in case of disk crashes or other data loss:

FinnTec '08

FinnTec is an annual show for metalworking, toolmaking, CAD/CAM etc. Some video shot with my latest toy, an N95 8Gb.

0:00 5-axis machining on a mazak.
0:35 coordinate measurement machine
0:55 Haas Toolroom lathe. Something to copy or take ideas from if I'm going to build a lathe?
1:27 another lathe
1:45 Hexapod (makes you want to start building one right away!)
2:30 laser cutting. They move around a whole lot of iron at high acceleration and feed although in principle only the laser beam needs to be moved. The machine and floor shakes while cutting!
3:45 waterjet cutting at the Knuth stand
4:02 wire-edm machine and some wire-edm cut parts
4:30 cut-out of an SKF spindle (bearings and motor nicely visible)

toggle2nist

EMC uses 'nist-logic' for most IO, meaning there is one on-switch/signal to switch a thing on, one off-switch/signal to switch it off, and one indicator-signal to tell you the state.

To connect momentary-on pushbuttons to EMC you need at least the toggle component, but I've found that it doesn't work that great with things that can be set/reset by other parts of EMC. For example the coolant state might be set from the AXIS checkbox, G-code, MDI, a pyVCP button, or a hardware button through halui.

I made toggle2nist to set the coolant state with a momentary-on pushbutton. The hardware button connects to a toggle, and the toggle output connects to toggle2nist. It also needs the is-on signal, and produces as outputs the on/off signals (to halui.flood.on and halui.flood.off in this case).

component toggle2nist "toggle button to nist logic";
pin in bit in;
pin in bit is_on;
pin out bit on;
pin out bit off;
variable int old_in;
variable int to_state=0;
function _;
license "GPL";
;;
FUNCTION(_) {
if (in!=old_in) /* a toggle has occurred */ {
if (is_on) { /* turn OFF if it's on */
on=0;
off=1;
to_state=0;
}
else if (!is_on) { /* turn ON if it's off */
on=1;
off=0;
to_state=1;
}
}
else {
/* reset pins when we see the desired state */
if (to_state==is_on) {
on=0;
off=0;
}
}
old_in=in;
}

idb - Inverse Deadband component for EMC2

Due to the open-loop response of my servo motors I found I need 'inverse-deadband' on the PID output to achieve a 'tight' PID loop.

The idea is that since the motors don't respond to DAC outputs between around -0.2 to +0.2 it's not a good idea to use this interval of the DAC. I'm mapping the -10 to +10 output of the PID loop to two ranges, -10 to -0.2 and +0.2 to +10, thus avoiding the [-0.2 , +0.2] interval where the amps/motors don't respond.

Comp is a fantastic tool for writing quick custom HAL components. As usual I received knowledgeable help on IRC and was able to test my 16-line idb-component within minutes.

component idb "Inverse Deadband";
pin in float in "Input";
pin out float out "Output";
param rw float amount;
function _ ;
license "GPL";
;;
FUNCTION(_)
{
if (in==0.0)
out=in;
else if (in<0.0)
out=in-amount;
else if (in>0.0)
out=in+amount;
}

PID Tunig

For a few weekends now I have been 'dry-running' the servo electronics that are going to replace stepper motors on the cnc mill. So far the servos are working in closed loop, I can control the VFD forward/reverse and set the RPM, I can read in a spindle-encoder to verify the RPM and also do rigid tapping. The coolant relay works. There's a jogwheel that can be used for jogging the machine or adjusting spindle/feed-override.

Still on the to-do list are limit switches, home switches and homing, improvements to the E-stop loop, and linking up some pendant buttons.

I did a little PID-tuning today with one servo motor just sitting on the bench - no load. The final PID parameters when the motor is hooked up to the machine are probably going to be different from these, but at least I got some experience with tuning. I'm using the Mesa m5i20 to read encoder counts and output PWM to pico-systems servo amplifiers. The servos have 1000-line encoders so I get 4000 counts per revolution. The ballscrews are 2.5mm/revolution, so one encoder count corresponds to 0.000625 mm.

When tuning I did a 200 mm long G0 (rapid) move which allowed the motors to get up to max speed which was set to 6000 mm/min. With the servo directly coupled to the 2.5mm/rev screw that corresponds to 2400 RPM. When coasting at 6 m/min the DAC output was at around 8.7, so this is about as fast as the motors will go (unloaded). In the machine I might not be able to reach 6 m/min. Below some hal-scope screenshots that show how the pid-error changes when tuning the PID parameters.

First I tried only Pgain. The error clearly shows the three phases of the EMC2 trapezoidal trajectory generator. There's an initial acceleration phase during which the error grows, then the cruise phase where it stays constant, and then a deceleration phase at the end. The following error is big, more than 1mm. Obviously I've set FERROR and MIN_FERROR quite high in my ini file so EMC2 doesn't respond with a following error and stop all motion.

Next I tried increasing the 1st order feed-forward, or FF1, parameter. That worked well, and the error is cut more than ten fold!

So FF1 is a good thing? More of that then! Well not quite. Here I've increased FF1 to 0.2 and get sustained oscillations at the end of the move.

It's back to FF1=0.1 and a little D-term to the rescue for damping out the oscillations. Seems to work quite well.

Finally I ramped up the Igain. That helps to reduce the cruise-phase error a lot, but there still remains some following error during the accel/decel phases. There are spikes at the beginning and end of the accel/decel phases which I should try to get rid of. I guess some spikes will always remain since EMC2's trajectory planner outputs a trajectory which is only once differentiable (i.e. the velocity plot has 'sharp corners', and the acceleration plot has discontinuities, see pic here). I'm also using the inverse-deadband component to compensate for the open-loop response of the motors (see next post).

The maximum error is around 0.02 mm, or ca 32 encoder counts. I'm hoping the motors will perform at least as good as this when in the machine!

WordPress 2.5

WordPress 2.5 is out, and I've upgraded. Most of the shiny new stuff is on the admin side only, and so the outward look of the site remains.

The upgrade went smoothly, with the usual tweaks to style.css for the ever changing header image and to put the blog title in the left upper corner.

I've started tagging my posts, and there's a new tag-cloud at the top of the sidebar. I'll use it as a way of sub-categorizing posts without actually creating new categories. Once it's been in use for a while it will be useful for searching too.

Another recent update to the site is the list of WWW-links in the sidebar ("Anders' Web tips"). It's an RSS feed of the links I mark as 'shared' in google reader. Hope you like them!

Hard disks are not forever

Just had a 2-3 year old SATA drive fail on me. If you're reading this, go and take backups of critical data. Do it. Now.

This is the cnc-mill controller machine so hopefully no critical data was lost. Some notes on the EMC2 install process, just in case I need to do it all over again sometime soon...

  • Install WinXP on a 50 Gb NTFS partition
  • Installed Ubuntu 6.06LTS from CD. Manual partition, 50 Gb for root file system, 2 Gb for swap.
  • Ubuntu update manager suggests 301 updates (278M) to install. I'm in Finland, but strangely my sources.list points me to au.something servers. Reboot.
  • Install EMC2 using emc2-install.sh. Reboot.
  • 'latency-test' shows reasonable jitter values - good.
  • Configure X to enable 1280x1024 resolution: 'sudo dpkg-reconfigure xserver-xorg'. Answer lots of techy-questions, remember to add the correct screen resolution and the correct keyboard (pc102). I wasn't able to log in the first time I tried this because I had chosen an incorrect keyboard type/layout.