Detecting cessation of rotating machine motion

Hello, this is my first arduino program. I would like to detect the cessation of a piece of rotating machinery (~1 Hz rate), and turn on a led+buzzer when it stops rotating. The goal is to draw attention to the fact the machine is no longer rotating, which periodically happens throughout the day at unexpected intervals. Normal operation is that the machine is rotating and nothing needs to be done by the program.

My first thought was to put a magnet on the rotating flange, and mount a Hall effect sensor nearby. During normal operation, a magnet periodically passes the sensor, and the LED+buzzer is given repeated instructions to remain LOW. If the machine is no longer rotating and no falling edges are detected after a set amount of time, the default program operation is to set the LED+buzzer HIGH. If noting is happening/detected, the LED+buzzer should default to HIGH.

I'm not sure if this is the best logic to use here, so if you have other suggestions for Hall logic, or maybe an easier sensor to use (acoustic?), I'm all ears.

My issue seems to be that the program roughly works as intended, but is unexpectedly turning the LED+buzzer pair HIGH periodically even when I pass a magnet by the Hall sensor at 1 Hz. I suspect my code is not working the way I intended it to, or maybe the sensor has a very slow "reset" time which won't allow it to continue receiving pulses quickly enough (~1 Hz)? Or something else? Any help is appreciated.

EDIT #2: The pinout below has some incorrect pins, this one may be more accurate from arduino.cc: https://content.arduino.cc/assets/Pinout-Micro_latest.png

-Board: micro (some bad pin data)
-Sensor: Gikfun A3144 (Amazon)
-Sensor configuration as shown here (only with 10 µF because I don't have 0.1 µF lying around)
-Digital pin 0 = LED+piezo-buzzer to ground
-Digital pin 3 = INT#1 looking at Hall sensor output pin

int outputState = HIGH;

void setup() {
  // put your setup code here, to run once:

  //pin 0 is LED/buzzer
  pinMode(0, OUTPUT);

  //pin 3 is INT#1
  pinMode(3, INPUT);

  //look for interrupt on INT#1 (pin 3)
  attachInterrupt(1, pin_ISR, FALLING);

  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (outputState == HIGH) {
    digitalWrite(0, HIGH);
  } else {
    digitalWrite(0, LOW);
    delay(2000);
    digitalWrite(0, HIGH);
    delay(2000);
  }

}

void pin_ISR() {
  outputState = LOW;
  Serial.print(F("Detect"));
  Serial.println();

EDIT: Forgot to mention, occasionally the Hall sensor will send an interrupt (which I see through the serial monitor text "Detect") even when nothing is moving by it, as if the Hall sensor has some internal "jitter/bounce" or noise causing it to change state? Is this just due to the fact these are cheap sensors?

There is no need to complicate things by using an interrupt to do what you describe

Instead, each time you detect the magnet save the value from millis(), then separately in loop(), if the current value of millis() minus the save value is greater than 1 second sound the alarm.

Use millis() for timing when sounding the alarm and you can continue to monitor the rotation if that is would be helpful

By the way, don't use Serial functions in an ISR. They depend on interrupts and interrupts are automatically disabled when in an ISR

According to that pinout image pin zero is used by the serial port.

What rotating machine ?

Thanks for the fast reply Bob! I'm not sure I understand this part:

"each time you detect the magnet save the value from millis()".

I thought I should use an interrupt because this magnet detection value could come at any time, so I need to be ready for it to show up even if the program is doing something else? I guess since I'm working ~1 Hz this is very slow compared to execution time so I don't need to necessarily use interrupt, is that right?

Do you mean to have one if/else loop looking for a change in state on the pin the Hall sensor is talking to, and if the pin changes state then it should save the value of millis()? Then aside from that loop there is the math to determine when to sound the alarm? And all of this is inside void loop()? So the if/else loop would run, followed by the math, again starting at the top with the if/else, ad inf?

Cheers,
Ollie

Yes. The Arduino will execute millions of commands per second so if the sketch is written properly you won't miss the input from the sensor

Yes to your final paragraph

In fact, using them is not straightforward, and introduces more problems to solve. For your case, interrupts are completely unnecessary.

@olliebdc,
Keeping things simple, you could add a second magnet & 180°

Good luck...........

You may want to check a circuit for a missing pulse detector.

Thanks Bob, I think I'm 99% of the way there with your advice! It works as I intended, with two open issues:

  1. Every time the magnet passes the sensor, instead of recording one LOW pulse, it registers between 20-40 LOWs, which I confirm by seeing that many "Detect"s being printed and the LED/alarm blinking/buzzing as well (later I commented out the serial print just to make sure this wasn't the problem). This looks like Hall sensor switch bounce, but could it be something with my code? I have the 100 µF cap on the output to try and minimize bounce (even though it calls for a smaller value); anything else I can do hardware wise?

  2. Every time the magnet passes the sensor, when the LED is supposed to stay off, it causes the LED to blink briefly on, and then turn off, which should not happen. The 5 second countdown in there currently still works from the last magnet pass, but there is this issue of a brief LED blink right when the magnet passes by every single time.

unsigned long hallTime = 0;
unsigned long currentTime = 0;
int hallState = HIGH;

void setup() {
  // put your setup code here, to run once:

  //pin 0 is LED/buzzer
  pinMode(0, OUTPUT);

  //pin 3 is input from Hall sensor
  pinMode(3, INPUT);

  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  hallState = digitalRead(3);

  currentTime = millis();

  if (hallState == HIGH) {
  }
  else {
    //Serial.print(F("Detect"));
    //Serial.println();
    hallTime = millis();
  }

  if (currentTime - hallTime > 5000) {
    digitalWrite(0, HIGH);
  }
  else {
    digitalWrite(0, LOW);
  }

}

Cheers,
Ollie

Hall sensors do not "bounce". That is why they have been used for many years. Look at your magnet? What is it actually mounted on? Bet it is something magnetic!!!
Paul

Hi,
A3144 has open collector output.

How have you got your hall effect wired?
If you do not have a pull up resistor on the Arduino input,
Change:

 pinMode(3, INPUT);

TO:

 pinMode(3, INPUT_PULLUP);

It will use the Arduino's internal pullup resistor for you.

Tom... :grinning: :+1: :coffee: :australia:

You need to detect when the inputbecomes LOW or HIGH rather than when it is LOW or HIGH
See the StateChangeDetection example in the IDE

  pinMode(0, OUTPUT);

Don't use pins 0 and 1 as they are used by the Serial interface

Thanks for clarifying; it is of course a solid state switch, so it shouldn't bounce mechanically like a relay, but couldn't the electronics in some cases produce an output that looks like a bounce, from the interplay between op-amp and transistor?

Thanks, I removed one component this way. I also removed the cap and the sensor still worked, which makes me wonder why the schematic I linked to required the cap? Maybe for high-speed operations much faster than my application?

If that happens, then that is called oscillation and is a result of either poor design or poor implementation.

You're the man Bob! You made my week with your help on this one. Final code with all your suggestions integrated below:

unsigned long hallTime = 0;
unsigned long currentTime = 0;
int hallState = HIGH;
int lastHallState = HIGH;
int outputPin = 23;
int inputPin = 3;

void setup() {
  // put your setup code here, to run once:

  //pin 0 is LED/buzzer
  pinMode(outputPin, OUTPUT);

  //pin 3 is input from Hall sensor
  pinMode(inputPin, INPUT_PULLUP);

  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  hallState = digitalRead(inputPin);

  currentTime = millis();

if (hallState != lastHallState){
  if (hallState == HIGH) {
  }
  else {
    Serial.print(F("Detect"));
    Serial.println();
    hallTime = millis();
  }
}
lastHallState = hallState;

  if (currentTime - hallTime > 5000) {
    digitalWrite(outputPin, HIGH);
  }
  else {
    digitalWrite(outputPin, LOW);
  }

}

Cheers from across the pond,
Ollie

/thread

I am glad that the technique worked
Good luck with the project

Hi,

What schematic link?

Do you understand why you need a pullup resistor?

Tom..... :grinning: :+1: :coffee: :australia: