Arduino projects

Digital Taxi Meter Using Arduino

Digital Taxi Meter Using Arduino

Digital Taxi Meter Using Arduino 

Nowadays, digital meters are gradually replacing analog meters in various sectors, whether it is electricity meters or taxi fare meters. The main reason is that the mechanical parts of analog meters are prone to wear after long-term use and are not as accurate as digital meters.

A good example is the analog speedometer and odometer used on older motorcycles to measure speed and distance travelled. They have a special component called a pinion and rack arrangement where a cable is used to rotate the pins of the speedometer as the wheel rotates. This wears out over time and also requires replacement and maintenance.

In digital meters, mechanical parts are not used, instead sensors like optical interrupters or hall sensors are used to calculate the speed and distance. This is more accurate than analog meters and does not require any maintenance for a long time. In this project, we will make a prototype of a digital taxi meter using Arduino. This project calculates the speed and distance travelled by the wheels of the taxi and displays it continuously on a 1602 LCD display. Based on the distance travelled, the fare is generated when a button is pressed.

The following image shows the complete setup of Digital Taxi Meter Project

Digital Taxi Meter Using Arduino

This prototype uses an RC car chassis with a speed sensor module and an encoder wheel attached to the motor. Once the speed is measured, we can measure the distance travelled and get the fare value by pressing a button. We can set the speed of the wheel using a potentiometer. Let’s look at a short introduction to the speed sensor module.

Infrared slot optical LM-393 speed sensor module

Digital Taxi Meter Using Arduino

This prototype uses an RC car chassis with a speed sensor module and an encoder wheel attached to the motor. Once the speed is measured, we can measure the distance travelled and get the fare value by pressing a button. We can set the speed of the wheel using a potentiometer. Let’s look at a short introduction to the speed sensor module.

This is a slot type module which can be used to measure the rotation speed of the encoder wheel. This speed sensor module works on the basis of slot type optical interrupter also known as light source sensor. This module requires a voltage of 3.3V to 5V and produces a digital output. So it can be interfaced with any microcontroller.

The infrared light sensor consists of a light source (IR-LED) and a phototransistor sensor. There is a small gap between the two. When an object is placed between the gap of the IR LED and the phototransistor, it will interrupt the light beam, causing the phototransistor to stop passing current.

Digital Taxi Meter Using Arduino


So with this sensor, a slotted disc (encoder wheel) is used which can be attached to the motor and as the wheel rotates with the motor, it interrupts the light beam between the IR LED and the phototransistor causing the output to switch on and off (generating pulses).

In this way, it produces a high output when there is a break between the source and the sensor (when any object is placed in between) and produces a low output when no object is placed. In the module, we have an LED to indicate the optical break caused.

This module is equipped with LM393 comparator IC for producing precise HIGH and LOW signals at OUTPUT. Hence, this module is sometimes called LM393 speed sensor.

Measuring speed and distance traveled to calculate fares

To measure the speed of rotation, we need to know the number of slots present in the encoder wheel. I have an encoder wheel with 20 slots. When they rotate one complete rotation, we have 20 pulses at the output. So, to calculate the speed, we need the number of pulses produced per second.

For example, if there are 40 pulses in one second, then

Speed = Noo. Of pulses / No. of slots = 40/20 = 2RPS (Revolution per second)

To calculate the speed in RPM (revolutions per minute), multiply by 60

Speed in RPM = 2 X 60 = 120 RPM (Revolutions per Minute)

Measuring distance: Measuring the distance traveled by a wheel is very simple. Before calculating the distance, the circumference of the wheel should be known.

Circumference of the wheel = π*d 

Where d is the diameter of the wheel.

The value of π is 3.14.

I have a wheel (RC wheel) with a diameter of 6.60 cm, so the circumference is (20.7 cm).

Therefore, to calculate the distance traveled, simply multiply the number of pulses detected by the circumference.

Distance Travelled = Circumference of Wheel x (No. of Pulses / No. of slots)

So when a wheel with a circumference of 20.7 cm requires 20 pulses, or one rotation of the encoder wheel, the distance the wheel travels is given by

Distance travelled = 20.7 x (20/20) = 20.7cm

To calculate the distance in meters, divide the distance in cm value by 100.

NOTE: This is a small RC wheel, real-time cars are bigger than this wheel. So I’m assuming a circumference of 230cm for this tutorial.

Calculate fares based on distance traveled:

To get the total fare amount, multiply the distance traveled by the fare (amount/meter).

Assume that the charge is Rs 5 per meter. So if the wheel travels 20 meters then the fare will be 20*5 = 100 Rs.

So now let’s get the components and build the circuit.

Required Components

● Arduino UNO development board

● LCD (16×2)

● Button

● Potentiometer-10k

● ULN2003 motor driver IC

● LM393 speed sensor module (FC-03)

● RC smart car chassis with speed encoder

● Battery 9V

● Breadboard

● Connecting cable

Circuit Schematic

Digital Taxi Meter Using Arduino

RC vehicle chassis mounted speed sensor

The speed sensor is mounted so that the encoder wheel is between the sensor gaps. In my case, there is a special hole for placing the sensor. See the picture below

Digital Taxi Meter Using Arduino
Digital Taxi Meter Using Arduino

Connection between Speed ​​Sensor Module and Arduino

Connection between Arduino and ULN2003

Connection between ULN2003, DC motor and 9v battery

Use a 9V battery and ULN2003 to provide external power to the motor.

Connection of buttons and potentiometers

The button is connected to pin 3 of the Arduino via a pull-down resistor to generate the fare when the button is pressed.

The potentiometer is used to provide an analog input voltage to pin A0 of the Arduino to vary the speed of the wheel.

Arduino Programming for Digital Taxi Meter

The complete code is given at the end of this article. Here we introduce some important parts of the code.

Before we start introducing the code, we need to understand interrupts and the Timer One library as they will be used in the code.

Interrupts are used here because we need to keep checking if the output detected on the speed sensor module is of high priority. So ISR is used in the code. ISR is Interrupt Service Routine which is called when an interrupt occurs on interrupt pins 2 and 3.

Arduino UNO has two interrupt pins 2 and 3.

● At pin 2, connect the output of D0 of the speed sensor.

● At pin 3, connect a push button with a pull-down resistor.

The TimerOne library is used in the code to check the number of rotations detected in one second (how many pulses), then we can calculate the speed per second and display them on the output. This ISR function is executed once per second.

Let’s look at the code in detail:

1. First, the library containing the functions will be used in the program.

#include "TimerOne.h"
#include <LiquidCrystal.h>

2. Next we declare global variables as they will be used throughout the program.

volatile unsigned int counter=0;
volatile unsigned int rotation=0;         
float rotationinm=0;
unsigned int speed=0;

3. Next define and initialize the LCD pins connected to the Arduino.

const int rs = 12, en = 13, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

4. Next in the void setup() function,

Define the pin mode, here PIN A0 is used to take the analog input from the potentiometer and pin 5 is used to write the analog output connected to the IN1 pin of the ULN2003 IC.

pinMode(A0,INPUT);               
pinMode(5,OUTPUT);

Next it displays some welcome message and then clears.

lcd.begin(16,2);                   //Sets LCD as 16x2 type
  lcd.setCursor(0,0);               
  lcd.print("CIRCUIT DIGEST");
  lcd.setCursor(0,1);
  lcd.print("WELCOME TO TAXI");
  delay(3000);
  lcd.clear();
  lcd.print("LETS START :)");
  delay(1000);
  lcd.clear();

The next important part is setting up the interrupt pin and the ISR to be called when the interrupt occurs.

First, we need to set timer1 to 1 second, and then attach an ISR to timer1 so that the ISR is called once every second. The ISR name is timerIsr

Timer1.initialize(1000000);         
Timer1.attachInterrupt( timerIsr );

Next we associate two external interrupts. The first interrupt makes Arduino pin 2 an interrupt pin and calls the ISR (counts) when a RISING (low to high) is detected on pin 2. This pin 2 is connected to the D0 output of the speed sensor module.

The second one makes Arduino pin 3 as interrupt pin and calls ISR(Generate) when a high level is detected on pin 3. This pin is connected to a push button via a pull-down resistor.

attachInterrupt(digitalPinToInterrupt(2), count, RISING);
attachInterrupt(digitalPinToInterrupt(3), generatefare, HIGH);


5. Next let’s look at the ISR we use here:

When a rising edge interrupt (low to high) occurs on pin 2 (connected to the speed sensor), ISR1- count() ISR function is called.

void count()  // ISR for counts from the speed sensor
{
  counter++;  // increase the counter value by one
  rotation++; //Increase the rotation value by one
  delay(10);
}

ISR2- timerIsr() ISR is called once every second and executes those codes present in ISR.

void timerIsr()
{
detachInterrupt(digitalPinToInterrupt(2));
Timer1.detachInterrupt();
lcd.clear();

float speed = (counter / 20.0)* 60.0;
float rotations = 230*( rotation / 20);
rotationinm = rotations/100;

lcd.setCursor(0,0);
lcd.print("Dist(m):");
lcd.print(rotationinm);
lcd.setCursor(0,1);
lcd.print("Speed(RPM):");
lcd.print(speed);
  counter=0;

  int analogip = analogRead(A0);
  int motorspeed = map(analogip,0,1023,0,255);
  analogWrite(5,motorspeed);

Timer1.attachInterrupt( timerIsr );
attachInterrupt(digitalPinToInterrupt(2), count, RISING);
}

This function contains the lines that actually first detach Timer1 and interrupt pin2 since we have the LCD print statements in the ISR.

To calculate SPEED in RPM we use the following code where 20.0 is the number of slots preset in the encoder wheel.

float speed = (counter / 20.0) * 60.0;

And to calculate the distance, the following code is used:

float rotations = 230*( rotation / 20);

Here the circumference of the wheel is assumed to be 230 cm (which is normal for a real-time car)

Next, convert the distance (m) by dividing it by 100

rotationinm = rotations/100;

After that, we display SPEED and DISTANCE on the LCD display.

lcd.setCursor(0,0);
lcd.print("Dist(m):");
lcd.print(rotationinm);
lcd.setCursor(0,1);
lcd.print("Speed(RPM):");
lcd.print(speed);

Important: We have to reset the counter to 0 because we need to get the number of pulses detected per second, so we use this code

counter=0;

Next read the analog pin A0 and convert it into digital values ​​(0 to 1023) and further map these values ​​to 0-255 for PWM output (to set the motor speed) and finally write these PWM values ​​using analogWrite function connected to the ULN2003 motor IC.

int analogip = analogRead(A0);
int motorspeed = map(analogip,0,1023,0,255);
analogWrite(5,motorspeed);

ISR3: generatefare() ISR is used to generate the fare amount based on the distance travelled. This ISR is called when interrupt pin 3 is detected high (when the button is pressed). This function separates the interrupt from pin 2 and the timer interrupt and then clears the LCD.

void generatefare()                          
{
   detachInterrupt(digitalPinToInterrupt(2)); pin at 2
   Timer1.detachInterrupt();                 
   lcd.clear();                              
   lcd.setCursor(0,0);
   lcd.print("FARE Rs: ");      
   float rupees = rotationinm*5;            
   lcd.print(rupees);                       
   lcd.setCursor(0,1);
   lcd.print("Rs 5 per metre");
   }

After that, multiply the distance traveled by 5. You can change this as you wish.

float rupees = rotationinm*5;

After the values ​​are calculated, they are displayed on the LCD display connected to the Arduino.

 lcd.setCursor(0,0);
   lcd.print("FARE Rs: ");      
   lcd.print(rupees);                       
   lcd.setCursor(0,1);
   lcd.print("Rs 5 per metre");

You can further improve this prototype by improving its accuracy, robustness and adding more features like Android app, digital payment etc. and develop it into a product.

Code

main Dowload <here

#include "TimerOne.h"                      //Include Timer1 library for using Timer1 functions
#include <LiquidCrystal.h>                 //Include LCD library for using LCD display functions     

const int rs = 12, en = 13, d4 = 8, d5 = 9, d6 = 10, d7 = 11;   //Define the LCD pins 
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);                      

volatile unsigned int counter=0;          
volatile unsigned int rotation=0;          
float rotationinm=0;
unsigned int speed=0;

void count()  // ISR for counts from the speed sensor
{
  counter++;  //increase the counter value by one
  rotation++; //Increase the rotation value by one
  delay(10); 
} 

void timerIsr()
{
 detachInterrupt(digitalPinToInterrupt(2));          //Stops the interrupt pin 2
 Timer1.detachInterrupt();                           //Stops the timer1 interrupt

 lcd.clear();          
 
 float speed = (counter / 20.0)* 60.0;              //Calcukate speed in minute (20-No of slots in Encoder Wheel)
 float rotations = 230*( rotation / 20);            //Calculate distance in cm (230-Circumference of the wheel assumed 20- No of slots)
 rotationinm = rotations/100;

 lcd.setCursor(0,0);
 lcd.print("Dist(m):");
 lcd.print(rotationinm);                            //Display rotationinm at LCD
 lcd.setCursor(0,1);
 lcd.print("Speed(RPM):");                       
 lcd.print(speed);                                  //Dsiplay speed in RPM
 
  counter=0;                                        //Reset counter to 0 

  int analogip = analogRead(A0);                   // Analog read from pin A0
  int motorspeed = map(analogip,0,1023,0,255);     //convert digital vales 0-1023 to 0-255
  analogWrite(5,motorspeed);                      //Sets PWM value at pin 5 
 
 Timer1.attachInterrupt( timerIsr );                        //Starts timer1 again
 attachInterrupt(digitalPinToInterrupt(2), count, RISING);  //Attaches interrupt at pin2 again
}

void generatefare()                           //ISR to generate the fareamount
{
   detachInterrupt(digitalPinToInterrupt(2)); //Disables the Interrupt pin at 2
   Timer1.detachInterrupt();                  //Disables the Timer1 interrupt
   float rupees = rotationinm*5;              //Muliply 5 with distance travelled (Rs 5 per meter )
   lcd.clear();                               //Clears LCD
   lcd.setCursor(0,0);
   lcd.print("FARE Rs: ");       
   lcd.print(rupees);                        //Display fare amount 
   lcd.setCursor(0,1);
   lcd.print("Rs 5 per metre");
}

void setup() 
{
  pinMode(A0,INPUT);                 //Sets pin A0 as INPUT 
  pinMode(5,OUTPUT);                 //Sets pin 5 as OUTPUT 
  
  lcd.begin(16,2);                   //Sets LCD as 16x2 type
  lcd.setCursor(0,0);                //The following code displays welcome messages
  lcd.print("CIRCUIT DIGEST");
  lcd.setCursor(0,1);
  lcd.print("WELCOME TO TAXI");
  delay(3000);
  lcd.clear();
  lcd.print("LETS START :)");
  delay(1000);
  lcd.clear();

  Timer1.initialize(1000000);          //Initilize timer1 for 1 second 
  Timer1.attachInterrupt( timerIsr );  //ISR routine to be called for every one second
  
  attachInterrupt(digitalPinToInterrupt(2), count, RISING);     // Pin 2 as Interrupt pin with count ISR is called when LOW to RIGH happens.
  attachInterrupt(digitalPinToInterrupt(3), generatefare, HIGH); //Pin 3 as Interrupt pin with generatefare ISR is called when HIGH is detected.
 } 

void loop()
{
 
 
}

Back to top button