Friday, June 10, 2016

Main Project - Speedometer

Arduino Main Project
Oscar Macdonald

The Project: Speedometer, or the Arduinospeedo
A magnet is attached to a wheel on the outermost edge or as close as possible. It does not matter if the south or north side of the magnet is showing. A linear hall sensor is placed just above the surface of the wheel, allowing no more than 2cm of space between the sensor and the magnet while still allowing the wheel to spin freely.
As the wheel spins, the Arduino detects when the magnet passes the sensor and stores the number of revolutions in an array of ten separate counts. Every second, the Arduino calculates the average revolutions per minute (rpm), and when the readings are stable (roughly once every 11 seconds) it converts the rpm to kilometres per hour (km/h) by multiplying the rpm by the circumference of the wheel, which is hard coded into the Arduino. The km/h is presented on a liquid crystal display (LCD) in a comfortable, easy-to-read style.

Fritzing Diagram:




C Code:
/* Linear Hall Sensor and Speedometer
 * Takes the circumference of a wheel and revolutions per minute
 * using a magnet and a linear hall sensor to calculate the speed
 * of the wheel in kilometers per hour and output result to an LCD.
 *
 * Assistance from Elimelec Lopez: http://playground.arduino.cc/Main/ReadingRPM
 * and http://elimelecsarduinoprojects.blogspot.co.nz/2013/06/measure-rpms-arduino.html
 *
 * http://www.ehow.com/how_7448165_calculate-wheel-speed.html
 *
 * Oscar Macdonald
 * 11/06/16
 */
#include <LiquidCrystal.h>  //library to use LCD
LiquidCrystal lcd(12,11,5,4,3,2); //pins attached to LCD
const int LHSP = 0; //Linear Hall Sensor Pin
const int PP = 1;  //Potentiometer Pin
const int MP = 10; //Motor Pin
const double circumference = 1.41;  //circumference of the wheel in meters (2πr)
double rpm = 0; //revolutions per minute
int revCount = 0; //count of revolutions
int index = 0;  //
const int numreadings = 10; //size of readings array
int readings[numreadings];  //array of revCounts, used to find average
unsigned long lastmillis = 0; //used to calculate the frequency of readings
unsigned long total;
double kmh = 0; //Kilometers per hour
bool pass;
void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("Km/h"); //Kilometers per hour
}

void loop() {
  if(millis() - lastmillis >= 1000)//Update every one second, this will be equal to reading frequency (Hz).
  {
    total = 0;
    readings[index] = revCount * 60; // Convert frecuency to RPM (the 60 converts the readings from seconds to minutes)
    for(int i = 0; i < readings.length; i++)
    {
      total = total + readings[i];
    }
    rpm = total / numreadings;  //this calculates the average rpm every second
    revCount = 0; // Restart the RPM counter
    index++;
    if(index >= numreadings)
    {
      index=0;
    }
    if (millis() > 11000)  // wait for RPMs average to get stable
    {
      kmh = (circumference * rpm) / 60; //calculate the speed in kilometers per hour
      lcd.clear();
      lcd.print("Km/h"); //Kilometers per hour
      lcd.setCursor(0,1);
      lcd.print(kmh);
    }
    lastmillis = millis(); // Update lasmillis
  }
  else
  {
    int magnet = analogRead(LHSP); //reads the hall sensor
    /*
     * This segment of code detects when the magnet is in range aka 1 rotation.
     * When the magnet is in range, a "flag" is raised and the revCount increases.
     * While the flag is up and the magnet is in range, the revCount can't increase
     * When the magnet passes out of range, the flag is lowered.
     * This allows for the revCount to increase only once every rotation.
     */
    if (!pass && (magnet <= 400 || magnet >= 650))
    {
      pass = true;
      revCount++;
    }
    if(pass && (magnet >= 500 && magnet <= 570))
    {
      pass = false;
    }
  }
}

Reflection:
My first project was originally going to be a Levitron: a magnet which is suspended using an electromagnet and a linear hall sensor to detect and adjust the magnetic field. However this project was too complex to achieve on time, and after several setbacks I decided to change to the speedometer. For example, I couldn’t get the electromagnet to work at all, and there was almost no reliable material about Arduino Levitrons online. I had the linear hall sensor and magnet from the Levitron project already, setting up the circuitry was easy (especially compared to the Levitron circuitry) and all that was required to create the speedometer was the code. 

In the LED project I used the serial output and the LEDs themselves to display the output, but this time I thought it would be more appropriate to use the LCD. LCDs are often used today to display speedometers in cars.

Lots of other people have made speedometers from Arduinos, including Elimelec Lopez (1) who used a state hall sensor instead of a linear hall sensor. This allowed him to use interrupts whenever the hall sensor went from HIGH output to LOW output. In my code I had to design a “flag” method that detected whenever the magnet came in range, raise the flag to prevent multiple readings of the same revolution, increment the revolution count, and then lower the flag once the magnet had passed out of range. 

In some ways I prefer my method, because it does not require the sensor or the magnet to face a certain direction: with some state hall sensors, they might only trigger when the north or south side of the magnet comes in range, but not either. It was difficult adjusting the threshold levels correctly, and getting the logic of the IF statements correct took several attempts. At one point, before the second video, I was using the radius of the wheel in my calculation instead of the circumference! But after I fixed the problem then the speedometer began working correctly. In one of my previous attempts I tried to include a DC motor that spun a wheel, so I could measure its speed. If I wanted to show the speed of the motor changing, I could attach a potentiometer to the Arduino and use it to control the motors speed. The Arduino isn’t capable of supporting both the LCD, the potentiometer, the motor and the sensor simultaneously however, so I decided that any manual wheel would do.

Speedometers are used all the time in vehicles. The advantage of this project is that it can be applied to anything that travels on wheels, including bicycles, remote-controlled cars and power chairs. It can be used in other aspects of engineering such as production lines, proximity sensors, magnetic card readers and many more. In future applications I might include this in a powered longboard design, so that I can monitor how fast the longboard is travelling via mobile phone.

References:

No comments:

Post a Comment