Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Once again I’m planning to attend the Cabin Fever Expo in York; my shop assistant says this year she won’t barf in the kitchen sink Thursday evening just before bedtime…
If I’m going to haul a Sherline CNC setup that far and spend all day talking machining, I must have some tchotchkes / swag to talk about. We figured a small plastic dog tag with relevant URLs would be appropriate.
Cabin Fever Dog Tag
I modeled the tag after my father’s WWII tag, including the mysterious notch. The rounded ends actually have three curves: two small fairing arcs blend the sides into the end cap.
The G-Code routine figures out all the coordinates and suchlike from some basic physical measurements & guesstimates, so tweaking the geometery is pretty straightforward. There was a blizzard going on while I wrote it: a fine day to spend indoors hacking code.
My assistant fired up Inkscape, laid out the text, figured out how to coerce G-Code out of Inkscape using the cnc-club.ru extension, then aligned it properly with the center of the chain hole as the origin on the right side. My routine calls the text G-Code file as a subroutine.
The extension’s header and footer files wrap EMC2’s SUB / ENDSUB syntactic sugar around the main file. The default files include an M2 that kills off the program; took a while to track that one down.
The header file:
O<dogtagtext> SUB
And the matching footer file:
O<dogtagtext> ENDSUB
The Inkscape-to-gcode instructions come out with absolute coordinates relative to the origin you define when you create the layout. The nested loops in my wrapper slap a G55 coordinate offset atop each label in turn, then call the subroutine.
The result is pretty slick:
Screenshot: AXIS Dog Tags
I carved out that proof-of-concept label atop double-sided adhesive tape, but peeling off the goo is a real pain; a 2×3 array will be much worse. I’d rather do that than figure out how to clamp the fool things to the sacrificial plate, though.
The engraving is 0.2 mm deep with a Dremel 30 degree tool. My shop assistant describes it as “disturbing” the acrylic, not actually engraving a channel. This isn’t entirely a Bad Thing, as the font isn’t quite a stick font and the outline of each character mushes together. We must fiddle with the font a bit more; she favors a boldified OCR-A look.
Some lessons:
The Kate G-Code syntax highlighter isn’t down with EMC2’s dialect
Be very sure you touch off the workpiece origin in G54, not G55
Xylene doesn’t bother acrylic and works fine on tape adhesive
Symlinks aimed across an NFS link work fine in ~/emc2/nc_files/
That 2×3 array may be too big for the Sherline’s tooling plate
Tool length probing FTW!
The G-Code:
(Cabin Fever 2011 Dogtag)
(Ed Nisley - KE4ZNU - December 2010)
(Origin at center of chain hole near right side)
(Stock held down with double-stick tape)
(--------------------)
(Flow Control)
#<_DoText> = 1
#<_DoDrill> = 1
#<_DoMill> = 1
( Sizes and Shapes)
(-- Tag array layout)
#<_NumTagsX> = 3 (number of tags along X axis)
#<_NumTagsY> = 2 ( ... Y axis)
#<_TagSpaceX> = 60 (center-to-center along X axis)
#<_TagSpaceY> = 35 ( ... Y axis)
(-- Tag Dimensions)
#<_TagSizeX> = 50.8 (2.0 inches in WWII!)
#<_TagSizeY> = 28.6 (1-1/8 inches)
#<_TagSizeZ> = 2.0
#<_HoleOffsetX> = 4.0 (hole center to right-side tag edge)
#<_NotchSizeX> = 3.5 (locating notch depth from far left edge)
#<_NotchCtrY> = 5.0 (locating notch from Y=0)
#<_NotchAngleBot> = 30 (lower angle in notch)
#<_NotchAngleTop> = 45 (upper angle in notch)
(-- Fairing Curve Dimensions as offsets from end arc center)
#<_EndFairR> = [0.68 * #<_TagSizeY>]
#<_CornerFairR> = [0.25 * #<_TagSizeY>]
#<_PCRadius> = [#<_EndFairR> - #<_CornerFairR>]
#<_PCY> = [[#<_TagSizeY> / 2] - #<_CornerFairR>]
#<_PCTheta> = ASIN [#<_PCY> / #<_PCRadius>]
#<_PCX> = [#<_PCRadius> * COS [#<_PCTheta>]]
#<_P1Y> = [#<_TagSizeY> / 2] (top / bottom endpoint)
#<_P1X> = #<_PCX>
#<_P2X> = [#<_EndFairR> * COS [#<_PCTheta>]]
#<_P2Y> = [#<_EndFairR> * SIN [#<_PCTheta>]]
(-- Tooling)
#<_TraverseZ> = 1.0 (safe clearance above workpiece)
#<_DrillDia> = 3.2 (drill for hole and notch)
#<_DrillNum> = 1 ( ... tool number)
#<_DrillRadius> = [#<_DrillDia> / 2]
#<_DrillFeed> = 200 (drill feed for holes)
#<_DrillRPM> = 3000
#<_MillDia> = 3.2 (mill for outline)
#<_MillNum> = 1 ( ... tool number)
#<_MillRadius> = [#<_MillDia> / 2]
#<_MillFeed> = 150 (tool feed for outlines)
#<_MillRPM> = 5000
#<_TextDia> = 0.1 (engraving tool)
#<_TextNum> = 1
#<_TextFeed> = 600 (tool feed for engraving)
#<_TextRPM> = 10000
(-- Useful calculated values)
#<_TagRightX> = #<_HoleOffsetX> (extreme limits of tag in X)
#<_TagLeftX> = [#<_TagRightX> - #<_TagSizeX>]
#<_EndFairRtX> = [#<_TagRightX> - #<_EndFairR>]
#<_EndFairLfX> = [#<_TagLeftX> + #<_EndFairR>]
#<_NotchCtrX> = [#<_TagLeftX> + #<_NotchSizeX> - #<_DrillRadius>]
(--------------------)
(--------------------)
( 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
(--------------------)
(Start machining)
G40 G49 G54 G80 G90 G94 G97 G98 (reset many things)
G21 (metric!)
(msg,Verify G30.1 position in G54 above tool change switch)
M0
(msg,Verify XYZ=0 touched off at left front tag hole center on surface)
M0
O<Probe_Init> CALL
T0 M6 (clear the probe tool)
(-- Engrave Text)
O<DoText> IF [#<_DoText>]
(msg,Insert engraving tool)
T#<_TextNum> M6 (load engraving tool)
O<Probe_Tool> CALL
F#<_TextFeed>
S#<_TextRPM>
(debug,Set spindle to #<_TextRPM>)
M0
G0 X0 Y0 (get safely to first tag)
G0 Z#<_TraverseZ> (to working level)
G10 L20 P2 X0 Y0 Z#<_TraverseZ> (set G55 origin to 0,0 at this point)
G55 (activate G55 coordinates)
O3000 REPEAT [#<_NumTagsX>]
O3100 REPEAT [#<_NumTagsY>]
O<dogtagtext> CALL
G0 X0 Y0
G10 L20 P2 Y[0 - #<_TagSpaceY>] (set Y orgin relative to next tag in +Y direction)
O3100 ENDREPEAT
G10 L20 P2 X[0 - #<_TagSpaceX>] Y[[#<_NumTagsY> - 1] * #<_TagSpaceY>] (next to +X, Y to front)
O3000 ENDREPEAT
G54 (bail out of G55 coordinates)
(-- Drill holes)
O<DoDrill> IF [#<_DoDrill>]
T0 M6
(msg,Insert drill)
T#<_DrillNum> M6
O<Probe_Tool> CALL
F#<_DrillFeed>
S#<_DrillRPM>
#<_DrillZ> = [0 - #<_TagSizeZ> - #<_DrillRadius>]
(debug,Set spindle to #<_DrillRPM>)
M0
G0 X0 Y0 (get safely to first tag)
G0 Z#<_TraverseZ> (to working level)
#<IndexX> = 0
O1000 DO
#<IndexY> = 0
O1100 DO
#<TagOriginX> = [#<IndexX> * #<_TagSpaceX>]
#<TagOriginY> = [#<IndexY> * #<_TagSpaceY>]
G81 X#<TagOriginX> Y#<TagOriginY> Z#<_DrillZ> R#<_TraverseZ>
G81 X[#<TagOriginX> + #<_NotchCtrX>] Y[#<TagOriginY> + #<_NotchCtrY>] Z#<_DrillZ> R#<_TraverseZ>
#<IndexY> = [#<IndexY> + 1]
O1100 WHILE [#<IndexY> LT #<_NumTagsY>]
#<IndexX> = [#<IndexX> + 1]
O1000 WHILE [#<IndexX> LT #<_NumTagsX>]
G30 (go home)
O<DoDrill> ENDIF
(-- Machine outlines)
O<DoMill> IF [#<_DoMill>]
T0 M6 (eject drill)
(msg,Insert end mill)
T#<_MillNum> M6 (load mill)
O<Probe_Tool> CALL
F#<_MillFeed>
S#<_MillRPM>
(debug,Set spindle to #<_MillRPM>)
M0
G0 X0 Y0 (get safely to first tag)
G0 Z#<_TraverseZ> (to working level)
G10 L20 P2 X0 Y0 Z#<_TraverseZ> (set G55 origin to 0,0 at this point)
G55 (activate G55 coordinates)
O2000 REPEAT [#<_NumTagsX>]
O2100 REPEAT [#<_NumTagsY>]
G0 X[#<_NotchCtrX>] Y[#<_NotchCtrY>] (get to center of notch hole)
G0 Z[0 - #<_TagSizeZ>] (down to cutting level)
G91 (relative coordinate for notch cutting)
G1 X[0 - #<_NotchSizeX>] Y[0 - #<_NotchSizeX> * TAN [#<_NotchAngleBot>]]
G1 X[0 + #<_NotchSizeX>] Y[0 + #<_NotchSizeX> * TAN [#<_NotchAngleBot>]]
G1 X[0 - #<_NotchSizeX>] Y[0 + #<_NotchSizeX> * TAN [#<_NotchAngleTop>]]
G90 (back to abs coords)
G42.1 D#<_MillDia> (cutter comp to right)
G1 X[#<_TagLeftX>] Y0 (comp entry move to tip of left endcap)
G3 X[#<_EndFairLfX> - #<_P2X>] Y[0 - #<_P2Y>] I[#<_EndFairR>] J0 (left endcap front half)
G3 X[#<_EndFairLfX> - #<_P1X>] Y[0 - #<_P1Y>] I[#<_P2X> - #<_PCX>] J[#<_P2Y> - #<_PCY>]
G1 X[#<_EndFairRtX> + #<_P1X>] (front edge)
G3 X[#<_EndFairRtX> + #<_P2X>] Y[0 - #<_P2Y>] I0 J[#<_CornerFairR>]
G3 X[#<_EndFairRtX> + #<_P2X>] Y[#<_P2Y>] I[0 - #<_P2X>] J[#<_P2Y>] (right endcap)
G3 X[#<_EndFairRtX> + #<_P1X>] Y[#<_P1Y>] I[#<_PCX> - #<_P2X>] J[#<_PCY> - #<_P2Y>]
G1 X[#<_EndFairLfX> - #<_P1X>] (rear edge)
G3 X[#<_EndFairLfX> - #<_P2X>] Y[#<_P2Y>] I0 J[0 - #<_CornerFairR>]
G3 X[#<_EndFairLfX> - #<_P2X>] Y[0 - #<_P2Y>] I[#<_P2X>] J[0 - #<_P2Y>] (left endcap complete)
G0 Z#<_TraverseZ>
G40
G0 X0 Y0
G10 L20 P2 Y[0 - #<_TagSpaceY>] (set Y orgin relative to next tag in +Y direction)
O2100 ENDREPEAT
G10 L20 P2 X[0 - #<_TagSpaceX>] Y[[#<_NumTagsY> - 1] * #<_TagSpaceY>] (next to +X, Y to front)
O2000 ENDREPEAT
G54 (bail out of G55 coordinates)
G30 (go home)
O<DoMill> ENDIF
M2
However, the head puts the two 5 Ω resistors in parallel, directly across the +12 V supply: each 25 W (* see bottom) resistor dissipates 29 W. To make matters worse, the heater block is wrapped in ceramic cloth tape thermal insulation, bundled up in Kapton, and servo-controlled to something over 200 °C.
What’s wrong with that picture?
Here’s the note I put up on the Google MakerBot Operator’s group a few days ago, with slightly cleaned-up formatting:
———————–
MK5 / Thing-O-Matic Heater Problems
My TOM is on order, halfway through its 7-week leadtime. In the meantime, I’ve been reading the mailing lists and poring over the documentation. One thing stands out: a disturbing number of “my MK5 extruder stopped heating” problems.
Right up front, I’m not slagging the folks at MakerBot. I attended Botacon Zero, toured their “factory”, and ordered a Thing-O-Matic the next day. This is my contribution to tracking down what looks like a problem, ideally before my TOM runs into it. I *want* to be shown that my analysis is dead wrong!
What follows is, admittedly, a technical read, but that’s what I *do*.
Background
The heater uses two 5-ohm 25-watt panel-mount resistors in parallel across the 12 V supply to raise the thermal core to well over 200 C. Some folks run their extruders at 225 C, which seems to be near the top end of the heater’s range.
The resistors are standard items from several manufacturers. The datasheets can be downloaded from:
My back-of-the-envelope calculations suggest several problems with the heater, all of which combine to cause early failures.
1) Too much power
Putting 12 V across a 5 ohm resistor dissipates 28.8 W. Allowing for 0.5 V drop in the wiring, it’s still 26.5 W.
That exceeds the resistor’s 25 W rating, not by a whole lot, and might be OK at room temperature, but …
2) No temperature derating
The 25 W power rating applies only when mounted to the heatsink specified in the datasheet at 25 C ambient temperature. Above that temperature, the maximum allowed power decreases linearly to 2.5 W at 250 C: 0.1 W/C.
When the resistor is not mounted to a heatsink, its maximum free-air rating is 12.5 W. That limit declines by 0.044 W/C to the same 2.5 W limit at 250 C.
What this means: at 200 C *and* mounted on a heatsink, the resistors must not dissipate more than 4.7 W. The MK5 heater runs them at 28 W, six times their 200 C rating, and they’re not on a heatsink.
3) Excessive heat
The resistors will always be hotter than the thermal core: they are being used as heaters. The temperature difference depends on the “thermal resistance” of the gap between the resistor body and the core.
The MK5 resistors are dry mounted without thermal compound, so the gap consists largely of air.
I recently measured the thermal resistance of the 50 W version of these resistors on an aluminum heatsink using ThermalKote II compound in the gap. In round numbers, the thermal resistance is about 0.2 C/W: at 28 W the resistors will be 6 C hotter than the thermal core.
The default air-filled gap to the MK5 thermal core will make the resistors *much* hotter than that. With the core at 225 C, the resistors will probably heat beyond their 250 C absolute maximum operating temperature.
4) Insulation
The datasheet ratings for the resistors assume mounting on a heatsink in a given ambient temperature, so that the resistors can dump heat to the heatsink (that’s why it’s called a *sink*) and to the surrounding air. The MK5 thermal core and resistors live inside ceramic insulation and Kapton tape, specifically to prevent heat loss.
Conclusion
The resistors operate with far too much power at too high a temperature, inside a hostile environment with too much thermal resistance to the core. They will fail at a high rate because they are being operated far beyond their specifications.
Given that, the failures I’ve read here over the last few weeks aren’t
surprising. Some links:
I do not know what fraction of the MK5 extruders those messages represent. There are about 1000 members of this group, but not everybody has a MK5 extruder head. Assuming 250 MK5 heads, that’s a 2% failure rate.
The number of problem reports seem to be increasing in recent weeks, but that can be a fluke.
Observations
Depending on the room temperature, a MK5 thermal core can probably reach operating temperature with only one functional resistor, but it will take much longer than normal.
Indeed, I suspect some of the “my MK5 has difficulty extruding” problems may come from a thermal core that’s nominally at operating temperature, but with one dead resistor: the steel block is cooler on the side with the failed resistor. The thermistor reports the temperature at the block’s surface, not inside where the plastic actually melts.
It’s entirely possible that a resistor failure can lead to an extruder motor failure: too-cool plastic → difficult extrusion → high motor load → extruder motor failure. That’s a guess, but it seems reasonable.
Diagnosis
The symptoms fall into two categories, with what I think are the obvious causes:
Slow heating = one resistor failed
No heat at all = both resistors failed
To discover what’s happened, disconnect the heater power cable from the extruder controller, then measure the resistance across the wires. You should find one of three situations:
1) 2.5 ohms = both resistors good = normal condition
2) 5 ohms = one failed resistor
3) Open circuit = two failed resistors
The resistance value may vary wildly if you move the wires at the extruder head, because a failed resistor element can make intermittent contact. If you measure the resistance at the extruder controller connector end of the cable, leaving the thermal core alone, you should get more stable results.
What to do
Given that the resistors operate under such hostile conditions, I think there’s not much you can do to make them happier. Some untested ideas:
1) Use the remainder of the anti-seize thread lube as thermal compound between the resistors and the thermal core. It’ll stink something awful until the oil boils off, but ought to keep the resistors significantly cooler by improving heat transfer to the core. Standard PC CPU thermal compound (Arctic Silver, et al) deteriorates well below 225 C, so it probably won’t survive in this environment.
2) Rearrange the thermal wrap to expose the ends of the resistor leads, which will cool the resistor element end plugs and reduce the deformation causing the slug to work loose inside the aluminum shell.
3) Use thicker connecting wire, without insulation, outside the thermal wrap, to dump more heat from the resistor leads.
The last two changes will cause more heat loss from the thermal core which means the controller will turn the resistors on more often. Perhaps reducing the thermal stress on the weakest part of the resistors will delay the failures, but I don’t know.
When my TOM arrives, I’ll instrument the thermal core with a handful of thermocouples, measure what’s going on inside, try some of those ideas, and report back.
If you get there first, I’d like to know what you find!
———————–
* From above
Now, as it turns out, my TOM arrived on Christmas Eve! Given the usual holiday distractions, I’m only now getting down to construction & measurements, but one thing pops right out: contrary to what I’d assumed / read somewhere, those resistors are rated for 10 W at 25 C. Everything I wrote above applies to 25 W resistors: the situation is actually much worse: a 10 W resistor dissipating 30 W while tucked inside an insulating blanket?
I actually did get around to plugging the holes directly under the power resistors on those heatsinks, even though we all know it makes absolutely no difference whatsoever.
Heatsink hole plugs
Start with some 5/16-inch aluminum rod, face and center-drill one end, turn down about two inches to a scant 0.200 inch diameter, saw off a stub on the end.
Grab the stub in the 3-jaw Sherline chuck clamped to the mill table and slice off 0.240 inch slugs using a teeny slitting saw and manual CNC.
No pix of the setup, for reasons that made sense at the time, but that project gives you the general idea.
Repeat three times to get 3 x 6 = 18 slugs, plus a few spares.
Clean out the heatsink holes, clamp a bar (covered with tape) on the flat side, butter up the holes & slugs with JB Weld epoxy, squish ’em in place, scrape off the excess epoxy after a few hours.
Actually, this was a thinly veiled excuse to get my shop assistant some Quality Shop Time on the lathe and CNC mill. Wouldn’t you do the same?
The PC won’t need a CD after it’s up and running, but it’s easiest to boot/install from a CD. Get a random SATA CD drive from eBay or, more usefully, a USB-to-SATA/IDE converter, harvest an IDE CD drive from a old donor box, plug it into the Foxconn box, and tweak the BIOS to boot from that USB device.
Install Ubuntu 10.04 (not the current 10.10) from CD. I use the mini-iso CD (link to Overview), which has the advantage of fetching the current version of everything from the Ubuntu site. You can putz around making a bootable USB image, which is cute, but the USB-to-IDE drive adapter will come in handy for other things.
Toward the end of the installation you get a list of configurations and packages to install. Pick Ubuntu desktop, down near the bottom of the list. Include SSH server if you want to do remote maintenance.
Install / tweak / twiddle to set up some comfort items:
NFS shares to the file server holding my CNC files
Desktop sharing so I can dry-run from a warmer chair
Screen backdrop on file server to show network is running
Lest all this seem like a lot of hocus pocus, remember that you’re
becoming a system integrator with your fingers on all the knobs and
buttons normally hidden behind the “Do Not Open: No User Serviceable Parts Inside” covers.
You could, of course, pay somebody to do this for you… [grin]
Just got a stack of surplus fans for the heatsinks I’ll probably use in the disinsector: Cofan FP925HH12B. Either these are really old or there’s a typo in the model number printed on the fan label. I’d expect it to be …9225… to indicate a 92 mm frame x 25 mm thickness. It’s close enough to get to their specs page.
Cofan axial fan
They draw 370 mA (rated 450 mA) in free air = 4.4 W. The “HH” designation means “Super High Speed” and wow are they noisy despite their 37.6 dbA spec. Fortunately, that won’t matter inside a closed box.
The label is downstream, which means the hub and bare blades are upstream. They’ll be under the shelves, so I think I can get away without guards.
The model number breakdown says that they have a “protection chip” which seems to be the thing that produces the status output. That output (yellow wire) is a square wave with a frequency twice the fan’s actual speed: 107 Hz → 6420 cycles / min → 3210 RPM. The open collector output requires a pullup resistor to +5 V. It take a while to spin up the fan enough to get a decent output waveform; don’t sample the status for maybe a second after power-on.
Putting a fan on that crude air flow straightener produces about 3.2 m/s across the exit end, which works out to 10.5 ft/s = 630 ft/min. There’s a distinct flow dent near the middle of the air column, so I suspect the baffles are too far upstream for this fan.
Making a number of barely justifiable assumptions, the output is around 1.4 m3/min = 50 ft3/min, which is close enough to the rated free air output of 1.8 m3/min = 64 ft3/min.
They will start and run at 5 V (below the 8 V minimum rating), draw 110 mA, spin at 1470 RPM, and push 1.1 m/s. For whatever that’s worth.
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:
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