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.

Category: Machine Shop

Mechanical widgetry

  • M2 Nozzle Clog: FOD

    M2 Nozzle Clog: FOD

    This happened while switching from natural to black PETG:

    M2 nozzle clog - exterior
    M2 nozzle clog – exterior

    A closer look:

    M2 nozzle clog - exterior detail
    M2 nozzle clog – exterior detail

    Those pix happened after trying to extract whatever-it-is with tweezers, so it’s definitely something with a higher melting point than PETG.

    Removing the (warm) nozzle with the block held in a vise reveals a tuft of something:

    M2 nozzle clog - interior
    M2 nozzle clog – interior

    The tuft accumulated several turns while unthreading the nozzle from the hot end.

    Heating the nozzle a bit more released the tuft:

    M2 nozzle clog - extracted tuft
    M2 nozzle clog – extracted tuft

    The black-to-clear transition tailing off at the bottom came from the PETG around the tuft in the cone-shaped end of the nozzle above the aperture. The 100 mil squares suggest the tuft was a distinct entity, rather than a collection of threads, and might have been over 5 mm long.

    Perhaps a fragment of PTFE or another high-melting-point plastic?

    Reassemble in reverse order, reset the nozzle to Z=0 on the platform, and it’s all good.

  • Tour Easy: Asymmetric Handlebar Grips

    Tour Easy: Asymmetric Handlebar Grips

    Installing the Bafang BBS02 motor on Mary’s Tour Easy replaced the triple chainring, so I removed the front derailleur and SRAM grip shifter. This produced enough room for the thumb throttle and a full-length handgrip on the left side:

    Tour Easy grips - left installed
    Tour Easy grips – left installed

    The round button is the PTT switch for the HT.

    The right handlebar still has the rear shifter, so it requires a shorter grip:

    Tour Easy grips - right installed
    Tour Easy grips – right installed

    Although it may be possible to buy such a grip and, thereby, get a backup pair of mismatched grips, it seemed easier straightforward to just shorten the grip to the correct length and be done with it.

    Saw off a convenient length of aluminum rod:

    Tour Easy grips - mandrel sawing
    Tour Easy grips – mandrel sawing

    Although I actually used a steady rest to produce this, it happened during a remote Squidwrench meeting and I have no proof:

    Tour Easy grips - lathe mandrel
    Tour Easy grips – lathe mandrel

    The 22.2 mm = 7/8 inch end matches the more-or-less standard handlebar diameter, so the grip clamp can get a good hold:

    Tour Easy grips - right peeled
    Tour Easy grips – right peeled

    A live center supports the right end of the grip.

    The red coating seems to be gooey silicone rubber molded atop a PVC tube. Rather than (try to) use a lathe bit to cut through the silicone, I cut two slits with a utility knife and the spindle turning slowly in reverse, then peeled off the rubber between the slits.

    With the silicone out of the way, an ordinary cutoff tool made short work of the PVC:

    Tour Easy grips - right trimming
    Tour Easy grips – right trimming

    That was a cleanup pass with the utility knife, as the cutoff tool left a slight flange around part of the circumference. If I had the courage of my convictions, I could probably have cut the PVC with the knife.

    Chamfer the end of the cut, slide it on the handlebar, tighten the clamp, and it’s all good.

    The alert reader will note the clamp should go on first, but that would produce an inconvenient lump against the right shifter. Sliding them on backwards puts the clamp at the end of the handlebar and works out better in this admittedly unusual situation.

  • Bafang USB Programming Adapter

    Bafang USB Programming Adapter

    Changing (“programming”) the Bafang BBS02 motor controller parameters requires a USB-to-serial adapter with a connector matching the end of the cable from the motor to the display. While you can buy such things directly from the usual randomly named Amazon sellers, I happen to have a wide variety of bare adapter boards, so I just bought a display extender cable and cut it in half to get the connector; you can apparently buy pigtailed connectors (for more than the price of an extender) if you dislike cutting cables in half.

    Various documents provide versions of the canonical illustration of the motor end of the display cable, as ripped from Penoff’s original documentation:

    Bafang BBS02 display cable pinout
    Bafang BBS02 display cable pinout

    The pin colors correspond to the wiring inside the motor cable, but the extender uses different colors, because nobody will ever know:

    Bafang programmer - wire colors
    Bafang programmer – wire colors

    A bit of work with a continuity meter gave the pinout:

    Bafang BBS02 display extender - wire colors
    Bafang BBS02 display extender – wire colors

    Don’t trust stuff you read on the Intertubes: make your own measurements and draw your own diagrams!

    You want the cable end carrying the sockets to mate with the pins on the motor cable (coming in from the left):

    Bafang programmer - cable ends
    Bafang programmer – cable ends

    Soldering the cable to a known-counterfeit FTDI USB adapter went swimmingly:

    Bafang programmer - USB adapter wiring
    Bafang programmer – USB adapter wiring

    Note that the yellow-blue connection carries the full 48 V from the battery and may or may not have any current limiting / fusing / protection, so be a little more careful than usual in your wiring layout.

    The red jumper from DTR to CTS, shown in all the Amazon and eBay listIngs, turns out to be unnecessary.

    A quick and dirty case (eventually held together with generous hot-melt glue blobs) protects the PCB and armors the cables:

    Bafang USB-serial adapter interior
    Bafang USB-serial adapter interior

    The solid model over on the right looks about like you’d expect:

    Bafang Battery Mount - complete build view
    Bafang Battery Mount – complete build view

    Most of the instructions will tell you to hot-plug the cable to the motor with the battery connected, which strikes me as foolhardy; not all of those pins make contact in the right order, which means you will slap 50-odd volts across the wrong parts of the circuitry.

    Instead:

    • Disconnect the battery
    • Unplug the display
    • Plug the adapter cable into the motor connector
    • Plug the USB cable into the Token Windows Laptop
    • Reconnect the battery
    • Fire up the “programming” routine
    • Send the new configuration to the motor controller
    • Disconnect the battery
    • Unplug the adapter cable
    • Reconnect the display cable
    • Reconnect the battery

    Makes more sense to me, even if it’s more tedious.

    Tuck this OpenSCAD source code for the case into the original program that produces the battery mounts:

    Layout = "Build";               // [Frame,Block,Show,Build,Bushing,Cateye,Case]
    
    … snippage …
    
    // Programming cable case
    
    ProgCavity = [70.0,19.0,10.0];
    ProgBlock = [85.0,25.0,15.0];
    ProgCableOD = 4.0;
    
    module ProgrammerCase() {
    
        difference() {
            hull() {
                for (i=[-1,1], j=[-1,1])
                    translate([i*(ProgBlock.x/2 - CornerRadius),j*i*(ProgBlock.y/2 - CornerRadius),-ProgBlock.z/2])
                        cylinder(r=CornerRadius,h=ProgBlock.z,$fn=12);
                }
            translate([-ProgBlock.x,0,0])
                rotate([0,90,0])
                    PolyCyl(ProgCableOD,3*ProgBlock.x,6);
            cube(ProgCavity,center=true);
        }
    }
    
    // Half case sections for printing
    
    module HalfCase(Section = "Upper") {
    
        intersection() {
           translate([0,0,ProgBlock.z/4])
                cube([2*ProgBlock.x,2*ProgBlock.y,ProgBlock.z/2],center=true);
            if (Section == "Upper")
                translate([0,0,-Kerf/2])
                    ProgrammerCase();
            else
                translate([0,0,ProgBlock.z/2])
                    ProgrammerCase();
        }
    }
    
    … snippage …
    
    // tuck this into the Build conditional
    
        translate([0,3*Block.x,0]) {
    
            translate([gap*ProgBlock.x/2,0,ProgBlock.z/2])
                rotate([180,0,0])
                    HalfCase("Upper");
            translate([-gap*ProgBlock.x/2,0,0])
                HalfCase("Lower");
    

  • Miniblind Mounting Brackets: Version 4

    Miniblind Mounting Brackets: Version 4

    Miniblinds don’t last forever:

    Miniblind failure
    Miniblind failure

    The plastic frame failed at the pull cord opening, obviously a weak and, alas, non-repairable point.

    A quick trip to Lowe’s produced a new miniblind with mounting hardware completely different from the old one. This came as no surprise, as every new miniblind differs from all previous ones; miniblind mounting hardware is not strongly conserved.

    The broken frame fit into the plastic end caps mounted just beyond the scarred paint marking the bracket location required for the previous miniblind:

    Miniblind bracket - V3
    Miniblind bracket – V3

    Note that the caps mount with a single screw in the homebrew bracket’s face, which has two holes to match the previous-previous cap.

    Also note how the curved moulding strips around the 1955-era windows in this house do not fit any contemporary miniblind hardware, thus requiring Quality Shop Time with every installation.

    Although the shiny new hardware had two slots, they neither lined up with the existing bracket holes nor extended quite far enough vertically. I lined things up, marked and drilled a single midline hole in both the new hardware and the old bracket, and reused the old screw and nut:

    Miniblind bracket - V4 side
    Miniblind bracket – V4 side

    Moving the bracket back to its previous-previous location exposed the scarred paint under the previous position:

    Miniblind bracket - V4 front
    Miniblind bracket – V4 front

    Fortunately, it’s hidden by the installed miniblind.

    That was, all things considered, easy …

  • Tour Easy: Bafang Brake Sensors

    Tour Easy: Bafang Brake Sensors

    Over the decades, we have devoted considerable time and attention to adjusting the reach and travel of the brake levers on Mary’s bike, so I ordered a pair of brake sensors for the Bafang BBS02 motor to mount on the existing hardware:

    Tour Easy Bafang BBS02 - brake sensor - installed
    Tour Easy Bafang BBS02 – brake sensor – installed

    The sensor is the black block secured to the brake mount (with good outdoor foam tape), with the bar magnet similar secured to the handle. The magnet ended up slightly off-center from the switch due to the overlapping joint between the lever and the mount; I can’t detect any difference from having it centered.

    The Bafang switches included cute little disk-shaped neodymium magnets which weren’t suited for the levers and stuck out in all directions without getting particularly close to the sensor. As a result, the least pressure on the brake handle produced a hair-trigger switch activation.

    So I harvested two bar-shaped magnets from a defunct Philips Sonicare toothbrush head, reducing the rather large assortment I’ve been saving for just such an occasion by one item. Each brush head contains a pair magnets attached to a steel backing plate, seen here after removing the lower magnet:

    Tour Easy Bafang BBS02 - brake sensor - donor magnet assembly
    Tour Easy Bafang BBS02 – brake sensor – donor magnet assembly

    I don’t know how Philips attaches the magnets, but a few shots to the steel backing plate with a drift punch breaks the bond without any obvious damage:

    Tour Easy Bafang BBS02 - brake sensor - donor magnet loosened
    Tour Easy Bafang BBS02 – brake sensor – donor magnet loosened

    Neodymium magnets have a nickel plating to prevent corrosion, but AFAICT the only way to know whether I’ve cracked the plating is waiting to see if the magnet falls apart. If it does, I promise to be more careful with the next toothbrush head.

    They’re magnetized through the thinnest section, not along the length like an old-school bar magnet, but the disk magnets are similarly magnetized and I think the net effect is about the same.

    The bars fit the brake handles more closely, put more of the magnet closer to the switch, and allow about 5 mm of travel before tripping the switch.

    Pending more road testing, the switches seem more usable.

    Protip 1: Demagnetize your tools after working with neodymium magnets.

    Protip 2: Don’t put a loose magnet anywhere near your bench block, because it will shatter when it snaps onto the block from a surprising distance.

  • Tour Easy: Bafang Shift Sensor

    Tour Easy: Bafang Shift Sensor

    The shift sensor detects motion of the rear derailleur cable so the Bafang BBS02 can briefly cut motor power while the chain moves across the sprockets:

    Tour Easy Bafang BBS02 - shift sensor - installed
    Tour Easy Bafang BBS02 – shift sensor – installed

    This should be a drop-in fit on most bikes, but the Tour Easy’s front brazed cable stop is a little shorter than the ferrule. Trimming a plastic tube poses little problem:

    Tour Easy Bafang BBS02 - shift sensor - bushing
    Tour Easy Bafang BBS02 – shift sensor – bushing

    The ferrule now fits neatly in the stop, although the sensor casing sits at a slight angle because the stop’s centerline puts the cable slightly closer to the frame than the back of the sensor body will allow. You could mount it elsewhere, but the cable stop sits directly above the motor and doesn’t require an extension cable.

    The sensor works wonderfully well, with the motor pausing for perhaps a second during the shift: just shift normally and it’s done.

    A red LED (the small dot to the right of the label) blinks when the sensor detects a shift, so you can verify its operation on the work stand.

  • Tour Easy: Bafang 48 V 11.6 A·h Battery Mount

    Tour Easy: Bafang 48 V 11.6 A·h Battery Mount

    Bafang BBS02 batteries should mount on the water bottle bosses along a more-or-less standard bicycle’s downtube, which a Tour Easy recumbent has only in vestigial form. The battery does, however, fit perfectly along the lower frame tubes:

    Tour Easy Bafang mid-drive - battery
    Tour Easy Bafang mid-drive – battery

    You might be forgiven for thinking Gardner Martin (not to be confused with Martin Gardner of Scientific American fame) designed the Tour Easy frame specifically to hold that battery, but the design dates back to the 1970s and it’s just a convenient coincidence.

    The battery slides into a flat baseplate and locks in place, although it’s definitely not a high-security design. Mostly, the lock suffices to keep honest people honest and prevent the battery from vibrating loose while riding:

    Tour Easy Bafang battery mount - baseplate installed
    Tour Easy Bafang battery mount – baseplate installed

    The flat enclosure toward the rear was obviously designed for more complex circuitry than it now contains:

    Tour Easy Bafang battery mount - interior
    Tour Easy Bafang battery mount – interior

    Those are all neatly drilled and tapped M3 machine screw holes. The cable has no strain relief, despite the presence of suitable holes at the rear opening. I tucked the spare cable inside, rather than cut it shorter, under the perhaps unwarranted assumption they did a good job crimping / soldering the wires to the terminals.

    The red frame tubes are not parallel, so each of the four mounting blocks fits in only one location. They’re identified by the side-to-side tube measurement at their centerline and directional pointers:

    Bafang Battery Mount - Show bottom
    Bafang Battery Mount – Show bottom

    The first three blocks have a hole for the mounting screw through the battery plate. The central slot fits around the plate’s feature for the recessed screw head. The two other slots clear the claws extending downward from the battery into the plate:

    Bafang Battery Mount - Show view
    Bafang Battery Mount – Show view

    The rear block has a flat top and a recessed screw head, because the fancy metal enclosure doesn’t have a screw hole:

    Tour Easy Bafang battery mount - top detail
    Tour Easy Bafang battery mount – top detail

    I thought of drilling a hole through the plate, but eventually put a layer of carpet tape atop the block to encourage it to not slap around, as the whole affair isn’t particularly bendy. We’ll see how well it works on the road.

    I had intended to put an aluminum plate across the bottom to distribute the clamping force from the screw, but found a suitable scrap of the institutional-grade cafeteria tray we used as a garden cart seat:

    Tour Easy Bafang battery mount - bottom detail
    Tour Easy Bafang battery mount – bottom detail

    I traced around the block, bandsawed pretty close to the line, then introduced it to Mr Disk Sander for final shaping.

    The round cable runs from the rear wheel speed sensor through all four blocks to join the motor near the bottom bracket. Because a recumbent bike’s rear wheel is much further from its bottom bracket, what you see is actually an extension cable with a few extra inches doubled around its connection just ahead of the battery.

    Each of the four blocks takes about an hour to print, so I did them individually while making continuous process improvements to the solid model:

    Bafang Battery Mount - Build view
    Bafang Battery Mount – Build view

    The heavy battery cable runs along the outside of the left frame tube, with enough cable ties to keep it from flopping around:

    Tour Easy Bafang battery mount - bottom view
    Tour Easy Bafang battery mount – bottom view

    I wanted to fit it between the tubes, but there just wasn’t enough room around the screw in the front block where the tubes converge. It’s still pretty well protected and should be fine.

    The chainline worked out much better than I expected:

    Tour Easy Bafang battery mount - chainline
    Tour Easy Bafang battery mount – chainline

    That’s with the chain on the lowest (most inboard) rear sprocket, so it’s as close to the battery as it gets. I’m sure the battery will accumulate oily chain grime, as does everything else on a bike.

    Lithium batteries have a vastly higher power density than good old lead acid batteries, but seven pounds is still a lot of weight!

    The OpenSCAD source code as a GitHub Gist:

    // Tour Easy Bafang Battery Mount
    // Ed Nisley KE4ZNU 2021-04
    Layout = "Build"; // [Frame,Block,Show,Build,Bushing,Cateye]
    FrameWidths = [60.8,62.0,63.4,66.7]; // last = rear overhang support block
    Support = true;
    //- Extrusion parameters must match reality!
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    ID = 0;
    OD = 1;
    LENGTH = 2;
    //———-
    // Dimensions
    // Bike frame lies along X axis, rear to +X
    FrameTube = [350,22.6 + HoleWindage,22.6 + HoleWindage]; // X = longer than anything else
    FrameAngle = atan((65.8 – 59.4)/300); // measured distances = included angle between tubes
    TubeAngle = FrameAngle/2; // .. frame axis to tube
    FrameSides = 24;
    echo(str("Frame angle: ",FrameAngle));
    SpeedOD = 3.5; // speed sensor cable along frame
    PowerOD = 6.7; // power cable between frame tubes
    BatteryBoss = [5.5,16.0,2.5]; // battery mount boss, center is round
    BossSlotOAL = 32.0; // .. end bosses are elongated
    BossOC = 65.0; // .. along length of mount
    LatchWidth = 10.0; // battery latches to mount plate
    LatchThick = 1.5;
    LatchOC = 56.0;
    WallThick = 5.0; // thinnest wall
    Block = [25.0,78.0,FrameTube.z + 2*WallThick]; // must be larger than frame tube spacing
    echo(str("Block: ",Block));
    // M5 SHCS nyloc nut
    Screw = [5.0,8.5,5.0]; // OD, LENGTH = head
    Washer = [5.5,10.1,1.0];
    Nut = [5.0,9.0,5.0];
    // 10-32 Philips nyloc nut
    Screw10 = [5.2,9.8,3.6]; // OD, LENGTH = head
    Washer10 = [5.5,11.0,1.0];
    Nut10 = [5.2,10.7,6.2];
    Kerf = 1.0; // cut through middle to apply compression
    CornerRadius = 5.0;
    EmbossDepth = 2*ThreadThick; // lettering depth
    //———————-
    // 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(d=(FixDia + HoleWindage),h=Height,$fn=Sides);
    }
    // clamp overall shape
    module ClampBlock() {
    difference() {
    hull()
    for (i=[-1,1], j=[-1,1])
    translate([i*(Block.x/2 – CornerRadius),j*(Block.y/2 – CornerRadius),-Block.z/2])
    cylinder(r=CornerRadius,h=Block.z,$fn=4*8);
    translate([0,0,-(Block.z/2 + Protrusion)])
    rotate(0*180/6)
    PolyCyl(Screw[ID],Block.z + 2*Protrusion,6);
    cube([2*Block.x,2*Block.y,Kerf],center=true);
    translate([0,-(Block.y/2 – PowerOD + Protrusion/2),-PowerOD/2])
    cube([2*Block.x,2*PowerOD + Protrusion,PowerOD],center=true);
    }
    }
    // frame tube layout with measured side-to-side width
    module Frame(Outer = FrameWidths[0],AdjustDia = 0.0) {
    TubeOC = Outer – FrameTube.y/cos(TubeAngle); // increase dia for angle
    for (i=[-1,1])
    translate([0,i*TubeOC/2,0])
    rotate([0,90,i*TubeAngle]) rotate(180/FrameSides)
    cylinder(d=FrameTube.z + AdjustDia,h=FrameTube.x,center=true,$fn=FrameSides);
    }
    // complete clamp block
    module Clamp(Outer = FrameWidths[0]) {
    TubeOC = Outer – FrameTube.y/cos(TubeAngle); // increase dia for angle
    difference() {
    ClampBlock();
    Frame(Outer);
    translate([0,(TubeOC/2 – FrameTube[OD]/2),-SpeedOD/2])
    cube([2*Block.x,2*SpeedOD,SpeedOD],center=true);
    translate([0,15,Block.z/2 – EmbossDepth/2 + Protrusion])
    cube([9.0,8,EmbossDepth],center=true);
    translate([0,22,-Block.z/2 + EmbossDepth/2 – Protrusion])
    cube([9.0,26,EmbossDepth],center=true);
    if (Outer == FrameWidths[len(FrameWidths) – 1]) { // special rear block
    translate([0,0,Block.z/2 – 2*Screw10[LENGTH]])
    PolyCyl(Washer10[OD],2*Screw10[LENGTH] + Protrusion,6);
    }
    else { // other blocks have channels
    translate([0,0,Block.z/2 – BatteryBoss[LENGTH]/2 + Protrusion])
    cube([BossSlotOAL,BatteryBoss[OD],BatteryBoss[LENGTH] + Protrusion],center=true);
    for (i=[-1,1])
    translate([0,i*LatchOC/2,Block.z/2 – LatchThick/2 + Protrusion])
    cube([BossSlotOAL,LatchWidth,LatchThick + Protrusion],center=true);
    }
    }
    translate([0,15,Block.z/2 – EmbossDepth])
    linear_extrude(height=EmbossDepth)
    rotate(90)
    text(text="^",size=5,spacing=1.00,font="Bitstream Vera Sans:style=Bold",
    halign="center",valign="center");
    translate([0,22,-Block.z/2])
    linear_extrude(height=EmbossDepth)
    rotate(-90) mirror([0,1,0])
    text(text=str("^ ",Outer),size=4.5,spacing=1.00,font="Bitstream Vera Sans:style=Bold",
    halign="center",valign="center");
    if (Support)
    color("Yellow") {
    NumRibs = 7;
    RibOC = Block.x/(NumRibs – 1);
    intersection() {
    translate([0,0,Block.z/2 + Kerf/2])
    cube([2*Block.x,2*Block.y,Block.z],center=true);
    union() for (j=[-1,1]) {
    translate([0,j*TubeOC/2,Kerf/2])
    cube([1.1*Block.x,FrameTube.y – 2*ThreadThick,4*ThreadThick],center=true);
    for (i=[-floor(NumRibs/2):floor(NumRibs/2)])
    translate([i*RibOC,j*TubeOC/2,0])
    rotate([0,90,0]) rotate(180/FrameSides)
    cylinder(d=FrameTube.z – 2*ThreadThick,h=2*ThreadWidth,$fn=FrameSides,center=true);
    }
    }
    }
    }
    // Half clamp sections for printing
    module HalfClamp(i = 0, Section = "Upper") {
    render()
    intersection() {
    translate([0,0,Block.z/4])
    cube([Block.x,Block.y,Block.z/2],center=true);
    if (Section == "Upper")
    translate([0,0,-Kerf/2])
    Clamp(FrameWidths[i]);
    else
    translate([0,0,Block.z/2])
    Clamp(FrameWidths[i]);
    }
    }
    // Handlebar bushing for controller
    BushingSize = [16.0,22.2,15.0];
    module Bushing() {
    difference() {
    cylinder(d=BushingSize[OD],h=BushingSize[LENGTH],$fn=24);
    translate([0,0,-Protrusion])
    cylinder(d=BushingSize[ID],h=2*BushingSize[LENGTH],$fn=24);
    translate([0*(BushingSize[OD] – BushingSize[ID])/4,0,BushingSize[LENGTH]/2])
    cube([2*BushingSize[OD],2*ThreadWidth,2*BushingSize[LENGTH]],center=true);
    }
    }
    // Cateye cadence sensor bracket
    module Cateye() {
    Pivot = [3.0,10.0,8.0];
    Slot = [4.2,14.0,14.0];
    Clip = [8.0,Slot.y,Slot.z + Pivot[OD]/2];
    translate([0,0,Clip.z])
    difference() {
    union() {
    translate([0,0,-Clip.z/2])
    cube(Clip,center=true);
    translate([-Clip.x/2,0,0])
    rotate([0,90,0])
    cylinder(d=Clip.y,h=Clip.x,$fn=12);
    }
    translate([-Clip.x,0,0])
    rotate([0,90,0]) rotate(180/6)
    PolyCyl(3.0,2*Clip.x,6);
    translate([0,0,-(Clip.z – Slot.z/2)])
    cube(Slot + [0,Protrusion,Protrusion],center=true);
    }
    }
    //———-
    // Build them
    if (Layout == "Frame")
    Frame();
    if (Layout == "Block")
    ClampBlock();
    if (Layout == "Bushing")
    Bushing();
    if (Layout == "Cateye")
    Cateye();
    if (Layout == "Upper" || Layout == "Lower")
    HalfClamp(0,Layout);
    if (Layout == "Show") {
    Clamp();
    color("Red", 0.3)
    Frame();
    }
    if (Layout == "Build") {
    n = len(FrameWidths);
    gap = 1.2;
    for (i=[0:n-1]) {
    j = i – ceil((n-1)/2);
    translate([-gap*Block.y/2,j*gap*Block.x,0])
    rotate(90)
    HalfClamp(i,"Upper");
    translate([gap*Block.y/2,j*gap*Block.x,0])
    rotate([0,0,90])
    HalfClamp(i,"Lower");
    }
    }