-
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 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 The flat enclosure toward the rear was obviously designed for more complex circuitry than it now contains:

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 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 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 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 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 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 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 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:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// 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"); } }