Digital Odometer for Bicycles
You will learn how to develop the control circuit and code for a digital bicycle speedometer.
Supplies
- Arduino Nano
- Reed Switch
- Jumpers
- Protoboard
- Display Nokia 5110
- Switch buttons
Introduction
Cycling, increasingly popular both as a recreational activity and as a means of transport, has led cyclists to seek technological solutions to optimize their experience. Among these advances, the odometer stands out as an essential tool. This device not only provides accurate data on the cyclist's performance, but also significantly contributes to the safety and efficiency of cycling. The growing demand for odometers reflects the need to solve a series of problems faced by cyclists, ranging from speed monitoring to time and route management.
Speed monitoring is one of the main incentives for using odometers. Knowing the current, average and maximum speed allows cyclists to adjust their pace as needed, whether to improve performance in training or competitions, or to ensure a safer journey in urban environments. Furthermore, time management is crucial, especially for those who use bicycles as a means of daily transportation. With an odometer, cyclists can accurately estimate the time needed to cover certain routes, improving the organization of their routines and commitments.
Another relevant problem is controlling the distance traveled. Cyclists training for competitions need to closely monitor their distances to achieve specific training goals. Finally, the continuous recording of performance data allows a detailed analysis of progress over time, encouraging continuous improvement and motivation of cyclists.
In this article we will show you step by step how to build the electronic circuit of an odometer to calculate average speed, instantaneous speed and distance covered. In addition, we will make the control code available to perform these calculations.
The electronic project is available and you can download all the files and electronic schematics.
Electronic Project Operation
To present the operation of the odometer, we developed the circuit below. The Nokia 5110 display shows the instantaneous speed and distance traveled by the cyclist.
The calculation of instantaneous speed and distance traveled is done using a reed switch sensor and a magnet. This calculation is based on the radius of the bicycle tire and the number of revolutions the tire rotates when the cyclist is moving.
To detect the number of rotations, it is necessary to install the magnet on the bicycle tire. The reed switch must be installed in a region close to the tire to be activated when the magnet passes close to its structure. Below we have a simulation of the magnet movement in the face region of the reed switch sensor. From this simulation it is possible to observe the value of instantaneous speed (km/h) and distance traveled (km).
After all, how does the calculation work to detect the instantaneous speed and distance covered by the cyclist. We will explain this in the next topic
How to Calculate Instantaneous Speed and Distance Traveled?
The principle for calculating these two variables is directly related to the radius of the bicycle tire. The radius of the bicycle is the parameter used to first measure the distance traveled. This calculation is carried out when we know the length of the tire.
The length of a circle is defined by:
C = 2*PI*r
The user needs to measure the radius of the bicycle wheel. With this value, it is necessary to enter it into the system. For this, there is a functionality in the code that allows the user to enter and save this information in memory.
From this, the system will calculate the distance traveled and the instantaneous speed.
Calculation of distance traveled
The distance traveled is calculated based on the number of laps that the sensor detects. Therefore, we can take the number of laps from the starting moment and multiply it by the length of the wheel. This way, we can know the distance covered by the cyclist.
Calculation of instantaneous speed
Instantaneous speed is calculated based on the length of the wheel and the time difference between the current full turn and the time of the previous full turn.
From this, it is possible to determine the instantaneous speed of the bicycle.
Presentation of data on the display
These calculations are performed and presented on the display. Additionally, we have implemented the following features below:
- Reset the speed when the cyclist is stopped;
- Reset the distance traveled by pressing one of the buttons for 3 seconds, and
- Change the wheel radius.
- Below we provide the complete odometer code.
Odometer Programming Logic
The complete programming logic to execute the project is presented below. The electronic project is available and you can download all the files and electronic schematics.
//Declaração de Bibliotecas
#include <Adafruit_GFX.h>
#include <EEPROM.h>
#include <Adafruit_PCD8544.h>
// pin 8 - Serial clock out (SCLK)
// pin 9 - Serial data out (DIN)
// pin 10 - Data/Command select (D/C)
// pin 11 - LCD chip select (CS/CE)
// pin 12 - LCD reset (RST)
//Configuracao dos Pinos do Display Nokia 5110
Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);
//Definicao dos numeros de memoria para gravacao de dados
#define MEMORIA 120
#define PosRaio 125
#define ReedSwitch 2
#define BotaoEnterOk 14
#define BotaoIncremento 15
#define BotaoDecremento 16
//Declaracao de Variaveis
bool sensor = 0, estado_anterior = 0, Incremento = 0, Decremento = 0, ativa = 0, LimpaDisplay = 0;
bool IncrementoAnterior = 0, DecrementoAnterior = 0, BotaoEnter = 0, EstadoAnteriorIncremento = 0;
bool FlagReset = 1, FlagConfig = 0;
byte RaioRoda = 0;
float start = 0, speedk = 0, elapsed = 0;
float tf = 0, inicioPulso = 0, finalPulso = 0, iPulsoReset = 0;
byte cont = 0;
unsigned long int VoltaCompleta = 0;
unsigned long int tempo_atual = 0, ultimo_tempo = 0;
float DistKm = 0;
int raio = 0;
float Distancia = 0;
void MostraTela(float veloc, float dista)
{
display.clearDisplay(); //Apaga o buffer e o display
display.drawRoundRect (0, 0, 84, 48, 3, BLACK);
//Texto invertido - Branco com fundo preto
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(18,3); //Seta a posição do cursor
display.println("Vel(km/h)");
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(30,13); //Seta a posição do cursor
display.println(veloc);
display.drawLine(0, 23, 84, 23, BLACK);
//Texto invertido - Branco com fundo preto
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(19,27); //Seta a posição do cursor
display.println("Dist(km)");
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(30,37); //Seta a posição do cursor
display.println(dista);
display.display();
}
//Funcao para calculo da velocidade
void VelocDist()
{
if((millis()-start)>100)
{
//calculate elapsed
elapsed = millis()-start;
float comprimento = ((float)(2*3.14*raio));
//reset start
start=millis();
//calculate speed in km/h
speedk=(3.6*comprimento)/elapsed;
VoltaCompleta++;
Distancia = ((float)(2*3.14*raio*VoltaCompleta)/100000.0);
MostraTela(speedk, Distancia);
}
tf = millis();
ativa = 1;
}
//Funcao para configurar o raio do pneu da bicicleta
void ConfiguraRaio()
{
display.clearDisplay(); //Apaga o buffer e o display
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(0,1); //Seta a posição do cursor
display.setTextColor(WHITE, BLACK);
display.println("Insira o Raio:");
display.display();
Incremento = digitalRead(BotaoIncremento);
while(Incremento == 0)
{
Incremento = digitalRead(BotaoIncremento);
}
do
{
Incremento = digitalRead(BotaoIncremento);
Decremento = digitalRead(BotaoDecremento);
BotaoEnter = digitalRead(BotaoEnterOk);
if(Incremento == 1 && IncrementoAnterior == 0)
{
RaioRoda = RaioRoda + 1;
IncrementoAnterior = 1;
display.clearDisplay(); //Apaga o buffer e o display
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(0,1); //Seta a posição do cursor
display.setTextColor(WHITE, BLACK);
display.println("Insira o Raio:");
display.display();
}
if(Incremento == 0 && IncrementoAnterior == 1)
{
IncrementoAnterior = 0;
}
if(Decremento == 1 && DecrementoAnterior == 0)
{
RaioRoda = RaioRoda - 1;
DecrementoAnterior = 1;
display.clearDisplay(); //Apaga o buffer e o display
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(0,1); //Seta a posição do cursor
display.setTextColor(WHITE, BLACK);
display.println("Insira o Raio:");
display.display();
}
if(Decremento == 0 && DecrementoAnterior == 1)
{
DecrementoAnterior = 0;
}
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(38,20); //Seta a posição do cursor
display.print(RaioRoda);
display.display();
}while(BotaoEnter == 1);
EEPROM.write(PosRaio, RaioRoda);
MostraTela(speedk, Distancia);
return;
}
//Declaracao da funcao setup
void setup()
{
display.begin();
display.setContrast(50); //Ajusta o contraste do display
display.clearDisplay(); //Apaga o buffer e o display
display.setTextSize(1); //Seta o tamanho do texto
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
//Regiao de codigo para configurar o raio da roda do veiculo
if(EEPROM.read(MEMORIA) != 75)
{
ConfiguraRaio();
EEPROM.write(MEMORIA, 75);
display.clearDisplay(); //Apaga o buffer e o display
}
start = millis();
raio = EEPROM.read(PosRaio);
MostraTela(speedk, Distancia);
attachInterrupt(digitalPinToInterrupt(2), VelocDist, RISING);
Serial.begin(9600);
}
void loop()
{
Incremento = digitalRead(BotaoIncremento);
Decremento = digitalRead(BotaoDecremento);
if(Incremento == 0 && FlagConfig == 0)
{
FlagConfig = 1;
inicioPulso = millis();
}
if(Incremento == 0 && FlagConfig == 1)
{
if(millis() - inicioPulso >= 3000)
{
ConfiguraRaio();
FlagConfig = 0;
}
}
if(Decremento == 0 && FlagReset == 1)
{
FlagReset = 0;
iPulsoReset = millis();
}
if(Decremento == 1 && FlagReset == 0)
{
FlagReset = 1;
LimpaDisplay = 0;
}
if(Decremento == 0 && FlagReset == 0)
{
if((millis() - iPulsoReset >= 3000)&&(LimpaDisplay == 0))
{
FlagReset = 0;
LimpaDisplay = 1;
VoltaCompleta = 0;
Distancia = 0;
MostraTela(speedk, Distancia);
}
}
if((millis() - tf > 5000)&&(ativa == 1))
{
speedk = 0;
ativa = 0;
display.clearDisplay(); //Apaga o buffer e o display
display.drawRoundRect (0, 0, 84, 48, 3, BLACK);
//Texto invertido - Branco com fundo preto
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(18,3); //Seta a posição do cursor
display.println("Vel(km/h)");
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(30,13); //Seta a posição do cursor
display.println(speedk);
display.drawLine(0, 23, 84, 23, BLACK);
//Texto invertido - Branco com fundo preto
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(19,27); //Seta a posição do cursor
display.println("Dist(km)");
display.setTextSize(1); //Seta o tamanho do texto
display.setTextColor(BLACK); //Seta a cor do texto
display.setCursor(30,37); //Seta a posição do cursor
display.println(Distancia);
display.display();
}
}
Using the code above and the electronic circuit on the breadboard, we assembled the electronic schematic of the project with the ATMEGA328P CHIP. From this schematic we developed the printed circuit board below.
Based on the project structure on the electronic bench, we developed an electronic scheme for creating the odometer electronic board with the ATMEGA328P CHIP.
Electronic Project Development
One of the most important aspects that we must consider when developing the odometer is its operating principle. Which sensor element is used to calculate speed? How to determine the distance? These and many other questions will be answered below.
The electronic project is available and you can download all the files and electronic schematics.
The odometer's operating principle is based on a magnetic sensor installed on the bicycle wheel. The sensor that is widely used is the reed switch. Using a magnet attached to the bicycle wheel, we can determine the number of revolutions of the bicycle tire.
Based on this information, the ATMEGA328P microcontroller performs the calculations and presents the information on a Nokia 5110 display. From this, we developed the electronic schematic below. It contains all the circuit blocks necessary to configure the odometer and present the data to the cyclist.
As you can see, the odometer design is made up of 9 blocks of electronic circuits.
Connectors and Power Supply Circuit
The design consists of two connectors. One will be used to connect the reed switch sensor and the other will be used to connect the power battery. Below we have the connector block.,
The input voltage is applied to the input of 2 AMS1117 voltage regulators. One will be used to supply a voltage of +5V (sensor and microcontroller) and the other for +3V3 (powering the Nokia 5110 display circuit). The LED circuit is used to signal that the electronic board is energized.
ATMEGA328P Microcontroller Circuit
The Microcontroller used in the project is an ATMEGA328P. Its electrical connections are shown in the figure below, along with the oscillator circuit.
As you can see, the other elements of the project will be connected to the Microcontroller. In its structure we will connect 3 buttons and the Nokia 5110 display. As you can see, the other elements of the project will be connected to the Microcontroller. In its structure we will connect 3 buttons and the Nokia 5110 display. The circuit of the other elements is shown below.
Each button above has a different functionality and will be used to configure the odometer parameters. Next, we will present how the circuit works.
Odometer Printed Circuit Board
Below we have the result of the printed circuit board layout. As you can see, its structure is made up of 2 JST connectors and 3 buttons
In the printed circuit board structure there are two pin busses: code transfer with USB-SERIAL converter and pins for connecting the Nokia 5110 display.
Final Thoughts
As can be seen in the video, the electronic circuit system and the control algorithm showed excellent operating results and all functionalities are similar to odometer devices sold on the market.
The electronic project is available and you can download all the files and electronic schematics.
Acknowledgments
We would like to thank PCBWAY for supportting the creation of this project and made some units available for you to earn for free and receive 5 units at your home. To receive them, access this link, create an account on the website and receive coupons for you to win right now.