View the source code for this project here. 

Image processed by CodeCarvings Piczard ### FREE Community Edition ### on 2014-01-04 04:19:31Z | |


A commission for an artist workshop, the Ribbons Timer is a large format mechanical countdown timer that uses ribbons on rollers to display numbers, driven by small motors.


The timer was intended to show the time remaining that a current artist was in residency at the workshop, displayed in in days, hours, minutes and seconds.


IMG_0157My office for a few months during prototyping and development.

Sometimes I wonder what all the wires do…





Driven by ARDUINO, the system controller manages the following:

  • Keep track of the time using a real time clock module.
  • Maintain a target time for countdown.
  • Give the user the ability to set the current and target time and date.
  • Detect the ribbons current position by reading sensors on each ribbon.
  • Determine what position each ribbon should be in.
  • Move the ribbons each second to show the correct countdown time.
  • Manage erroneous behaviour and shut down problematic ribbons in case of fault.
  • Display the current state of the system.


IMG_0169An LCD display gives the user access to set the time and date, and set a target for the count down, such as 5.30 pm on Friday the 11th of August 2014.



To move the motors the Sparkfun 4×4 Driver Shield. This neat shield plugs on top of the Arduino Uno or Mega, and uses a Parallel Port adapter to connect directly to the DC motors. Setting up to 16 bits high or low turns on the motors.

To vary the speed of the motors, a software PWM library was created. It works by introducing a four step cycle. If a motor is deemed to be on for 1/4 power, then the motor is turned on for one of four of the cycles is activated. If the motor is on 100 percent power, then the motor is on for all four steps of the cycle.

void ItteratePWM()
  AdvanceGlobalPWMCycle(); //Change to the next PWM cycle
  CalculateNextPWMBufferValues(); //Set Motors
  PushTo4x4Shield(LowMotorByte, HighMotorByte); //Push to the motor controller chip

void AdvanceGlobalPWMCycle()
  globalPWMCycle == 4 ? globalPWMCycle = 1 : globalPWMCycle++;

void CalculateNextPWMBufferValues()
  //reset the motor buffers
  LowMotorByte = 0;
  HighMotorByte = 0;

  //loop through each motor/ribbon
  for(int idx = 0; idx<ribbonCount; idx++)
    //Set the masks based on the current motor/ribbon
    byte lowMask = 0;
    byte highMask = 0;

    if(idx <=7)
      lowMask = 1 << idx;
      highMask = 1 << idx % 8;

    //set the motors based on the current pwmCycle and ribbon duty
    if(RIBBONS[idx].pwmDuty >= globalPWMCycle)
      LowMotorByte = LowMotorByte | lowMask;
      HighMotorByte = HighMotorByte | highMask;

void PushTo4x4Shield(byte lowbyte, byte highbyte)
  digitalWrite(LATPIN, LOW); // Prepares latch
  shiftOut(11, 13, MSBFIRST, highbyte); // shift data for OUT8-OUT15
  shiftOut(11, 13, MSBFIRST, lowbyte); // shift data for OUT0-OUT7
  digitalWrite(LATPIN, HIGH); // latch


EIMG_0196ach sensor reads a binary number that is embedded using light and dark lines behind each number on the ribbons.

In development the original printed white lines were not sufficient to give a strong reading, so a second attempt using reflective material was performed. This also proved to be unreliable.


The final version used a mix of Silicone and Graphite that was painted over the white lines.

IMG_0197Graphite absorbed the infra red light of the sensors, and, interestingly, the black material of the canvas reflected it.

The contrast was sufficient for a good detection to be made.


The system keeps track of the EDGES, and looks for the start of the GRAPHITE block. It tracks which bit has been found from zero to three, and can detect when it is in open space between the number bits. So long as the contrasting is working it can accurately detect the current number.

To make management of the pins easier, two Multiplexers were used to read the 18 positioning sensors.

Sensor calibration is shown below. Each sensor can have its sensitivity adjusted.

IMG_0222      IMG_0217



IMG_0145The length of the  Ribbons are around 1.5 meters long, with numbers from Zero to Nine for most. The Tens of Days ranging from ZERO to THREE.

To accommodate for different lengths of the ribbons, the roller assemblies have varying rollers installed.


The final tension is provided by the weight of the motor.

Each roller can only move in one direction due to the method used for sensing the ribbons location.

If the ribbon direction is reverse, the bits order from LSB to MSB, and change the numbering. They will still register, but be incorrect.

The rollers are made form PVC piping, with bearings inside each one housed in a small wooden CNC milled housing.



Here we can see that the ribbons are wrapped around many rollers, in a zigzag formation.

The motor assembly is down below the wires, adding tension to the ribbon.


Several Ribbon drive assemblies IMG_0190are bolted together to give meaningful values.

Three numerals for days.

Two each for Hours, Minutes and Seconds.




While the system is 5 volts, the motors are 12 volts. An ATX power supply was jigged up to give more than ample current to run all the motors at onces. The maximum draw of each motor is 1.5 amps when under heavy load. IMG_0194

If all motors are running, which can happen when tracking to the first countdown location, there could be up to 15 amps being pulled.

15 x 12 = 180 watts.

The 600 watt power supply gives plenty of overhead so as not to get hot, or dip in voltage as the current turns on.

IMG_0193A number of fused circuits was installed, with a small power bus to provide direct power to all of the circuits in the system controller.



IMG_0184The system starting to take shape during testing.

In total there are four banks of ribbons.

  • DAYS