Treindraaiklok

Summary

This is a summary of a clock I built. Some years ago I bought some digits from an old NS (Dutch Railways) clock. These resided in a cardboard box for a long time waiting to be changed into a working clock. The digits consist of two cylinders transporting a plastic coated cloth with printed digits. On top of each digit a gear is placed that converts the plane of rotation, and provides the mechanical interface to the old host, the railway sign.
I wanted to make a clock, with as little modifications to the original as possible. Also, I liked the idea of being able to place the digits in free order, not necessarily HH:MM, or at equal distances from each other. Just to make it easy to change their place in my interior, or to make the readout more interesting.
In previous projects, I used MSP430 or AVR xMega processors with the GCC compiler. For this project, I decided to use an Arduino. I heard so many good stories about it (as member of Hackerspace Tkkrlab)that I thought it would be good to try some Arduino programming myself. I’ll write my experience down below.

Drive Train

Gears

Broken...

Method to drive out wedge

Grinded down spike as tool

All four unmodded digits

The original gearing provided a big toothed wheel on the outside of the digit to the drive shaft of the complete sign. I wanted to mount a small motor on top of the digit, with as little new parts as possible. The gearing as present on the digit provided one big advantage: one rotation of the drive axle meant moving the roll one digit further / back!
To interface with the drive axle, I wanted to use the original gears, but driving the main axle (on back side) from another angle. To do this, I had to remove the lateral axle. All gears were fixed with cotters / wedges which were pretty much stuck. Other members of Tkkrlab helped me by creating a beatiful but simple tool to remove the cotters: a nail which was ground down! It provided the right diameter, and a good interface to a hammer! With aid of this tool I was able to remove 3 out of 4 axles without damage, the fourth was broken, unfortunately.

Servo’s

To rotate the digits I wanted to have a simple motor construction. Years ago I looked into driving the digits with rubber tracks and a huge motor with gearing, but it became too bulky to be nice. When looking for a simple, small solution I found the ‘continuous rotational servo’ from Parallax. I ordered one to try it, but the first test immediately showed that it was way too sensitive for input PWM change, there was a minimal range over which the speed could be changed, and the ‘center’ trimming was also VERY sensitive. This might be OK for an R/C vehicle, but not for a clock that should be able to run unattended for a long time. A second issue I had with this servo is that it is VERY noisy. The sound resembles the screaming of a young pig, which is not the sound I’d like my clock to have.

First test continuous rotational servo

When taking a look in the parallax servo there’s just a normal servo controller, without potmeter to determine the position of the end axle, and no end stop on the (plastic) gears. I decided to buy servo’s with metal gears and ended up (budget servo with good ratings) with the MG995 servo from DealExtreme. These servos have metal gears, and I found them very easy to modify. See end pin modification below:

MG995 Tower Pro

Servo electronics + motor

End pin in gears

End pin removed

The bevel gear I removed from one of the axles had to be mounted to the servo. The hole in the bevel gear was a bit larger than the radius of the output axle of the servo. I found a bit of aluminium tubing in the local R/C store, which fit loosely over the output axle, and snug in the bevel gear. Using some bison glue I was able to join these parts together. I used the original cotters to secure the bevel gear to the aluminium tube.

Driving the servos

With a ‘normal’ servo hack (removing end pin, replacing potmeter with fixed resistor divider) there is very little room for speed control. I wanted to have some form of speed control, as I already found out with the parallax servo that slower speed equals less noise from the gears. Normally you’d use an H-bridge driver for something like this, but I didn’t feel like doing that for several reasons:

  • I wanted to try the Arduino environment, and Arduino ‘AnalogWrite’ means PWM of circa 490Hz. I didn’t want a ‘singing’ tone from my motors, and 490Hz lies well within hearing range.
  • The motor is supposed to run in two directions, and I had very little room to cramp a full bridge driver
  • Digital control would mean a PWM and a direction line. I had some very nice old telephone cable lying around with 4 conductors, of which I wanted to use GND, Power, PositionDetection (sense when complete digit is transported), and 1 line for motor control

In the end I came up with this schematic (click for readable version):

Explanation: R1&R2 form a divider to half the supply voltage. A1B buffers this voltage. When the input is disconnected, the motor will halt, as R4 keeps the input of A1A (also buffering) on the same half-supply-voltage. R3&C1 form a lowpass filter for the PWM signal. If an input is connected, the difference between M1&M2 motor connections can only get as large as plus or minus half the supply voltage. Result: 5V in gives full throttle forward (+2.5 V over motor), 0V in is full throttle reverse (-2.5V over motor), 50% PWM will make the motor stop as there will be (almost) no difference between the input voltage and the divider voltage. THe opamp I used for this circuit is a TCA0372 because of its high current rating and single supply operation. The input and output are not completely rail-to-rail, thus limiting the control range a bit further, but it still functions as wished for.
Using the circuit above I was able to fit the new driver into the housing of the servo’s; this made me very happy since I didn’t like the idea of dangling motor drivers and / or bunches of wires all around the digits. See the ‘layout’ of the board below.

mounting of electronix (ex wires) in servo housing

mounting of electronix (ex wires) in servo housing

Servo motor driver, component side

Servo motor driver, solder side

Servo mounting

To mount the servos to the digits I used a piece of angled aluminium. Slits were sawn in the places where the servos needed to be mounted, and I was able to mount the servo holder to the original screws on top of the digits. The gears were glued on a piece of aluminium tube that fit snug over the output wheel of the servo and into the plastic gear. I used some 2-component glue to fix the tube to the servo output shaft.

Position feedback

Now I was able to drive the digits from the arduino board, I had to know when to start / stop driving the digits. One of the first things I noticed when looking at these digits with the intention of making a clock was that one turn of the cogged wheels / axles converges to moving a digit one step forward or back. So what I needed was a way to detect when the axle had made one full turn. Several ways sprang to mind here; use reed switches, hall sensors, optical sensors (ripped from an old mouse?), microswitch,….
I chose to use a small neodynium magnet, orderable at Farnell in combination with reed switches. The Atmega pins of the Arduino can provide a pullup, I just needed a switch to pull these pins down. I must admit I first bought some Hall sensors, but the look of these just couldn’t please me, and adjusting there position to get a good readout would mean fiddling / bending their pins, not something to yield a nice result to look at. Reed switches might bounce a bit, but that’s no problem in this clock. The ‘pro’ of the reed switches was that they look vintage (matching the clock), and through the glass tube you have an immediate look at the effect of magnet position on your contacts.
To mount the magnets I made a small pocket in each gear wheel glued to the servos. The tricky part here, is that the metal gears in the servos attract the magnets, so they tend to fly out of their pocket while the glue is curing. I prevented this using cocktail sticks and matches (see pictures below). The magnets are really great,for some servos the magnet-to-reed distance is >3mm, and still they manage to reliably trigger the reed. I fiddled quite a lot with the reed’s position, finding out that the end of the reed switch is more sensitive than the middle.

Magnets

Pocket for magnet

Match stick holding the pressure

Match stick holding the pressure

Top view of gluing setup

Result: glued magnet

Magnet and reed switch, final assembly

Arduino & Proto Shield

Until now I used the Arduino by sticking wires into the sockets of the Arduino, I found the time had come to make a more permanent solution. I wanted to use a real time clock (RTC) to not have to set the time after power outages or maintenance, and to and minimize clock drift. My first solution was to use a piece of proto board, but as many have found out the pitch between two of the four connectors of the Arduino is NOT 2.54mm….. Also, I found my own protoboard a bit clumsy-looking and it was mechanically unstable so I decided to go Arduino-solution-style all the way and bought the Olimex Arduino Proto Shield.

Side by side, old and new

Hand soldered board

?Que Pasa?

Olimex proto shield

Detail; switch and small power vias

Protoshield

The protoshield was a great benefit for this project. It has several features really helping out; 2 buttons, a LEDs and several places to connect wires for GND and… 3V3! This made me wonder a bit; I designed everything for 5V, thought the voltage most used in projects was 5V and now I find out that this board is using 3V3 as standard? Interesting…. One of the features of this board is that it has small vias between the proto grid that provide GND and 3V3 connectivity all over the board. Very handy most of the time (also for decoupling), but selection of ‘VCC’ between 3V3 or 5V would have been appreciated…..
Something else that surprised me is that two pins protruded from the board and touched the electrolytic caps from the Uno. I clipped them ;)

Arduino

I never used an Arduino before, always wrote my own code from scratch. I heard a lot of people being enthousiastic about the Arduino, and thought this project would be a great test case; no strict millisecond timing requests, simple IO, a few PWM lines. So I started out on the Arduino, and found out it does not suit my needs in a complete project. For prototyping this is a great product, and for starters in electronics this is also quite a good start, but before I’ll write my positive experience I have to point out some drawbacks:

  • Documentation is quite good for starters, but not if you’d like to know what is REALLY happening; what is the I2C bitrate? Is the SerialWrite function interrupt based, or blocking? This info is probably around somewhere on the web, but not in the reference
  • The IDE does not provide code completion
  • Why do I have to call two functions that write AVR registers to make a pin tristate with pullup? I’d think that that should have been an good addition to the language
  • To unlock the power of the ATMEGA you’d be writing your good old programs; PWM (incorrectly named analog output) is ‘around’ 490 Hz and frequency is not settable by standard Arduino functions, which would have been an improvement both in functionality as in programmability
  • I’m afraid the ‘simpleness’ of the Arduino environment lets people create solutions that waste processor (peripheral) power. It’s a bit like writing LabView code: it’s very easy to get a simple thing going, but for a GOOD program that gets a bit more complex you have to be able to use programming techniques, something not really developed by using Arduino

I guess I’d start a new project writing code from scratch, IF it is to be used for a permanent solution. The big benefits of Arduino I see in:

  • Easy implementation of external IC’s. I did NOT have to look into the DS1307 datasheet except for the pinout when soldering. That’s cool! Chip demo’s can easily be made
  • Debugging by sending messages is really easy. Although I still wonder if sending a long string blocks all my other code
  • Making simple projects that are allowed to be completely messy is wonderful using the Arduino.
  • Using the results of other people’s projects to get something working fast!

The clock works by letting the user run all rolls to start position at startup. After that, one digit is turned at a time to the position needed as dictated by the DS1307. Several time limits are used to ensure the roll is moving, and is not broken by continuous pulling; when a magnet is not detected in several seconds, the clock just stops. Not elegant, but better safe than sorry. Programming / change of time is done by programming the Arduino. Time adjustment by using the buttons is on my whish / to do list.

First test run

First test run. Can you spot this was at the end of the year ;) ?

Noise!

Now, after the first test run the clock ran for several days in my living room. It really looks great, but it was quite noisy, especially when one of the rolls needs to roll all the way back. I thought something like a bell jar would solve this, and started looking around for these items. I found most of them were quite expensive ( > EUR 50 each), and buying four of them would ruin my budget and fun.
Looking around in the post-christmas sale at the Intratuin (gardening warehouse) I found a vase that had just the right dimensions to fit over a digit. I took 4 of them home for a total of EUR 16! The vase had the right diameter, but was a bit high. I used PVC end caps for sewage pipes to raise the digits. To let the cable exit I bought a glass engraving Dremel bit, and ground away an opening. Exciting to do!

Cable exit

Grinded cable slot

Preparation and grinded cable slot

The vases do a wonderful job muffling the servo sound!

Housing Electronics

At last, the end is near….. I made a small housing for the electronics, using ugly DIN connectors to get a good retro feeling.

Internal cabling, protoshield, Arduino

Housing with connectors and switch

Finished digits

Side

Front

back

Evaluation

One of the things that cost me some time is to use speed control; in the end I didn’t use it, I just go ‘full throttle’ back or forward. Full throttle means the servo motor is driven by circa 2,5 Volts, which is slow enough for not making a lot of noise. But at least I’ve got the opportunity to scale the speed, maybe someone else can use the circuit with all its capabillities…..
The clock has been running for a week or so by now, and its a pleasure to the eye, and a real conversation starter!

Arduino code

Available for download here

#include <Wire.h>
#include "RTClib.h"

#define BUT_SET         6
#define BUT_OK          7

#define SPEED_STOP 127
#define SPEED_FWD  255
#define SPEED_BACK 0

#define MIN_UNITS_SPEED 3
#define MIN_TENS__SPEED 5
#define HRS_UNITS_SPEED 9
#define HRS_TENS__SPEED 10
#define MIN_UNITS_POS   2
#define MIN_TENS__POS   4
#define HRS_UNITS_POS   8
#define HRS_TENS__POS   12

RTC_DS1307 RTC;
unsigned char min_units = 0;
unsigned char min_tens  = 0;
unsigned char hrs_units = 0;
unsigned char hrs_tens  = 0;

void FindStartPos(char speedpin, char positionpin)
{
  while(digitalRead(BUT_OK) == HIGH);
  while(digitalRead(BUT_OK)  == LOW);
  while(digitalRead(BUT_OK) == HIGH)  
  {
    analogWrite(speedpin, SPEED_BACK);
    delay(100);
  }  
  analogWrite(speedpin, SPEED_FWD);
  while(digitalRead(positionpin) == HIGH);
  analogWrite(speedpin, SPEED_STOP);
}

struct roll
{
  unsigned char numbers[10];
  unsigned char length;
};

struct roll min_units_roll = {{1,2,3,4,5,6,7,8,9,0},10};
struct roll min_tens__roll = {{0,9,8,7,6,5,4,3,2,1},10};
struct roll hrs_units_roll = {{0,9,8,7,6,5,4,3,2,1},10};
struct roll hrs_tens__roll = {{1,2,0},3};

unsigned char search_roll(char to_be_number, unsigned char *current_number , struct roll *roll_p)
{
  char count;
  char number_current_index;
  Serial.print("|SR. To be number: ");
  Serial.print(to_be_number, DEC);
  Serial.print(";");
  Serial.print("|SR. current number: ");
  Serial.print(*current_number, DEC);
  Serial.print(";");
  //stop if nothing has to be done
  if( *current_number == to_be_number )
    return SPEED_STOP;
  //find current position on roll
  for(count = 0; count < (roll_p->length) ; count++)
  {
    number_current_index = count;
    Serial.print(number_current_index,DEC);
    if(roll_p->numbers[count] == *current_number)
      break;
  }
  //min_units_current_index gives index to value of current position
  Serial.print(number_current_index, DEC);
  //See if new digit is placed before old digit on roll
  for(count = 0 ; count < number_current_index ; count++ )
  {
    //if so, update min_units (in advance!) and give direction to turn
    if(roll_p->numbers[count] == to_be_number)
    {
      *current_number = roll_p->numbers[--number_current_index];
      Serial.print("; back, min_units: ");
      Serial.print(*current_number, DEC);
      return SPEED_BACK;
    }
  }
  //otherwise, turn other way
  *current_number = roll_p->numbers[++number_current_index];
  Serial.print("; forward, min_units: ");
  Serial.print(*current_number, DEC);
  return SPEED_FWD;
}

char movestep( unsigned char speed, char speedpin, char positionpin)
{
  int loopcounter;
  analogWrite(speedpin, speed);
  for(loopcounter = 0; loopcounter < 3   ; loopcounter++)
  {
     delay(300);
     if(digitalRead(positionpin) == HIGH)
       break;         
  }
  for(loopcounter = 0; loopcounter < 300 ; loopcounter++)
  {
    delay(50);
    if(digitalRead(positionpin) == LOW)
      break;  
  }
  analogWrite(speedpin, SPEED_STOP);
  if(loopcounter > 250)
    return(1);
  else
    return(0);
 }
 
void setup()
{
  pinMode(HRS_UNITS_SPEED,OUTPUT);
  pinMode(HRS_TENS__SPEED,OUTPUT);
  pinMode(MIN_UNITS_SPEED,OUTPUT);
  pinMode(MIN_TENS__SPEED,OUTPUT);
  analogWrite(HRS_UNITS_SPEED,SPEED_STOP);
  analogWrite(HRS_TENS__SPEED,SPEED_STOP);
  analogWrite(MIN_UNITS_SPEED,SPEED_STOP);
  analogWrite(MIN_TENS__SPEED,SPEED_STOP);
  pinMode(HRS_UNITS_POS,INPUT);
  pinMode(HRS_TENS__POS,INPUT);
  pinMode(MIN_UNITS_POS,INPUT);
  pinMode(MIN_TENS__POS,INPUT);
  digitalWrite(HRS_UNITS_POS, HIGH);
  digitalWrite(HRS_TENS__POS, HIGH);
  digitalWrite(MIN_UNITS_POS, HIGH);
  digitalWrite(MIN_TENS__POS, HIGH);
  pinMode(BUT_SET,INPUT);
  pinMode(BUT_OK ,INPUT);
  Serial.begin(57600);
  Wire.begin();
  RTC.begin();
  if(!RTC.isrunning())
  {
    Serial.println("RTC is not running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  FindStartPos(HRS_TENS__SPEED, HRS_TENS__POS);
  FindStartPos(HRS_UNITS_SPEED, HRS_UNITS_POS);
  hrs_units = hrs_units_roll.numbers[0];
  hrs_tens  = hrs_tens__roll.numbers[0];
  FindStartPos(MIN_TENS__SPEED, MIN_TENS__POS);
  FindStartPos(MIN_UNITS_SPEED, MIN_UNITS_POS);
  min_units = min_units_roll.numbers[0];
  min_tens  = min_tens__roll.numbers[0];
}


void loop()
{
  int incoming;
  char minuteunits,minutetens,hrstens,hrsunits;
  char error;
  DateTime now = RTC.now();
  Serial.print("|main. now:");
  Serial.print(now.minute(), DEC);
  Serial.println();
  delay(1000);
  minuteunits = now.minute() % 10;
  minutetens  = now.minute() / 10;
  hrsunits    = now.hour() % 10;
  hrstens     = now.hour() / 10;

  Serial.print("|main. min_units:");
  Serial.print(min_units, DEC);
  if( minuteunits != min_units)
  {
    error = movestep(search_roll( minuteunits, &amp;amp;amp;amp;min_units, &amp;amp;amp;amp;min_units_roll), MIN_UNITS_SPEED, MIN_UNITS_POS);
    if(error)
      setup();
  }
  if( minutetens != min_tens)
  {
    error = movestep(search_roll( minutetens, &amp;amp;amp;amp;min_tens, &amp;amp;amp;amp;min_tens__roll), MIN_TENS__SPEED, MIN_TENS__POS);
    if(error)
      setup();
  }
  if( hrsunits != hrs_units)
  {
    error = movestep(search_roll( hrsunits, &amp;amp;amp;amp;hrs_units, &amp;amp;amp;amp;hrs_units_roll), HRS_UNITS_SPEED, HRS_UNITS_POS);
    if(error)
      setup();
  }
  if( hrstens != hrs_tens)
  {
    error = movestep(search_roll( hrstens, &amp;amp;amp;amp;hrs_tens, &amp;amp;amp;amp;hrs_tens__roll), HRS_TENS__SPEED, HRS_TENS__POS);
    if(error)
      setup();
  }
}

3 thoughts on “Treindraaiklok

  1. [...] to display the digits 0 through 9. It’s been many years, but [Victor] finally got around to building a clock out of these single digit displays and we’re loving the [...]

  2. [...] to display the digits 0 through 9. It’s been many years, but [Victor] finally got around to building a clock out of these single digit displays and we’re loving the [...]

  3. MedUsa says:

    Haha heel leuk gedaan! Kun je trouwens de buizen niet vacuüm zuigen ? dat zou het geluid aanzienlijk verminderen denk ik ( dan kun je ook full auto voor en terug )

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>