Categories
3D Print algorithm Arduino hardware software

LED Matrix Hourglass Timer

I was intrigued by a recent project I saw that used two LED matrices placed diagonally to create an hourglass. The animated movement of the LEDs seemed a good simulation of the sand particles moving through the hourglass.

As is common, the project emphasized on how the hardware was wired together, which is trivial, without much explanation of its more challenging/interesting software aspects.

Additionally, most of the solutions I saw used an inertial position sensor to determine the position of the matrix, which seemed overkill for the simple functionality required.

So I decided to explore this topic and here is my solution.

Hourglass Basics

Hourglass

An hourglass (also known as a sand clock) is used to measure the passage of time. An hourglass is usually made up of two symmetric glass bulbs connected vertically by a narrow neck through which sand, or other suitable material, goes from the upper to the lower bulb under the action of gravity. The hourglass is turned upside-down to start another timer when all the sand runs into the bottom bulb.

Each hourglass is designed to measure a specific time interval – the time it takes to empty one bulb into the other. This time is regulated by factors that include the amount and size of the sand particles, the bulb size and the neck width.

Hardware Assembly

LED Matrices

The LED matrices are the commonly available 8×8 LED modules controlled by a MAX7219 controller. For this project the matrices with smaller PCBs that fit under the LED module are the best form factor.

Orientation Sensor

To keep things simple the orientation of the matrix is measured by a simple digital input wired to a tilt switch. These small and inexpensive sensors are available in many shapes and sizes, but all work similarly – a digital signal in one orientation and no signal for the opposite orientation, as shown in the figure below.

Internally the switch commonly has a metal ball that moves to make/break the electrical circuit.

This sensor is not able to detect intermediate states (eg, the hourglass on its side) but I am happy to live with that tradeoff compared to a much more expensive inertial sensor.

Hourglass Bezel

For testing purposes, using Fusion 360, I designed and 3D printed an hourglass shaped bezel to hold the 2 modules a jam fit.

This keeps the modules in the correct diagonal orientation with respect to each other and allows me to conveniently rotate the whole device easily.

Software Implementation

The software discussed in this section is available as the MD_MAX72xx_Hourglass example code with the MD_MAX72xx library.

Simulating the Hourglass

When thinking about this closed system, the top bulb can be considered a silo filled with sand with an exit at the bottom. As the sand passes through the neck, the sand particles above the moved particle also move into the void below and this is repeated all the way to the top of the sand reservoir.

As the mechanism is driven by gravity, it can be thought of as the particles trying to minimize their potential energy with respect to the hourglass neck.

Once the sand passes the neck it will fall (again trying to minimize the potential energy with respect to the base of the lower bulb) until it reaches the rest of the sand pile, at which time it will move over the surface of the existing pile trying to find its minimum energy state.

A good proxy for simulating the energy of each particle could be the distance between each particle and the neck/base, as potential energy is related to the height of each particle from the relevant ‘zero energy’ point.

Some Definitions

As these ‘zero energy’ point are points to which the particles are attracted, I decided to call them attractors in the software.

There are four attractors relevant to the simulation, shown in the figure at left, called HIHI, HI, LO, LOLO. When particles are travelling from the top to the bottom bulb, they are initially attracted to the HI attractor (the bottom of the top bulb) and then the LOLO attractor when they pass through the neck.

Conversely when the hourglass is turned over the attractors become the LO and HIHI attractors.

When wiring the matrices together, the module with the HI and HIHI attractor is module 0 (the first in the chain) and the other is module 1. The electrical connections are from the top to the bottom modules, as shown on the left.

Software Structure

There is a relatively simple structure to this software:

  1. Initialization (ie, the setup() function).
  2. Check if hourglass has changed orientation.
  3. At the appropriate time
    • Moving all the particles in both bulbs
    • Moving a particle from the upper to the lower bulb if one is ready to drop
    • Updating the matrices with the new arrangement

We’ll discuss each of these in turn below.

Data Structures and Static Data

Two simple data structures are defined to help manage the simulation.

The first is small container for the row and column coordinates of a LED ‘particle’.

typedef struct
{
  int8_t r, c;
} coord_t;

The next is the definition of a particle, which comprises its coordinates on the display and the attractor that is controlling its motion.

typedef struct
{
  attractorId_t att;
  coord_t p;
} particle_t;

The attractor enumerated type has the values as discussed earlier. The enumerated values are specifically nominated as they are used as the index into an array of constant coordinates for each of the attractors.

typedef enum 
{ 
  ATT_HIHI = 0,
  ATT_HI = 1,
  ATT_LO = 2,
  ATT_LOLO = 3
} attractorId_t;

Finally, an enumerated type is defined to track the current orientation of the hourglass (ie, the direction in which the particles are flowing due to the action of gravity).

// flow direction for particles (HI->LO or LO->HI)
typedef enum 
{ 
  FLOW_HI2LO, 
  FLOW_LO2HI 
} flowDirection_t;

Initialization

The particle array is statically initialized when it is declared. As the matrix is on the diagonal corner, this seemed an easier way to get a specific pattern in the top bulb at the start.

The normal hardware initialization happens in setup(), and the display is updated with the starting particle arrangement.

Check Hourglass Orientation

The hourglass orientation is given by a simple digital input from the tilt sensor. When that input changes it needs to be processed into a direction indicator (FLOW_* enumerated value) and a different attractor (ATT_*) for each particle.

For example, if a particle is in the top bulb, travelling FLOW_HI2LO directions, is currently attracted to ATT_HI. Once the flow is reversed (to FLOW_LO2HI) that particle is now attracted to HIHI.

Moving Particles

Particle moves occur periodically, controlled by the total timer duration, 30 seconds for the example code. Given that all the particles need to transition to the next bulb by the end of the period, each time slice is a total time divided by the number of particles.

For each particle, each of the 8 points surrounding the particle need to be tested to see if the particle should move into that location. A particle can move into a new location if:

  1. The location is unoccupied.
  2. The location is within the bounds of the hourglass bulb containing the particle.
  3. The distance to the particle’s attractor is the minimum distance of the current set of potential locations.

The distance between the particle and its attractor is the length of the line segment that connects the two points, given by d=√((r2 – r1)² + (c2 – c1)²). As d is just for comparison the square root is unnecessary and the software uses d².

If two or more points are found to be equal minima, then a random choice is made between them.

Transition Particles

Once all the particles have moved, a special check is made to see if a particle is at the ATT_HI or ATT_LO points (depending on the flow direction).

If one is found, it is moved to the top of the lower bulb if there is no other particle there and its attractor is changed so that it travels to the bottom of the hourglass.

Display Update

The display update clears the display and then redraws all the particles at their current coordinates.

So does it work?

Given the simplicity of the approach and simulation code, the LED hourglass display looks good and works surprisingly well.

One reply on “LED Matrix Hourglass Timer”

Leave a comment