Finderscope rings

Last weekend we made some rings for mounting a finderscope on the main telescope. Today I got the holes drilled and tapped so the rings are ready to use. The gallery below shows the adaptive pocketing paths that were used to cut both the part and the jig that allowed drilling the holes at +/- 120 degrees.

There is a video of the roughing operation at 2000 mm/min that will be online soon.


Bulbs of Steel

As a first serious test-run for our now servo-controlled cnc mill we decided to make an IOM bulb out of steel. It ends up a bit bigger in volume when made out of steel compared to lead, but the difference isn't huge. Making it with a cnc mill allows designing almost any reasonable 3D shape you can imagine.

The mill worked fine during the whole run, about 3 hours of rough-cutting and 1.5 hours of finish cutting, but there was a slight operator error in the setup which means this bulb will likely not sail. The following error stayed low throughout the run, and the servos weren't even hot to the touch after the workout.

We used adaptive roughing paths and then a simple parallel finish path. Both operations are cut with an 8 mm flat cutter. The adaptive paths did seem to work, and on this size machine they are really handy since a slight over-cut will likely stall the spindle motor (1.5 kW and 5000 rpm, small by big-iron cnc-standards).

0:00 rough cutting begins. The stock is a 45 mm diameter steel bar, face-milled down on the sides so it can be clamped to the machine vises. Note the cutting feedrate which is 500mm/min and 'high-feed' in the (x,y)-plane when the tool is positioned for the next cut. When the tool lifts up to the clearance plane it does normal G0 (rapid) moves.
1:34 more rough cutting on the other end of the bulb.
1:58 still pics of the rough-pass almost ready
2:15 view of emc2 while cutting. Note pyVCP bar widgets showing commanded PWM to servo motors.
4:29 beginning of parallel finish cut. programmed feed 1500 mm/min which is attained briefly in the middle of the move.
5:00 more finish cutting, about 2/3 done.
5:50 another view of emc2 and the pyVCP panel. Note Y and Z motors working to position the tool. The following error for each axis is also shown.
6:15 still pictures of the finished bulb (well, one half of it anyway). Note at the front of the bulb we tried to run the program at 150% of programmed feedrate, but that didn't work at all and resulted in a poor surface finish. We did try to slow down also from 100% but that didn't improve the surface much.

Google video doesn't really do justice to the nice 640x480 video and 5 Mpix still-photos that come out of the N95, so if you've bothered to read this far, here's the original 100 Mb mp4 (I hope I don't exceed my bandwidth limit).

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.

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...


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 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";
if (in!=old_in) /* a toggle has occurred */ {
if (is_on) { /* turn OFF if it's on */
else if (!is_on) { /* turn ON if it's off */
else {
/* reset pins when we see the desired state */
if (to_state==is_on) {

pyVCP m5i20 HOSTMOT-4 test panel

For testing the servo-drives and all the electronics I found this test-panel for the HOSTMOT-4 conifiguration of the m5i20 quite useful.

It uses an XML file (iotest.xml) to define the pyVCP panel layout, and then a HAL file (pyiotest.hal) to hook up the IO pins of the m5i20 to the panel. I'm also using a shell script ( to start the realtime environment and run pyvcp followed by the HAL file automatically.

Compare this to my earler effort with the old VCP. Now with many more widgets in pyVCP I have better control of the DACs etc.

Dah-Lih EMC2 conversion

Stuart Stevenson wrote about his Dah-Lih EMC2 conversion on the emc-mailinglist, and has allowed me to publish these pictures of his mill. I've scaled the pictures to 1024 pixels wide - click the picture to see it in high-resolution.

Machine after conversion.

Machine before conversion. Pendant has original CRT and buttons.

Control electronics. Jon Elson's PPMC cards at the top.

Relays and transformers.

The new control. The computer is a Gateway Profile 3.

There is a MagicTouch touch screen mounted in front of the computer.

Back side of control. The computer is connected to the PPMC cards by the parallel port only. Jog-wheel and buttons are wired directly to PPMC. The network cable goes to a Linksys WET11 bridge mounted on the back panel.

Extending AXIS with pyVCP

Maybe the most popular GUI for EMC is called AXIS. It shows a number of useful buttons, the 3D view, G-code file view etc. But depending on machine configuration and hardware, users might want to display different things on the screen and have customized controls. There's been some previous work on virtual control panels, or VCP. That was done in C using GTK widgets which I am not at all familiar with... I really want this kind of control panel for the new mill setup, so I've put together two Python programs that create Tkinter widgets that are connected to HAL pins. I call it pyVCP (Python Virtual Control Panel). Here's the first test from yesterday:

The uppermost widget is a slider that controls a HAL_FLOAT. Next is a button which sets a HAL_BIT true when pressed. The small rectangle is a checkbutton, which stays down when pressed, also for controlling a HAL_BIT. The status of a bit can be shown with a LED (red circle). HAL_FLOAT values can be indicated either by bars (green), or as a number.

To enable users to individually configure their extra bells and whistles it makes sense to have a text file that describes the panel setup. The easiest way I found to read and write structured data in Python was XML. Here I've used a number of the different widgets and ways to pack them to demonstrate what's possible:

Finally the best part. Since AXIS is also written in Python/Tkinter, AXIS author Jeff Epler was quickly able to integrate my work with the current AXIS, so you can have your custom control panel right next to the familiar view:

There's a bit more (including source files) in the EMC Wiki, and the latest versions are committed to CVS.