The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Tag: CNC

Making parts with mathematics

  • Atom D520: Config Files for Smoother Sherline Stepping

    The dual-core-ness of the D520, as set up there, allows a distinct improvement in the EMC2 BASE_PERIOD setting, which is exactly why I undertook this adventure.

    The 100 µs period I used on the Dell Dimension 4550 ensured the occasional long-latency burps wouldn’t cause much trouble… and they didn’t. The setup used the HAL step generator’s ability to supply a single pulse within one base period, so the maximum stepping rate was 1/100 µs = 10 k steps / second.

    However, that also determines the granularity of speed changes, so the controller can only drive the motors at multiples of the basic 100 µs without interpolating. For example, the four fastest step rates are:

    • 1/100 µs = 10 k step/sec
    • 1/200 µs =5 k step/sec
    • 1/300 µs = 3.3 k step/sec
    • 1/400 µs = 2.5 k step/sec

    The motors have 200 major steps / revolution and run in quarter-step mode: 800 microsteps / revolution. The axes have 20 turn-per-inch leadscrews, thus requiring 16 k step pulses per inch of travel.

    That means the corresponding traverse speeds are (step/sec) / (step/inch):

    • 10 k step/sec -> 0.625 in/sec = 37 in/min
    • 5 k step/sec -> 0.313 in/sec = 18.75 in/min
    • 3.3 k step/sec -> 0.206 in/sec = 12.37 in/min
    • 2.5 k step/sec -> 0.156 in/sec = 9.37 in/min

    Those are fairly large jumps between the speeds, which means the motor acceleration when the step rate changes is fairly high. HAL interpolates by bunching groups of pulses, but higher resolution is better.

    The Atom CPU has latencies under 10 µs, with no large burps that I’ve seen so far, so I set the BASE_PERIOD to 50 µs. However, that required changing the HAL step generator to produce a pulse during two successive periods (one high, one low) to keep the pulses wide enough for the motor controller. That means the highest step rate is still 10 k steps/sec and the top speed is still 37 inch/min.

    However, HAL can now adjust the period in smaller increments with lower acceleration between the jumps. The four fastest rates are now:

    • 1/100 µs = 10 k step/sec -> 0.625 in/sec = 37 in/min
    • 1/150 µs =6.7 k step/sec -> 0.417 in/sec = 25 in/min
    • 1/200 µs = 5 k step/sec -> 0.313 in/sec = 18.75 in/min
    • 1/250 µs = 4 k step/sec -> 0.250 in/sec = 15 in/min

    A stock Sherline CNC milling machine is rated for 22 inch/min (0.37 inch/sec) rapid motion on all three axes. That means the maximum step rate is

    • (0.37 inch/sec) * (16 k step/in) = 5.9 kHz

    Quite some years ago, I rebuilt my Sherline controller box to reduce its electrical and acoustic noise, then did a clean-room reimplementation of the firmware in the PIC microcontrollers. After the dust settled, my firmware could handle 8 k steps / sec, which works out to 0.5 in/sec = 30 in/min.

    That turns out to be slightly more aggressive than the whole lashup can tolerate; I can hear the motors take occasional hits as they miss the odd step at 30 inch/min.

    So I set the overall MAX_LINEAR_VELOCITY = 0.400 inch/sec = 24 inch/min, which is also the MAX_VELOCITY for both X and Y. The Z axis, as always, is happier with a bit slower top speed: 0.333 inch/sec = 20 inch/min. The maximum step rate is 0.4 x 16 k = 6.4 kHz, comfortably under the controller’s upper limit.

    The MAX_ACCELERATION for X and Y = 5.0 in/sec2, with Z at 3.0. STEPGEN_MAXACCEL for each axis is twice that; I have each axis set for a few mils of backlash compensation.

    With all that in mind, the changed configuration files look like this, with the others remaining as described there.

    Sherline.hal, with the new stepgen pulse specs

    # Generated by stepconf at Sat Aug 23 12:10:22 2008
    # If you make changes to this file, they will be
    # overwritten when you run stepconf again
    loadrt trivkins
    loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD traj_period_nsec=[EMCMOT]SERVO_PERIOD key=[EMCMOT]SHMEM_KEY num_joints=[TRAJ]AXES
    loadrt probe_parport
    loadrt hal_parport cfg="0x378 out"
    setp parport.0.reset-time 60000
    loadrt stepgen step_type=0,0,0,0
    loadrt pwmgen output_type=0
    
    addf parport.0.read base-thread
    addf stepgen.make-pulses base-thread
    addf pwmgen.make-pulses base-thread
    addf parport.0.write base-thread
    addf parport.0.reset base-thread
    
    addf stepgen.capture-position servo-thread
    addf motion-command-handler servo-thread
    addf motion-controller servo-thread
    addf stepgen.update-freq servo-thread
    addf pwmgen.update servo-thread
    
    net spindle-cmd <= motion.spindle-speed-out => pwmgen.0.value
    net spindle-enable <= motion.spindle-on => pwmgen.0.enable
    net spindle-pwm <= pwmgen.0.pwm
    setp pwmgen.0.pwm-freq 100.0
    setp pwmgen.0.scale 1166.66666667
    setp pwmgen.0.offset 0.114285714286
    setp pwmgen.0.dither-pwm true
    net spindle-cw <= motion.spindle-forward
    
    net estop-out => parport.0.pin-01-out
    net xdir => parport.0.pin-02-out
    net xstep => parport.0.pin-03-out
    setp parport.0.pin-03-out-reset 0
    setp parport.0.pin-04-out-invert 1
    net ydir => parport.0.pin-04-out
    net ystep => parport.0.pin-05-out
    setp parport.0.pin-05-out-reset 0
    setp parport.0.pin-06-out-invert 1
    net zdir => parport.0.pin-06-out
    net zstep => parport.0.pin-07-out
    setp parport.0.pin-07-out-reset 0
    net adir => parport.0.pin-08-out
    net astep => parport.0.pin-09-out
    setp parport.0.pin-09-out-reset 0
    net spindle-cw => parport.0.pin-14-out
    net spindle-pwm => parport.0.pin-16-out
    net xenable => parport.0.pin-17-out
    
    setp stepgen.0.position-scale [AXIS_0]SCALE
    setp stepgen.0.steplen 1
    setp stepgen.0.stepspace 1
    setp stepgen.0.dirhold 60000
    setp stepgen.0.dirsetup 60000
    setp stepgen.0.maxaccel [AXIS_0]STEPGEN_MAXACCEL
    net xpos-cmd axis.0.motor-pos-cmd => stepgen.0.position-cmd
    net xpos-fb stepgen.0.position-fb => axis.0.motor-pos-fb
    net xstep <= stepgen.0.step
    net xdir <= stepgen.0.dir
    net xenable axis.0.amp-enable-out => stepgen.0.enable
    
    setp stepgen.1.position-scale [AXIS_1]SCALE
    setp stepgen.1.steplen 1
    setp stepgen.1.stepspace 1
    setp stepgen.1.dirhold 60000
    setp stepgen.1.dirsetup 60000
    setp stepgen.1.maxaccel [AXIS_1]STEPGEN_MAXACCEL
    net ypos-cmd axis.1.motor-pos-cmd => stepgen.1.position-cmd
    net ypos-fb stepgen.1.position-fb => axis.1.motor-pos-fb
    net ystep <= stepgen.1.step
    net ydir <= stepgen.1.dir
    net yenable axis.1.amp-enable-out => stepgen.1.enable
    
    setp stepgen.2.position-scale [AXIS_2]SCALE
    setp stepgen.2.steplen 1
    setp stepgen.2.stepspace 1
    setp stepgen.2.dirhold 60000
    setp stepgen.2.dirsetup 60000
    setp stepgen.2.maxaccel [AXIS_2]STEPGEN_MAXACCEL
    net zpos-cmd axis.2.motor-pos-cmd => stepgen.2.position-cmd
    net zpos-fb stepgen.2.position-fb => axis.2.motor-pos-fb
    net zstep <= stepgen.2.step
    net zdir <= stepgen.2.dir
    net zenable axis.2.amp-enable-out => stepgen.2.enable
    
    setp stepgen.3.position-scale [AXIS_3]SCALE
    setp stepgen.3.steplen 1
    setp stepgen.3.stepspace 1
    setp stepgen.3.dirhold 60000
    setp stepgen.3.dirsetup 60000
    setp stepgen.3.maxaccel [AXIS_3]STEPGEN_MAXACCEL
    net apos-cmd axis.3.motor-pos-cmd => stepgen.3.position-cmd
    net apos-fb stepgen.3.position-fb => axis.3.motor-pos-fb
    net astep <= stepgen.3.step
    net adir <= stepgen.3.dir
    net aenable axis.3.amp-enable-out => stepgen.3.enable
    
    net estop-out <= iocontrol.0.user-enable-out
    net estop-out => iocontrol.0.emc-enable-in
    
    loadusr -W hal_manualtoolchange
    net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change
    net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed
    net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
    net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
    

    Sherline.ini, with new periods, speeds, and accelerations

    # Ed Nisley - KE4ZNU
    # Just do not run stepconf ever again...
    
    [EMC]
    MACHINE = Sherline-XYZA
    DEBUG = 0
    RS274NGC_STARTUP_CODE = G21 G40 G49 G54 G80 G90 G92.1 G94 G97 G98
    
    [DISPLAY]
    DISPLAY = axis
    EDITOR = gedit
    GEOMETRY = AXYZ
    POSITION_OFFSET = RELATIVE
    POSITION_FEEDBACK = ACTUAL
    MAX_FEED_OVERRIDE = 3.0
    INTRO_GRAPHIC = /home/ed/emc2/configs/Sherline-XYZA/Sherline.gif
    INTRO_TIME = 3
    #PROGRAM_PREFIX = /mnt/bulkdata/
    PROGRAM_PREFIX = ~/emc2/nc_files
    #INCREMENTS = .1in .05in .01in .005in .001in .0005in .0001in
    INCREMENTS = 10 mm, 1 mm, 0.1 mm, 90 deg, 45 deg, 10 deg
    
    [FILTER]
    PROGRAM_EXTENSION = .py Python Script
    py = python
    
    [TASK]
    TASK = milltask
    CYCLE_TIME = 0.010
    
    [RS274NGC]
    PARAMETER_FILE = emc.var
    
    [EMCMOT]
    EMCMOT = motmod
    SHMEM_KEY = 111
    COMM_TIMEOUT = 1.0
    COMM_WAIT = 0.010
    BASE_PERIOD = 50000
    SERVO_PERIOD = 1000000
    
    [HAL]
    HALUI=halui
    HALFILE = Sherline.hal
    HALFILE = custom.hal
    HALFILE = Logitech_Gamepad.hal
    POSTGUI_HALFILE = custom_postgui.hal
    
    [TRAJ]
    AXES = 4
    COORDINATES = X Y Z A
    MAX_ANGULAR_VELOCITY = 45.00
    DEFAULT_ANGULAR_VELOCITY = 36.0
    LINEAR_UNITS = inch
    ANGULAR_UNITS = degree
    CYCLE_TIME = 0.010
    DEFAULT_VELOCITY = 0.400
    MAX_LINEAR_VELOCITY = 0.400
    POSITION_FILE =	lastposition.txt
    NO_FORCE_HOMING = 1
    
    [EMCIO]
    EMCIO = io
    CYCLE_TIME = 0.100
    TOOL_TABLE = Sherline.tbl
    TOOL_CHANGE_AT_G30 = 1
    
    [AXIS_0]
    TYPE = LINEAR
    MAX_VELOCITY = 0.400
    MAX_ACCELERATION = 5.0
    STEPGEN_MAXACCEL = 10.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = -1.0
    MAX_LIMIT = 9.5
    BACKLASH = 0.003
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 2
    HOME_SEARCH_VEL = 0.3
    HOME_LATCH_VEL = 0.016
    HOME_FINAL_VEL = 0.4
    HOME_OFFSET = 9.1
    HOME = 4.5
    
    [AXIS_1]
    TYPE = LINEAR
    MAX_VELOCITY = 0.400
    MAX_ACCELERATION = 5.0
    STEPGEN_MAXACCEL = 10.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = -0.5
    MAX_LIMIT = 4.90
    BACKLASH = 0.003
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 1
    HOME_SEARCH_VEL = -0.3
    HOME_LATCH_VEL = -0.016
    HOME_FINAL_VEL = 0.4
    HOME_OFFSET = 0.0
    HOME = 4.0
    
    [AXIS_2]
    TYPE = LINEAR
    MAX_VELOCITY = 0.333
    MAX_ACCELERATION = 3.0
    STEPGEN_MAXACCEL = 6.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = 0.0
    MAX_LIMIT = 6.930
    BACKLASH = 0.005
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 0
    HOME_SEARCH_VEL = 0.200
    HOME_LATCH_VEL = 0.016
    HOME_FINAL_VEL = 0.3
    HOME_OFFSET = 6.93
    HOME = 6.5
    
    [AXIS_3]
    TYPE = ANGULAR
    ###WRAPPED_ROTARY = 1
    MAX_VELOCITY = 40.0
    MAX_ACCELERATION = 250.0
    STEPGEN_MAXACCEL = 275.0
    SCALE = 160.0
    FERROR = 1
    MIN_FERROR = .25
    MIN_LIMIT = -999999999.9
    MAX_LIMIT =  999999999.9
    HOME_SEARCH_VEL = 0
    HOME_LATCH_VEL = 0
    HOME = 0.0
    

     

     

  • An Atom for the Sherline Milling Machine

    Somewhat against the recommendations of the experts on the EMC2 mailing list, I bought a Foxconn R30-D2 with an Intel Atom D520 from Newegg during a sale: add 2 GB of memory from Crucial, a spare SATA drive from my collection, and it’s ready to go. I also bashed a spare parallel printer port card into the box, although it isn’t really needed right now: unlike the Intel system board, Foxconn brings the on-board parallel port directly to the back panel.

    The Foxconn support site is a nightmare and was, AFAICT, dead for the first few weeks I had the box. The key fact to remember is that the -D2 part of the number specifies the system board / CPU, so the same downloads / BIOS updates apply to the R10, R20, R30, and R40 models. There is no new BIOS available to fix the “fan runs all the time” problem reported by so many people.

    I installed Ubuntu 10.04 LTS from the distro CD, then ran the EMC2 installation script. All that is routine, as described there. You probably want to install the EMC2 Live CD, though, and to get much the same result with less fiddling.

    Turn off Hyperthreading in the BIOS, which seems to make the RTAI real-time hypervisor happier. Under those conditions, the default install has an interrupt latency of about 13 µs.

    The Atom D520 is a dual-core processor and you can devote one core to EMC2’s real-time functions, thus eliminating much of the usual contention and interrupt latency. That works surprisingly well and is completely automagic after you add the isolcpus=1 kernel option to the appropriate line in /boot/grub/grub.cfg. Thusly:

    linux	/boot/vmlinuz-2.6.32-122-rtai root=UUID=57fe2b04-ffe4-4de3-a597-89bd4ed01018 ro  vga=758  noquiet nosplash isolcpus=1
    

    With that done, the latency drops down under 8 µs, which is entirely satisfactory. I can push it to 10 µs by doing stupid things: scrubbing a glxgears window over a Flash video in Firefox, for example.

    The catch is that the wonderful new grub2 bootloader rewrites its boot configuration file on the fly, based on a set of rules that, evidently, cannot apply different kernel configuration parameters to different kernels within the same partition. As a result, you must choose between:

    • Running stock Ubuntu on one core
    • Manually tweaking grub.cfg after every kernel update

    Given that an Atom isn’t exactly a blinding flash and a deafening report in the performance department, I opted for the second method. If Ubuntu was still using Legacy Grub, then I’d just tweak menu.lst and be done with it. This is, I suppose, progress.

    Memo to Self: Adjust grub.cfg every mumble time.

    [Update: There’s now a fix for that, as described in the EMC2 wiki. Go for it!]

  • Aluminum-Housed Resistor Hole Locations and Derating

    The battle plan is to mount some resistors on those heatsinks to warm up the disinsector.

    These seem to be the right hammer for the job:

    Aluminum housed resistors
    Aluminum housed resistors

    The big one is rated 50 W @ 25 °C ambient. Use two, derated by 50%, times three air-cooled heatsinks for 150 W of low-temperature heating. The little one is 25 W @ 25 °C.

    The derating curve is linear from 100% @ 25 °C down to 10% @ 250 °C, when mounted to a square foot of flat aluminum plate: -0.40% / °C.

    Assuming a max heater ambient of  150 °F = 65 °C, you can use 84% of full power. Derating by 50% isn’t all that unreasonable.

    The relevant hole locations:

    • 50 W: X=1.562 inch / 39.67 mm Y=0.844 inch / 21.44 mm
    • 25 W: X=0.719 inch / 18.26 mm Y=0.781 inch / 19.84 mm
    • 10 W: X=0.562 inch / 14.27 mm Y=0.625 inch / 15.88 mm

    Divide those by 2.0 for from-the-center offsets, which may be more useful for manual CNC operations: zero at the resistor mounting center, then back-and-forth from there.

    The mounting hole size for 25 & 50 W resistors: 0.125 inch / 3.18 mm diameter, just exactly what you want for a 4-40 mounting screw. Tap drill #43, clearance drill #32 (close fit) or #30 (loose fit).

    The mounting hole size for 10 W resistors: 0.094 inch / 2.39 mm to fit a 2-56 screw. Tap drill #50 (better: #49 for 50% threads), clearance drill #43 (close) or #41 (loose).

    The Vishay-Dale data sheet is there

  • Sherline Rotary Table CD Bushing

    CDs being such a useful source of raw material, I cooked this up on the lathe while puttering around in the shop thinking about something else. The general idea is to align a short stack of CDs on the Sherline rotary table, close enough to the center, so that you can gnaw away on the top platter and get nearly concentric results. If you really care about concentricity, this isn’t the way to go, but …

    CD adapter bushing in place
    CD adapter bushing in place

    The washer clamps the CDs in place with the bushing sticking up a bit from the top layer, so it need not be more than eyeball-aligned; the air gap eliminates the need to get the bushing height Exactly Right. If you’re perpetrating fancy machining on the CD, you probably want a form-fitting metal plate atop the stack to hold it down near the perimeter to prevent getting swarf jammed underneath. Note the stack of washers require to reduce that gaping hole to meet a 3/8-16 bolt threaded into the table.

    All by itself, the bushing looks like this:

    CD Adapter Bushing
    CD Adapter Bushing

    The dimensions, roughly as-built:

    Rotary Table CD Adapter Bushing
    Rotary Table CD Adapter Bushing

    I used a random plastic cylinder from the scrap pile and cleaned up the edges with a razor knife. Next time, I’d put the fat end near the lathe tailstock, so as to make the chamfer easier.

    Memo to Self: Use brass, dammit!

  • Improved Tool Length Probe Switch: Repeatability

    After doing a repeatability test immediately after screwing the new switch to the tooling plate, I let everything sit overnight and ran the test again. In between, I’d done a few small moves, but didn’t change any of the mechanical positions.

    The positions look like this:

    Trial	Z-axis mm	Delta mm
    1	26.303561	0.000000
    2	26.305558	0.001997
    3	26.304226	0.000665
    4	26.304226	0.000665
    5	26.303561	0.000000
    6	26.305558	0.001997
    7	26.305558	0.001997
    8	26.303561	0.000000
    9	26.303561	0.000000
    10	26.304226	0.000665
    11	26.304892	0.001331
    
    	Maximum	0.001997
    	Minimum	0.000000
    	Range	0.001997
    

    The initial position is 0.07 mm, about 3 mils, higher than before, which may well be due to the limited amount of fiddling I’d done in between.

    The corresponding picture shows that the values are well and truly quantized to far fewer positions than the number of digits would lead you to believe:

    Probe Repeatability 2
    Probe Repeatability 2

    The total range is 0.002 mm = 78 microinch, so the steps are on the order of 666 nm: separated by just about exactly one wavelength of the red He emission line.

    What’s of interest is that the regression line is perfectly flat, which means the switch has pretty much stabilized. I have absolutely no reason to believe it’s repeatable to anywhere near that accuracy, particularly from day to day, but the switch is normally used to set tool lengths relative to a specific tool that’s touched off against the work surface at the start of what passes for a machining job around here.

    It’s good enough!

  • Improved Tool Length Probe Switch

    This relay-like object appeared while shoveling off the Electronics Workbench. Most likely, it started life in the white-goods world, where recurring cost is everything:

    Original relay
    Original relay

    Now, doesn’t that look just like a tool length probe? It’s certainly less hideous than the one that’s been working fine on my Sherline mill, ever since I figured out how to make tool length probing work.

    Here’s what caught my eye:

    • Plenty of switch overtravel
    • Nice metal bracket with screws
    • All the vital pieces in one convenient assembly!

    Some brute force removed the spring and actuator, a few shots with a chisel broke the adhesive holding the coil in place, and this collection of parts emerged relatively unscathed:

    Disassembled relay parts
    Disassembled relay parts

    Another shot with a pin punch removed the post from the frame. I intended to un-bend the L-shaped feature that held the post, enlarge the hole, and screw it to the mill. Alas, they formed the angle by notching the steel and it cracked when I un-bent it. No great loss.

    The two bumps on the frame held the (now defunct) restoring spring. I simply filed those off while cleaning up the broken edges.

    Drill a 10-32 clearance hole, solder a cable with a 3.5 mm stereo plug to the switch, add a plastic cable clamp, screw it to the end of the tooling plate, and it’s all good. That’s the butt end of a broken 2 mm end mill poking down from the spindle…

    New tool length probe in action
    New tool length probe in action

    Does it work any better than the previous kludge?

    A G-Code routine that displays the Z-axis coordinate where the switch trips looks like this:

    (Tool length probing test)
    
    (--------------------)
    ( Initialize first tool length at probe switch)
    (    Assumes G59.3 is still in machine units, returns in G54)
    ( ** Must set these constants to match G20 / G21 condition!)
    
    #<_Probe_Speed> =        400            (set for something sensible in mm or inch)
    #<_Probe_Retract> =        1            (ditto)
    
    O<Probe_Tool> SUB
    
    G49                     (clear tool length compensation)
    G30                     (move above probe switch)
    G59.3                   (coord system 9)
    
    G38.2 Z0 F#<_Probe_Speed>           (trip switch on the way down)
    G0 Z[#5063 + #<_Probe_Retract>]     (back off the switch)
    G38.2 Z0 F[#<_Probe_Speed> / 10]    (trip switch slowly)
    
    #<_ToolZ> = #5063                    (save new tool length)
    G43.1 Z[#<_ToolZ> - #<_ToolRefZ>]    (set new length)
    
    G54                     (coord system 0)
    G30                     (return to safe level)
    
    O<Probe_Tool> ENDSUB
    
    (-------------------)
    (-- Initialize first tool length at probe switch)
    
    O<Probe_Init> SUB
    
    #<_ToolRefZ> = 0.0      (set up for first call)
    O<Probe_Tool> CALL
    #<_ToolRefZ> = #5063    (save trip point)
    
    G43.1 Z0                (tool entered at Z=0, so set it there)
    
    O<Probe_Init> ENDSUB
    
    (--------------------)
    ( Set up length)
    
    G21                     ( metric units)
    
    (msg,Verify G30.1 above tool change switch, hit Resume)
    M0
    (msg,Verify blunt tool installed, hit Resume)
    M0
    
    O<Probe_Init> CALL
    
    (debug,Initial Z trip = #<_ToolRefZ>)
    
    O100 REPEAT [10]
    
    O<Probe_Tool> CALL
    #<DeltaZ> = [#<_ToolZ> - #<_ToolRefZ>]
    (debug,Z trip=#<_ToolZ> DeltaZ=#<_DeltaZ>)
    
    O100 ENDREPEAT
    
    M2
    

    Which produced these results:

    Trial	Z-axis mm	Delta mm
    1	26.376973	-0.000000
    2	26.376307	-0.000666
    3	26.374976	-0.001997
    4	26.376307	-0.000666
    5	26.375641	-0.001332
    6	26.374310	-0.002663
    7	26.374976	-0.001997
    8	26.373645	-0.003328
    9	26.373645	-0.003328
    10	26.372979	-0.003994
    11	26.372979	-0.003994
    
             Maximum	-0.000000
             Minimum	-0.003994
             Range  	 0.003994
    

    Notice that the results have six figures after the decimal point, but they’re really less precise: you’ll find four pairs of duplicates, which seems highly unlikely. I think the values are quantized to about 25 µ-inch and displayed as whatever the metric equivalent might be.

    The corresponding plot looks like this:

    Probe Repeatability
    Probe Repeatability

    The trend line is highly suspect, but the slope shows that the trip point gets lower by one wavelength of violet light (393 microns) per trip. The total difference is a whopping 0.004 mm during the test, call it 160 millionth of an inch.

    Both of those are better, by roughly a factor of two, than the previous probe switch.

    Bottom line: That’s OK for the sort of machining I do… ship it!

  • Sherline EMC2 CNC Mill: Configuration Files

    This is a stick in the ground for the current config files I’m using with EMC 2.4.5. Even the automagically generated files may have some tweakage, which is why I’m putting them here…

    [Update: this is for a Dell Dimension 4550 with a latency around 10 µs, occasional glitches to 20 µs, and a very rare burp to 80 µs. Worked fine, but those rare burps were disturbing.]

    Sherline.ini

    # Ed Nisley - KE4ZNU
    # Just don't run stepconf ever again...
    
    [EMC]
    MACHINE = Sherline-XYZA
    DEBUG = 0
    RS274NGC_STARTUP_CODE = G21 G40 G49 G54 G80 G90 G92.1 G94 G97 G98
    
    [DISPLAY]
    DISPLAY = axis
    EDITOR = gedit
    GEOMETRY = AXYZ
    POSITION_OFFSET = RELATIVE
    POSITION_FEEDBACK = ACTUAL
    MAX_FEED_OVERRIDE = 3.0
    INTRO_GRAPHIC = Sherline.gif
    INTRO_TIME = 3
    PROGRAM_PREFIX = /mnt/bulkdata/
    #PROGRAM_PREFIX = /home/ed/
    #INCREMENTS = .1in .05in .01in .005in .001in .0005in .0001in
    INCREMENTS = 10 mm, 1 mm, 0.1 mm, 90 deg, 45 deg, 10 deg
    
    [FILTER]
    PROGRAM_EXTENSION = .py Python Script
    py = python
    
    [TASK]
    TASK = milltask
    CYCLE_TIME = 0.010
    
    [RS274NGC]
    PARAMETER_FILE = emc.var
    
    [EMCMOT]
    EMCMOT = motmod
    SHMEM_KEY = 111
    COMM_TIMEOUT = 1.0
    COMM_WAIT = 0.010
    BASE_PERIOD = 100000
    SERVO_PERIOD = 1000000
    
    [HAL]
    HALUI=halui
    HALFILE = Sherline.hal
    HALFILE = custom.hal
    HALFILE = Logitech_Gamepad.hal
    POSTGUI_HALFILE = custom_postgui.hal
    
    [TRAJ]
    AXES = 4
    COORDINATES = X Y Z A
    MAX_ANGULAR_VELOCITY = 45.00
    DEFAULT_ANGULAR_VELOCITY = 36.0
    LINEAR_UNITS = inch
    ANGULAR_UNITS = degree
    CYCLE_TIME = 0.010
    #DEFAULT_VELOCITY = 0.333
    DEFAULT_VELOCITY = 0.475
    #MAX_LINEAR_VELOCITY = 0.400
    MAX_LINEAR_VELOCITY = 0.500
    POSITION_FILE =	lastposition.txt
    NO_FORCE_HOMING = 1
    
    [EMCIO]
    EMCIO = io
    CYCLE_TIME = 0.100
    TOOL_TABLE = Sherline.tbl
    TOOL_CHANGE_AT_G30 = 1
    
    [AXIS_0]
    TYPE = LINEAR
    #MAX_VELOCITY = 0.400
    MAX_VELOCITY = 0.475
    #MAX_ACCELERATION = 1.5
    MAX_ACCELERATION = 5.0
    #STEPGEN_MAXACCEL = 1.7
    STEPGEN_MAXACCEL = 10.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = -1.0
    MAX_LIMIT = 9.5
    BACKLASH = 0.003
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 2
    HOME_SEARCH_VEL = 0.3
    HOME_LATCH_VEL = 0.016
    HOME_FINAL_VEL = 0.4
    HOME_OFFSET = 9.1
    HOME = 4.5
    
    [AXIS_1]
    TYPE = LINEAR
    #MAX_VELOCITY = 0.400
    MAX_VELOCITY = 0.475
    #MAX_ACCELERATION = 1.5
    MAX_ACCELERATION = 5.0
    #STEPGEN_MAXACCEL = 1.7
    STEPGEN_MAXACCEL = 10.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = -0.5
    MAX_LIMIT = 4.90
    BACKLASH = 0.003
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 1
    HOME_SEARCH_VEL = -0.3
    HOME_LATCH_VEL = -0.016
    HOME_FINAL_VEL = 0.4
    HOME_OFFSET = 0.0
    HOME = 4.0
    
    [AXIS_2]
    TYPE = LINEAR
    MAX_VELOCITY = 0.333
    #MAX_VELOCITY = 0.400
    #MAX_ACCELERATION = 1.0
    MAX_ACCELERATION = 3.0
    #STEPGEN_MAXACCEL = 1.2
    STEPGEN_MAXACCEL = 6.0
    SCALE = 16000.0
    FERROR = 0.05
    MIN_FERROR = 0.01
    MIN_LIMIT = 0.0
    MAX_LIMIT = 6.930
    BACKLASH = 0.005
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 0
    HOME_SEARCH_VEL = 0.200
    HOME_LATCH_VEL = 0.016
    HOME_FINAL_VEL = 0.3
    HOME_OFFSET = 6.93
    HOME = 6.5
    
    [AXIS_3]
    TYPE = ANGULAR
    ###WRAPPED_ROTARY = 1
    MAX_VELOCITY = 40.0
    MAX_ACCELERATION = 250.0
    STEPGEN_MAXACCEL = 275.0
    SCALE = 160.0
    FERROR = 1
    MIN_FERROR = .25
    MIN_LIMIT = -999999999.9
    MAX_LIMIT =  999999999.9
    HOME_SEARCH_VEL = 0
    HOME_LATCH_VEL = 0
    HOME = 0.0
    

    Sherline.tbl

    ;common end mills
    T1 P1 Z1 D0.1225 ; 1/8
    T2 P2 Z1 D0.1535 ; 5/32
    T3 P3 Z1 D0.1870 ; 3/16
    T4 P4 Z1 D0.2500 ; 1/4
    T5 P5 Z1 D0.3122 ; 5/16
    T6 P6 Z1 D0.3755 ; 3/8 - 4 flute long
    T7 P7 Z1 D0.4374 ; 7/16
    T8 P8 Z1 D0.4720 ; 1/2
    ;random metric equivalents
    T20 P20 Z1 D0.09787 ; 2 mm
    ;number drills 1xx = xx
    T107 P107 Z1 D0.201 ;  7	 5.11	10-32 clear
    T109 P109 Z1 D0.196 ;  9	 4.98	10-32 clear
    T118 P118 Z1 D0.170 ; 18	 4.32	 8-32 clear
    T121 P121 Z1 D0.159 ; 21	 4.04	10-32 tap
    T127 P127 Z1 D0.144 ; 27	 3.66	 6-32 clear
    T129 P129 Z1 D0.136 ; 29	 3.45	 8-32 tap
    T136 P136 Z1 D0.107 ; 36	 2.72	 6-32 tap
    T132 P132 Z1 D0.116 ; 32	 2.95	 4-40 clear
    T143 P143 Z1 D0.089 ; 43	 2.26	 4-40 tap
    T141 P141 Z1 D0.096 ; 41	 2.44	 2-56 clear
    T146 P146 Z1 D0.081 ; 46	 2.06	 good for 2 mm pin
    T148 P148 Z1 D0.076 ; 48	 1.93	 1-72 clear
    T150 P150 Z1 D0.070 ; 50	 1.78	 2-56 tap 0-80 clear
    T152 P152 Z1 D0.064 ; 52	 1.63	 0-80 clear
    T153 P153 Z1 D0.060 ; 53	 1.52	 1-72 tap
    ;fraction drills 2xx = xx/64
    T203 P203 Z1 D0.047 ; 3/64	 1.2	 0-80 tap
    ;inch decimal drills for eagle drilling
    ; 1xxx = xxx/1000
    T1000 P1000 Z1 D0.000	; center drill
    T1024 P1024 Z1 D0.024
    T1025 P1025 Z1 D0.025
    T1032 P1032 Z1 D0.032
    T1039 P1039 Z1 D0.039
    T1040 P1040 Z1 D0.040
    T1045 P1045 Z1 D0.045
    T1047 P1047 Z1 D0.047
    T1052 P1052 Z1 D0.052
    T1067 P1067 Z1 D0.067
    T1125 P1125 Z1 D0.125
    T1140 P1140 Z1 D0.140
    T1150 P1150 Z1 D0.150
    

    custom.hal

    # Include your customized HAL commands here
    # This file will not be overwritten when you run stepconf again
    
    #--------------
    # Get buttons and joysticks from Logitech Dual Action gamepad
    
    loadusr -W hal_input -KA Dual
    
    #--------------
    # Home switches are all in parallel, active low
    
    net homeswitches <= parport.0.pin-10-in-not
    net homeswitches => axis.0.home-sw-in
    net homeswitches => axis.1.home-sw-in
    net homeswitches => axis.2.home-sw-in
    
    #--------------
    # Probe input is active low
    
    net probe-in <== parport.0.pin-15-in-not
    net probe-in ==> motion.probe-input
    

    custom_postgui.hal

    #-- empty
    

    Logitech_Gamepad.hal

    # HAL config file automatically generated by Eagle-CAD ULP:
    # [/mnt/bulkdata/Project Files/eagle/ulp/hal-write-array.ulp]
    # (C) Martin Schoeneck.de 2008
    # Mods Ed Nisley 2010
    # Path        [/mnt/bulkdata/Project Files/eagle/projects/EMC2 HAL Configuration/]
    # ProjectName [Logitech Gamepad]
    # File name   [/mnt/bulkdata/Project Files/eagle/projects/EMC2 HAL Configuration/Logitech_Gamepad.hal]
    # Created     [11:51:27 10-Nov-2010]
    
    ####################################################
    # Load realtime and userspace modules
    loadrt constant		count=16
    loadrt and2		count=17
    loadrt flipflop		count=4
    loadrt mux2		count=5
    loadrt mux4		count=1
    loadrt not		count=8
    loadrt or2		count=10
    loadrt scale		count=7
    loadrt timedelay		count=1
    loadrt toggle		count=1
    loadrt wcomp		count=6
    
    ####################################################
    # Hook functions into threads
    addf toggle.0		servo-thread
    addf wcomp.1		servo-thread
    addf wcomp.2		servo-thread
    addf wcomp.3		servo-thread
    addf and2.0		servo-thread
    addf and2.4		servo-thread
    addf and2.3		servo-thread
    addf and2.2		servo-thread
    addf and2.1		servo-thread
    addf constant.6		servo-thread
    addf constant.5		servo-thread
    addf constant.4		servo-thread
    addf constant.3		servo-thread
    addf constant.2		servo-thread
    addf constant.1		servo-thread
    addf constant.0		servo-thread
    addf constant.7		servo-thread
    addf constant.8		servo-thread
    addf scale.1		servo-thread
    addf scale.2		servo-thread
    addf scale.3		servo-thread
    addf mux4.0		servo-thread
    addf mux2.0		servo-thread
    addf scale.4		servo-thread
    addf scale.0		servo-thread
    addf wcomp.5		servo-thread
    addf wcomp.4		servo-thread
    addf wcomp.0		servo-thread
    addf flipflop.1		servo-thread
    addf flipflop.0		servo-thread
    addf and2.5		servo-thread
    addf and2.6		servo-thread
    addf and2.7		servo-thread
    addf and2.8		servo-thread
    addf flipflop.2		servo-thread
    addf flipflop.3		servo-thread
    addf or2.4		servo-thread
    addf or2.8		servo-thread
    addf or2.7		servo-thread
    addf or2.6		servo-thread
    addf or2.5		servo-thread
    addf or2.3		servo-thread
    addf or2.2		servo-thread
    addf or2.1		servo-thread
    addf or2.0		servo-thread
    addf not.1		servo-thread
    addf not.2		servo-thread
    addf not.3		servo-thread
    addf not.4		servo-thread
    addf not.5		servo-thread
    addf not.6		servo-thread
    addf not.7		servo-thread
    addf not.0		servo-thread
    addf constant.9		servo-thread
    addf mux2.1		servo-thread
    addf mux2.2		servo-thread
    addf mux2.3		servo-thread
    addf mux2.4		servo-thread
    addf constant.10		servo-thread
    addf constant.11		servo-thread
    addf scale.5		servo-thread
    addf scale.6		servo-thread
    addf constant.12		servo-thread
    addf constant.13		servo-thread
    addf timedelay.0		servo-thread
    addf constant.14		servo-thread
    addf constant.15		servo-thread
    addf and2.16		servo-thread
    addf and2.15		servo-thread
    addf and2.14		servo-thread
    addf and2.13		servo-thread
    addf and2.12		servo-thread
    addf and2.11		servo-thread
    addf and2.10		servo-thread
    addf and2.9		servo-thread
    addf or2.9		servo-thread
    
    ####################################################
    # Set parameters
    
    ####################################################
    # Set constants
    setp constant.0.value	+0.02
    setp constant.1.value	-0.02
    setp constant.2.value	60
    setp constant.3.value	1.00
    setp constant.4.value	0.10
    setp constant.5.value	0.50
    setp constant.6.value	0.10
    setp constant.7.value	+0.5
    setp constant.8.value	-0.5
    setp constant.9.value	0.0
    setp constant.10.value	[TRAJ]MAX_LINEAR_VELOCITY
    setp constant.11.value	[TRAJ]MAX_ANGULAR_VELOCITY
    setp constant.12.value	-1.0
    setp constant.13.value	0.1
    setp constant.14.value	0.020
    setp constant.15.value	0.000
    
    ####################################################
    # Connect Modules with nets
    net a-button-minus input.0.btn-trigger or2.2.in0 and2.15.in0
    net a-button-plus input.0.btn-thumb2 or2.2.in1 and2.16.in0
    net a-buttons-active or2.2.out or2.3.in0 or2.4.in1
    net a-disable not.7.out and2.5.in1
    net a-enable or2.4.in0 flipflop.3.out not.7.in mux2.4.sel
    net a-jog wcomp.2.in input.0.abs-z-position mux2.4.in1
    net a-knob-active not.2.out and2.7.in1
    net a-knob-inactive wcomp.2.out not.2.in and2.6.in1
    net a-select and2.8.in0 and2.7.out
    net a-set flipflop.3.set and2.8.out
    net angular_motion or2.4.out mux2.0.sel
    net any-buttons-active mux4.0.sel0 or2.8.out
    net az-buttons-active or2.3.out or2.8.in1 or2.9.in0
    net az-reset flipflop.2.reset and2.6.out flipflop.3.reset
    net button-crawl scale.4.out mux4.0.in3
    net button-fast scale.2.out mux4.0.in1 scale.4.in
    net jog-crawl toggle.0.out mux4.0.sel1
    net jog-speed halui.jog-speed mux4.0.out
    net knob-crawl mux4.0.in2 scale.3.out
    net knob-fast mux4.0.in0 scale.1.out scale.3.in
    net n_1 constant.10.out mux2.0.in0
    net n_2 and2.0.in0 input.0.btn-top2
    net n_3 and2.0.in1 input.0.btn-base
    net n_4 and2.0.out halui.abort
    net n_5 halui.mode.manual input.0.btn-base3
    net n_6 wcomp.0.max wcomp.1.max wcomp.2.max wcomp.3.max constant.0.out
    net n_7 halui.program.resume input.0.btn-base4
    net n_8 wcomp.0.min wcomp.1.min wcomp.2.min wcomp.3.min constant.1.out
    net n_9 mux2.0.in1 constant.11.out
    net n_10 constant.12.out scale.5.gain scale.6.gain
    net n_11 input.0.btn-base5 or2.0.in0
    net n_12 input.0.btn-base6 or2.0.in1
    net n_13 constant.9.out mux2.1.in0 mux2.2.in0 mux2.3.in0 mux2.4.in0
    net n_14 mux2.1.out halui.jog.0.analog
    net n_15 toggle.0.in or2.0.out
    net n_16 constant.2.out scale.0.gain
    net n_17 constant.5.out scale.1.gain
    net n_18 constant.3.out scale.2.gain
    net n_19 constant.4.out scale.3.gain
    net n_20 scale.4.gain constant.6.out
    net n_21 halui.jog.1.analog mux2.2.out
    net n_22 mux2.2.in1 scale.5.out
    net n_23 scale.6.out mux2.3.in1
    net n_24 constant.13.out halui.jog-deadband
    net n_25 wcomp.4.max constant.7.out wcomp.5.max
    net n_26 constant.8.out wcomp.4.min wcomp.5.min
    net n_27 mux2.3.out halui.jog.2.analog
    net n_28 halui.jog.3.analog mux2.4.out
    net n_29 timedelay.0.out and2.9.in1 and2.10.in1 and2.12.in1 and2.11.in1 and2.13.in1 and2.14.in1 and2.16.in1 and2.15.in1
    net n_30 and2.9.out halui.jog.0.minus
    net n_31 or2.9.out timedelay.0.in
    net n_32 constant.14.out timedelay.0.on-delay
    net n_33 constant.15.out timedelay.0.off-delay
    net n_34 and2.10.out halui.jog.0.plus
    net n_35 and2.11.out halui.jog.1.minus
    net n_36 halui.jog.1.plus and2.12.out
    net n_37 and2.13.out halui.jog.2.minus
    net n_38 and2.14.out halui.jog.2.plus
    net n_39 and2.15.out halui.jog.3.minus
    net n_40 and2.16.out halui.jog.3.plus
    net vel-per-minute scale.0.out scale.1.in scale.2.in
    net vel-per-second mux2.0.out scale.0.in
    net x-buttons-active or2.7.in0 or2.5.out
    net x-disable not.4.out and2.4.in1
    net x-enable not.4.in flipflop.0.out mux2.1.sel
    net x-hat-jog wcomp.4.in input.0.abs-hat0x-position
    net x-hat-minus wcomp.4.under or2.5.in1 and2.9.in0
    net x-hat-plus or2.5.in0 wcomp.4.over and2.10.in0
    net x-jog wcomp.0.in input.0.abs-x-position mux2.1.in1
    net x-knob-active not.0.out and2.1.in0
    net x-knob-inactive wcomp.0.out not.0.in and2.2.in0 and2.3.in0
    net x-set and2.1.out flipflop.0.set
    net xy-buttons-active or2.7.out or2.8.in0 or2.9.in1
    net xy-reset flipflop.0.reset and2.2.out flipflop.1.reset
    net y-buttons-active or2.6.out or2.7.in1
    net y-disable not.5.out and2.1.in1
    net y-enable flipflop.1.out not.5.in mux2.2.sel
    net y-hat-jog input.0.abs-hat0y-position wcomp.5.in
    net y-hat-minus wcomp.5.under or2.6.in1 and2.12.in0
    net y-hat-plus or2.6.in0 wcomp.5.over and2.11.in0
    net y-jog wcomp.1.in input.0.abs-y-position scale.5.in
    net y-knob-active not.1.out and2.3.in1
    net y-knob-inactive not.1.in wcomp.1.out and2.2.in1
    net y-select and2.4.in0 and2.3.out
    net y-set flipflop.1.set and2.4.out
    net z-button-minus input.0.btn-thumb or2.1.in0 and2.13.in0
    net z-button-plus or2.1.in1 input.0.btn-top and2.14.in0
    net z-buttons-active or2.1.out or2.3.in1
    net z-disable not.6.out and2.8.in1
    net z-enable not.6.in flipflop.2.out mux2.3.sel
    net z-jog wcomp.3.in input.0.abs-rz-position scale.6.in
    net z-knob-active not.3.out and2.5.in0
    net z-knob-inactive not.3.in wcomp.3.out and2.7.in0 and2.6.in0
    net z-set and2.5.out flipflop.2.set
    

    Sherline.hal

    # Generated by stepconf at Sat Aug 23 12:10:22 2008
    # If you make changes to this file, they will be
    # overwritten when you run stepconf again
    loadrt trivkins
    loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD traj_period_nsec=[EMCMOT]SERVO_PERIOD key=[EMCMOT]SHMEM_KEY num_joints=[TRAJ]AXES
    loadrt probe_parport
    loadrt hal_parport cfg=0xecd8
    setp parport.0.reset-time 60000
    loadrt stepgen step_type=0,0,0,0
    loadrt pwmgen output_type=0
    
    addf parport.0.read base-thread
    addf stepgen.make-pulses base-thread
    addf pwmgen.make-pulses base-thread
    addf parport.0.write base-thread
    addf parport.0.reset base-thread
    
    addf stepgen.capture-position servo-thread
    addf motion-command-handler servo-thread
    addf motion-controller servo-thread
    addf stepgen.update-freq servo-thread
    addf pwmgen.update servo-thread
    
    net spindle-cmd <= motion.spindle-speed-out => pwmgen.0.value
    net spindle-enable <= motion.spindle-on => pwmgen.0.enable
    net spindle-pwm <= pwmgen.0.pwm
    setp pwmgen.0.pwm-freq 100.0
    setp pwmgen.0.scale 1166.66666667
    setp pwmgen.0.offset 0.114285714286
    setp pwmgen.0.dither-pwm true
    net spindle-cw <= motion.spindle-forward
    
    net estop-out => parport.0.pin-01-out
    net xdir => parport.0.pin-02-out
    net xstep => parport.0.pin-03-out
    setp parport.0.pin-03-out-reset 1
    setp parport.0.pin-04-out-invert 1
    net ydir => parport.0.pin-04-out
    net ystep => parport.0.pin-05-out
    setp parport.0.pin-05-out-reset 1
    setp parport.0.pin-06-out-invert 1
    net zdir => parport.0.pin-06-out
    net zstep => parport.0.pin-07-out
    setp parport.0.pin-07-out-reset 1
    net adir => parport.0.pin-08-out
    net astep => parport.0.pin-09-out
    setp parport.0.pin-09-out-reset 1
    net spindle-cw => parport.0.pin-14-out
    net spindle-pwm => parport.0.pin-16-out
    net xenable => parport.0.pin-17-out
    
    setp stepgen.0.position-scale [AXIS_0]SCALE
    setp stepgen.0.steplen 1
    setp stepgen.0.stepspace 0
    setp stepgen.0.dirhold 60000
    setp stepgen.0.dirsetup 60000
    setp stepgen.0.maxaccel [AXIS_0]STEPGEN_MAXACCEL
    net xpos-cmd axis.0.motor-pos-cmd => stepgen.0.position-cmd
    net xpos-fb stepgen.0.position-fb => axis.0.motor-pos-fb
    net xstep <= stepgen.0.step
    net xdir <= stepgen.0.dir
    net xenable axis.0.amp-enable-out => stepgen.0.enable
    
    setp stepgen.1.position-scale [AXIS_1]SCALE
    setp stepgen.1.steplen 1
    setp stepgen.1.stepspace 0
    setp stepgen.1.dirhold 60000
    setp stepgen.1.dirsetup 60000
    setp stepgen.1.maxaccel [AXIS_1]STEPGEN_MAXACCEL
    net ypos-cmd axis.1.motor-pos-cmd => stepgen.1.position-cmd
    net ypos-fb stepgen.1.position-fb => axis.1.motor-pos-fb
    net ystep <= stepgen.1.step
    net ydir <= stepgen.1.dir
    net yenable axis.1.amp-enable-out => stepgen.1.enable
    
    setp stepgen.2.position-scale [AXIS_2]SCALE
    setp stepgen.2.steplen 1
    setp stepgen.2.stepspace 0
    setp stepgen.2.dirhold 60000
    setp stepgen.2.dirsetup 60000
    setp stepgen.2.maxaccel [AXIS_2]STEPGEN_MAXACCEL
    net zpos-cmd axis.2.motor-pos-cmd => stepgen.2.position-cmd
    net zpos-fb stepgen.2.position-fb => axis.2.motor-pos-fb
    net zstep <= stepgen.2.step
    net zdir <= stepgen.2.dir
    net zenable axis.2.amp-enable-out => stepgen.2.enable
    
    setp stepgen.3.position-scale [AXIS_3]SCALE
    setp stepgen.3.steplen 1
    setp stepgen.3.stepspace 0
    setp stepgen.3.dirhold 60000
    setp stepgen.3.dirsetup 60000
    setp stepgen.3.maxaccel [AXIS_3]STEPGEN_MAXACCEL
    net apos-cmd axis.3.motor-pos-cmd => stepgen.3.position-cmd
    net apos-fb stepgen.3.position-fb => axis.3.motor-pos-fb
    net astep <= stepgen.3.step
    net adir <= stepgen.3.dir
    net aenable axis.3.amp-enable-out => stepgen.3.enable
    
    net estop-out <= iocontrol.0.user-enable-out
    net estop-out => iocontrol.0.emc-enable-in
    
    loadusr -W hal_manualtoolchange
    net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change
    net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed
    net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
    net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared