How to ignore single current spike

Sketch Overview:
The sketch compiles and is working as intended.
The servo rotates forward from angle/degree "0" to "180". If the DC current monitor detects any value from the servo above a certain threshold along the way, the servo immediately stops rotating forward and goes backward to its original starting position (and then loops indefinitely)

Issue:
Sometimes the current monitor will detect a single current "spike" coming from the servo motor while it rotates. This "spike" then trips the flag and sends the servo rotating backwards.
Is there any way that I can tell the current monitor to ignore a single current spike and only trip the flag when x3 consecutive spikes are detected?

Hardware Used:

Wiring Schematic:

Sketch:

#include <Wire.h>  //Used for the current monitor
#include <Servo.h>  //Servo library
#include <Adafruit_INA219.h>  //Current monitor library

Adafruit_INA219 ina219_3;  //Instance for the current monitor
Servo Servo3;  //Instance for the servo motor

int Servo3_Position = 0;  //Variable to store Servo3's degree/angle


//---------------

void setup()
{
  Serial.begin(115200);  //Baud rate
  ina219_3.begin();  //Start the current monitor
  uint32_t currentFrequency;  //Used for the current monitor. Unsure what this actually does, but the current monitor won't work properly without it.
  Servo3.attach(9);  //Attach Servo3 on PWM pin 9
  Servo3.write(0);  //Send Servo3 to the starting angle/degree ("0")
  delay(1500);  //Let Servo3 run for 1.5 seconds to get to angle/degree ("0") if it's not alreay there
}

//---------------

void loop()
{
  for (Servo3_Position = 0; Servo3_Position <= 180; Servo3_Position += 1)  //Servo3 goes from 0 angle/degree to 180 angle/degree in increments of +1 angle/degree at a time
  {
    Servo3.write(Servo3_Position);  //Tells Servo3 to go to position in variable 'Servo3_Position'
    float current_mA = 0;  //This is for the current monitor
    current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
    Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
    Serial.print(current_mA);  //Serial print the variable "current_mA"
    Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
    Serial.print("Angle:         ");  //Serial print the angle of Servo3
    Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
    Serial.println("");  //Serial print a blank line for spacing
    delay(15);  //This delay controls Servo3's rotational speed from 1 angle to the next. Example: Going from angle 5 to angle 6 has a delay of 15 ms in between
    if ((current_mA) >= 175.00)  //If the current monitor detects a value greater than or equal to 175.00
    {
      Servo3.detach();  //Disconnect Servo3 from PWM pin 9
      Serial.println("Flag - FORWARD");
      Serial.println();
      Servo3.attach(9);  //Reconnect Servo3 to PWM pin 9
      Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0")
      delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
      break;  //Exit the "if" loop
    }
  }

  Serial.print("////////////////////////////////////");  //Serial print a dividing line for easy viewing
  Serial.println();
  Serial.println();

  delay (1000);  //Once Servo3 has reached angle/degree 180, wait for 1 second

  Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0") without monitoring current
  delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
}

Do You have access to an oscilloscope capable of registering that disturbing pulse, checking the length of it?
One way could be to make a second current reading when that pulse occur. If the second reading also finds a pulse, then it's a trigger, else, ignore.

1 Like

No sir, unfortunately I do not.
Thank you for the suggestion though.

Okey.
Try a 1 mS or a few, delay and a second reading to verify.
Make sure that that You don't miss the real situation, when the return move must be done.

@Railroader It's working! Thank you sir!! That's a pretty clever trick you suggested :slight_smile:

Edited sketch with the suggestions from @Railroader

#include <Wire.h>  //Used for the current monitor
#include <Servo.h>  //Servo library
#include <Adafruit_INA219.h>  //Current monitor library

Adafruit_INA219 ina219_3;  //Instance for the current monitor
Servo Servo3;  //Instance for the servo motor

int Servo3_Position = 0;  //Variable to store Servo3's degree/angle


//---------------

void setup()
{
  Serial.begin(115200);  //Baud rate
  ina219_3.begin();  //Start the current monitor
  uint32_t currentFrequency;  //Used for the current monitor. Unsure what this actually does, but the current monitor won't work properly without it.
  Servo3.attach(9);  //Attach Servo3 on PWM pin 9
  Servo3.write(0);  //Send Servo3 to the starting angle/degree ("0")
  delay(1500);  //Let Servo3 run for 1.5 seconds to get to angle/degree ("0") if it's not alreay there
}

//---------------

void loop()
{
  for (Servo3_Position = 0; Servo3_Position <= 180; Servo3_Position += 1)  //Servo3 goes from 0 angle/degree to 180 angle/degree in increments of +1 angle/degree at a time
  {
    Servo3.write(Servo3_Position);  //Tells Servo3 to go to position in variable 'Servo3_Position'
    float current_mA = 0;  //This is for the current monitor
    current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
    Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
    Serial.print(current_mA);  //Serial print the variable "current_mA"
    Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
    Serial.print("Angle:         ");  //Serial print the angle of Servo3
    Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
    Serial.println("");  //Serial print a blank line for spacing
    delay(15);  //This delay controls Servo3's rotational speed from 1 angle to the next. Example: Going from angle 5 to angle 6 has a delay of 15 ms in between
    if ((current_mA) >= 150.00)  //If the current monitor detects a value greater than or equal to 175.00
    {
      delay(1);
      Serial.println("Flag #1 - FORWARD");
      float current_mA = 0;  //This is for the current monitor
      current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
      Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
      Serial.print(current_mA);  //Serial print the variable "current_mA"
      Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
      Serial.print("Angle:         ");  //Serial print the angle of Servo3
      Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
      Serial.println("");  //Serial print a blank line for spacing
      if ((current_mA) >= 150.00)  //If the current monitor detects a value greater than or equal to 175.00
      {
        delay(1);
        Serial.println("Flag #2 - FORWARD");
        float current_mA = 0;  //This is for the current monitor
        current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
        Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
        Serial.print(current_mA);  //Serial print the variable "current_mA"
        Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
        Serial.print("Angle:         ");  //Serial print the angle of Servo3
        Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
        Serial.println("");  //Serial print a blank line for spacing
        if ((current_mA) >= 150.00)  //If the current monitor detects a value greater than or equal to 175.00
        {
          Serial.println("Flag #3 - FORWARD");
          float current_mA = 0;  //This is for the current monitor
          current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
          Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
          Serial.print(current_mA);  //Serial print the variable "current_mA"
          Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
          Serial.print("Angle:         ");  //Serial print the angle of Servo3
          Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
          Serial.println("");  //Serial print a blank line for spacing
          if ((current_mA) >= 150.00)  //If the current monitor detects a value greater than or equal to 175.00
          {
            Servo3.detach();  //Disconnect Servo3 from PWM pin 9
            Serial.println("Flag - FORWARD");
            Serial.println();
            Servo3.attach(9);  //Reconnect Servo3 to PWM pin 9
            Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0")
            delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
            break;  //Exit the "if" loop
          }
        }
      }
    }
  }

  Serial.print("////////////////////////////////////");  //Serial print a dividing line for easy viewing
  Serial.println();
  Serial.println();

  delay (1000);  //Once Servo3 has reached angle/degree 180, wait for 1 second

  Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0") without monitoring current
  delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
}

Thanks! Great!
How many "Flag" does it take to kill the disturbance?

Store the number of consecutive spikes and the timestamp (millis) of the last spike. Run a function in the loop that looks at the current millis and the last spike millis; if it's longer than X milliseconds, clear the number of spikes and the stored timestamp. If the number of spikes is 3, trigger your servo to reverse direction. Fairly straightforward.

@Railroader's solution will also work of course, albeit with slightly different behavior.

1 Like

@Railroader I have it set up to flag x3 in a row before it finally sends the servo backwards. Is that what you were asking?

Not exactly. How many "Flag" pops up in Serial monitor when the spike appears?

It's only showing x1 flag when a normal current spike occurs, then it continues reading as shown in the first screenshot. However, if I manually stall the servo, it will flag x3 and then trip the real flag to reset the servo back to it's home position - (screenshot 2)

Fine!
I suggest that You can comment out "Flag3" in order to speed up the response time when the hard stop is reached.
Doing some more thinking about the pulse, how, from where it comes and get the signal more reliable is not bad.

@Railroader I tried removing "Flag3" like you suggested, but it causes too many resets.

Unfortunately, sometimes when the servo resets normally back to 0 and begins rotating, there are multiple power spikes which trips the flags and resets the servo back to 0.

Okey.
Using 3 Flags, 3 mS, is most likely good enough, and safe.

I was able to get rid of the last issue I was having where the servo would flag x3 and rest upon starting by adding "&& Servo3_Position >= 15" to the 1st flag condition!
This allows the servo to keep rotating without flagging through the first 15 angles/degrees. After that, it will begin monitoring the servos current draw.

#include <Wire.h>  //Used for the current monitor
#include <Servo.h>  //Servo library
#include <Adafruit_INA219.h>  //Current monitor library

Adafruit_INA219 ina219_3;  //Instance for the current monitor
Servo Servo3;  //Instance for the servo motor

int Servo3_Position = 0;  //Variable to store Servo3's degree/angle


//---------------

void setup()
{
  Serial.begin(115200);  //Baud rate
  ina219_3.begin();  //Start the current monitor
  uint32_t currentFrequency;  //Used for the current monitor. Unsure what this actually does, but the current monitor won't work properly without it.
  Servo3.attach(9);  //Attach Servo3 on PWM pin 9
  Servo3.write(0);  //Send Servo3 to the starting angle/degree ("0")
  delay(1500);  //Let Servo3 run for 1.5 seconds to get to angle/degree ("0") if it's not alreay there
}

//---------------

void loop()
{
  for (Servo3_Position = 0; Servo3_Position <= 180; Servo3_Position += 1)  //Servo3 goes from 0 angle/degree to 180 angle/degree in increments of +1 angle/degree at a time
  {
    Servo3.write(Servo3_Position);  //Tells Servo3 to go to position in variable 'Servo3_Position'
    float current_mA = 0;  //This is for the current monitor
    current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
    Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
    Serial.print(current_mA);  //Serial print the variable "current_mA"
    Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
    Serial.print("Angle:         ");  //Serial print the angle of Servo3
    Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
    Serial.println("");  //Serial print a blank line for spacing
    delay(15);  //This delay controls Servo3's rotational speed from 1 angle to the next. Example: Going from angle 5 to angle 6 has a delay of 15 ms in between
    if ((current_mA) >= 120.00  && Servo3_Position > 15)  //If the current monitor detects a value greater than or equal to 120.00 and has an "Angle" of greater than 15
    {
      delay(1);
      Serial.println("*****FLAG #1*****");
      Serial.println();
      float current_mA = 0;  //This is for the current monitor
      current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
      Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
      Serial.print(current_mA);  //Serial print the variable "current_mA"
      Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
      Serial.print("Angle:         ");  //Serial print the angle of Servo3
      Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
      Serial.println("");  //Serial print a blank line for spacing
      if ((current_mA) >= 120.00)  //If the current monitor detects a value greater than or equal to 120.00 and the angle is greater or equal to 10
      {
        delay(1);
        Serial.println("*****FLAG #2*****");
        Serial.println();
        float current_mA = 0;  //This is for the current monitor
        current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
        Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
        Serial.print(current_mA);  //Serial print the variable "current_mA"
        Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
        Serial.print("Angle:         ");  //Serial print the angle of Servo3
        Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
        Serial.println("");  //Serial print a blank line for spacing
        if ((current_mA) >= 120.00)  //If the current monitor detects a value greater than or equal to 120.00
        {
          Serial.println("*****FLAG #3*****");
          Serial.println();
          float current_mA = 0;  //This is for the current monitor
          current_mA = ina219_3.getCurrent_mA();  //This is for the current monitor
          Serial.print("Forward:       ");  //Serial print which direction Servo3 is rotating
          Serial.print(current_mA);  //Serial print the variable "current_mA"
          Serial.println(" mA");  //Serial print "mA" after printing the variable current_mA
          Serial.print("Angle:         ");  //Serial print the angle of Servo3
          Serial.println(Servo3_Position);  //Serial print the variable "Servo3 Position"
          Serial.println("");  //Serial print a blank line for spacing
          if ((current_mA) >= 120.00)  //If the current monitor detects a value greater than or equal to 120.00
          {
            Servo3.detach();  //Disconnect Servo3 from PWM pin 9
            Serial.println("*****RESET FLAG*****");
            Serial.println();
            Servo3.attach(9);  //Reconnect Servo3 to PWM pin 9
            Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0")
            delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
            break;  //Exit the "if" loop
          }
        }
      }
    }
  }

  Serial.print("////////////////////////////////////");  //Serial print a dividing line for easy viewing
  Serial.println();
  Serial.println();

  delay (1000);  //Once Servo3 has reached angle/degree 180, wait for 1 second

  Servo3.write(0);  //Send Servo3 back to the starting angle/degree ("0") without monitoring current
  delay(1500);  //Let Servo3 run for 1.5 seconds to get back to angle/degree ("0")
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.