Skip to content

Instantly share code, notes, and snippets.

@mossprescott
Created March 26, 2022 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mossprescott/06377e42bbbe4bd30925b1ae306928d7 to your computer and use it in GitHub Desktop.
Save mossprescott/06377e42bbbe4bd30925b1ae306928d7 to your computer and use it in GitHub Desktop.
OpenSCAD model of an interesting clock
/*
Crude copy of Fibonacci Clocks' "Hyperbola Clock" (https://www.youtube.com/watch?v=DgqTGXB9KNk).
Really needs an interesting shape for the face, but I'd rather come up with something
original than copy the original clock. Hmm...
*/
/* [Special] */
$fa = 1;
$fs = 0.2;
$t = 0; // [0:0.5:12.0]
/* [Base and Face] */
length = 20;
height = 16.5;
face_angle = 90;
face_anchor = 0;
face_notch = 2.5;
face_extra = 0.2; // embedded in the base
label_scale = 0.075; // relative to h
/* [Post] */
post_height = 22;
post_angle = 45;
post_offset = 1.875; // [0.5:0.125:2.0]
post_radius = 0.2;
/* [Time] */
start_hour = 7; // [11] The hour that appears on the lower right
// Intersection points (empirical):
// These were manually adjusted to align with the intersection of
// the post with the front plane of the face.
/* [Path] */
x1 = 0.7;
x2 = 0.265;
x3 = 0.2;
// TODO: re-calibrate these to be up from the rotor plate, not relative to the notch
cy = 0.67;
y2 = 0.185;
y3 = 0.05;
module base() {
translate([0, 0, 0.5])
cube([length, length, 1], center = true);
}
module face() {
translate([0, -face_anchor, 0.5])
rotate([face_angle, 0, 0])
translate([0, face_notch, 0])
difference() {
// Plank:
translate([-length/2, -(face_notch + face_extra), -0.5])
cube([length, height + face_notch + face_extra, 0.5]);
// Notch:
translate([0, -face_notch/2 - 0.5, -0.25])
cube([length - 2*1, face_notch+1, 1], center = true);
// Indicators:
translate([0, 0, -0.55])
linear_extrude(0.6)
union() {
scale([length/2, length/2]) {
// Note: these positions aren't really completely
// independent of start_hour. That is, if the digits
// get shifted around, their positions will need adjustment.
digit(0, x1 - 0.18, cy - cy + 0.05, false);
digit(1, x2 - 0.08, cy - 1.2*y2, false);
digit(2, x3 - 0.08, cy - 1.3*y3, false);
digit(3, x3 - 0.08, cy + 1.3*y3, false);
digit(4, x2 - 0.08, cy + 1.2*y2, false);
digit(5, x1 - 0.10, cy + cy + 0.025, false);
digit(6, x1 - 0.18, cy - cy + 0.05, true);
digit(7, x2 - 0.08, cy - 1.2*y2, true);
digit(8, x3 - 0.08, cy - 1.3*y3, true);
digit(9, x3 - 0.08, cy + 1.3*y3, true);
digit(10, x2 - 0.08, cy + 1.2*y2, true);
digit(11, x1 - 0.10, cy + cy + 0.025, true);
}
// Bottom to top, right side:
/* 0 */ hole(x1, cy - cy);
/* 1 */ hole(x2, cy - y2);
/* 2 */ hole(x3, cy - y3);
/* 3 */ hole(x3, cy + y3);
/* 4 */ hole(x2, cy + y2);
/* 5 */ hole(x1, cy + cy);
// Left side:
/* 6 */ hole(-x1, cy - cy);
/* 7 */ hole(-x2, cy - y2);
/* 8 */ hole(-x3, cy - y3);
/* 9 */ hole(-x3, cy + y3);
/* 10 */ hole(-x2, cy + y2);
/* 11 */ hole(-x1, cy + cy);
path();
mirror([1, 0])
path();
}
}
}
function hour_str(d) =
str((d-1+start_hour) % 12 + 1);
module digit(d, x, y, flip) {
translate([flip ? -x : x, y])
text(hour_str(d),
size=label_scale,
halign = flip ? "left" : "right",
valign = "center");
}
module path() {
x1_5 = (x1+x2)/2 - 0.02;
y1_5 = (cy + y2)/2;
q = 0.1; // how far past the last intersection point)
m = 0.025; // radius of the chamfer
e = 0.1/2-m; // width of the path (in x, not perpendicular)
scale([length/2, length/2])
minkowski($fn = 20) {
circle(m);
polygon(points = [
// start at the lower right (outside):
// [x1 + e, cy - cy - e],
[x1 + e, cy - cy],
[x1_5 + e, cy - y1_5], // a little bend in the long side
[x2 + e, cy - y2],
[x3 + e, cy - y3],
[x3 + e, cy + y3],
[x2 + e, cy + y2],
[x1_5 + e, cy + y1_5], // bend again
[x1 + e, cy + cy],
[x1 + q + e, cy + cy + q], // extend a bit to clear the post
// now back down around the left (inside):
[x1 + 1.3*q - e, cy + cy + 1.2*q],
[x1 - e, cy + cy],
[x1_5 - e, cy + y1_5],
[x2 - e, cy + y2],
[x3 - e, cy + y3],
[x3 - e, cy - y3],
[x2 - e, cy - y2],
[x1_5 - e, cy - y1_5],
[x1 - e, cy - cy],
// [x1 - e, cy - cy - e], // extend to chamfer the lower corner
]);
}
}
module hole(x, y) {
translate([length/2*x, length/2*y, 0])
circle(r = 0.25);
}
module rotor(hr) {
rotate(-30*(hr - start_hour + 0.5)) {
// Plate
translate([0, 0, 1.5])
cylinder(h = 1, r = length/2 - 1);
// Axle
translate([0, 0, 1.25])
cylinder(h = 1.01, r = 0.5, center = true);
// Post
translate([length/2 - 2, post_offset, 1.7])
rotate([0, -post_angle, 0])
cylinder(h = post_height, r = post_radius, $fn = 20);
}
}
/*
Visualize the intersection points of the post with the front edge of the
clock face.
Note: this isn't working right, now that the face module is fancier.
*/
module locate_hours() {
face();
translate([0, -0.1, 0])
color("red")
intersection() {
scale([1, 0.05, 1])
face(); // Need a simple plane here; the face now been sliced up
for (i = [0:12]) {
rotor(i);
}
}
}
face();
base();
color("gray")
rotor($t);
//locate_hours();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment