Linear Clock (MVMT 113)

40,624

412

45

About: I'm an inventor / maker / designer based in the Bay Area. My background is in residential architecture, film set design, animatronics, media arts, exhibit design, and electronics. I use digital design and fa...

Intro: Linear Clock (MVMT 113)

No matter what Deepak Chopra tells you, time is linear. Hopefully this clock is a little closer to reality than the circular ones we're all used to. The five minute intervals feel less neurotic than being precise down to the minute, and each number is magnified, reminding you to focus on the present.

I made this using just about every machine at Pier 9 (waterjet, sand blaster, laser cutter, 3D printer, electronics lab, etc.). It's made of 6061 aluminum, steel hardware (screws, nuts, bearings), 3D printed gears, an Arduino Uno, and the hour and minute panels are laser cut / etched plywood.

Of course I know this project isn't accessible to almost everyone who doesn't have the insanely good fortune of having access to a shop like this, but hopefully you'll find it inspiring.

Fusion 360 is free for students and hobbyists, and there's a ton of educational support on it. If you want to learn to 3D model the kind of work I do, I think this is the best choice on the market. Click the links below to sign up:

Student/Educator

Hobbyist/Startup

I also led a series of webinar classes related to 3D modeling projects with moving parts. In these webinars, you will learn Fusion 360 features like advanced mechanical assemblies (meaning two or more joints interacting) and rendering. The last webinar focused on modeling this clock design in Fusion 360. You can watch the entire video here:

If you're interested, check out the other two webinars in this series where you will learn to design a Giant Knob Lamp and a Perpetual Clock with Arduino.

Step 1: 507 Mechanical Movements

507 Mechanical Movements is an encyclopedia of common mechanisms from the 1860's that serves as a good reference for this kind of thing. This mechanism is bases on Movement 113, "Rack and Pinion".This is going to be a long project, so if you've got a specific mechanism you'd like me to make, feel free to make a request in the comments!

Step 2: Design & 3D Model

The video above is a recording of a webinar I did for the rack and pinion design part of the project.

The hardest part of the design to figure out was the rack and pinion gear assembly. The math for gear design can get pretty complicated (in fact, there are engineers who basically only design gear assemblies for this very reason), but based on a great Youtube tutorial by Rob Duarte, I made my own template that works with the latest version of the Spur Gear add-in for Fusion.

The video above walks you through the process of making the rack and pinion assembly, but if you want a more thorough tutorial, please join me for the Design Now Hour Of Making in Motion webinar on April 5. If you miss the webinar, it'll be recorded and I'll post the video here.

The template (link below) has all of the parameters shown above already entered. I won't get into the math here, but if you follow the instructions, it should work for you.

Use the Spur Gear add-in by going to ADD-INS > Scripts and Add-Ins... > Spur Gear > Run. When you get the window shown above, enter the parameters. Number of Teeth won't let you use a parameter for the value, so just make sure it matches the teethNum value if you change it. You also have to multiply the named parameters by 1 as shown above.

Keep in mind that once the gear is made, you can edit it just like any other object in Fusion.

As shown in the video demo, this is an example of how you'd construct a tooth profile using the parameters.

Here are the links to the template you can use to make your own rack and pinion in Fusion:

Template with parameters:http://a360.co/2oeT5El

After the rack and pinion gear was figured out, I spent a lot of time modeling motors, switches, and other electronic parts, then figuring out all the details. With the motion link described above, I was able to get a good picture of how it would look in motion.

You can access the file through the link below, and play around with it or even try to make your own version out of the file. There was quite a bit of tinkering and alteration after the parts were made, so don't expect to be able to just laser cut all the parts and have a finished product. This project was expensive and took a lot of time! If you're really serious about making it and need some help, just comment below and I'll do my best to get you going.

Finished Clock Design: http://a360.co/2nk51nw

If you aren't already a Fusion 360 user, sign up for my free 3D Printing Class. It's a crash course in Fusion for making, and Lesson 2 has all the info you need to get Fusion for free.

Step 3: Hardware

Step 4: Electronics & Programming

The electronics are all done with an Arduino Uno and an Adafruit Motor Shield.

Here's the basic idea of how I want it to work:

  1. When the unit is turned on, the steppers run the racks back until the limit switches on the left side are triggered. This sets the position to zero. The steppers then run the racks forward until 1 is centered on the hour panel and 00 is centered on the minute panel.
  2. Once the hour and minute is centered, the racks move forward in time. A full position move on the bottom at full speed every 5 minutes, and a full position move on the top every hour.
  3. The momentary switches (pins 6-7) to move the racks forward by one position (about 147 steps), then continue with the clock counting.
  4. The hour and minute movements have counters that send the bars back to the left limit switches and reset them to zero once hour has gone past 12, and the minutes have gone past 55.

I'm still not clear on what exactly I need to do with the code. I've got it working in theory with the code below that got from Randofo. This code moves the minute bar forward one step every 200 ms (I think) once one of the limit switches is triggered. It works, but I'm pretty quickly out of my depth past the basic work I've done here. This seems like a pretty easy problem for a savvy Arduino user, but I only do a project with one maybe once a year, and every time I do, I've basically forgotten everything I learned in the last project.

<p>/*************************************************************</p>
Motor Shield Stepper Demo
by Randy Sarafan
For more information see:
<a href="https://www.instructables.com/id/Arduino-Motor-Shield-Tutorial/">
https://www.instructables.com/id/Arduino-Motor-Shi...</a>
*************************************************************/
#include <wire.h>
#include <adafruit_motorshield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"</adafruit_motorshield.h></wire.h>
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myMotor1 = AFMS.getStepper(300, 1);
Adafruit_StepperMotor *myMotor2 = AFMS.getStepper(300, 2);
int delaylegnth = 7;
void setup() {
    //start serial connection
  Serial.begin(9600);
  //configure pin2 as an input and enable the internal pull-up resistor
  pinMode(2, INPUT_PULLUP);
  //  Serial.begin(9600);           // set up Serial library at 9600 bps
  Serial.println("Stepper test!");
  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  
  myMotor1->setSpeed(100);  // 10 rpm   
  
}
void loop(){
  
 //read the pushbutton value into a variable
  int sensorVal = digitalRead(2);
  sensorVal == LOW;
  int delayL = 200;
  
  if (sensorVal == LOW) {
  
  Serial.println("Minutes ++");
  //myMotor1->step(1640, BACKWARD, DOUBLE);
  for (int i=0; i <= 10; i++){
      myMotor1->step(147, BACKWARD, DOUBLE);
      //analogWrite(PWMpin, i);
      delay(delayL);
   } 
   
  Serial.println("Hours ++");
  myMotor1->step(1615, FORWARD, DOUBLE); 
  //myMotor2->step(1600, BACKWARD, DOUBLE);
  myMotor2->step(220, FORWARD, DOUBLE); 
  //delay(delayL);
  
  }
  else {
  //Serial.println("Double coil steps");
  myMotor1->step(0, FORWARD, DOUBLE); 
  myMotor1->step(0, BACKWARD, DOUBLE);
    
  }
}

Step 5: Assemble the Base

The base is made of two plates with spacers holding them together. The screws fasten to the plate through tapped holes. Part number 6 on this drawing is another 3D printed part- a spacer that's also a cradle for the power terminal for the stepper motors.

Step 6: Add Momentary Switches

The momentary switches, Arduino, and limit switches all fasten to the front plate, so accessing the electronics to make changes is easy- just take the back plate off and you can reach everything.

Step 7: Add Mounting Plate and Limit Switches

The mounting plate holds the limit switches and the bearing assembly for the racks. This part can also stay together when editing the electronics.

Step 8: Add Stepper Motors & Gears

The stepper motors fasten to the panel with M4 screws through threaded holes, and the 3D printed gears are press-fit onto the motor posts. I used a trigger clamp to get them snug and flush.

Step 9: Add Racks

The racks have slots cut into them that bear on the two ball bearings. There's a small gap (.1mm) between the bearings and the slots, which allows the rack to move freely.

The bearings are sandwiched between custom 3D printed spacers to get the exact fit I needed. There's a rack plate on the front that acts as a washer holding the racks in place.

Step 10: Add Hour and Minute Bars

The hour and minute bars fasten to the racks with 12mm spacers creating a gap that allows clearance between the bars and the racks.

Step 11: Add Magnifiers

The magnifiers are cheap pocket magnifying glasses I found on amazon. They're offset from the front of the bars with 25mm spacers.

Step 12: Lessons Learned

I learned a lot about linear motion with this project. The tolerance I used between the bearings and slots on the racks was a bit too much, so if I were to make it again I think I would probably cut it in half. The gap on the sides of the gaps was also a bit too big.

The motors work, but the longer the cantilever gets, the more they have to work. I'd probably go with 12V steppers instead of 5V ones.

The backlash also should have been greater, maybe 0.25mm. The gears were bearing down on the racks too tightly with the first gears I tried.

Share

    Recommendations

    • Electronics Tips & Tricks Challenge

      Electronics Tips & Tricks Challenge
    • Plastics Contest

      Plastics Contest
    • Audio Contest 2018

      Audio Contest 2018

    45 Discussions

    0
    None
    RobY16

    1 year ago

    ooooo... very nice! - as an aside, in the a360 link, did you create the first story board step by step by moving each component seperately? or did you find a quicker way? I'm driving myself crazy trying to animate a similar mechanism to a360!

    1 reply
    0
    None
    JON-A-TRONRobY16

    Reply 1 year ago

    Yeah, the animation environment needs a lot of work. The developers know that though, and they're working on it.

    I basically moved groups of parts individually in the timeline to make that animation.

    0
    None
    AveryF3

    1 year ago

    What about this is perpetual? Am i missing something?

    3 replies
    0
    None
    JON-A-TRONAveryF3

    Reply 1 year ago

    I admit, it's the wrong title. I was referring to the perpetual calendar, which it borrows its shape from. I should have called it "linear clock", since all clocks are essentially perpetual.

    il_fullxfull.456872412_lcfh.jpg
    0
    None
    AveryF3JON-A-TRON

    Reply 1 year ago

    ooOOOoo very neat!

    If its not against your design ascetics,
    Could revision II of this clock have numbers bubbles in a circular shape instead of linear? Then you have a perpetual clock!

    Better still, you could add seconds(if someone wanted neuroticism) and put the three loops in a triangle shape(just offset by 120° ) or those three number circles nested inside one another, that would be also neat I think!

    0
    None
    JON-A-TRONAveryF3

    Reply 1 year ago

    Good idea! Should be easy enough to pull off, though a round rack turning would need a different kind of liner motion- maybe they could be on lazy susans...

    0
    None
    woofman

    1 year ago

    Very nice design, though I like my clocks to be easily read to the minute. Love the effect of the magnifier. This fairly begs for a steampunk aesthetic.....

    1 reply
    0
    None
    JON-A-TRONwoofman

    Reply 1 year ago

    It might work with minute-by-minute numbers, I haven't tested it.

    0
    None
    RemyB2

    1 year ago

    Wow, impressive and really beautiful.

    Would love to make one with brass and copper to have a nice steampunk look!

    1 reply
    0
    None
    NathR2RemyB2

    Reply 1 year ago

    Great idea, though I think black oxide body with copper fixings and cogs would look just as good.

    0
    None
    WillHenson

    1 year ago

    Such an amazingly well presented instructable! As an engineer, I've got a lot of time for those exploded views!!

    1 reply
    0
    None
    rams273

    1 year ago

    i love clocks this is brilliant concept just keep inspering and please make them to sell would defo buy

    1 reply
    0
    None
    jmaxado

    1 year ago

    Just a suggestion.

    I recently made a nixie tube clock, and I added a ESP8266 and my clock gets the time directly from the web.
    when it starts and every 5 hours, just in case it misses some minutes.

    Quite simple code, I can provide it in case you need.

    great work

    Jose Machado

    5 replies
    0
    None
    DurkVelljmaxado

    Reply 1 year ago

    Oi Jose,

    I'm interested in your ESP-code! Is it written in Arduino?

    Steve Vellinga

    0
    None
    jmaxadoDurkVell

    Reply 1 year ago

    I never got it to work with the NTP, so I found this way of doing it.
    I try to access some fake page on google, that will return 404 not found,
    and I extract the date and time from the reply HTML header.
    This will be UTC time, you can adjust them to your own time zone
    I believe the code is clear, but I am available to assist:

    #define SSID "Mama Dina"
    #define PASS "********" // My luggage has the same combination!
    #define DEST_HOST "google.com"
    #define DEST_IP "216.58.210.228"
    #define TIMEOUT 10000 // mS
    #define CONTINUE false
    #define HALT true
    #include SoftwareSerial

    Serial1 = SoftwareSerial(3, 2);
    char lf=10; //line feed character
    String readString, readString1;
    int x=0; //for counting line feeds

    // ******** SETUP ********

    void setup() {

    Serial.begin(9600); // Communication with PC monitor via USB Serial1.
    begin(9600); // Communication with ESP8266 via 5V/3.3V level shifter //

    Serial1.setTimeout(TIMEOUT);
    Serial.println("ESP8266 Demo");
    delay(2000);
    Serial.println("AT+RST");
    Serial1.println("AT+RST");
    show();
    Serial1.println("AT+GMR");
    show();
    Serial1.println("AT+CWMODE=1");
    show();
    Serial1.println("AT+CIPMUX=0");
    show();
    String cmd="AT+CWJAP=\"";
    cmd+=SSID;
    cmd+="\",\"";
    cmd+=PASS;
    cmd+="\"";
    Serial1.println(cmd);
    show();
    Serial.println("Finished!!!");
    Serial1.println("AT+CIFSR");
    show();
    cmd = "AT+CIPSTART=\"TCP\",\"";
    cmd += DEST_IP;
    cmd += "\",80";
    Serial1.println(cmd);
    show();
    cmd = "GET /1.txt"; // this is the fake page that does not exist in Google
    cmd += DEST_HOST;
    cmd += "\r\n\r\n";
    Serial1.print("AT+CIPSEND=");
    Serial1.println(cmd.length());
    show();
    Serial1.println(cmd);
    show();
    }

    void loop(){ }

    //Shows the output from the ESP directly to the serial monitor. This is helpful for debugging

    void show(){
         String keyword="Date:"; //this is the keyword we are searching on the response HTML header
         byte current_char = 0;
         byte keyword_length = keyword.length();
         long deadline = millis() + TIMEOUT;
         int temp=0;  
         readString="";  
         while(millis() < deadline){
                if (Serial1.available()) {
                      char ch = Serial1.read();
                      Serial.write(ch);
                      if (temp<200){
                           temp++; readString += ch; }
                      if (ch == keyword[current_char])
                      if (++current_char == keyword_length) {
                            Serial.println("Found it");
                           Serial.println(current_char);
                       }
                 }
         }
         int aux = readString.indexOf("Date: ");//Find the position of the word "Date:"
         /*translations:
         dia=day
         Mes=month  
         Ano=year
          Hora=hour
         minuto=minutes
         segundo=second
         */
         if (aux>0){
                String dia=readString.substring(aux+11,(aux+13));
                String mes=readString.substring(aux+14,(aux+17));
                String ano=readString.substring(aux+18,(aux+22));
                String hora=readString.substring(aux+23,(aux+25));
                String minuto=readString.substring(aux+26,(aux+28));
                String segundo=readString.substring(aux+28,(aux+31));
                Serial.print("Dia:");
                Serial.println(dia);
                Serial.print("Mes:");
                Serial.println(mes);
                Serial.print("Ano:");
                Serial.println(ano);
                Serial.print("Hora:");
                Serial.println(hora);
               Serial.print("Minuto:");
               Serial.println(minuto);
               Serial.print("segundo:");
               Serial.println(segundo);
          }
    } //___________________________________________________________________________________________________
    // Read characters from WiFi module and echo to serial until keyword occurs or timeout.
    boolean echoFind(String keyword) {

         byte current_char = 0;
         byte keyword_length = keyword.length(); // Fail if the target string has not been sent by deadline.
         long deadline = millis() + TIMEOUT;
         while(millis() < deadline) {
               if (Serial1.available()) {
                    char ch = Serial1.read();
                    Serial.write(ch);
                    if (ch == keyword[current_char])
                    if (++current_char == keyword_length) {
                           Serial.println(); return true;
                     }
                }
          }
          return false; // Timed out
    }

    0
    None
    diy_blokejmaxado

    Reply 1 year ago

    thats a nifty solution.
    I didnt have that much trouble getting it from an ntp server but more as a gimmick, never put it to work yet.
    time can be gotten from many places, also from several weatherstation api's such as weatherunderground

    0
    None
    jmaxadodiy_bloke

    Reply 1 year ago

    Hello,

    Can you explain what you mean by nifty solution ?

    JMaxado

    0
    None
    DurkVelljmaxado

    Reply 1 year ago

    Oi Jose,

    Muito obrigado!!!

    Steve