How to Work Two Linear Actuator Synchronously by Using Arduino and VNH5019 Motor Driver?

Thread Starter

rennie1080

Joined Apr 10, 2017
48
I am newbie and I want to build a project that contains two linear actuator that move synchronously. Two of them will lift up and down at same time. I use arduino mega and VNH5019 motor driver. I have thompson electrac ELD linear actuator. I have never tried to synchronize two linear actuator. Linear actuator have encoder output ( it is hall effect encoder -( not absolute. So it cannot keep last position in case of power cut )). Encoder type is hall effect type. Encoder output voltage levels low (logical zero), typical / max is 0.1/0.25 Vdc. Also it has output fully extented/retracted signal. I tested it with H-Bridge motor driver made of 4 SSR relays and push button switches to retract and extract. There is a synchronization problem. How should I solve that synchronozation problem could you help me ? What should I do?

upload_2019-8-9_14-57-58.png
 

shortbus

Joined Sep 30, 2009
7,670
Also it has output fully extented/retracted signal. I tested it with H-Bridge motor driver made of 4 SSR relays and push button switches to retract and extract. There is a synchronization problem. How should I solve that synchronozation problem could you help me ? What should I do?
Not much to work with in the explanation. So will ask some questions of you.

1. How are the actuators terminated on the part that is moving?

2. When either at rest or extended are the rams of the actuators the same length? From mounting point to mounting point on the actuator.

3. With your H-bridge are you using the same bridge to drive both actuators, or do you have separate bridges for each?
 

dendad

Joined Feb 20, 2016
3,517
You will need to drive them separately, and read the limit switches and encoders. Then for a start, drive them home to reset the position. When running, the encoders counts will be kept the same by changing the PWM to alter the motor speeds. One could be at a fixed PWM, not maximum, and the other driven to track the first.

A couple of linear actuators I have only give on pulse per rev.
To get finer control, the rotating magnet can be replaced with a toothed wheel and magnet setup to give more pulses per rev.
 

Thread Starter

rennie1080

Joined Apr 10, 2017
48
1- The system will stop when actuators extracted 500 mm ( actuators have 900 mm stroke length)
2- Yes, they are identical
3- For testing I used same H-birdges by wiring actuators at same wire points.

I will drive actuators by using VNH5019 motor driver and arduino. I want to control them by using push buttons.

Not much to work with in the explanation. So will ask some questions of you.

1. How are the actuators terminated on the part that is moving?

2. When either at rest or extended are the rams of the actuators the same length? From mounting point to mounting point on the actuator.

3. With your H-bridge are you using the same bridge to drive both actuators, or do you have separate bridges for each?
 

MaxHeadRoom

Joined Jul 18, 2013
20,657
The problem is that those encoders will give you rate of speed only, not position, for this you would at least require quadrature encoder.
I one did a freight car hydraulic lifter that had quad encoders on four hydraulic cylinders, I used a Galil Motion card that has electronic gearing feature, one master and 3 slaves, depends on just how accurate you need the control.
Max.
 

shortbus

Joined Sep 30, 2009
7,670
I will drive actuators by using VNH5019 motor driver and arduino. I want to control them by using push buttons.
If your controlling with push buttons why the Arduino? If you want to limit the movement of the actuators why not use a limit switch on what you are moving?

Mounting two actuators to something has some mechanical things that need to be followed to make them work together and you haven't given the answers to that.
 

Thread Starter

rennie1080

Joined Apr 10, 2017
48
I just want to make them work synchronously. When I push button 1, actuators move forward, and when I push button 2, actuators move down. Could you have any idea for synchronization?

If your controlling with push buttons why the Arduino? If you want to limit the movement of the actuators why not use a limit switch on what you are moving?

Mounting two actuators to something has some mechanical things that need to be followed to make them work together and you haven't given the answers to that.
 

dendad

Joined Feb 20, 2016
3,517
The only ways are to mechanically connect them together, or monitor the pulses and sync them together. An Arduino to do that is a good idea, then, if there is a large error, the system can stop and raise an alarm.
As I mentioned, have 2 H bridges. One driven at maybe 75% speed, and the other synced to the first one by altering its PWM drive.
Quite a bit of tuning may be required.
 

shortbus

Joined Sep 30, 2009
7,670
The only ways are to mechanically connect them together, or monitor the pulses and sync them together. An Arduino to do that is a good idea, then, if there is a large error, the system can stop and raise an alarm.
As I mentioned, have 2 H bridges. One driven at maybe 75% speed, and the other synced to the first one by altering its PWM drive.
Quite a bit of tuning may be required.
But there are many applications of using two or even more electrical actuators not using synchronization. Lift gates in an SUV, convertible tops, etc. So it can be done without total synchronization of the motors. But then the type of mounting comes into play, the biggest problem is no "play" in the mounting.
 

Thread Starter

rennie1080

Joined Apr 10, 2017
48
Hi again, I found different code to synchronize two linear actuator by using another motor driver named MegaMoto. This code drive two linear actuator simultaneously. How can I adapt this code for VNH5019 driver module ? Could you give any idea?

Best Regards


Code:
#define amp0 A5
#define PWMA0 6
#define PWMB0 5
#define enable0 13   //pins for first MegaMoto

#define amp1 A4
#define PWMA1 9
#define PWMB1 10
#define enable1 12   //pins for second MegaMoto

#define hall0 52
#define hall1 53   //interrupt pins for hall effect sensors

#define switch0 8   //Up button
#define switch1 7   //Down button

int amp[] = {0, 0}; //current readings
int maxAmps = 100;
int minAmps = 0;
int spd[] = {0, 0, 0, 0}; //speeds (fwd, rev, fwd, rev)
int sw[] = {1, 1}; //switch up, switch down
int prev[] = {0, 0};//previous switch state

volatile int count[] = {0, 0};//Act0, Act1
int ave[] = {0, 0}; //average speed values
int timedelay[] = {750, 50}; //first, regular delay for current readings
int FWDspd = 255, REVspd = 255;//default speed values (max)
int maxSpeed = 255;

int hitLimits = 0;
int hitLimitsmax = 20;//value to know when at limits

bool forwards = false;
bool backwards = false;
bool dontExtend = false;
bool dontRetract = false;
bool fullyRetracted = true;//trigger for homing
bool firstRun = true;//first run of the motor once the button is pushed

void setup() {
  pinMode(amp0, INPUT);
  pinMode(amp1, INPUT);
 
  digitalWrite(amp0, LOW);
  digitalWrite(amp1, LOW);//set Current sensors

  pinMode(PWMA0, OUTPUT);
  pinMode(PWMA1, OUTPUT);
  pinMode(PWMB0, OUTPUT);
  pinMode(PWMB1, OUTPUT);//set PWM outputs

  pinMode(enable0, OUTPUT);
  pinMode(enable1, OUTPUT);
  digitalWrite(enable0, LOW);
  digitalWrite(enable1, LOW); //set enable and turn boards off

  pinMode(switch0, INPUT);
  pinMode(switch1, INPUT); //set up/down switch
  digitalWrite(switch0, HIGH);
  digitalWrite(switch1, HIGH);//enable enternal pullups

  pinMode(hall0, INPUT);
  pinMode(hall1, INPUT);//set interrupts
  digitalWrite(hall0, LOW);
  digitalWrite(hall1, LOW);//set low, to wait for rising edge

  attachInterrupt(digitalPinToInterrupt(52), speed0, RISING);
  attachInterrupt(digitalPinToInterrupt(53), speed1, RISING); //enable the two hall effect interupts

  dontExtend = false;
  dontRetract = false;
  fullyRetracted = true;//start assuming retracted

  Serial.begin(9600);
}//end setup

void loop() {
   ReadInputs();//check input button, calculate speeds

  if (sw[0] == 0 && sw[1] == 1) goForwards();
  else if (sw[0] == 1 && sw[1] == 0) goBackwards();
  else stopMoving();

  for (int i = 0; i <= 1; i++) prev[i] = sw[i]; //store switch values as previous values
}//end loop

void ReadInputs() {
  amp[0] = analogRead(amp0);
  amp[1] = analogRead(amp1);//read current sensors
  sw[0] = digitalRead(switch0);
  sw[1] = digitalRead(switch1);//read switches
}//end read inputs

void goForwards()
{
  if (prev[0] == 1 && sw[0] == 0) firstRun = true;
  else firstRun = false;//when the switch changes, use firstRun delay
  forwards = true;
  backwards = false;
  fullyRetracted = false;
  //Serial.println("Moving forwards");
  spd[0] = FWDspd;
  spd[1] = 0;
  spd[2] = FWDspd;
  spd[3] = 0; // set base speeds
  FWDsync();//update speeds based on hall effect counts
  getFeedback();//check current draw

  digitalWrite(enable0, HIGH);
  digitalWrite(enable1, HIGH);//enable both boards
  //Serial.print("Dont Extend"), Serial.println(dontExtend);
  if (dontExtend == true)
  {
    digitalWrite(enable0, LOW);
    digitalWrite(enable1, LOW);//disable both boards
  }
  delay(10);//slight delay

  Serial.print(" Speeds "), Serial.print(spd[0]), Serial.print(", "), Serial.print(spd[1]);
  Serial.print(", "),       Serial.print(spd[2]), Serial.print(", "), Serial.println(spd[3]);

  analogWrite(PWMA0, spd[0]);
  analogWrite(PWMB0, spd[1]);
  analogWrite(PWMA1, spd[2]);
  analogWrite(PWMB1, spd[3]);//set speeds
 
  if (firstRun == true) delay(timedelay[0]);
  else delay(timedelay[1]); //small delay to get to speed

  dontRetract = false;//once you have moved forwards, you can move back again.
  firstRun = false;
}//end goForwards

void goBackwards()
{
  if (prev[1] == 1 && sw[1] == 0) firstRun = true;
  else firstRun = false;//when the switch changes, use firstRun delay
  forwards = false;
  backwards = true;
  //Serial.println("Moving backwards");
  spd[0] = 0;
  spd[1] = REVspd;
  spd[2] = 0;
  spd[3] = REVspd;  // set base speeds
  REVsync();//update speeds based on hall effect counts
  getFeedback();//check current draw

  digitalWrite(enable0, HIGH);
  digitalWrite(enable1, HIGH);//enable both boards
  //Serial.print("Dont Retract"), Serial.println(dontRetract);
  if (dontRetract == true)
  {
    digitalWrite(enable0, LOW);
    digitalWrite(enable1, LOW);//disable both boards
  }
  delay(10);//slight delay

  Serial.print(" Speeds "), Serial.print(spd[0]), Serial.print(", "), Serial.print(spd[1]);
  Serial.print(", "),       Serial.print(spd[2]), Serial.print(", "), Serial.println(spd[3]);

  analogWrite(PWMA0, spd[0]);
  analogWrite(PWMB0, spd[1]);
  analogWrite(PWMA1, spd[2]);
  analogWrite(PWMB1, spd[3]);//set speeds
 
  if (firstRun == true) delay(timedelay[0]);
  else delay(timedelay[1]); //small delay to get to speed

  dontExtend = false;//once you have moved backwards, you can move forwards again.
  firstRun = false;
}//end goBackwards

void stopMoving()
{
  forwards = false;
  backwards = false;
  //Serial.println("Stopped");
  analogWrite(PWMA0, 0);
  analogWrite(PWMB0, 0);
  analogWrite(PWMA1, 0);
  analogWrite(PWMB1, 0);//set speeds to 0

  digitalWrite(enable0, LOW);
  digitalWrite(enable1, LOW);//disable both boards
}//end stopMoving

void FWDsync() {
  Serial.println("FWD");
  int diff = count[0] - count[1];
  diff = abs(diff);
  //Serial.print(" Diff - "), Serial.print(diff);
  if (diff >= 5)
  {
    if (count[0] > count [1]) spd[0] = FWDspd - 10;
    else spd[2] = FWDspd - 10;
    if (diff >= 10)
    {
      if (count[0] > count [1]) spd[0] = FWDspd - 25;
      else spd[2] = FWDspd - 25;
      if (diff >= 20)
      {
        if (count[0] > count [1]) spd[0] = FWDspd - 50;
        else spd[2] = FWDspd - 50;
        if (diff >= 40)
        {
          if (count[0] > count [1]) spd[0] = 0;
          else spd[2] = 0;
        }//end if diff>40
      }//end if diff>30
    }//end if diff>20
  }//end if diff>10

   else {
    spd[0] = maxSpeed;
    spd[2] = maxSpeed;
  }
  Serial.print(" ACT1 counts - "), Serial.print(count[0]);
  Serial.print(" ACT2 counts - "), Serial.print(count[1]);
}//end FWDSync

void REVsync() {
  Serial.println("REV");
  int diff = count[0] - count[1];
  diff = abs(diff);
  //Serial.print(" Diff - "), Serial.print(diff);
  if (diff >= 5)
  {
    if (count[0] < count [1]) spd[1] = REVspd - 10;
    else spd[3] = REVspd - 10;
    if (diff >= 10)
    {
      if (count[0] < count [1]) spd[1] = REVspd - 25;
      else spd[3] = REVspd - 25;
      if (diff >= 20)
      {
        if (count[0] < count [1]) spd[1] = REVspd - 50;
        else spd[3] = REVspd - 50;
        if (diff >= 40)
        {
          if (count[0] < count [1]) spd[1] = 0;
          else spd[3] = 0;
        }//end if diff>40
      }//end if diff>30
    }//end if diff>20
  }//end if diff>10

  else {
    spd[1] = maxSpeed;
    spd[3] = maxSpeed;
  }
  Serial.print(" ACT1 counts - "), Serial.print(count[0]);
  Serial.print(" ACT2 counts - "), Serial.print(count[1]);
}//end REVsync

void speed0() {
  //Serial.println("Update 1");
  if (forwards == true) count[0]++; //if moving forwards, add counts
  else count[0]--; //if moving back, subtract counts
}//end speed0

void speed1() {
  //Serial.println("Update 2");
  if (forwards == true) count[1]++; //if moving forwards, add counts
  else count[1]--; //if moving back, subtract counts
}//end speed1

void getFeedback()
{
  amp[0] = analogRead(amp0);
  amp[1] = analogRead(amp1);
  //Serial.print(" Amp readings - "), Serial.print(amp[0]), Serial.print(", "), Serial.println(amp[1]);

  if ((amp[0] <= minAmps|| amp[1] <= minAmps) && hitLimits < hitLimitsmax) hitLimits = hitLimits + 1;
  else hitLimits = 0;
  if (hitLimits == hitLimitsmax && backwards == true) fullyRetracted = true;
  else fullyRetracted == false;

  if (fullyRetracted == true)
  {
    for (int e = 0; e <= 4; e = e + 1) count[e] = 0;
    hitLimits = 0;
  }//end fullyretracted

  if (amp[0] > maxAmps)
  {
    //Serial.println(amp[0]);
    spd[0] = 0;
    spd[1] = 0;
    spd[2] = 0;
    spd[3] = 0;//stop all motion
    //Serial.println("TRIPPED 0");
    if (forwards == true) dontExtend = true;
    else if (backwards == true) dontRetract = true;//disable movement in the direction the limit was tripped
  }//end if

  if (amp[1] > maxAmps)
  {
    //Serial.println(amp[1]);
    spd[0] = 0;
    spd[1] = 0;
    spd[2] = 0;
    spd[3] = 0;//stop all motion
    //Serial.println("TRIPPED 1");
    if (forwards == true) dontExtend = true;
    else if (backwards == true) dontRetract = true;//disable movement in the direction the limit was tripped
  }//end if
}//end getFeedback
 

dendad

Joined Feb 20, 2016
3,517
You probably will only have to select the correct port pins used.
If you have the boards, try it and see. Do your linear actuators have hall sensors for the feedback?
You will need some.
 

Thread Starter

rennie1080

Joined Apr 10, 2017
48
Yes, Actuators have hall sensors to obtain position /speed. I can arrange it by using VNH5019, Bu I dont understand some snippets of code. I attached snippet. I dont understand why they use (diff >= 5), (diff >= 10), (diff >= 40)

Code:
void FWDsync() {
  Serial.println("FWD");
  int diff = count[0] - count[1];
  diff = abs(diff);
  //Serial.print(" Diff - "), Serial.print(diff);
  if (diff >= 5)
  {
    if (count[0] > count [1]) spd[0] = FWDspd - 10;
    else spd[2] = FWDspd - 10;
    if (diff >= 10)
    {
      if (count[0] > count [1]) spd[0] = FWDspd - 25;
      else spd[2] = FWDspd - 25;
      if (diff >= 20)
      {
        if (count[0] > count [1]) spd[0] = FWDspd - 50;
        else spd[2] = FWDspd - 50;
        if (diff >= 40)
        {
          if (count[0] > count [1]) spd[0] = 0;
          else spd[2] = 0;
        }//end if diff>40
      }//end if diff>30
    }//end if diff>20
  }//end if diff>10
   else {
    spd[0] = maxSpeed;
    spd[2] = maxSpeed;
  }
  Serial.print(" ACT1 counts - "), Serial.print(count[0]);
  Serial.print(" ACT2 counts - "), Serial.print(count[1]);
}//end FWDSync
void REVsync() {
  Serial.println("REV");
  int diff = count[0] - count[1];
  diff = abs(diff);
  //Serial.print(" Diff - "), Serial.print(diff);
  if (diff >= 5)
  {
    if (count[0] < count [1]) spd[1] = REVspd - 10;
    else spd[3] = REVspd - 10;
    if (diff >= 10)
    {
      if (count[0] < count [1]) spd[1] = REVspd - 25;
      else spd[3] = REVspd - 25;
      if (diff >= 20)
      {
        if (count[0] < count [1]) spd[1] = REVspd - 50;
        else spd[3] = REVspd - 50;
        if (diff >= 40)
        {
          if (count[0] < count [1]) spd[1] = 0;
          else spd[3] = 0;
        }//end if diff>40
      }//end if diff>30
    }//end if diff>20
  }//end if diff>10
  else {
    spd[1] = maxSpeed;
    spd[3] = maxSpeed;
  }
  Serial.print(" ACT1 counts - "), Serial.print(count[0]);
  Serial.print(" ACT2 counts - "), Serial.print(count[1]);
}//end REVsync
 

dendad

Joined Feb 20, 2016
3,517
It look like "diff" is a measure of the position difference and the "(diff >= 5), (diff >= 10), (diff >= 40)" parts are tests to see how much speed to apply to move both actuators back into sync.
 

shortbus

Joined Sep 30, 2009
7,670
This sounds like it is a "school assignment". Not a practical project. Having used these actuators in industrial situations we never ever worried about synchronization of the actuators, just engineered them so it wasn't necessary using good practices of design.
 

Thread Starter

rennie1080

Joined Apr 10, 2017
48
Could you explain what you mean ? It is industrial project. But in tests, there are differences between two side of actuators.( added photos for example)
 

shortbus

Joined Sep 30, 2009
7,670
The frame of the "lid"(or whatever you're calling it) needs to be a real and stable thing. It can't be flexible and saggy when lifting it by one corner. The whole lid should stay in one plane and not sag when moved by one corner. If this requirement isn't meant it probably can't be done with an electric actuator, but would need hydraulics feed by a single valve port.

It isn't common to do lifting in the center of a lid like you show, but if a requirement of the project you need to put a cross bar from one side to the other at the lift point. This is so one side can't get ahead of the other and bind. The actuator attachments to both the lid and the main body of the point have to have a flexible mounting. like a rose joint or heim end. This is just the normal practice for a nonlinear movement like this one that is from a pivot point at one end.

Then a final point, don't count on or use the built in limit switches in the electric actuators. Use external limit switches that are actuated by the lid it's self. this will make both actuators controlled from one single point of reference at the extremes of movement. This is true any time you use more than one point of movement of any kind hydraulic, air or electrical. Internal limits like used in the electrical actuators are to keep them from destroying themselves at ends of travel, not positioning.
 
Top