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.

Year: 2009

  • Toner Transfer PCBs: Alignment Accuracy

    Here’s an example of the dimensional accuracy you can get from toner-transfer PCBs in real life.

    I drill the holes with a CNC-ed Sherline mill, so they’re pretty much spot on. Drilling the holes by hand simply isn’t practical: there’s no way to get both global alignment and local accuracy.

    The toner transfer sheet, printed on a laser printer, gets aligned to the existing holes atop a light table. The paper stretches & shrinks and moves around while printing, but I can generally average out the errors so that the 24-mil holes (the smallest I generally use) across the board have no more than a few mils of error: the pads don’t show more than that inside the drilled holes. In the picture below, you can see a dark rim around the corner alignment hole that looks worse than it really is due to the perspective.

    I put the toner transfer sheet on the light table, toner-side up, lay the PCB atop the paper, and adjust for best overall alignment. I then tape them together along one edge with strips of laser-printer address labels: guaranteed to hold up to high temperatures, which is more than you can say for most tapes.

    PCB alignment and taping
    PCB alignment and taping

    Here’s the board after etching both sides, with the black toner and green sealant film still in place. The toner & film are slightly smeared from the solvent I used to clean off the other side before etching it. The brownish dabs on the green areas come from a brown Sharpie that works fine as a touch-up etching resist.

    WWVB Simulator - Top surface toner mask
    WWVB Simulator – Top surface toner mask

    The narrowest traces are 16 mils, most of the others are 32 mils, and the fat ones down the middle of the chip are 40 mils. Click on the images for bigger versions; you’ll get some JPG compression artifacts, but the resolution is good enough to see what’s going on.

    Here’s the same area with the toner removed and a touch of silver plating applied to make it pretty and more easily solderable. The colors aren’t particularly reliable; in real life, it’s a lot more silvery.

    Top surface copper
    Top surface copper

    Fairly obviously, the alignment isn’t nearly as good as you’d expect from the initial taping. In round numbers, the pads to the left side seem offset by about the diameter of the holes; call it 25 mils. The holes in the DIP pads are off by perhaps 10 mils.

    The bottom surface looks pretty much the same, with similar alignment issues.

    Bottom surface copper
    Bottom surface copper

    The misalignments are not uniform, as you’d expect if the toner transfer sheet moved across the board during fusing. The sheet deforms during the fusing process in a completely unpredictable way, despite my trying all of the usual tricks:

    • Pre-shrinking the transfer paper by running it through the printer with a pure-white image (so no toner gets applied)
    • Fusing quickly after printing to prevent moisture absorption (there’s a limit to how fast I can work)
    • Taping more than one edge to lock the paper in place

    It’s fair to say you (well, I) can get within 25 mils of a board hole for sure, less than that most of the time, and be spot on over much of the board. I use large pads and vias for anything I have control over, as witness the pads surrounding the DIP, and avoid very fine features near holes.

    Anyhow, it’s good enough for what I do, but you shouldn’t get your hopes up that toner-transfer circuit boards come anywhere close to commercial quality. If you’re doing a lot of pure surface-mount work, it’ll probably be good enough because there’s no need for global alignment to holes in the underlying board. Obviously, the smaller the board, the better off you’ll be.

    I etched this board by rubbing ferric chloride on it with a sponge (wearing forearm-length rubber gloves and a shop apron!), renewing the solution as it turned black and gooey. Works like a charm, gives good control of the process, doesn’t erode the Sharpie masking, doesn’t over-etch the traces (much, anyway), and uses less etchant than soaking the board in a bath.

    I have other posts describing the process in more detail. Search for PCB, toner-transfer, and other keywords to unearth those entries.

  • Converting Day-of-Year to Month and Day-of-Month, Then Back Again

    I needed the conversions for a WWVB simulator, so it knows when to twiddle the leap-year and leap-second bits.

    The general notion is a table with the Day-of-Year values for the last day of each month. The most expedient way of doing this is with two columns: one for normal years and the other for leap years, thusly…

    Month EOM EOM-LY DOY DOY-LY
    0 0 0 0 0
    1 31 31 31 31
    2 28 29 59 60
    3 31 31 90 91
    4 30 30 120 121
    5 31 31 151 152
    6 30 30 181 182
    7 31 31 212 213
    8 31 31 243 244
    9 30 30 273 274
    10 31 31 304 305
    11 30 30 334 335
    12 31 31 365 366

    Hint: even if you can recite the “Thirty days hath November …” jingle, it’s much better to build a spreadsheet so the additions all work out. It’s even better if you don’t attempt any of this with a late-summer head cold. You might want to check all my work, because I’m still stuffy.

    With table in hand, the code is straightforward.

    Define a structure with all the various bits & pieces of the current time, much of which isn’t used here. It’s all needed in the WWVB simulator:

    enum EVENTSTATE {EVENT_INACTIVE,EVENT_PENDING,EVENT_ACTIVE};
    
    struct timecode_ {			// The current moment in time...
      byte Year;				// 0 - 99
      word DayOfYear;			// 1 - 366
      byte Hour;				// 0 - 23
      byte Minute;				// 0 - 59
      byte Second;				// 0 - 60 (yes!)
      byte Tenth;				// 0 - 9
      enum EVENTSTATE LeapYear;		// 0 = no, 1 = pending, 2 = active
      enum EVENTSTATE LeapSecond;		// 0 = no, 1 = pending, 2 = active in this minute
      enum EVENTSTATE DaylightSavingTime;	// 0 = no, 1 = pending, 2 = active
      char UT1Correction;			// 100 ms units, -10 to +10 range (+/- 1 second)
      byte MinuteLength;			// 60 or 61
      byte Month;				// 1 - 12 (not sent in frame)
      byte DayOfMonth;			// 1 - 28..31	(not sent in frame)
    };
    

    That’s obviously overspecified, because DayOfYear with LeapYear uniquely determines Month and DayOfMonth. It’s handy to have both forms around, sooo there they are.

     

    Then set up the table, glossing over the quick matrix transposition that turns the entries for each year into rows rather than columns:

    prog_uint16_t PROGMEM MonthEnds[2][13] = {
      0,31,59,90,120,151,181,212,243,273,304,334,365,
      0,31,60,91,121,152,182,213,244,274,305,335,366
    };
    

    Conversion from DayOfYear to Month and DayOfMonth requires searching backwards through the appropriate table row until you find the entry that’s smaller than the DayOfYear value, at which point you’ve found the right month.

    void ConvertDOYtoDOM(struct timecode_ *pTime) {
    byte Index,LY;
    word EndOfMonth;
      LY = (EVENT_INACTIVE != pTime->LeapYear) ? 1 : 0;
      Index = 12;
      while ((EndOfMonth = pgm_read_word(&MonthEnds[LY][Index])) >= pTime->DayOfYear) {
    	--Index;
      };
      pTime->Month = Index + 1;									// months start with 1, not 0
      pTime->DayOfMonth = (byte)(pTime->DayOfYear - EndOfMonth);
    }
    

    Converting from Month and DayOfMonth to DayOfYear is much easier, as it’s pretty much just a table lookup:

    word ConvertDOMtoDOY(struct timecode_ *pTime) {
    word EndOfMonth;
      EndOfMonth = pgm_read_word(&MonthEnds[(EVENT_INACTIVE != pTime->LeapYear) ? 1 : 0][pTime->Month - 1]);
      return EndOfMonth + pTime->DayOfMonth;
    }
    

    This code might actually work, but if I were you, I’d test it pretty thoroughly before lashing it into your project…

     

    The PROGMEM and pgm_read_word() stuff is the Arduino mechanism that puts the lookup table into Flash program memory rather than the ATMega168’s exceedingly limited RAM space. The definitive word about that process resides there.

    Memo to Self: Using const simply makes the variable kinda-sorta read-only, but still initializes RAM from Flash. The PROGMEM routines delete the RAM copy entirely.

  • They’re Not Redundant When One’s Broken

    Vassar College Chapel sump pumps
    Vassar College Chapel sump pumps

    The basement of the Vassar College Chapel has a mighty drainage sump, a pair of pumps, and a mass of old-school cast-iron plumbing. I’m not certain, but I think the greenish pipe coming in from the rear is storm drainage from one side of the building.

    Looks like they’ve got backup: two separate pumps and motors, with doubled plumbing on the ejection side.

    Vassar College Chapel sump pumps - broken float switch rod
    Vassar College Chapel sump pumps – broken float switch rod

    On closer inspection, however, you’ll see that the near-side float switch rod coming up through the cover is broken and bent; that motor will never turn on.

    One hopes this is deliberate, but the failed-off motor seems to be the newer / larger / less corroded of the two. We’ve had a lot of rain this summer, so I suppose if this was a problem, it would have already occurred.

    It’s always a good idea to have all your sump pumps ready to run, should you be in a position to need sump pumps in the first place. Believe me, it’s much easier to fix things when you’re not hip-deep in rising water!

  • Camouflaged Katydid

    Katydid on matching umbrella
    Katydid on matching umbrella

    This gadget appeared on an umbrella we’d left outdoors to dry.

    We wonder if the green surface seemed like a leaf…

  • Extended Sewing Machine Quilting Surface

    Extended quilting surface
    Extended quilting surface

    Mary has been quilting up a storm lately and wanted a larger surface to handle a bed-sized quilt. A table in the basement was big enough, but she wanted a larger flat surface around the sewing machine adjacent to the table.

    I converted the typing return (*) from her upstairs desk into a table, then cut a piece of aluminum-clad 1-inch foam insulation board to fit. It’s 4 feet long, a convenient length to cut from the 4×8-foot insulation board, and slightly narrower than the typing return. Cutting it required a long X-Acto knife blade, but a really sharp utility knife would work as well.

    Some stainless-steel tape finished off the edges. The tape itself is lethally sharp-edged, but it’s perfectly harmless if you do a good job of smoothing it against the foam board…

    A pair of closed-cell rigid foam blocks held one end of the board at the proper height around the sewing machine, while a pair of cutoffs from the wood pile were just the right thickness & length to extend under the other end. It turns out that precise height isn’t nearly as vital as we expected; close enough is fine.

    I cannibalized a pair of table-saw feed roller stands for this project; they had just the right height adjustment and shape to support the typing return and the foam board.

    The end result aligns the surface of the sewing machine with both the top of the table and the surface of the foam board. The quilt slides easily over the whole affair and doesn’t bunch up like it did before. Success!

    Foam support blocks
    Foam support blocks

    (*) A “typing return” is the little table that sticks out from a desk, upon which you put a typewriter, back in the day when typewriters ruled the land. Nowadays, she uses it for her sewing machine, which normally lives at her desk, because there’s no practical way to type at right angles to one’s desk.

    That’s the sort of item you can’t do web searches for, because all the terms are so heavily overloaded. Give it a try; you’ll find one or two useful hits. There’s a difference between syntax and semantics; we’re not in the semantic web yet by long yardage.

  • Sherline Z-axis Backlash: Check the Bearing Preload Nut!

    Loose bearing nut
    Loose bearing nut

    I don’t do any fancy 3D milling, so it takes a lot of Z-axis backlash to get my attention. While setting up for some circuit-board drilling, I finally noticed that the backlash far exceeded even my slovenly specs: something like 20 mils.

    The Z-axis backlash adjusting nut on the saddle was as snug as it usually is. Heaving on the saddle, though, pulled it up & down and moved the handwheel on the top of the Z-axis motor.

    Ah-ha! That says the leadscrew itself is moving, which shouldn’t be possible because it’s captured at the bearings in the stepper motor mount.

    Some tedious disassembly later, the top picture shows the Z-axis leadscrew and motor mount, with the nut obviously too far away from the lower ball bearing housing. The nut was finger-loose and I moved it while extracting the leadscrew; it’s supposed to be snug against the bearing in normal operation.

    The solution is a drop of Loctite, which should be applied to the canonical “clean and dry” threads. Hosing this part of the leadscrew down with solvents isn’t a good idea, because you don’t want any inside the lower bearing in the motor mount, so I spent some Quality Shop Time spinning the threads against a (dry) rag, running the nut to the other end (all of a few millimeters), and repeating until most of the oil was gone.

    Properly adjusted nut
    Properly adjusted nut

    Sherline documents how to assemble & install the motor mounts, so there’s not much mystery involved. I loosened the preload nut until the housing spun freely on the shaft, then tightened it a teensy bit; the housing still spun freely and there’s no detectable end play.

    Reinstallation requires putting the motor mount at the same spot on the Z-axis column as before. I moved the saddle to the top of the column, ran the leadscrew into the saddle nut, and then tightened the motor mount screws. That allows the mount to move to suit the saddle nut’s position, rather than going through the tedious saddle alignment process I mentioned as part of the gib adjustment.

    It’s all good… call it 3 mils of backlash on all three axes.

    Memo to Self: It’s possible to run the Z-axis backlash adjusting nut off the top of the leadscrew thread, then re-engage it without removing the motor mount. The trick is to hold the anti-backlash nut firmly against the saddle nut while turning the leadscrew to engage the thread. Remember that it’s a left-hand thread…

  • Clothes Rack Dowel Splicing

    Clothes Rack Dowel Glue
    Clothes Rack Dowel Glue

    Mary picked up a rather well-used wooden-dowel clothes drying rack at a tag sale for essentially nothing; one of the dowels was missing. That’s easy enough to fix, as I have a stash of dowels from what seems to be another rack of the same type on my wood stockpile…

    Of course, those dowels are just an inch or two shorter than needed.

    So…

    • Turn down the ends of two dowels to 0.29″ x 3/4″ to fit the holes in the support struts
    • Sand a small taper on the ends
    • Pull the staples, insert the longer dowel and mash the staple back in place
    • Eyeball the length of the other dowel, hacksaw to fit, install similarly
    • Find a length of brass tubing that slips over the dowels
    • Cut some heat stink shrink tubing to fit
    Spliced dowels
    Spliced dowels

    I used urethane adhesive, because it expands as it cures and will fill the gaps inside the brass tubing. The heat stink tubing is just for nice… although it does make for a rather stunning contrast to the aged wood dowels, I’ll agree.

    And it’s all good!

    (Use it up, wear it out, repair it, wear it out again, then save the pieces because they’ll come in handy for something else.)