What is the best type of sensor for motorcycle ODOMETER..??

Joy:

dc42:
I think the latch effect is an advantage in your application. Imagine that your bike is stationary but the magnet just happens to be over the sensor. Without a latch effect, very small movements of the wheel back and forth will generate pulses, making it appear that the bike has travelled. With the latch effect of the US1881, you would have the move the wheel back and forth half a revolution to get any pulses.

The circumference of your wheel is much less than 0.1km so you don't need more than 1 pulse per revolution.

Good point ..
Even I was thinking earlier about the thing you told..But it never came to mind that the US1881 can solve the problem...

Will you please help me out in writing the code for the odometer..
The thread about it is here..
http://arduino.cc/forum/index.php/topic,72801.15.html

I know you are using one interrupt-enabled pin already for the RPM counter, but is the other interrupt pin still free? On the Uno it is pins 2 and 3 that can generate interrupts as standard.

dc42:
I know you are using one interrupt-enabled pin already for the RPM counter, but is the other interrupt pin still free? On the Uno it is pins 2 and 3 that can generate interrupts as standard.

yes..
My pin 3 on the arduino is free...
I am trying to use it for the ODO..

OK, here is a first attempt, compiled but otherwise untested.

#include <EEPROM.h>

const int odometerPin = 3;
const int odometerInterrupt = 1;
const int odometerEepromLocation = 0;  // address of the first of 4 bytes in which the total wheel revs is stored
const int powerPin = A0;               // analog pin used to sense impending loss of power

const float wheelCircumference = 0.002035;  // wheel circumference in km
const int minPowerOkReading = 700;          // minimum reading on the power sense analog input that indicates good power
const int minPowerRestoredReading = 750;    // minimum reading on the power sense analog input that indicates we have powered back up

volatile unsigned long wheelRevs;       // total wheel revolutions counted, will overflow after 85 million km
unsigned long lastDisplayedMs = 0UL;    // time when we last refreshed the display

void setup()
{
  // Initialise wheel revs from value stored in EEPROM
  wheelRevs = 0UL;
  for (int i = odometerEepromLocation + 3; i >= odometerEepromLocation; --i)
  {
    wheelRevs <<= 8;
    wheelRevs |= (unsigned long)EEPROM.read(i);
  }
  
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, RISING);  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)savedWheelRevs);
      savedWheelRevs >>= 8;
    }
    
    // wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  else
  {  
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display evert 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      Serial.print(km, 1);
      Serial.println("km");
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }
}

Thank you dc42..

I tried your code and connect the hall and a magnet to a fan but there was no increments on the reading..
It kept showing 0..

I want to test it with a push button instead of the hall..and according to my wheel circumference 491 pulse = 1Km..
so what values in the code should I change so that with the push button 5 or 10 clicks make one Km...
Should I change this..??
const float wheelCircumference = 0.002035;

Yes, change the wheel circumference to something much higher for debugging. Alternatively, display wheelRevs directly instead of converting it to km. Remember that if you are using the US1881, the sensor needs to see both a north pole and a south pole per simulated wheel revolution.

dc42:
Yes, change the wheel circumference to something much higher for debugging. Alternatively, display wheelRevs directly instead of converting it to km. Remember that if you are using the US1881, the sensor needs to see both a north pole and a south pole per simulated wheel revolution.

I tried these changes in the code..

#include <EEPROM.h>

const int odometerPin = 3;
const int odometerInterrupt = 1;
const int odometerEepromLocation = 0;  // address of the first of 4 bytes in which the total wheel revs is stored
const int powerPin = A0;               // analog pin used to sense impending loss of power

const float wheelCircumference = 1;  // wheel circumference in km
const int minPowerOkReading = 700;          // minimum reading on the power sense analog input that indicates good power
const int minPowerRestoredReading = 750;    // minimum reading on the power sense analog input that indicates we have powered back up

volatile unsigned long wheelRevs;       // total wheel revolutions counted, will overflow after 85 million km
unsigned long lastDisplayedMs = 0UL;    // time when we last refreshed the display

void setup()
{
  Serial.begin(9600);
  Serial.print("odometer");
  // Initialise wheel revs from value stored in EEPROM
  wheelRevs = 0UL;
  for (int i = odometerEepromLocation + 3; i >= odometerEepromLocation; --i)
  {
    wheelRevs <<= 8;
    wheelRevs |= (unsigned long)EEPROM.read(i);
  }
  
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, RISING);  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)savedWheelRevs);
      savedWheelRevs >>= 8;
    }
    
    // wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  else
  {  
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display evert 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      Serial.print(km, 1);
      Serial.println("km");
      Serial.println(wheelRevs);
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }
}

Changing the wheel circumference to 1
Serial.println(wheelRevs);

connected push button
Push button pin pin 3 of arduino and other pin to 5V+ . A 10k resistor connected to pin 3 of arduino and GND..

Still no result.. :frowning:

Is it because my A0 of arduino is open..??

Yes, you don't have the power sense pin wired up yet, so it thinks you are powering down all the time. As a temporary measure, try connecting pin A0 to +5v.

After connecting the A0 to 5v+ and some changes made the code working correctly.. :slight_smile:

Now another challenge is to add trip meter extracted from the odometer..
I will connect a push button on A1 of arduino and the GND
which will shift the trip meter from TRIP A, TRIP B, TRIP C.
And a long press on any A, B or C will reset the trip meter to 0Km..

Will I have to store every trip on separate position on the EEPROM...??

Joy:
Will I have to store every trip on separate position on the EEPROM...??

Yes, if you want the trip meters to be preserved when you power off and on again. You could maybe use less than 4 bytes per trip meter, but you've got loads of EEPROM space left, so I wouldn't bother trying to reduce the amount of data stored, unless keeping the mcu powered while you write all the data becomes a problem.

Joy:
I didnt get this part " unless keeping the mcu powered while you write all the data becomes a problem. "

Did you mean that the more data I want to write the more longer I t wil take to write and hence I will have to use much bigger Capacitor to keep the MCU powered that long...??

Yes. Each byte you write to EEPROM takes 3.3ms according to the EEPROM library documentation, so you have to make sure that the capacitor is big enough to power the mcu for the length of time it takes to recognise the power loss plus the length of time it takes to write all the bytes.

What is the best way to calculate for the TRIP meters..??

Freshly use odometer interrupts and calculate for the TRIP Meter..??

OR

just display the difference between the odometer reading when the TRIP Meter was reset and and odometer reading present..??

Joy:
What is the best way to calculate for the TRIP meters..??

Freshly use odometer interrupts and calculate for the TRIP Meter..??

OR

just display the difference between the odometer reading when the TRIP Meter was reset and and odometer reading present..??

Either, but the second is probably simpler. Store the value of wheelRevs at which each trip meter was last reset, then subtract it from savedWheelRevs and convert the result to km as usual for display. This also means you don't need to write the trip counters to EEPROM when the power goes down - instead, whenever you reset a trip counter, write its wheelRevs to EEPROM immediately.

I wrote this code, but it is not working..

#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
const int rstPin = 7;
int rstState = 0;
int Trip;
const int odometerPin = 3;
const int odometerInterrupt = 1;
const int odometerEepromLocation = 0;  // address of the first of 4 bytes in which the total wheel revs is stored
const int powerPin = A0;               // analog pin used to sense impending loss of power

const float wheelCircumference =  0.5;            //0.002035;  // wheel circumference in km
const int minPowerOkReading = 700;          // minimum reading on the power sense analog input that indicates good power
const int minPowerRestoredReading = 750;    // minimum reading on the power sense analog input that indicates we have powered back up

volatile unsigned long wheelRevs;       // total wheel revolutions counted, will overflow after 85 million km
unsigned long lastDisplayedMs = 0UL;    // time when we last refreshed the display

void setup()
{
  lcd.begin(16,2);
  // Initialise wheel revs from value stored in EEPROM
  wheelRevs = 0UL;
  for (int i = odometerEepromLocation + 3; i >= odometerEepromLocation; --i)
  {
    wheelRevs <<= 8;
    wheelRevs |= (unsigned long)EEPROM.read(i);
  }
  
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, FALLING);  
  
  
  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)savedWheelRevs);
      savedWheelRevs >>= 8;
    }
    
    // wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  else
  {  
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display every 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      lcd.setCursor(0, 0);
      lcd.print(km, 1);
      lcd.print("Km");
      
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }
  
  rstState = digitalRead(rstPin);
  
  if (rstState == HIGH){
    EEPROM.write(9, wheelRevs);
  }
 
  Trip = (savedWheelRevs - EEPROM.read (9)) * wheelCircumference;  
  lcd.setCursor(0, 1);
  lcd.print (Trip, 1);
  lcd.print(" ");
}

You need to save the wheel revs when the trip counter was started in 4 bytes of EEPROM, not one. First, let's write functions to read and write 4 bytes of EEPROM since you will be doing it in more than one place. Add this just before setup():

unsigned long readEepromLong(unsigned int address)
{
  unsigned long ret = 0UL;
  for (int i = address + 3; i >= address; --i)
  {
    ret <<= 8;
    ret |= (unsigned long)EEPROM.read(i);
  }
  return(ret);
}

void writeEepromLong(unsigned int address, unsigned long val)
{
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)val);
      val >>= 8;
    }
}

Next, change my original setup() and loop() to make use of these:

void setup()
{
  // Initialise wheel revs from value stored in EEPROM
  wheelRevs = readEepromLong(odometerEepromLocation);
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, RISING);  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    writeEepromLong(odometerEepromLocation, savedWheelRevs);
    
    // Wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  ...

Now change your trip meter code to use those functions:

    if (rstState == HIGH){
      writeEepromLong(TripMeterEepromLocation, wheelRevs);
    }
   
    Trip = (savedWheelRevs - readEepromLong(TripMeterEepromLocation)) * wheelCircumference;

Also, I'd keep the trip meter wheel revs in a local variable to save reading it from the eeprom every time.

Huh... :frowning:

I am jumbling up things :frowning:

#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
int rstState = 0;
int Trip;
const int odometerPin = 3;
const int odometerInterrupt = 1;
const int odometerEepromLocation = 0;  // address of the first of 4 bytes in which the total wheel revs is stored
const int powerPin = A0;               // analog pin used to sense impending loss of power

const float wheelCircumference = 0.002035;  // wheel circumference in km
const int minPowerOkReading = 700;          // minimum reading on the power sense analog input that indicates good power
const int minPowerRestoredReading = 750;    // minimum reading on the power sense analog input that indicates we have powered back up

volatile unsigned long wheelRevs;       // total wheel revolutions counted, will overflow after 85 million km
unsigned long lastDisplayedMs = 0UL;    // time when we last refreshed the display


unsigned long readEepromLong(unsigned int address)
{
  unsigned long ret = 0UL;
  for (int i = address + 3; i >= address; --i)
  {
    ret <<= 8;
    ret |= (unsigned long)EEPROM.read(i);
  }
  return(ret);
}

void writeEepromLong(unsigned int address, unsigned long val)
{
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)val);
      val >>= 8;
    }
}


void setup()
{
  lcd.begin(16,2);
    // Initialise wheel revs from value stored in EEPROM
  wheelRevs = readEepromLong(odometerEepromLocation);
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, RISING);  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    writeEepromLong(odometerEepromLocation, savedWheelRevs);
    
    // Wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  else
  {  
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display every 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      lcd.setCursor(0, 0);
      lcd.print(km, 1);
      lcd.print("Km");
      
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }
  
      if (rstState == HIGH){
      writeEepromLong(TripMeterEepromLocation, wheelRevs);
    }
   
    Trip = (savedWheelRevs - readEepromLong(TripMeterEepromLocation)) * wheelCircumference;  
}

Joy:
Huh... :frowning:

I am jumbling up things :frowning:

Meaning... ?

Your code to display the trip meter seems to have disappeared. It and the calculation of Trip should be inside the 'if' alongside the display of total km:

    if (now - lastDisplayedMs >= 200)    // update display every 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      lcd.setCursor(0, 0);
      lcd.print(km, 1);
      lcd.print("Km");

      Trip = (savedWheelRevs - readEepromLong(TripMeterEepromLocation)) * wheelCircumference;
      lcd.setCursor(...);
      lcd.print(trip, ...);
      
    }
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
int rstState = 0;
int Trip;
int TripMeterEepromLocation;
const int rstPin = 7;
const int odometerPin = 3;
const int odometerInterrupt = 1;
const int odometerEepromLocation = 0;  // address of the first of 4 bytes in which the total wheel revs is stored
const int powerPin = A0;               // analog pin used to sense impending loss of power

const float wheelCircumference = 0.002035;  // wheel circumference in km
const int minPowerOkReading = 700;          // minimum reading on the power sense analog input that indicates good power
const int minPowerRestoredReading = 750;    // minimum reading on the power sense analog input that indicates we have powered back up

volatile unsigned long wheelRevs;       // total wheel revolutions counted, will overflow after 85 million km
unsigned long lastDisplayedMs = 0UL;    // time when we last refreshed the display


unsigned long readEepromLong(unsigned int address)
{
  unsigned long ret = 0UL;
  for (int i = address + 3; i >= address; --i)
  {
    ret <<= 8;
    ret |= (unsigned long)EEPROM.read(i);
  }
  return(ret);
}

void writeEepromLong(unsigned int address, unsigned long val)
{
    for (int i = odometerEepromLocation; i < odometerEepromLocation + 4; ++i)
    {
      EEPROM.write(i, (unsigned char)val);
      val >>= 8;
    }
}


void setup()
{
  lcd.begin(16,2);
    // Initialise wheel revs from value stored in EEPROM
  wheelRevs = readEepromLong(odometerEepromLocation);
  if (wheelRevs == 0xFFFFFFFFUL)
  {
    // must be the first time we have run
    wheelRevs = 0UL;
  }
  
  // Set up the odometer sensor pin and interrupt
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, odometerIsr, RISING);  
}

void odometerIsr()
{
  ++wheelRevs;
}

void loop()
{
  // Capture the wheel revs with interrupts disabled in case it changes while we read it
  noInterrupts();
  unsigned long savedWheelRevs = wheelRevs;
  interrupts();
  
  if (analogRead(powerPin) < minPowerOkReading)
  {
    // Looks like power is going down, so write wheel revs to EEPROM (takes 13.2ms to write 4 bytes)
    writeEepromLong(odometerEepromLocation, savedWheelRevs);
    
    // Wait until either we die or the power comes back up
    while (analogRead(powerPin) < minPowerRestoredReading) 
    {
      delay(200);
    }    
  }
  else
  {  
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display every 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      lcd.setCursor(0, 0);
      lcd.print(km, 1);
      lcd.print("Km");
      
       Trip = (savedWheelRevs - readEepromLong(TripMeterEepromLocation)) * wheelCircumference;
      lcd.setCursor(0, 1);
      lcd.print(Trip, 1);
      
    
      
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }
  
      if (rstState == HIGH){
      writeEepromLong(TripMeterEepromLocation, wheelRevs);
    }
   
   
}

Is everything ok now...??

I would change the start of your program to this (main change is that TripMeterEepromLocation is constant and initialised):

#include <EEPROM.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
const int rstPin = 7;
const int powerPin = A0;               // analog pin used to sense impending loss of power
const int odometerPin = 3;
const int odometerInterrupt = 1;

const int odometerEepromLocation = 0;   // address of the first of 4 bytes in which the total wheel revs is stored
const int TripMeterEepromLocation = 4;   // address of the first of 4 bytes where the trip meter wheel revs is stored

const float wheelCircumference = 0.002035;  // wheel circumference in km

I would add the following to setup(), assuming that your reset button is connected between pin 'rstPin' asnd ground with no external pullup or pulldown resistors:

  pinMode(rstPin, INPUT);
  digitalWrite(rstPin, HIGH);   // enable internal pullup resistor

I would change the end of loop() to the following. Note that Trip is declared as float, and when the reset button is pressed we only write the wheel revs if it has changed.

  else
  {  
    if (digitalRead(rstPin) == LOW && readEepromLong(TripMeterEepromLocation) != savedWheelRevs)
    {
      writeEepromLong(TripMeterEepromLocation, savedWheelRevs);
    }
    
    unsigned long now = millis();
    if (now - lastDisplayedMs >= 200)    // update display every 200ms
    {
      lastDisplayedMs = now;
      float km = wheelCircumference * savedWheelRevs;
      lcd.setCursor(0, 0);
      lcd.print(km, 1);
      lcd.print("Km");
         
      float Trip = (savedWheelRevs - readEepromLong(TripMeterEepromLocation)) * wheelCircumference;
      lcd.setCursor(0, 1);
      lcd.print(Trip, 1);
    }
    delay(5);    // repeat after 5ms so that we check for power down often enough
  }