Step2 Garden Seat: Replacement Seat

A pair of Step2 rolling garden seats (they have a new version) served in Mary’s gardens long enough to give their seat panels precarious cracks:

Step2 Seat - OEM seat
Step2 Seat – OEM seat

The underside was giving way, too:

Step2 Seat - cracks
Step2 Seat – cracks

We agreed the new seat could be much simpler, although it must still hinge upward, so I conjured a pair of hinges from the vasty digital deep:

Rolling Cart Hinges - solid model - bottom
Rolling Cart Hinges – solid model – bottom

The woodpile disgorged a slab of 1/4 inch = 6 mm plywood (used in a defunct project) of just about the right size and we agreed a few holes wouldn’t be a problem for its projected ahem use case:

Step2 Seat - assembled
Step2 Seat – assembled

The screw holes on the hinge tops will let me run machine screws all the way through, should that be necessary. So far, a quartet of self-tapping sheet metal (!) screws are holding firm.

Rolling Cart Hinges - solid model - top
Rolling Cart Hinges – solid model – top

A closer look at the hinges in real life:

Step2 Seat - top view
Step2 Seat – top view

The solid model now caps the holes; I can drill them out should the need arise.

From the bottom:

Step2 Seat - bottom view
Step2 Seat – bottom view

Three coats of white exterior paint make it blindingly bright in the sun, although we expect a week or two in the garden will knock the shine right off:

Step2 Seat - painted
Step2 Seat – painted

After the first coat, I conjured a drying rack from a bamboo skewer, a cardboard flap, and some hot-melt glue:

Step2 Seat - drying fixture
Step2 Seat – drying fixture

Three small scars on the seat bottom were deemed acceptable.

The OpenSCAD source code as a GitHub Gist:

// Hinge brackets for rolling garden stool
// Ed Nisley - KE4ZNU - 2019-06
Layout = "Build"; // [Block,Build,Show]
Support = true;
/* [Hidden] */
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2;
Protrusion = 0.1; // make holes end cleanly
ID = 0;
OD = 1;
LENGTH = 2;
//----------------------
// Dimensions
SeatThick = 6.0; // seat panel above cart body
HingePin = [11.5,12.0,7.0]; // ID = tip OD = base
HingeOffset = 8.0; // hinge axis above cart body (larger than radius!)
HingeBolster = [5.0,24.0,SeatThick]; // backing block below hinge
Block = [25.0,HingeOffset + 30.0,23.0]; // Z = above cart body
Screw = [3.8,11.0,2.5]; // self-tapping #8 OD=head LENGTH=head thickness
ScrewOC = 15.0; // spacing > greater than head OD
ScrewOffset = Block.y/2 - (ScrewOC/2 + Screw[OD]/2 + HingeOffset); // space for head behind hinge
BlockRadius = 7.0; // corner rounding
//----------------------
// 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(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
// Basic block shape
// X axis collinear with hinge axes, hinge base at X=0
module HingeBlock() {
PinSides = 3*4;
PinSupport = [HingePin[LENGTH] - 2*ThreadWidth,0.6*HingeOffset,HingePin[OD]]; // pre-rotated
union() {
translate([Protrusion,Block.y/2 - HingeOffset,HingeOffset])
rotate([0,-90,0])
rotate(180/PinSides)
cylinder(d=HingePin[OD],h=HingePin[LENGTH] + Protrusion,$fn=PinSides);
difference() {
hull() {
translate([Block.x - BlockRadius,-(Block.y/2 - BlockRadius),Block.z - BlockRadius])
rotate(180/PinSides)
sphere(r=BlockRadius/cos(180/PinSides),$fn=PinSides);
translate([0,-(Block.y/2 - BlockRadius),Block.z - BlockRadius])
rotate([0,90,0]) rotate(180/PinSides)
cylinder(r=BlockRadius/cos(180/PinSides),h=Block.x/2,$fn=PinSides);
translate([Block.x - BlockRadius,(Block.y/2 - BlockRadius),Block.z - BlockRadius])
sphere(r=BlockRadius/cos(180/PinSides),$fn=PinSides);
translate([0,(Block.y/2 - BlockRadius),Block.z - BlockRadius])
rotate([0,90,0]) rotate(180/PinSides)
cylinder(r=BlockRadius/cos(180/PinSides),h=Block.x/2,$fn=PinSides);
translate([0,-Block.y/2,0])
cube([Block.x,Block.y - HingeOffset,Block.z/2],center=false);
translate([0,Block.y/2 - HingeOffset,HingeOffset])
rotate([0,90,0]) rotate(180/PinSides)
cylinder(r=HingeOffset/cos(180/PinSides),h=Block.x,$fn=PinSides);
}
translate([Block.x/2 + HingeBolster.x,0,(SeatThick - Protrusion)/2])
cube([Block.x,2*Block.y,SeatThick + Protrusion],center=true);
translate([0,-HingeBolster.y,(SeatThick - Protrusion)/2])
cube([3*Block.x,Block.y,SeatThick + Protrusion],center=true);
for (j=[-1,1])
translate([Block.x/2,j*ScrewOC/2 + ScrewOffset,-4*ThreadThick])
rotate(180/8)
PolyCyl(Screw[ID],Block.z,8);
}
}
if (Support) { // totally ad-hoc
color("Yellow") render(convexity=4)
difference() {
translate([-(PinSupport.x/2 + 2*ThreadWidth),Block.y/2 - PinSupport.y/2,HingeOffset])
cube(PinSupport,center=true);
translate([Protrusion,Block.y/2 - HingeOffset,HingeOffset])
rotate([0,-90,0])
rotate(180/PinSides)
cylinder(d=HingePin[OD] + 2*ThreadThick,h=2*HingePin[LENGTH],$fn=PinSides);
for (i=[-1:1])
translate([i*4*ThreadWidth - HingePin[LENGTH]/2,
Block.y/2 - (PinSupport.y + 1*ThreadThick),
HingeOffset])
cube([2*ThreadWidth,2*PinSupport.y,2*PinSupport.z],center=true);
}
}
}
module Blocks(Hand = "Left") {
if (Hand == "Left")
HingeBlock();
else
mirror([1,0,0])
HingeBlock();
}
//- Build it
if (Layout == "Block")
HingeBlock();
if (Layout == "Show") {
translate([1.5*HingePin[LENGTH],0,0])
Blocks("Left");
translate([-1.5*HingePin[LENGTH],0,0])
Blocks("Right");
}
if (Layout == "Build") {
translate([0,-Block.z/2,Block.y/2])
rotate([-90,0,0]) {
translate([1.5*HingePin[LENGTH],0,0])
Blocks("Left");
translate([-1.5*HingePin[LENGTH],0,0])
Blocks("Right");
}
}

This original doodle gives the key dimensions, apart from the rounded rear edge required so the seat can pivot vertically upward:

Cart Hinge - dimension doodle
Cart Hinge – dimension doodle

The second seat looks just like this one, so life is good …