Introduction: Monitoring Load Feedback of an Actuator

About: Progressive Automations is your primary source for electric linear actuators, motion control systems and automation accessories. For over a decade, we have supplied various industries with top quality automati…

In this Instructable, we'll be learning how to monitor the amount of current that an actuator is using, so that you can tell how much force it is applying. This is a more advanced project, requiring in-depth coding and calibrating.

The programming we will be doing today will cover debouncing of switches through two methods, the monitoring of an analog input, and the use of functions.

First we will wire the circuit together, then go over the coding, and finish by calibrating the code to suit your application.

Parts required:

- 1x Megamoto

- 1x Linear actuator

- 1x Arduino Uno

- 1x 12V power supply

Let's get started!

Step 1: Wiring

The wiring part of this project is attaching the motor controller to the Arduino, and adding two buttons to move the actuators.


Do the following:

1) Plug the MegaMoto shield into the Arduino

2) Connect a wire from the BAT+ terminal to the Vin pin on the Arduino. Since it is a shield, the GNDs are already connected

3) Connect your actuator to the A and B terminals

4) Connect 12V to BAT+, and GND to BAT-

5) Verify the jumper settings on the MegaMoto. See here for detailed instructions on each jumper.

For the buttons:

1) Wire a button between an unused pin and GND, so that when you push the button the pin is pulled LOW

2) Do the same with a second button

On to coding!

Step 2: Basic Coding

The goal of this code is to check the buttons, and depending on the state of them move the motor to extend or retract. Once the motor is extending, the current is constantly monitored, to see if it surpasses the max current limit. If it has passed the limit, then the motor stops, and will no longer extend, until you retract it.

Since motors have a large current spike when they start, the code has a small delay before it starts taking current readings. This can be changed depending on the motor. The value to change is firstfeedbacktimedelay.

The code also monitors for when the actuators have reached the limit switches. When the current drops to 0, the actuator knows that it has reached the limits. The current sensor will only stop the motor if it has read 0 a few times in a row, else a false reading would stop the motor mid stroke.

The code is attached, the code pasted below has more detailed comments. The code uses lots of functions, so that each part can be changed individually.

/*  Code to monitor the current amp draw of the actuator, and to cut power if it
  rises above a certain amount.

  Written by Progressive Automations
  August 19th, 2015

  Hardware:
  - RobotPower MegaMoto control boards
  - Arduino Uno
  - 2 pushbuttons
 */

const int EnablePin = 8;
const int PWMPinA = 11;
const int PWMPinB = 3; // pins for Megamoto

const int buttonLeft = 4;
const int buttonRight = 5;//buttons to move the motor

const int CPin1 = A5;  // motor feedback

int leftlatch = LOW;
int rightlatch = LOW;//motor latches (used for code logic)

int hitLimits = 0;//start at 0
int hitLimitsmax = 10;//values to know if travel limits were reached

long lastfeedbacktime = 0; // must be long, else it overflows
int firstfeedbacktimedelay = 750; //first delay to ignore current spike
int feedbacktimedelay = 50; //delay between feedback cycles, how often you want the motor to be checked
long currentTimefeedback = 0; // must be long, else it overflows

int debounceTime = 300; //amount to debounce buttons, lower values makes the buttons more sensitive
long lastButtonpress = 0; // timer for debouncing
long currentTimedebounce = 0;

int CRaw = 0;      // input value for current readings
int maxAmps = 0; // trip limit 

bool dontExtend = false;
bool firstRun = true;
bool fullyRetracted = false;//program logic

void setup()
{
  Serial.begin(9600);
  pinMode(EnablePin, OUTPUT);
  pinMode(PWMPinA, OUTPUT);
  pinMode(PWMPinB, OUTPUT);//Set motor outputs
  pinMode(buttonLeft, INPUT);
  pinMode(buttonRight, INPUT);//buttons
  
  digitalWrite(buttonLeft, HIGH);
  digitalWrite(buttonRight, HIGH);//enable internal pullups
  pinMode(CPin1, INPUT);//set feedback input
  
  currentTimedebounce = millis();
  currentTimefeedback = 0;//Set initial times

  maxAmps = 15;// SET MAX CURRENT HERE

}//end setup

void loop()
{
  latchButtons();//check buttons, see if we need to move

  moveMotor();//check latches, move motor in or out

}//end main loop

void latchButtons()
{
  if (digitalRead(buttonLeft)==LOW)//left is forwards
  {
    currentTimedebounce = millis() - lastButtonpress;// check time since last press
    if (currentTimedebounce > debounceTime && dontExtend == false)//once you've tripped dontExtend, ignore all forwards presses
    {
      leftlatch = !leftlatch;// if motor is moving, stop, if stopped, start moving
      firstRun = true;// set firstRun flag to ignore current spike
      fullyRetracted = false; // once you move forwards, you are not fully retracted
      lastButtonpress = millis();//store time of last button press
      return;
    }//end if
  }//end btnLEFT

  if (digitalRead(buttonRight)==LOW)//right is backwards
  {
    currentTimedebounce = millis() - lastButtonpress;// check time since last press

    if (currentTimedebounce > debounceTime)
    {
      rightlatch = !rightlatch;// if motor is moving, stop, if stopped, start moving
      firstRun = true;// set firstRun flag to ignore current spike
      lastButtonpress = millis();//store time of last button press
      return;    }//end if
  }//end btnRIGHT
}//end latchButtons

void moveMotor()
{
  if (leftlatch == HIGH) motorForward(255); //speed = 0-255
  if (leftlatch == LOW) motorStop();
  if (rightlatch == HIGH) motorBack(255); //speed = 0-255
  if (rightlatch == LOW) motorStop();

}//end moveMotor

void motorForward(int speeed)
{
  while (dontExtend == false && leftlatch == HIGH)
  {
    digitalWrite(EnablePin, HIGH);
    analogWrite(PWMPinA, speeed);
    analogWrite(PWMPinB, 0);//move motor
    if (firstRun == true) delay(firstfeedbacktimedelay); // bigger delay to ignore current spike
    else delay(feedbacktimedelay); //small delay to get to speed

    getFeedback();
    firstRun = false;
    
    latchButtons();//check buttons again
  }//end while

}//end motorForward

void motorBack (int speeed)
{
  while (rightlatch == HIGH)
  {
    digitalWrite(EnablePin, HIGH);
    analogWrite(PWMPinA, 0);
    analogWrite(PWMPinB, speeed);//move motor
    if (firstRun == true) delay(firstfeedbacktimedelay);// bigger delay to ignore current spike
    else delay(feedbacktimedelay); //small delay to get to speed
    getFeedback();

    firstRun = false;
    
    latchButtons();//check buttons again

  }//end while

  dontExtend = false;//allow motor to extend again, after it has been retracted

}//end motorBack

void motorStop()
{
  analogWrite(PWMPinA, 0);
  analogWrite(PWMPinB, 0);

  digitalWrite(EnablePin, LOW);
  firstRun = true;//once the motor has stopped, reenable firstRun to account for startup current spikes

}//end stopMotor

void getFeedback()
{
  CRaw = analogRead(CPin1); // Read current

  if (CRaw == 0 && hitLimits < hitLimitsmax) hitLimits = hitLimits + 1;
  else hitLimits = 0; // check to see if the motor is at the limits and the current has stopped 

  if (hitLimits == hitLimitsmax && rightlatch == HIGH)
  {
    rightlatch = LOW; // stop motor
    fullyRetracted = true;
  }//end if

  else if (hitLimits == hitLimitsmax && leftlatch == HIGH)
  {
    leftlatch = LOW;//stop motor
    hitLimits = 0;
  }//end if

  if (CRaw > maxAmps)
  {
    dontExtend = true;
    leftlatch = LOW; //stop if feedback is over maximum
  }//end if

  lastfeedbacktime = millis();//store previous time for receiving feedback
}//end getFeedback

Step 3: Advanced Coding

Now that you've seen the code, we will go over individual sections to give deeper explanations.

First, we'll look at a section of code within the latchButtons() function. We're going to look at the button debouncing. When the left button is pushed, the time since the last button press must be calculated. This is done by using the last value that was stored, and calling the millis() function to check the current time. Once we know that the time is greater then our debounce time, the function then checks if the actuator is allowed to extend. If both of these conditions are met, the function can continue, and do all the things related to the button press.

if (digitalRead(buttonLeft)==LOW)//left is forwards
{
    currentTimedebounce = millis() - lastButtonpress;// check time since last press
    if (currentTimedebounce > debounceTime && dontExtend == false)//once you've tripped dontExtend, ignore all forwards presses
    {
      leftlatch = !leftlatch;// if motor is moving, stop, if stopped, start moving
      firstRun = true;// set firstRun flag to ignore current spike
      fullyRetracted = false; // once you move forwards, you are not fully retracted
      lastButtonpress = millis();//store time of last button press
      return;
    }//end if
  }//end btnLEFT

This next section is the while loop within the motorForward() function. The part to look at here is the two delays. The loop starts by enabling the motor controller, and starting the motor. If it is the first run though the loop, there is a bigger delay. This bigger delay is to ignore the current spike that comes with the starting of a motor. When setting this delay, be careful not to set it too big, because there is no control during it. If the motor is stuck for any reason, it will not be able to be stopped until this delay is over. If it is not the first run, there is a much smaller delay.

Once the motor is moving, getFeedback() is used to check the current sensor. firstRun is turned off, so that the next time through the loop it takes the small delay, rather then the big one. And finally, the buttons are checked to see what new action should be taken.

while (dontExtend == false && leftlatch == HIGH)  {
    digitalWrite(EnablePin, HIGH);
    analogWrite(PWMPinA, speeed);
    analogWrite(PWMPinB, 0);//move motor
    if (firstRun == true) delay(firstfeedbacktimedelay);
    else delay(feedbacktimedelay); //small delay to get to speed
    getFeedback();
    firstRun = false;
    
    latchButtons();
  }//end while

The next sections are all in the getFeedback() routine. The routine starts by reading the analog pin connected to the sensor, then acts accordingly.

The first thing that is checked is if the motor is at it's limits. The code knows when the motor is at the limits when the current reading is 0. Sometimes, there is a false reading, so we need to set up a counter, so that the motor only stops when it is actually at the limits. This piece of code has to count up to the hitLimitsmax before the motor will stop. If it counts less then that, the counter resets.

if (CRaw == 0 && hitLimits < hitLimitsmax) hitLimits = hitLimits + 1;  

else hitLimits = 0; // check to see if the motor is at the limits and the current has stopped

This next part is just after the hit limits. If the motor is moving forwards when it reached the limit, it turns off the rightlatch. If it was moving backwards, it turns off the leftlatch. The code is the same for leftlatch.

if (hitLimits == hitLimitsmax && rightlatch == HIGH)  {
    rightlatch = LOW;
    hitLimits = 0;
  }//end if

Finally, the current limit is checked against it's maximum. If it is over, the leftlatch is turned off, and the motor is no longer allowed to extend. To reenable extension, the motor must be reversed.

if (CRaw > maxAmps)  {
    dontExtend = true;
    leftlatch = LOW; //stop if feedback is over maximum
  }//end if

Now that we've gone over the code, we can customize it for your needs.

Step 4: Calibration

There are a few modifications that you can do to make this code more suited to your application.

The first thing to do is set the max current limit. To find out what value you want to set it at, you need to do some testing. The easiest way is to use the Arduino example code "AnalogReadSerial", and look at the serial monitor to see what the feedback is from the motor. Once you know the value that you want to stop at, you can set it in the void setup() routine, by changing the maxAmps value.

Another option is to make the limit adjustable. If you attach a potentiometer to the Arduino on one of the analog pins, you can vary the max amps by varying the potentiometer. To do so, all you need to add is a declaration at the beginning to set the potentiometer pin, like so:

const int CPin1 = A5;  // motor feedback
const int Pot = 4; // potentiometer for feedback adjustment

Once that is there, you need to put "pinMode(Pot, INPUT);" into the void setup() routine. Once that's there, you can use the analogRead() to set the limit. Every time the code loops, the max amperage will be updated. It would look like this:

void loop(){  

maxAmps = analogRead(Pot);
 
latchButtons();//check buttons, see if we need to move

moveMotor();//check latches, move motor in or out

}//end main loop

Another setting you can edit is the debounce timers, to make the buttons more or less responsive. The value to change is debounceTime, in the beginning of the program. If you make the value higher, the button can be pressed slower, without it being registered twice. If the value is too high, you have to wait a long time before it will register the button press again. If the value is too low, and you press the button slowly, it may register twice, and start/stop the motor immediately. Keeping the value between 300 and 1000 is a good range.

int debounceTime = 300; //amount to debounce
long lastButtonpress = 0; // timer for debouncing
long currentTimedebounce = 0;

The last thing to change is the hitLimitsmax variable. This variable is used to tell when the actuator is at the fully retracted or fully extended position. When the actuator is in one of those positions, the current monitor will be reading 0 amps. By adjusting the hitLimitsmax variable, you can set how long it takes for the actuator to realize that it is at the limits.

Ideally, the limit would be able to be set to 1. As soon as the feedback is 0, the actuator will stop. If you have a low amperage actuator (~1A), due to the fluctuations in the current reading, the current may be read as 0 even when the actuator is moving. This would cause the actuator to stop randomly. To fix this, the hitLimitsmax value is set so that the sensor needs to read 0 amps X amount of times before it will stop. If you have a higher current (>5 Amps) actuator, this value can be lower. I have it set at 10, so that the actuator will take 0.5 seconds to stop once it hits the limits. It will take 0.5 seconds because the feedbacktimedelay is 50 milliseconds, and it loops 10 times.

Step 5: Conclusion

In this Instructable, we learned how to monitor the current of an actuator so that we could know how much pressure the actuator is applying. This could be used as a safety system, so that if your actuator is pressing too hard in your application, it knows to automatically stop moving so it protects itself and everything around it. You can use the principles we learned here to add any analog sensor to your actuator project.

If you'd like to take a look at our selection of linear actuators, motions control systems and microcontrollers then please visit us at www.progressiveautomations.com for all your actuator needs! We can even build a custom actuator or control system for you based on your own custom specifications with the help of our highly trained staff of engineers. You can learn more about the custom order process right here!

Follow, Like and Subscribe!

Twitter -twitter.com/ProgAutoInc

Facebook - www.facebook.com/ProgressiveAutomations

Youtube -www.youtube.com/user/MrActuators