Arduino Forum

Topics => Robotics => Topic started by: Alimoestar_S_K on Jun 06, 2018, 08:41 pm

Title: rpm sensing with proximity sensor
Post by: Alimoestar_S_K on Jun 06, 2018, 08:41 pm
Hi,

i'm working on rpm sensing using a proximity sensor. when ever the sensor detects metal bolt on the motor axis it should blink BUILTIN LED. The time between blinks is used to calculate the rpm. thats the theory behind this project. but so far no luck....
any advise?

Code: [Select]
/* interrupt function testing
 *  created 30 may 2018 9:51
 *  by Alimoestar SK
 *  tested and improved till 6 june 2018
 *  work as follows. if a metal object is detected build in led is on
 *  the number led is on is counted and presented as "number of detections"
 *  RPM is measured using the number of detection and the time that has passed
 */


const byte interruptPin = 2;
volatile byte state = LOW;
float n = 0;
float RPM = 0;

unsigned long StartTime = millis();



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);
  /* CHANGE to trigger the interrupt whenever the pin changes value
   *  LOW to trigger the interrupt whenever the pin is low,
   *  RISING to trigger when the pin goes from low to high,
   *  FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
   *  HIGH to trigger the interrupt whenever the pin is high.
   */
  Serial.begin(9600);
 
}
void loop() {
  digitalWrite(LED_BUILTIN, state);
 
}

void blink() {
  state = !state;
{ if(digitalRead(LED_BUILTIN  == HIGH))
{n++;
  Serial.print("number of detections:");
  Serial.println(n);
}
  unsigned long CurrentTime = millis();
 
    RPM = ((float) n / CurrentTime - StartTime);
    CurrentTime = StartTime;
      Serial.print("RPM:");
      Serial.println(RPM);
     
}}
 
Title: Re: rpm sensing with proximity sensor
Post by: bos1714 on Jun 07, 2018, 01:08 pm
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);
  /* CHANGE to trigger the interrupt whenever the pin changes value
   *  LOW to trigger the interrupt whenever the pin is low,
   *  RISING to trigger when the pin goes from low to high,
   *  FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
   *  HIGH to trigger the interrupt whenever the pin is high.
   */
  Serial.begin(9600);
 
}
Hello there!

The first thing that strikes me as odd is that you have the interrupt pin set as INPUT_PULLUP, which leads me to believe that your sensor pulls the pin low when it sees the metal bolt. Your interrupt is set to run the ISR when the pin is high. Since the pin is set at INPUT_PULLUP, the ISR is going to continuously run when the sensor does not see the bolt, seeing as how the pin is always high (except for the metal bolt). Try changing the interrupt event so that it triggers the ISR during a FALLING edge, instead of HIGH.
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Jun 07, 2018, 05:38 pm
Code: [Select]
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);
The valid modes are RISING, FALLING, CHANGE, and LOW. HIGH is nowhere in that list.
Title: Re: rpm sensing with proximity sensor
Post by: bos1714 on Jun 07, 2018, 05:47 pm
The valid modes are RISING, FALLING, CHANGE, and LOW. HIGH is nowhere in that list.
Here is a snippet from the Arduino Reference page for attachInterrupt() (https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/). It clearly says that HIGH is on the list. Additionally, if HIGH wasn't allowed, wouldn't the compiler throw an error?

(https://forum.arduino.cc/index.php?action=dlattach;topic=551798.0;attach=261301)
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Jun 07, 2018, 06:33 pm
Quote
Additionally, if HIGH wasn't allowed, wouldn't the compiler throw an error?
The compiler would throw an error if you tried to use "SamIsAnIdiot" as the argument. You are free to use values of the correct type, but not that the function expects, and the compiler will let you.
Title: Re: rpm sensing with proximity sensor
Post by: bos1714 on Jun 07, 2018, 06:36 pm
I see. You say that HIGH is not a valid argument input, but yet is it on the reference snippet I posted. Any explanations?
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Jun 07, 2018, 06:46 pm
I see. You say that HIGH is not a valid argument input, but yet is it on the reference snippet I posted. Any explanations?
Other than that it doesn't make sense? Why would you want to trigger an interrupt continually when a pin was HIGH or LOW?

Interrupts are to handle changes from outside the microcontroller.

(LOW has a valid use in waking from sleep mode)
Title: Re: rpm sensing with proximity sensor
Post by: cattledog on Jun 08, 2018, 06:32 pm
Quote
Here is a snippet from the Arduino Reference page for attachInterrupt(). It clearly says that HIGH is on the list.
You are correct about this, but there is more to consider. Did you see this line  about the Due, Zero, and MKR1000 boards right before the listing of HIGH

Quote
The Due, Zero and MKR1000 boards allows also:
HIGH: to trigger the interrupt whenever the pin is HIGH
What Arduino do you have?

In the AT328 Arduinos the external interrupt mode HIGH is actually treated the same as CHANGE.

Arduino.h defines HIGH as 1 and LOW as 0. It also defines CHANGE as 1, FALLING as 2 and RISING as 3.

The attachInterrupt() function (defined in WInterrupts.c) just does an entry of that value into the External Interrupt Control Register A (EICRA) for interrupt sense control. The only values which fit into the two control bits of that register are 0 through 3.

Table 12-1. Interrupt 1 Sense Control
ISC11 ISC10 Description
0 0 The low level of INT1 generates an interrupt request.
0 1 Any logical change on INT1 generates an interrupt request.
1 0 The falling edge of INT1 generates an interrupt request.
1 1 The rising edge of INT1 generates an interrupt request.


Please elaborate on what your program is doing. "no luck" is not a very good problem statement.
Title: Re: rpm sensing with proximity sensor
Post by: Alimoestar_S_K on Aug 15, 2018, 03:55 pm
dear all,

i have changed the code a little.  the idea is now to measure the time between 2 pulses (1 bolt passes the sensr twice, thus 1 full rotation of the axis) and calculate the rpm. measurements happens in microseconds.

Code: [Select]

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float RPM = 0;
unsigned long previoustime = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}
void loop() {

  digitalWrite(LED_BUILTIN, state);
}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {n++;
  }
  Serial.print("number of detections : ");
  Serial.print(n);
 
  if (n == 2){
     unsigned long currenttime = micros();
     RPM = (((float) 1.00 / (float)(currenttime - previoustime)) * (float) 60000000.00);
     currenttime = previoustime;
     n=0;
  }
     
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }





but what happens in serial  monitor is that the rpm value keeps dropping till reaches zero.But motor speed is constant.

help please.
Title: time between 2 interupts using 1 sensor
Post by: Alimoestar_S_K on Aug 15, 2018, 05:22 pm
dear all,

im working with a inductive proximity sensor and want to measure the time between 2 interupts of this sensor.

this is my code, which for some reason keeps dropping till reaches zero

Code: [Select]


//15 augustus 2018
// Alimoestar S.K.

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float Time = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}
void loop() {

  digitalWrite(LED_BUILTIN, state);
}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {unsigned long previoustime= micros();
    n++;
 
  Serial.print("number of detections : ");
  Serial.print(n);
 
   
  if (n == 2){
     unsigned long currenttime = micros();
     Time=(float)(currenttime - previoustime);
        currenttime = previoustime;
     n=1;
  }
  }
 
 
       
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }



any idea's???
thank you in advance
Title: Re: time between 2 interupts using 1 sensor
Post by: AWOL on Aug 16, 2018, 12:25 am
Don't do serial I/O in interrupt context.

Quote
keeps dropping till reaches zero
I don't know what that means.

Code: [Select]
digitalRead(LED_BUILTIN  == FALLING)Oops
Title: Re: time between 2 interupts using 1 sensor
Post by: Alimoestar_S_K on Aug 16, 2018, 05:00 am
dear awol,

when i say keep dropping till reaches zero, i meant that the value printed on the serial monitor was decreasing till it reached zero.

i've recently found out that i made an error in
Code: [Select]
currenttime = previoustime;
// it should be the other way around
previoustime = currenttime;


since fixing this, no more decreasing till zero

Don't do serial I/O in interrupt context.

should i put this in the loop, like this? or do you suggest a different way?


Code: [Select]

//15 augustus 2018
// Alimoestar S.K.

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float Time = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {unsigned long previoustime= micros();
    n++;
 
  Serial.print("number of detections : ");
  Serial.print(n);
 
   
  if (n == 2){
     unsigned long currenttime = micros();
     Time=(float)(currenttime - previoustime);
        previoustime = currenttime;
     n=1;
  }
  }
  }
 
 void loop() {

  digitalWrite(LED_BUILTIN, state);

       
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }
Title: Re: time between 2 interupts using 1 sensor
Post by: AWOL on Aug 16, 2018, 08:53 am
Code: [Select]
if (digitalRead(LED_BUILTIN  == FALLING))Still oops.
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Aug 16, 2018, 12:40 pm
Code: [Select]
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
That is a stupid name for the function to call. Nothing is blinking...

Code: [Select]
  if (digitalRead(LED_BUILTIN  == FALLING))
Work out, on paper, EXACTLY which pin you are reading from. It is NOT the pin you want to read from.

There is NO need to read the state of an output pin. Keep track of the state you set it to.

Regardless, the state of the LED pin has NOTHING to do with the time that the sensor (assuming that it is indeed connected to pin 2) triggered the interrupt.

Your code is, as currently written, complete nonsense.
Title: Re: rpm sensing with proximity sensor
Post by: Alimoestar_S_K on Aug 16, 2018, 02:57 pm
dear all,

i've taken all coments and advise into consideration. did some extra reading and came up with the following.

Code: [Select]

/* Alimoestar S.K.
 *  original code may 2018
 *  16 aug 2018 revised
 *  coments and advise from arduino forum toopic :rpm sensing with proximity sensor
 *
  */

const byte interruptPin = 2;
volatile long n=0;
volatile long RPM=0;
volatile boolean flag=0;
long RPMperiod;
unsigned long previoustime=0;


void setup()
{
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sensor, FALLING);

}

void loop()
{
    if(flag)
  {
    RPM=(60000000UL/RPMperiod);   //One (1) signal per rotation.
    interrupts();
    Serial.print("RPM = ");
    Serial.println(RPM );
    flag=0;
  }
}

void sensor()
{unsigned long currenttime=micros();
  RPMperiod=float ( currenttime- previoustime);
  flag=1;
  previoustime = currenttime;

}

  
in the serial monitor i'm seeing my rpm value and a lot of other things.
Title: Re: rpm sensing with proximity sensor
Post by: Alimoestar_S_K on Aug 16, 2018, 03:03 pm
Work out, on paper, EXACTLY which pin you are reading from. It is NOT the pin you want to read from.


the pin i am reading from is pin 2 on the arduino uno R3, which has interrupts for pin 2 and 3.


There is NO need to read the state of an output pin. Keep track of the state you set it to.

so in other words leave out the write state to build in led and try something else?
will a flag function work?
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Aug 20, 2018, 07:22 pm
Quote
the pin i am reading from is pin 2 on the arduino uno R3, which has interrupts for pin 2 and 3.
With this code,
Code: [Select]
  if (digitalRead(LED_BUILTIN  == FALLING))
You are comparing LED_BUILTIN to FALLING, which returns true or false. Which of those values do you think is 2? Neither one is. That code is reading from pin true or pin false. Hardly a reasonable thing to do.

Even if you fix that to
Code: [Select]
  if (digitalRead(LED_BUILTIN)  == FALLING)
so that you are reading from the LED_BUILTIN pin, you are comparing HIGH or LOW to FALLING. Never will match...
Title: Re: rpm sensing with proximity sensor
Post by: Alimoestar_S_K on Sep 12, 2018, 03:29 pm
dear all,

after consideration of all your comments and some extra reading and testing, i came up with the following code:

Code: [Select]


/* RPM sensing using a arduino uno
    and inductive proximity sensor
    Alimoestar S.K.
    original code may 2018
    revised 20 aug 2018
    revised 27 aug 2018
    revised 1 sep 2018

*/

//---------------------------- declaration -------------------------------
const byte interruptPin = 2;
int n = 0;
volatile long RPM = 0;
volatile long RPMsum = 0;             // sum of 20 RPM measurements
volatile long RPMav = 0;              // average of 20 RPM measurements
float F = 0.000;                      // frequency
volatile boolean flag = 0;
unsigned long DeltaT;                 // time between two interupts
unsigned long previoustime = 0;



//---------------------------- setup --------------------------------------
void setup()
{
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sensor, FALLING);
}

//---------------------------- ISR sensor --------------------------------
void sensor()
{ flag = 1;
}

//----------------------------- loop --------------------------------------
void loop()
{ //-----------------------------------------------------------------------rpm measurement
  if (flag)
  { noInterrupts();                                            // disables interrupt, because the folloing is time sensitive
    n++;
    unsigned long currenttime = micros();                      // measure the current time
    DeltaT = (currenttime - previoustime);                     // calculate the time difference
    previoustime = currenttime;                                // set previoustime = currenttime


    if (DeltaT >= 32000) {                                     // deltaT 32000 => rpm= +-1800 (debouncing)
      RPM = float(60000000UL / DeltaT);                        // calculate the rpm (One (1) signal per rotation)
     
      Serial.print("delta T =\t");
      Serial.print(DeltaT);
      Serial.print("\t rpm =\t");
      Serial.println(RPM );
     
      //}

      //---------------------------------------------- frequency calculation
      F = (RPMav / 2) * 60.00;
      flag = 0;
      interrupts();

    }



    // Average RPM value of 200 measurements
    RPMsum = RPMsum + RPM; // sum of 200 measurements

    if (n == 20) {
      RPMav = (RPMsum / 20); // averge of 200 measurement
      //---------------------------------------------- print to serial screen
      Serial.print("    RPM = ");
      Serial.print(RPM );
      Serial.print("    RPMav = ");
      Serial.print(RPMav );
      Serial.print("     Freq = ");
      Serial.println(F );
      RPMsum = 0;
      n = 0;

    }
  }

}//-------------------------------- end loop -----------------------------------------


//--------------------------------- end code -----------------------------------------



this seemed to work at first, but after some time gave some nonsense reading.
any thoughts or coments???
Title: Re: rpm sensing with proximity sensor
Post by: PaulS on Sep 17, 2018, 02:36 pm
Quote
but after some time gave some nonsense reading.
any thoughts or coments
Yes. You ABSOLUTELY MUST understand what you can, and can not do, with interrupts disabled.

The ONLY thing you should be doing, while interrupts are disabled, is copying and resetting the values of the variables that the interrupt service routine(s) use.

NOT A SINGLE THING ELSE.

Title: Re: rpm sensing with proximity sensor
Post by: mrphysh on Oct 25, 2018, 07:51 pm
This is similar to my project.  These comments make little sense.  Watch this little video;  If you can understand this simple sketch, the solution will become obvious.  (use a Hall detector, not the photo module in the video.  I have since learned that RPM is usually done with a Hall effect detector)

https://youtu.be/ifZo87lrlfE