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
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
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
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
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
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:

// 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);
}
}

Spam comments get trashed, so don't bother. Comment moderation may cause a delay.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s