An exciting update on my Giant Lego Calculator project; I’ve succeeded in making a 7 segment display unit count upwards and also attached keys that change the value on the digit when you press them. This is a huge step forward after a lot of failed prototypes!

Watch it in action

In this first video watch it count from 0 to 9:

In this video I press keys from 0 to 3 to ddisplay that value on the digit.

Some pictures of the digits and keys

Here you see my current prototype with 4 keys attached to a single EV3.

There is a touch sensor in each key unit that responds to the key being pressed. Key faces can be swapped and changed.

Design inspiration

How did I come up with this design? I can’t claim this as an original idea. I was asking some friends on Facebook for advice and one of them forwarded this sketch to me which he had done some time ago. His idea was deceptive simple, as all the best ideas are! Connect two segments to each motor, and have them be out of phase with each other. Rotating the segments cycles through a sequence of on-off for both top and bottom. This means that each motor can drive two segments with one rotation and set them to one of four states. 4 motors can control 7 segments plus a decimal point, which means one EV3 can control a single digit. Perfect!

After a little work I came up with this design. It uses a 1×8 yellow or black tile for the faces of the segment. The interior of the segment is simple 1×2 technic bricks, with 1×1 bricks with a hole at either end.

Then I built this working prototype. 3 of the motors control the left, top two middle and right pairs of segments, with the bottom segment controlled by a motor on its own.

Code

Now that the building work is done the interesting question is how to control a single 7 segment digit? Like most programming problems this place boils down to coming up with an efficient data representation. Once I figured out how to efficiently represent the states of the digit and its segments then the code to rotate the motors was trivial!

Each segment pair is represented as a pair of bits, stored in a 2D array. There is a simple function to compute the degrees of rotation between two states, and another array maps each rotation onto a motor. In all the code required to run this is about 100 lines total. A lot of pre-work in how the segments are constructed and thinking about the code leads to a very efficient implementation.

Each pair of segments can be in one of four states: off-off, on-off, off-on, on-on. This lends itself perfectly to a binary representation using two bits. But rather than represent the state of the digit in a single byte I used an array of four integers to hold the state for each motor. A digit is encoded as a sequence of state values. The challenges then boils down to: what is the minimal number of motor rotations to move from state to state?

As you can see from my notebook below this again was easily solved using a little maths. Given the design I made all you need to do is rotate that motor by a positive or negative multiple of 90 degrees to move between states.

This results in compact and efficient code. It assumes a blank initial state and then counts up from 0..9 and displays E (for error) and then reverts back to blank to begin counting again. The changeState() function is where the magic happens; it takes the current state (from 0 to 3) and the desired state (from 0 to 3) of a segment pair and then computes the minimal number of rotations needed for each segment pair to move between those states. The rotationDegrees() function computes the rotation amount needed to move between states.

All of the state information is stored in the two-dimensional states[][] array. It defines the states for each possible display value. To change between two values the changeState() function looks up an array in the states table, and then calls the rotationDegrees() function to determine how much to rotate the motor by. The motorMap[] array is a convenience so that I don’t have to hard-code motor names into the code.

What about if I want to change what is displayed on the digit based on a key being pressed? Again the code is remarkably simple. I connect a touch sensor to ports 1 through 4, and based on the touch sensor pressed change the digit displayed.