Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Fancy new sewing machines can stop with the needle either up (so you can remove the fabric) or down (to nail it in place while you rotate it). This requires sensing the needle position, which prompted me to spend far too long contemplating all the mechanical gadgetry driven by the motor.
As nearly as I can tell, the crank counterweight behind the handwheel produces the most unambiguous position reports. Here’s what it looks like with the needle down:
Kenmore 158 – main shaft counterweight
As you’d expect, with the shaft rotated exactly 180° from that point, the needle is up.
The inviting space just above the shaft provides room for the bobbin winder that engages a knurled ring on the back of the handwheel, but the lower space seems to be available. The counterweight sits about halfway into the back of the handwheel, so the sensors must look at the frame side of the counterweight.
Two adjacent sensors could detect the edge of the counterweight, which would be enough to uniquely identify both positions. If they were spaced across the lower-left edge in that picture:
01 = trailing edge = bottom dead center = needle down (as shown)
00 = open air = needle rising
10 = leading edge = top dead center = needle up
11 = solid steel = needle falling
Either sensor gives you one pulse per handwheel revolution and the combination gives you a quadrature output of both position and direction. The top speed of 1000 RPM produces 17 Hz square waves.
An additional pulse/rev sensor on the motor shaft would give better control over the motor speed, as the handwheel runs at 1/10 the motor speed with belt slip built right in. Figure 10 kRPM → 170 Hz pulses.
From a cold start, you know the shaft angle to within a bit under 180°. If the motor can turn in both directions (as would a stepper or DC motor), you can always move the needle upward. If it turns only forward (as does the AC motor) and the needle is falling, then you probably don’t want to move the motor until you get a button push indicating that all fingers are clear.
A pair of Hall effect sensors might suffice to detect that big hunk of steel, perhaps with a pair of teeny magnets glued to the face or a magnetic circuit closed by the counterweight.
Huh. Who’d’a thunk it? That’s just too good to pass up…
Although you wouldn’t use PLA for the real motor mount, this was easy:
Drive Motor Mount – solid model
And the whole affair fits pretty much like you’d expect:
Kenmore 158 – NEMA 23 stepper – on adapter
The NEMA 23 motor doesn’t have the same end profile as the AC motor and the adapter plate gets in the way of the pulley, but flipping the pulley end-for-end perfectly aligned the belt.
For whatever it’s worth, here’s how I removed the pressed-on gear from the shaft:
NEMA 23 Stepper – removing gear
I’m pretty sure I have a little gear puller somewhere, but it’s not where I expected to find it, which means it could be anywhere.
Much to my astonishment, the shafts on both motors are exactly 1/4″ inch. I filed a flat on the shaft to avoid having the setscrew goober the poor thing.
A stepper isn’t the right hammer for this job, because it can’t possibly reach 8000 rpm, but it’ll be good enough to explore the parameter space and weed out the truly stupid mistakes. A brushless DC motor from halfway around the planet would fit in the same spot.
The OpenSCAD source code:
// NEMA 23 Stepper Mounting Plate
// Ed Nisley - KE4ZNU - June 2014
Layout = "Build"; // Build Show
//- Extrusion parameters must match reality!
// Print with 4 shells and 3 solid layers
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2; // extra clearance
Protrusion = 0.1; // make holes end cleanly
AlignPinOD = 1.70; // assembly alignment pins: filament dia
inch = 25.4;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
//----------------------
// Dimensions
// Origin at bottom front corner of plate as mounted on machine
// motor mounted on rear surface, so recess is on that side
PlateThick = 4.0; // overall plate thickness
SlotOffset = [10.0,13.0,0]; // center nearest origin, motor in X+,Y+ direction
SlotSize = [8.0,25.0]; // diameter of mounting screw , overall end-to-end length
CutoutOffset = [0.0,40.0,0]; // cutout around machine casting
CutoutSize = [18.0,18.0];
MotorBase = 58.0; // square base plate side
MotorHoleOC = 47.2; // hole center-to-center spacing
MotorHoleOffset = MotorHoleOC/2;
MotorHoleDia = 5.0;
MotorBaseCornerRadius = (MotorBase - MotorHoleOC)/2;
FlangeWidth = 20.0; // mounting flange
MotorCenter = [(FlangeWidth + MotorBase/2),(MotorBase/2),0]; // XY of shaft centerline
MotorShaftDia = 7.0; // allow some clearance
HubDia = 38.5; // allow some clearance
HubHeight = 1.8;
//----------------------
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
module ShowPegGrid(Space = 10.0,Size = 1.0) {
RangeX = floor(100 / Space);
RangeY = floor(125 / Space);
for (x=[-RangeX:RangeX])
for (y=[-RangeY:RangeY])
translate([x*Space,y*Space,Size/2])
%cube(Size,center=true);
}
//----------------------
// Build it!
module BasePlate() {
difference() {
// cube([(MotorCenter[0] + MotorBase/2),MotorBase,PlateThick],center=false);
linear_extrude(height = PlateThick) {
hull() {
translate([MotorBaseCornerRadius,MotorBaseCornerRadius])
circle(r=MotorBaseCornerRadius);
translate([MotorBaseCornerRadius,MotorBase - MotorBaseCornerRadius])
circle(r=MotorBaseCornerRadius);
translate([FlangeWidth + MotorBase - MotorBaseCornerRadius,MotorBase - MotorBaseCornerRadius])
circle(r=MotorBaseCornerRadius);
translate([FlangeWidth + MotorBase - MotorBaseCornerRadius,MotorBaseCornerRadius])
circle(r=MotorBaseCornerRadius);
}
}
translate(MotorCenter - [0,0,Protrusion]) {
rotate(180/8)
PolyCyl(MotorShaftDia,(PlateThick + 2*Protrusion),8); // shaft hole
PolyCyl(HubDia,(HubHeight + Protrusion)); // hub recess
for (x=[-1,1] , y=[-1,1]) {
translate([x*MotorHoleOffset,y*MotorHoleOffset,0])
rotate(180/8)
PolyCyl(MotorHoleDia,(PlateThick + 2*Protrusion),8);
}
}
translate(SlotOffset - [0,0,Protrusion]) { // adjustment slot
linear_extrude(height = (PlateThick + 2*Protrusion))
hull() {
circle(d=SlotSize[0]);
translate([0,(SlotSize[1] - SlotSize[0])])
circle(d=SlotSize[0]);
}
}
translate(CutoutOffset - [Protrusion,0,Protrusion])
linear_extrude(height = (PlateThick + 2*Protrusion))
square(CutoutSize + [Protrusion,Protrusion]);
}
}
ShowPegGrid();
if (Layout == "Show") {
BasePlate();
}
if (Layout == "Build") {
translate([-(SlotOffset[0] + MotorBase/2),MotorBase/2,PlateThick])
rotate([180,0,0])
BasePlate();
}
The Kenmore Model 158 sewing machine contains a 120 VAC / 1 A motor that powers all the moving parts through a V belt:
Kenmore 158 – AC drive motor – overview
Looking up through the body:
Kenmore 158 – AC motor and belt – bottom
A double pulley on a jackshaft reduces the motor speed on the way to the handwheel:
Kenmore 158 – handwheel – jackshaft pulley
The motor and handwheel turn counterclockwise in normal operation, but can be turned clockwise by hand as needed. The belt tension isn’t very high and the jackshaft pulleys can slip, but I’m not sure if that’s intentional or the result of several decades of runtime.
Despite the cogged belt, the pulleys are smooth; it’s not a positive-drive transmission with timing-belt pulleys.
You could, if you had to, run a belt from the handwheel directly to the motor, although the pulley would ride about 7 mm further out on the shaft. I have no way to measure the lengths with any confidence in the results; one could calculate the lengths based on pulley diameters and center spacing.
Sticking retroreflective tape on the pulleys and handwheel, then deploying the laser tachometer, provides some minimum and maximum speeds:
Motor: 2100 – 8500 rpm
Jackshaft: 800 – 3200 rpm
Handwheel: 200 – 930 rpm
Those aren’t entirely consistent, because I’m using the old foot pedal speed control with its defunct carbon disks; the low end, in particular, isn’t as slow as it can go.
In any event, there’s about a 10:1 speed reduction from motor to handwheel.
The motor label clearly states that it’s 100-120 V AC, but it has brushes, so it’s actually a universal-wound motor that should run happily on DC.
As you’d expect, the soft feet on the bottom of the Kenmore Model 158 sewing machine’s foot pedal control turn into hard buttons after a few decades. The OEM feet have mushroom tops that push through holes in the case and latch in place; of course, none of the rubber feet in my collection match the hole diameter or case thickness.
No problem! Design a bushing that fits the case hole and passes a 4-40 screw:
Speed Control Foot Bushing
Then print up a handful, add screws to fit the rubber feet, and top off with nuts:
Kenmore 158 – pedal foot bushing – detail
Installed, with the screws cropped to a suitable length, they look about like you’d expect:
Kenmore 158 – pedal foot bushing – interior
Turns out that the springs supporting the foot pedal rest in those pockets, so the bushing reduces the spring travel by a few millimeters. The springs aren’t completely compressed with the pedal fully depressed, so it’s all good.
The OpenSCAD source code:
// Kenmore Model 158 Sewing Machine Foot Control Bushings
// Ed Nisley - KE4ZNU - June 2014
//- Extrusion parameters must match reality!
// Print with 2 shells and 3 solid layers
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2; // extra clearance
Protrusion = 0.1; // make holes end cleanly
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
//----------------------
// Dimensions
Stem = [2.5,5.7]; // through the case hole
Cap = [3.0,10.0]; // inside the case
LEN = 0;
DIA = 1;
OAL = Stem[LEN] + Cap[LEN];
ScrewDia = 2.8; // 4-40 generous clearance
//----------------------
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
module ShowPegGrid(Space = 10.0,Size = 1.0) {
RangeX = floor(100 / Space);
RangeY = floor(125 / Space);
for (x=[-RangeX:RangeX])
for (y=[-RangeY:RangeY])
translate([x*Space,y*Space,Size/2])
%cube(Size,center=true);
}
//----------------------
// Build it!
ShowPegGrid();
difference() {
union() {
cylinder(d=Stem[DIA],h=OAL,$fn=16);
cylinder(d=Cap[DIA],h=Cap[LEN],$fm=16);
}
translate([0,0,-Protrusion])
PolyCyl(ScrewDia,OAL + 2*Protrusion,6);
}
Pinning the top of Mary’s latest quilt used more than 1600 pins: three boxes of specialized quilting safety pins, plus straight quilting pins tucked into all the 3D printed / silicone filled caps. Less than a quarter of the quilt top fits on the table:
Quilt top with pins
Although Mary doesn’t need them right now, I made another batch of 100 caps for her next project:
Quilting pin caps – 4 x 25 – on platform
I tweaked the OpenSCAD source to build a 10×10 array:
Quilting Pin Cap – 10×10 array
But it turns out that a 5×5 array of caps, duplicated four times, works out better:
Quilting Pin Cap – 5×5 array
Slic3r takes far longer to process the larger array than to make four copies of the smaller array.
Half an hour later, they’re ready for silicone fill. In retrospect, natural PLA wasn’t a good choice for this job: there’s no way (for me) to take a picture of translucent silicone in crystalline PLA atop waxed paper on a white cutting board under fluorescent light…
On the upside, however, you can see exactly how far the pin goes into the cap:
Natural PLA provides a nice, crystalline appearance:
Kenmore 158 Sewing Machine – Cool white LEDs – rear no flash
Cool white LEDs have somewhat higher lumen/watt efficiency, but the real gain came from doubling the number of LEDs:
Kenmore 158 Sewing Machine – Cool white LEDs – front flash
I overvolted the warm white LEDs to 14 V to get closer to 20 mA/segment, but the cool white ones run pretty close to 20 mA at 12 V, so I didn’t bother.
Commercial versions of this hack secure the wiring with little white clips and foam tape, so I should conjure up something like that. Mary specifically did not want the lights affixed under the arm, though, so those things weren’t even in the running.
The OpenSCAD source code widens the mount and moves the wiring conduit a little bit, to simplify the connections to both strips, but is otherwise identical to the earlier version:
// LED Strip Lighting Brackets for Kenmore Model 158 Sewing Machine
// Ed Nisley - KE4ZNU - March 2014
Layout = "Build"; // Build Show Channels Strip
//- Extrusion parameters must match reality!
// Print with 2 shells and 3 solid layers
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2; // extra clearance
Protrusion = 0.1; // make holes end cleanly
AlignPinOD = 1.70; // assembly alignment pins: filament dia
inch = 25.4;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
//----------------------
// Dimensions
Segment = [25.0,10.0,3.0]; // size of each LED segment
SEGLENGTH = 0;
SEGWIDTH = 1;
SEGHEIGHT = 2;
WireChannel = 3.0; // wire routing channel
StripHeight = 12.0; // sticky tape width
StripSides = 8*4;
DefaultLayout = [1,2,"Wire","NoWire"];
NUMSEGS = 0;
NUMSTRIPS = 1;
WIRELEFT = 2;
WIRERIGHT = 3;
EndCapSides = StripSides;
CapSpace = 2.0; // build spacing for endcaps
BuildSpace = 3.0; // spacing between objects on platform
//----------------------
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
module ShowPegGrid(Space = 10.0,Size = 1.0) {
RangeX = floor(100 / Space);
RangeY = floor(125 / Space);
for (x=[-RangeX:RangeX])
for (y=[-RangeY:RangeY])
translate([x*Space,y*Space,Size/2])
%cube(Size,center=true);
}
//-- The negative space used to thread wires into the endcap
module MakeWireChannel(Layout = DefaultLayout,Which = "Left") {
EndCap = [(2*WireChannel + 1.0),Layout[NUMSTRIPS]*Segment[SEGWIDTH],StripHeight]; // radii of end cap spheroid
HalfSpace = EndCap[0] * ((Which == "Left") ? 1 : -1);
render(convexity=2)
translate([0,Segment[SEGWIDTH]/2,0])
intersection() {
union() {
cube([2*WireChannel,WireChannel,EndCap[2]],center=true);
translate([-2*EndCap[0],0,EndCap[2]/2])
rotate([0,90,0]) rotate(180/6)
PolyCyl(WireChannel,4*EndCap[0],6);
}
translate([HalfSpace,0,(EndCap[2] - Protrusion)]) {
cube(2*EndCap,center=true);
}
}
}
//-- The whole strip, minus wiring channels
module MakeStrip(Layout = DefaultLayout) {
EndCap = [(2*WireChannel + 1.0),Layout[NUMSTRIPS]*Segment[SEGWIDTH],StripHeight]; // radii of end cap spheroid
BarLength = Layout[NUMSEGS] * Segment[SEGLENGTH]; // central bar length
hull()
difference() {
for (x = [-1,1]) // endcaps as spheroids
translate([x*BarLength/2,0,0])
resize(2*EndCap) rotate([0,90,0]) sphere(1.0,$fn=EndCapSides);
translate([0,0,-EndCap[2]])
cube([2*BarLength,3*EndCap[1],2*EndCap[2]],center=true);
translate([0,-EndCap[1],0])
cube([2*BarLength,2*EndCap[1],3*EndCap[2]],center=true);
}
}
//-- Cut wiring channels out of strip
module MakeMount(Layout = DefaultLayout) {
BarLength = Layout[NUMSEGS] * Segment[SEGLENGTH];
difference() {
MakeStrip(Layout);
if (Layout[WIRELEFT] == "Wire")
translate([BarLength/2,0,0])
MakeWireChannel(Layout,"Left");
if (Layout[WIRERIGHT] == "Wire")
translate([-BarLength/2,0,0])
MakeWireChannel(Layout,"Right");
}
}
//- Build it
ShowPegGrid();
if (Layout == "Channels") {
translate([ (2*WireChannel + 1.0),0,0]) MakeWireChannel(DefaultLayout,"Left");
translate([-(2*WireChannel + 1.0),0,0]) MakeWireChannel(DefaultLayout,"Right");
}
if (Layout == "Strip") {
MakeStrip(DefaultLayout);
}
if (Layout == "Show") {
MakeMount(DefaultLayout);
}
if (Layout == "Build") {
translate([0,(3*Segment[SEGWIDTH]),0]) MakeMount([1,2,"Wire","Wire"]); // rear left side, vertical
translate([0,0,0]) MakeMount([5,2,"Wire","NoWire"]); // rear top, across arm
translate([0,-(3*Segment[SEGWIDTH]),0]) MakeMount([6,2,"NoWire","Wire"]); // front top, across arm
}
Quite a while ago, I rebuilt a gooseneck shop lamp with an LED floodlight module, the light from which appears in many pictures of the Sherline mill. That module has a sibling that I just combined with a defunct halogen desk lamp to produce a better task light for the bench; the original 12 VAC 50 W transformer now loafs along at 4 W and ballasts the lamp base against tipping.
My initial idea, of course, was a 3D printed adapter from the existing arm hardware to the LED module, but PLA gets droopy at normal high-intensity LED heatsink temperatures. That led to doodling a metal bracket around the LED module flange, which led to pondering how annoying that would be to make, which led to the discovery that the screws holding the LED plug to the heatsink were ordinary M2x0.4 Philips head, which suggested I could just screw a bracket to the back of the module, which brought a recently harvested aluminum heatsink to hand, which led to the discovery that the tip of the pivot screw fit perfectly between the fins, which …
Shortly thereafter, I milled off the central fins to fit the shaft of the pivot screw, introduced the heatsink to Mr. Disk Sander to bevel the bottom, sawed the threads off the pivot, press-fit the two together, drilled a 2 mm cross-hole into the pivot, buttered it all up with epoxy, jammed a short M2 screw into the cross hole, and let the whole mess cure:
Desk Lamp LED Adapter – top view
The lamp modules were a surplus find, with one pin clipped nearly flush to the insulator. I soldered a pair of the same male pins as in the battery holders, with the matching female pins as a crude connector. The unshrunk heatstink tubing isn’t lovely, but got us to First Light:
Desk Lamp LED Adapter – front view
The original counterweight is, of course, much too heavy for the dinky LED module, so I’ll drill the mounting hole for the vertical arm further back on the beam to get another foot of reach. That will require more wire between the transformer to the lamp, soooo the connectors might just become soldered joints.
As you can tell from the background, Mary snatched the lamp from my hands and put it to immediate use in The Quilting Room.
The original doodles bear no resemblance to the final product, but do have some key dimensions that (having discarded the unused hardware) I’ll likely never need again.
The pivot between the arm and the lamp housing, with an idea for the LED holder:
Desk Lamp Bracket Dimensions – doodle
Details of the repurposed heatsink and the pivot bolt, with a block that never got built: