-
Tour Easy: SJCAM C100+ Mount
The batteries (which are no longer available) and the control buttons have worn out on the SJCAM M20 camera on the back of my Tour Easy, so a replacement is in order:

Tour Easy – SJCAM C100 mount – installed It’s an SJCAM C100+ in its waterproof housing, screwed to a block descended from the M20 mount:

SJCAM C100 Mount – solid model The C100+ has a non-replaceable lithium pouch battery that may not last for the hour or so we generally ride, but at least this is a starting point for seeing how the thing works.
The PrusaSlicer preview shows the support structure inside the seat rail arches:

SJCAM C100 Mount – slicer That appears under the four central facets of each arch, where I “painted” the support enforcers, because the automagic supports fill the entire arch and are basically impossible to pry off.
The hole between the ears on the top holds an aluminum tab intended to diffuse the wobble from that tall camera. A laser-cut chipboard template simplified drilling & cutting the tab from an aluminum sheet:

Tour Easy – SJCAM C100 mount – test fit The tab and the brass inserts are held in place with JB Weld Plastic Bonder, my new go-to adhesive for such things.
The camera includes WiFi and the inevitable app lets you download images without opening the case. Because I’ll be charging the camera after each ride, I may as well just haul the whole thing inside, plug it into a USB port, and proceed as before.
For future reference, the manual details the operating modes:

SJCAM C100 Manual – Modes Because the camera powers up with WiFi enabled and I have no plans to communicate with it while riding, the startup sequence will be:
- Long-press to power on
- Double-click to disable WiFi
- Single-click to start recording
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// SJCAM C100+ Camera Mount for Tour Easy seat back rail // Ed Nisley – KE4ZNU // 2023-04 /* [Layout Options] */ LookAngle = -20; // camera angle, looking backwards = 0° Layout = "Show"; // [Show,Build] /* [Hidden] */ ThreadWidth = 0.40; ThreadThick = 0.25; HoleWindage = 0.2; Protrusion = 0.1; ID = 0; OD = 1; LENGTH = 2; //—– // Dimensions ClampScrew = [5.0,10.0,40.0]; // ID=thread OD=washer LENGTH=total ClampInsert = [5.0,7.5,10.5]; // brass insert MountScrew = [5.0,10.0,23.0]; // ID=thread OD=washer LENGTH=under nut MountInsert = [5.0,7.5,10.5]; // ID=screw OD, OD=knurl dia EmbossDepth = 2*ThreadThick + Protrusion; // recess depth + Protrusion beyond surface DebossHeight = EmbossDepth; // text height + Protrusion into part RailOD = 20.0; // slightly elliptical in bent section RailSides = 2*3*4; ClampOA = [60.0,40.0,ClampScrew[LENGTH]]; // set clamp size to avoid weird screw spacing echo(ClampOA = ClampOA); ClampScrewOC = IntegerMultiple(ClampOA.x – ClampScrew[OD] – 10*ThreadWidth,1.0); echo(ClampScrewOC = ClampScrewOC); ClampOffset = 5.0; // in case we need more room on top ClampRadius = 3.0; ClampSides = 8; Kerf = 1.0; // slice through the middle // center mount blade, Z = depth into block MountBlade = [15.0 + 2*HoleWindage, 3.0 + 2*HoleWindage, (ClampOA.z – RailOD + ClampOffset)/2 – 4*ThreadThick + Protrusion]; echo(MountBlade = MountBlade); MountRadius = MountBlade.x / 2; MountGap = 9.5; // camera mount gap around center blade MountOffset = [0,0,7.0]; // mount hole offset from block surface FadeColor = "Green"; FadeAlpha = 0.25; //—– // Useful routines function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); 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); } //—– // Clamp // Grips seat frame rail // Origin at middle of seat rail, X rearward, Y parallel to seat frame rail // Block offset raises whole thing module Clamp() { difference() { translate([0,0,ClampOffset]) { difference() { union() { hull() // the main block for (i=[-1,1], j=[-1,1], k=[-1,1]) translate([i*(ClampOA.x – 2*ClampRadius)/2, j*(ClampOA.y – 2*ClampRadius)/2, k*(ClampOA.z – 2*ClampRadius)/2]) sphere(r=ClampRadius/cos(180/ClampSides),$fn=ClampSides); hull() // camera mount boss for (k=[0,1]) translate([0,0,k*(MountOffset.z) + ClampOA.z/2]) rotate([0,90,LookAngle + 90]) rotate(180/12) cylinder(r=MountRadius,h=MountScrew[LENGTH],center=true,$fn=12); } for (i=[-1,1]) // clamp inserts translate([i*ClampScrewOC/2,0,-(ClampOA.z/2 + Protrusion)]) rotate(180/6) PolyCyl(ClampInsert[OD],ClampInsert[LENGTH],6); for (i=[-1,1]) // clamp screw holes translate([i*ClampScrewOC/2,0,-ClampOA.z]) rotate(180/6) PolyCyl(ClampScrew[ID],2*ClampOA.z,6); translate([0,0,ClampOA.z/2 – (MountBlade.z/2 – Protrusion/2)]) // camera center blade rotate(LookAngle) cube(MountBlade,center=true); rotate(LookAngle + 90) // camera mount boss slot translate([0,0,ClampOA.z/2 + 2*MountRadius]) cube([MountGap,4*MountRadius,4*MountRadius],center=true); translate([0,0,ClampOA.z/2 + MountOffset.z]) // camera mount boss hole rotate([90,0,LookAngle]) cylinder(d=MountScrew[ID],h=4*MountGap,center=true,$fn=6); translate([0.3*ClampOA.x, // recess for LookAngle legend -(ClampOA.y/2 – (EmbossDepth – Protrusion)/2), ClampOA.z/4]) cube([15,EmbossDepth,8],center=true); translate([0,0,-ClampOA.z/2 + (EmbossDepth – Protrusion)/2]) // recess for ID legend cube([35,10,EmbossDepth],center=true); } translate([0.3*ClampOA.x, // LookAngle legend -ClampOA.y/2 + DebossHeight + Protrusion/2, ClampOA.z/4]) rotate([90,0,00]) linear_extrude(height=DebossHeight,convexity=20) text(text=str(LookAngle),size=6,spacing=1.20, font="Arial:style:Bold",halign="center",valign="center"); translate([0,0,-ClampOA.z/2]) // ID legend linear_extrude(height=DebossHeight,convexity=20) mirror([0,1,0]) text(text="KE4ZNU",size=5,spacing=1.20, font="Arial:style:Bold",halign="center",valign="center"); } cube([2*ClampOA.x,2*ClampOA.y,Kerf],center=true); // split across rail rotate([90,0,0]) // seat rail cylinder(d=RailOD,h=2*ClampOA.y,$fn=RailSides,center=true); } } //—– // Build things // Layouts for design & tweaking if (Layout == "Show") { Clamp(); color(FadeColor,FadeAlpha) rotate([90,0,0]) cylinder(d=RailOD,h=2*ClampOA.y,$fn=RailSides,center=true); } // Build layout if (Layout == "Build") { translate([0,0.7*ClampOA.y,0]) difference() { translate([0,0,-Kerf/2]) Clamp(); translate([0,0,-ClampOA.z]) cube(2*ClampOA,center=true); } translate([0,-0.7*ClampOA.y,-0]) difference() { translate([0,0,-Kerf/2]) rotate([0,180,0]) Clamp(); translate([0,0,-ClampOA.z]) cube(2*ClampOA,center=true); } }