Math Scroller

Updated 10 December 2021

I was looking for something educational to 3D-Print for my child in Thingiverse and came across the concept of the Math Spinner. I found the models lacked a method of checking the answer so I wanted to automate it. The core design is inspired by the ‘Math Spinner’ by FunFunBoy (https://www.thingiverse.com/thing:1604600) and the ‘Math Spinner Enhanced’ by Pauloblank (https://www.thingiverse.com/thing:452651).

The Math Scroller at its core, uses eight absolute encoders, a handful of 8-Bit I/O Expanders, and an Arduino Nano to read the values and check the answer function. A piezo provides some basic sounds and some RGB Leds are used to finish off the effects for a correct and incorrect answer.

From concept design to the completed unit, the project spanned several months of after-work hours. With many design iterations, excessive part purchases, and prototype failures along the way. In the end, the following tools would be required to repeat this project:

  • 3D CAD Software (To make design changes)
  • Electronic Circuit design software (To make design changes)
  • Soldering Iron
  • 3D Printer - A dual-extruder printer with a 300x300 bed size (0.2 was used for layer heights and some supports were used on some parts.
  • Drill (drill bits for reaming holes and thread taps to help seat screws)
  • Wire stripper and crimping tools
  • Pocket voltmeter
  • A large Bread Board

Parts Required

As for the Equipment Used in the final design:

Item

Qty

Part No

Description

Link

MCP

4

MCP23008

8 Bit I/O Expander with I2c

Core Electronics 

S1

1

TL1220R2BBBGHALO

Switch with Red LED

Mouser

S2

1

TL1220R2BBBYHALO

Switch with Yellow LED

Mouser

S3

1

TL1220R2BBBGHALO

Switch with Green LED

Mouser 

S4

1

TL1220R2BBBBHALO

Switch with LED

Mouser

IC5

8

PAC18R1-43D19F

Absolute encoder 16 positions

Mouser 

SP1

1

PS1240

Piezo speaker

Core Electronics

M1

1

COM-09288

Pot 10k ohm linear

Core Electronics 

D2-D5

4

N/A

White LED

See comment below

D6-D9

4

COM-09264

RGB LED common Cathode

Core Electronics

Q1

1

NDP6020P

P-Channel MOSFET 20V 24A - low Vgs(th)

Core Electronics

R*

-

N/A

Resistor 220k

Core Electronics

R*

-

N/A

Resistor 100k

R*

-

N/A

Resistor 10k

R*

-

N/A

Resistor 470

C1**

1

N/A

Capacitor 200uF

Core Electronics

D1

1

1N5819-B

Schottky Diodes & Rectifiers 40V 1A

Core Electronics

T1

1

2N3904

Bipolar Transistors - BJT TO-92

Core Electronics

Vcc

1

TOL-15204

USB Power bank

Core Electronics 

misc

1

FIT0151

DC barrel jack

Core Electronics

misc

4

N/A

PCB boards

Banggood

misc

4

N/A

20 Pin IC Socket

Banggood

misc

18

N/A

M3 x 6mm screws and washers

misc

1

CAB-10646

Ribbon cable 6x1 (for internal wiring)

Core Electronnics

*White LEDs were pilfered (desolder-ed and reused) from a dead household LED bulb.

** Capacitor value alters how long the charge remains in the start-up switch, so you can size this as you desire.

Source Code

The code that runs on the math scroller can be found at this GitHub repo or a zipped version available here.

The Design Process

I want to take a bit of time to talk through how It went from the Thingiverse designs to the final design. I have found previously that even though the ideas I had had along the way may not have worked for my project, it may trigger the spark needed for someone else’s design of their project.

First Concept:

The core objective of the design was to try and mount all electronics internal to the design.

An image of the first concept of the math scroller, with internal electronics

The first concept design, shown above, had a series of nodules inside each number ring so that as it was rotated, a switch would be either indented or released. This would create a type of grey bit code to allow the Math Scroller to know which position each ring was in.

To cover the 11 positions on the scroller, four rows of switches per scroller would be required. This allowed me to know I was looking at a minimum of 32 inputs, excluding any outputs and other functions, which exceeds most small microcontroller boards. To overcome this a series of 8 Bit I/O Expander chips will be used to increase the I/O of the board used, which is a nano due to its small form factor.

An Led was also planned for each ring, so the user could know which value on the ring was being used. Other additional I/O included a dial for changing a timer value, power switch and Start buttons and a couple of spares ports for further ideas.

An image showing how the rollers would function in the first design

After 3d printing several sections it became apparent that to keep the desired roller size, the internal void would be insufficient to house all the electronics along with wiring and battery source.

Second Concept:

To increase the internal space, An idea to use a concealed drive belt to drive an encoder external of the rollers was developed. This would leave the entire tube free to house the electronic component as the equipment to determine the rollers' positions was now in an external section. The design was also more modular, meaning it should be easier to expand the total number of rollers if desired. As an added plus my son liked the more combination lock appearance of the device.

An image showing the second iteration of the scroller, now with separate electronics

The drive belt was 3d printed using some Jaycar TPE, but my ability to design the correct belt and toothed belt needs work as I found the belts would skip once a rotation. Although after some adjustments it worked without an issue.

Further testing of the belt combination demonstrated that the ratio relationship of the absolute encoder's output (16 positions) and the roller ring's positioning (11 Positions) was not generating the easiest input data to work with. Changing to a relative encoder would eliminate the issues but would then re-introduce the issue of not knowing the roller position each time the device was powered on.

Final Concept:

The final design concept was developed by switching the encoders inside the rollers and moving the electronics, wiring, and power supply around. This kept the combination lock appearance but simplified the interaction between the encoders and the rollers.

Testing of the encoders found that the value of the encoder was held until halfway through its rotation to its new position. So the rollers of the final design used the physical grooved tube to lock into their expected 11 positions, overriding the detenting of the encoders. Simplifying the expected output values. This is explained further in the Determining the Roller Position section.

Building The Final Concept

The Circuit

The overall circuit looks complex but it is mostly the same smaller circuits, repeated over many times.

To enable each I/O expander to work on the I2C, they require a unique address set for each of them that has been hard-wired into the circuit layout. The expanders also have a reset port on the Chip, which is inverted, so requires power for the chip to remain active.

A detailed schematic of all the electrical connections for this project

Powering on the Math Scroller

The power latching section of the circuit was adapted from Random Nerd Tutorials (https://randomnerdtutorials.com/latching-power-switch-circuit-auto-power-off-circuit-esp32-esp8266-arduino/) where changing the capacitance of C1 adjusts the length of time the switch is held active before a secondary signal is required. They have quite a good write-up on how it works but in essence:

  • Pressing S1 will power the Arduino and charge the capacitor C1,
  • the Arduino provides a return signal via D3 to hold T1 on
  • When the signal from D3 is removed, the capacitor discharges and T1 opens, disconnecting the Arduino and the rest of the circuit from power.

The other change from the tutorial circuit was to swap out the diode from the board output, with the led of the switch.

User Input:

Each of the four Press Buttons have their LED’s independently controlled by the Arduino board, this allows the different states of the program to be indicated by the state or the light:

Button

LED On

LED Off

LED Flashing

POWER

System is on

System is off

<not used>

MODE

System is using a time value to auto check

System will wait for user input to check answer

<not used>

START/CHECK

Answer is being checked

System is waiting to start

System is waiting for the user to input their answer

SOUND

Sound is enabled

Sound is disabled

<not used>

With the current code, using start/check with the sound enabled will play a ticking sound in sync with the led flashing of the start check button. A feature my son has since dubbed “Bomb Mode”

LED Current Consumption and Resistor Sizes

The eight modular segments share a mix of white LEDs and RGB LEDs. It should be noted that the current draw of 4 LEDs with the resistors selected are below the current draw threshold for the ports on the Arduino, so if the LED type was changed or the quantity was increased, say to drive all the 8 LEDs from the one port, a BJT or similar would need to be used to switch power from the VCC to prevent damage to the Arduino.

The resistor values on the schematic should work for most 5mm LEDs; however, you should consult the datasheet for what the max expected current draws for the LED are and select accordingly. This is often shown in the data sheets as the “Continuous Forward Current” value and is the maximum value.

The RGB LEDs used in this project can have smaller resistors than shown in the circuit, which will increase their brightness, but I found these bright enough to light up the clear PLA without also beaming through the coloured PLA.

An image showing the effect of varying the brightness of the internal LEDs

The brightness of the RGB LEDs needed to be reduced slightly, with a higher resistor, to prevent their glow from blinding out the roller's symbol.

3D Printing

The physical design of the final edition, exploded to show internals

The project was printed on a Creality CR-X, in PLA, at 0.2mm layer heights with 15% to 20% infill. Some parts had supports added but only if absolutely necessary. Due to the size of the back box, I had to print this on an angle on the bed as even the 300x300 bed size was just a little too small to fit square.

As I was using a dual filament printer I was able to print the Coloured and Clear PLA at the same time. But I spent a long time before printing these parts to determine how much material needed to be purged between colours. This was achieved by printing a bunch of small squares with a clear zero in them. By printing ten in the same print I was able to view how long it took to print with nice clear PLA. After one batch print, I was able to dial in the amount of purge material needed to print clear after each change.

All parts were printed without a brim or raft. If you have a glass bed and are finding you have trouble getting your PLA to stick, warm the bed up and give it a good clean with methylated spirits and a paper towel. Once the bed has evaporated the remaining spirits, wipe down with a microfiber cloth and your first layer will stick every time. And after cleaning or printing, never touch the bed with your hands, the oils from your fingers are a big factor in preventing the PLA from sticking to the bed and can be next to impossible to see.

3D printers are great for taking your idea and literally putting it into your hands. Sometimes you’ll find that what looked great on a screen doesn’t feel as good as it looked. Maybe the scale is out, or the ratio between parts isn’t right, or sometimes the parts just don’t go together because the way you want to assemble it isn’t actually possible.

A collage showing the evolution of the printed parts

These are some of the parts that were printed on purpose to test parts or assemblies to get the right feel. The whole part doesn’t have to be printed either if you're limited on your material or concerned about waste. I’d personally rather do a couple of test pieces before printing eight of the same 8 hour part.

For example, the ring pieces were used to determine how deep the locking support would be, incremental changes in 0.1mm on the depth made testing the different resistances for twisting the numbers easier to gauge.

The nylon belt was the only part 3d printed with a brim and worked quite well but took a few goes to get the design right. I’m looking forward to testing a few ideas out with that, now that I know it is possible.

Hardware Testing

When I have a new piece of kit to use, I like to test it on its own to get comfortable working with the coding of the parts, before trying to drop it into my projects as it saves on complicated fault-finding later. So for the I/O expansion chips, I set up one as an input only using a button press to supply the input signal to each port.

Once I was happy with that I added a second I/O expansion ship for outputting 8 LEDs. I set the code to pass each button press to the corresponding LED that would then become activated.

An image showing the expander under test

With that testing out of the way, it was time to assemble the whole circuit. As the Nano I had purchased only had solder ports, I used my UNO for testing until I was happy with the wiring.

A test rig with all components in the final design present

Wiring all the LEDs and push-button indicators for the whole device.

Software coding:

An image showing the completed circuit undergoing software testing

During the development of the coding, several versions of code were developed simultaneously to allow the testing of certain components and their functions during assembly. This included;

  • A code for testing the power latching circuit (LSP_Test)
  • a code file for testing all the LED’s and the power button (LED_TEST)
  • A code file for testing the functionality of each button. This covered things like turning the sound on and off, activating the timer mode, and the start and checking states (Button_Test)
  • A code for testing each of the I/O expanders (MCP_Test)

These codes were then used a second time when the parts were transferred to the PCB boards. This helped confirm if any errors were made during the transfer as I now knew the code already worked on the breadboard.

The testing and final codes use the following external libraries:

Interesting Coding - Button debouncing

I was looking for a way to perform button debouncing without using timer delays and found out that the recommended way was to use several unsigned long variables (the largest of the variables @ 32 bits each) to store the time and as you add more buttons you have to increase the number of unsigned long variables used. To minimize the size of variable memory being used, I designed a different method of debouncing and I think it is also a bit easier to follow than the code proposed on the Arduino forum guides.

For this design, only 8 bits are used for each button, although if a longer time was required the bitshift method could be changed to get a larger range or the variable could simply be increased to 16 bits to double the time.

byte ButPRESS = B00000000;   // Debounce record for Button Press
byte DebounceRange = B11111111;   // Debounce threshold for Press
void setup() {
    pinMode(4, INPUT);     // Digital Pin for Button Activation
}
void loop() {
/* Write current button states */
  ButPRESS <<= 1;              // Bitshift Left x = x << 1
/* Add Current button state to each record */
  ButPRESS |= (digitalRead(4));  // Adds current value (0/1) to the RHS of the bit
 
/* Check if button has been pressed long enough */
  if (ButPRESS>=DebounceRange){  // Detects if the 'Power' button has been pressed
     ButPRESS <<= 8;               // Bitshift Left (x8) for Start Check Activation Press
    NewSubFunction();                     // Starts the new function for the button
  }
}

The button value is being read from digital pin 4, and in each loop of the code a value of 1 or 0 is added to the RHS (right-hand side) of the byte, and the LHS (left-hand side) of the byte is discarded. So as the button is pressed, the byte changes each loop from:

ButPRESS = 00000000        
ButPRESS = 00000001
ButPRESS = 00000011
ButPRESS = 00000111 … until ButPRESS = 11111111

This makes the button debounce length equal to the length of the cycle time of the code x 8 without stalling the code from other tasks. Where a bouncing press might end up looking like this, 00101101.

To prevent the sub-function from running multiple times before the user removed their finger, the byte for the button press is bit-shifted eight positions to clear the byte back to zero. This method also allows multiple buttons to be tracked and debounce without worrying about interrupts.

Determining the Roller Position

Each I/O expander reads two absolute encoders, so a bitwise AND operator is used to separate the incoming byte (8 bits) into a pair of nibbles (2x 4 bits)[... part of the reason I called the void that performs this action Hungry ;) ]. A switch case is then used to convert the gray code into an encoder position. By splitting the nibbles, a loop can be used to save on typed code when checking the position.

The encoder position is determined first before being converted to the appropriate number or symbol. This is done because the encoder is trying to match 16 positions to only 11 faces, meaning that there is the potential for the encoder to flick over to the next position without it being physically noticed on the actual roller. It would have been easier to use a 12-bit encoder but the small versions of these were found to either have a long lead time or cost too much by comparison.

To combat the fact I had used a detent encoder, the roller was printed with physical locking springs that could hold the roller in the correct place for the printed number. This ended up giving a nice positive ‘spring’ & ‘click’ feel to the rollers.

A diagram showing the way the wheels rotate

The image above shows the roller cross-section of eleven faces and the grey lines for the encoder positions. By positioning the first encoder position (red centerline) to the middle of the roller face it can be seen that some positions on the encoder will suit the same face. Just as some positions double up, some positions are very close to the next face, so the coding approach taken was that a number value will round up if the roller is over halfway between printed face numbers.

The Arduino arrays NumbReel1 & RollerNumb are used to simplify the translation from encoder grey-bit to encoder position, to number value on the face of the roller.

An image of a snippet of code showing the way the encoder values are stored in arrays

The End result:

To finally power the system, a USB Power bank was wired to the JP1 terminal and the charge port of the power bank was connected to a female DC jack (mounted to the side.)

An image showing the Math Scroller in operation

The Math Scroller

An image showing the response to getting it wrong

And when the answer is wrong

An image showing the location of the charging port

Charge port

Failures and future changes:

I had the intention of using connectors for each roller but had underestimated how much space these take up when used in large numbers. With such a small space, there were also some issues with wires becoming over-crimped, causing the connection to break but not the external part of the wire when trying to place the two parts together. This caused a lot of unexpected fault finding and head-scratching when it sometimes worked and sometimes didn’t. If I was to make this again I would start straight with soldering the wires into the boards.

An image showing the overcrowding of connectors

Another image showing the way the ribbon cables are run

The electronics are ready to be pressed into the case

I would like to have also moved the pot from internal to the design, to an external dial. This would allow the user to change the length of the timer when the mode is activated. I thought of this too late in the build and didn’t like any of the ideas I had to retrofit the pot externally.

Check out the GitHub Repo for all of the files you need to build this project

Have a question? Ask the Author of this guide today!

Please enter minimum 20 characters

Your comment will be posted (automatically) on our Support Forum which is publicly accessible. Don't enter private information, such as your phone number.

Expect a quick reply during business hours, many of us check-in over the weekend as well.

Comments


Loading...
Feedback

Please continue if you would like to leave feedback for any of these topics:

  • Website features/issues
  • Content errors/improvements
  • Missing products/categories
  • Product assignments to categories
  • Search results relevance

For all other inquiries (orders status, stock levels, etc), please contact our support team for quick assistance.

Note: click continue and a draft email will be opened to edit. If you don't have an email client on your device, then send a message via the chat icon on the bottom left of our website.

Makers love reviews as much as you do, please follow this link to review the products you have purchased.