Tachometer Peak acceleration displaying 'Infinite'

Hey guys,

I have built an optical tachometer capable of displaying the rpm (or rad/s) and acceleration of a pulley wheel. I’m now wanting to capture the peak acceleration and deceleration. A simple task it would seem, however I find that my tacho displays the peak values as ‘Inf’ infinity. I thought all I would need to do is implement this:

if(accel_rpm > accel_rpm_max_value)
  {
    accel_rpm_max_value = accel_rpm;
    accel_rads_max_value = ((accel_rpm_max_value/60)*2*PI);
  }

  if(accel_rpm < accel_rpm_min_value)
  {
    accel_rpm_min_value = accel_rpm;
    accel_rads_min_value = ((accel_rpm_min_value/60)*2*PI);
  }

When I increase the speed of the pulley wheel from rest, the tacho always displays a peak accel and deceleration of ‘Inf’, however if I reset the tacho whilst the pulley is rotating the peak accel is populated with a value.

Here is my full code:

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(11, 10, 3, 4, 5, 6);

// VARIABLES:
volatile unsigned long last_time, this_time, duration; //variables used in ISR declared as volatile
unsigned long old_time, duration_old, accel_duration, accel_duration_old, accel_time;
unsigned long disp_timeold = 0L, accel_time_temp = 0L, accel_calc_time = 0L, time_temp = 0L; 
const int disp_sample_time = 500, accel_sample_time=200;//LCD refresh rate & acceleration time period (ms)
const int button_pin = A0, button_pin_2 = A1, array_size = 10; //Pushbutton Pins and define array size
int button_state = 0, button_state_2 = 0, last_button_state = 0, last_button_state_2=0, my_button =0, my_button_2 =0;
float accel_rpm_max_value =0, accel_rpm_min_value =0, accel_rads_max_value =0, accel_rads_min_value =0;
float rpm_new =0, rpm_old =0, rads_new, accel_rads = 0, accel_rpm = 0;
float rpm_array[array_size] = {0}, accel_array[array_size] = {0};//RPM and acceleration arrays

//SETUP
void setup() 
{
  lcd.begin(16, 2);  // intialise the LCD
  pinMode(button_pin, INPUT); //initialise PTM button pins
  pinMode(button_pin_2, INPUT);
  attachInterrupt(0, rpm_interrupt, FALLING);//set interrupt on pin 2 & call rpm_interrupt on a falling edge 
} 

void loop() 
{
  for (int n=0; n<(array_size-1);n++) //loop to shift rpm array down by one place
  {
    rpm_array[n]=rpm_array[n+1];
  }
  rpm_array[array_size-1] = 60e6/(duration * 28);  // 60,000,000 us / duration per transition in us * 28 transitions per revolution 
  rpm_new=0; //clear previous value
  for (int n=0; n<(array_size);n++) //loop to add array of RPM's together
  {
    rpm_new+= rpm_array[n];
  }
  rpm_new = rpm_new/array_size; //Divide by array size to calculate average RPM over 10 pulses
  rads_new = ((rpm_new/60)*2*PI); //Convert RPM to rad/s

  ///////////////// ACCELERATION CALCULATIONS /////////////////////////////////////////////
  accel_time_temp = millis() - accel_calc_time;
  if( accel_time_temp >= accel_sample_time) 
  {   
    for (int n=0; n<(array_size-1);n++) //loop to shift rpm array down by one place
    {
      accel_array[n]=accel_array[n+1];
    }
    accel_calc_time += accel_time_temp;
    accel_duration = this_time - old_time;
    accel_array[array_size-1] = 1e6*((rpm_new - rpm_old)/accel_duration);
    accel_rpm=0; //clear previous value
    for (int n=0; n<(array_size);n++) //loop to add array of RPM's together
    {
      accel_rpm+= accel_array[n];
    }
    accel_rpm /= array_size; //Divide by arraysize to calculate average acceleration
    accel_rads = (accel_rpm/60)*2*PI;
    rpm_old = rpm_new;
    old_time= this_time;
  }
////////////////////////////////////////////////////////////////////////////////////
  if ((micros()- this_time)>= 5e5) //display 0 rpm if speed < 4 rpm
  {
    rpm_new = 0;
    rads_new = 0;
  }

  ////////////////Capturing peak acceleration data ///////////////////////////////
  if(accel_rpm > accel_rpm_max_value)
  {
    accel_rpm_max_value = accel_rpm;
    accel_rads_max_value = ((accel_rpm_max_value/60)*2*PI);
  }

  if(accel_rpm < accel_rpm_min_value)
  {
    accel_rpm_min_value = accel_rpm;
    accel_rads_min_value = ((accel_rpm_min_value/60)*2*PI);
  }

  ///////////////////////////////////////////////////////////////////////////////

  if(isnan(accel_rpm)) //If RPM =0, acceleration equation won't produce a valid number (nan)
  {                      
    accel_rpm = 0;
    accel_rads = 0;
  }
  
  /////////////////////////Display & Buttons ////////////////////////////////////
  button_state_2 = digitalRead(button_pin_2); 
  if (button_state_2 != last_button_state_2)
  {
    if (button_state_2 == 1) 
    { 
      my_button_2++;   
    }
    last_button_state_2 = button_state_2; // remember the last state of the button
  }
  button_state = digitalRead(button_pin); // See if the button1 has been pushed
  if (button_state != last_button_state) 
  {
    if (button_state == 1) 
    { 
      my_button++;   
    }
    last_button_state = button_state; // remember the last state of the button
  }
  
  time_temp = millis() - disp_timeold; //refresh LCD 
  if( time_temp >= disp_sample_time) 
  {   
    disp_timeold += time_temp;

    if (my_button_2%2==0)
    {
      if (my_button%2==0) //If switch if set high display RPM, if low display rad/s
      {   
        //Print out RPM to lcd
        lcd.clear();
        lcd.print("RPM: ");
        lcd.print(rpm_new);
        lcd.setCursor(0, 1);
        lcd.print("RPM/s: ");
        lcd.print(accel_rpm);
      }
      else 
      {
        //Print out Rad/s to lcd
        lcd.clear();
        lcd.print("Rad/s: ");
        lcd.print(rads_new);
        lcd.setCursor(0, 1);
        lcd.print("Rad/s^2: ");
        lcd.print(accel_rads);
      }  
    }
    else
    {
      if (my_button%2==0) //If switch if set high display RPM, if low display rad/s
      {   
        //Print out RPM to lcd
        lcd.clear();
        lcd.print("Peak Acc: ");
        lcd.print(accel_rpm_max_value);
        lcd.setCursor(0, 1);
        lcd.print("Peak Dec: ");
        lcd.print(accel_rpm_min_value);
      }
      else 
      {
        //Print out Rad/s to lcd
        lcd.clear();
        lcd.print("Peak Acc: ");
        lcd.print(accel_rads_max_value);
        lcd.setCursor(0, 1);
        lcd.print("Peak Dec: ");
        lcd.print(accel_rads_min_value);
      }  
    }
  }
}
void rpm_interrupt() //Interrupt function
{
  last_time = this_time;
  this_time = micros();
  duration = this_time - last_time; //Calculates duration between pulses
}

Please can someone see where I’m going wrong?

if you print a float that is larger than maxlong (2 billion something) it will print inf

You can test this by dividing the values printed by 1e9.

have a look at - Proposed update for the printFloat code of print.cpp - #11 by robtillaart - Libraries - Arduino Forum -

Managed to solve the issue.

As acceleration is the change of speed over time, if speed is zero, 0/t = infinity. The solution is check the accerlaeration using the 'isnan' and 'isinf' variables as shown:

 if(isnan(accel_array[array_size-1])) //if acceleration is NaN or Inf set to zero
    {                      
      accel_array[array_size-1] = 0;
    }
    if(isinf(accel_array[array_size-1]))
    {                      
      accel_array[array_size-1] = 0;
    }

Hence, zero will be stored to the acceleration array rather than the largest float value :slight_smile:

newb91:
Managed to solve the issue.

As acceleration is the change of speed over time, if speed is zero, 0/t = infinity. The solution is check the accerlaeration using the 'isnan' and 'isinf' variables as shown:

 if(isnan(accel_array[array_size-1])) //if acceleration is NaN or Inf set to zero

{                     
      accel_array[array_size-1] = 0;
    }
    if(isinf(accel_array[array_size-1]))
    {                     
      accel_array[array_size-1] = 0;
    }




Hence, zero will be stored to the acceleration array rather than the largest float value :)

0/t is always 0 unless t = zero ...