Linear Actuator BWoD

Hello,
I am using THIS linear actuator, with THIS help document. At the bottom of the help document lists the Control Modes, of which I am currently attempting “RC Servo Mode Interface”. My code reflects using a rotary encoder (jurs’ library) where turning one click clockwise results in continuous extension of the actuator, and vise versa.

My use of the linear actuator is to control the throttle of a small engine on a dynamometer. Therefore I need to have the actuator move only a very small increment and then stop, for every time I “click” (partially rotate the encoder) in a direction. I have tried using millis() and read the beginners guide to it but unfortunately I couldn’t get it working and abandoned that version, which is why I haven’t shown it in the code.

My Questions: How can I make the actuator move a small amount (1mm?) then stop? Would you recommend I use another control method that doesn’t involve using delays in 1 and 2ms pulses?

Current Code:

#include "encoder.h"

int pin = 9;
int count;
int lastCount;
int x;

void setup() {
  Serial.begin(9600);
  Serial.println("START");
  pinMode(pin,OUTPUT);
  beginEncoders();
}

void loop() {  
  lastCount = count;

  if (updateEncoders())
  {
    for(int i=0; i<NUMENCODERS; i++)
    {
      count = encoder[i].count;
      Serial.print(encoder[i].count);
      Serial.print('\t');
      Serial.print("lastCount ");
      Serial.println(lastCount);      
    }
  }

  if (count < lastCount)
  {
    x = 2;
  }

  if (count > lastCount)
  {
    x = 1;
  }

  switch (x){
    case 2:
    digitalWrite(pin,HIGH);
    delay(2);
    digitalWrite(pin,LOW);
    delay(2);
    break;

    case 1:
    digitalWrite(pin,HIGH);
    delay(1);
    digitalWrite(pin,LOW);
    delay(1);
    break;
  }
}

Thanks,
Laggy

Use the Servo.h library.

A delay(1) is 1000 microseconds, which is full-scale for a servo.

MorganS:
Use the Servo.h library.

A delay(1) is 1000 microseconds, which is full-scale for a servo.

When I open an example sketch for Servo, specifically "Sweep", a delay is used as "delay(15)", but I know that it's not for 15 seconds because the servo will continuously move. The delay used refers to 15 ms.

In what way, more specifically, could I use a Servo.h delay to resolve my problem? Thank you for the help.

  • Laggy

If your device acts like a real servo, the you write() the position you want it to go to. That might be left or right of the current position.

If your device acts like a continuous rotation not-really-a-servo, the you can control ONLY its speed and direction. Determine what value of writeMicroseconds() means stop, and whether higher values mean move left or move right. Then , use writeMicroseconds() to control the speed and direction, for some period of time, then get on the brakes.

Mr_Laggy:
When I open an example sketch for Servo, specifically "Sweep", a delay is used as "delay(15)", but I know that it's not for 15 seconds because the servo will continuously move. The delay used refers to 15 ms.

In what way, more specifically, could I use a Servo.h delay to resolve my problem? Thank you for the help.

  • Laggy

Did you try running the servo sweep with your actuator attached? How did it work?

delay(15) is used in the Sweep sketch to slow down the rotation. Basically it is commanding small near-instantaneous steps with 15ms gaps between each step.

An RC servo will always try to reach its commanded position as fast as possible. Great for model airplane controls. Not great for robot arms or other heavy things. So Sweep slows down the rotation.

vinceherman:
Did you try running the servo sweep with your actuator attached? How did it work?

  • Yes, it actually works inconsistently where it extends, then retracts more than it extended and vise versa...

PaulS:
If your device acts like a real servo, the you write() the position you want it to go to. That might be left or right of the current position.

If your device acts like a continuous rotation not-really-a-servo, the you can control ONLY its speed and direction. Determine what value of writeMicroseconds() means stop, and whether higher values mean move left or move right. Then , use writeMicroseconds() to control the speed and direction, for some period of time, then get on the brakes.

  • I thought it acted like a servo, so I would write difference positions, however the actuator could never repeatably go to those positions. I used floats to try and improve the resolution but that did not help. A position of 40 existed, but the next position wouldn't exist until, say, 50, where the actuator would move about 0.25 inches. The actuator company claims the resolution is about 1mm.

  • I also had that timing idea (using milliseconds) and could not get it to work. Perhaps I was using too many millis() but I deleted that draft as it was a mess and not working. Would you be able to provide a pseudo-example of how I could accomplish your idea? I just need a glimpse of which direction to move :wink:

Thank you both for the assistance!

  • Laggy

I assume that you are connecting to the pins of X3 on the LAC

How are you powering the Arduino and actuator ?

UKHeliBob:
I assume that you are connecting to the pins of X3 on the LAC

How are you powering the Arduino and actuator ?

  • Correct. X3
  • Both have dc power supplies, with shared ground. The power supply for the LAC was included, so most likely that's not an issue. I have tried powering the Arduino with USB (just curious) and it made no difference.

Thanks,
Laggy

Try Servo.writeMicroseconds(). If that gives inconsistent results and you're sure the power supply is sufficient then there is a problem with the actuator.

MorganS:
Try Servo.writeMicroseconds(). If that gives inconsistent results and you’re sure the power supply is sufficient then there is a problem with the actuator.

  • Ok I’ve tried that; my code is below. It gives a much better result, closer to what I am needing. However, I have noticed something odd, but it could be my code. I noticed that if I increment (via Serial) by only 5, the motor almost never moves. I have to enter a number usually at least 10 or more for the motor to move. This doesn’t always occur though…

Ultimately I will be using a rotary encoder to control it and not the serial port but I’m starting with the basics. Any idea on how to make the actuator respond to finer movements?

#include <Servo.h> 
byte b;
long i = 0;
Servo myservo;

void setup() 
{ 
  Serial.begin(9600);
  myservo.attach(9);
} 

void loop()
{
  while (Serial.available() == 0) {}
  i = Serial.parseInt();
  Serial.print("i = ");
  Serial.println(i);

  myservo.writeMicroseconds(i);
}

Thanks,
Laggy

No. It is not possible to adjust the internal workings of the servo. You would have to buy a different version or hack the one you have to make the Arduino take over the feedback control system.

Or maybe you can fake it. To move 5, tell it you want to move 10 but before it can reach the destination, change the destination.

I still need help. In my originally posted code, when I turn the rotary encoder one way or the other, the linear actuator moves appropriately, but continuously, never pausing. What I need is: When the rotary encoder is turned a single click in either direction, for the actuator pin to pulse (1ms for retract or 2ms for extend) for a certain duration say 100ms.

That way every time the rotary encoder is turned (clicked), the actuator only moves a very small amount then stops. For the life of me I cannot get millis to cooperate, even after reading all the beginner tutorials and youtube. Can someone provide a small example of how to accomplish this please?

I need some direction on how to replace the 4 delays with millis and then add another millis delay for the 100ms.

Thanks,
Laggy

I am afraid that I do not understand the operation of your actuator.

Does it have positional feedback?
If you servo.writeMicroseconds(1500) does it go to the middle of travel and stay there?
If you servo.writeMicroseconds(1000) does it go to one end of travel and stay there?
If you servo.writeMicroseconds(2000) does it go to the other end of travel and stay there?

From your description in reply #12, this is not clear.

vinceherman:
I am afraid that I do not understand the operation of your actuator.

Does it have positional feedback?
If you servo.writeMicroseconds(1500) does it go to the middle of travel and stay there?
If you servo.writeMicroseconds(1000) does it go to one end of travel and stay there?
If you servo.writeMicroseconds(2000) does it go to the other end of travel and stay there?

From your description in reply #12, this is not clear.

Yes, it has positional feedback and yes to all three scenarios. However, this actuator has 8 inches of movement and using the servo.writeMicroseconds commands makes it move in large increments of 0.25 inches at the smallest when I change the servo.writemicroseconds number to be smaller. Therefore servo.writemicroseconds cannot be used.

I have to control the actuator with a puleswidth of 1ms or 2ms for extend and retract. But I need it to only pulse for a short while; thus extending or retracting in small amounts. The manufacturer says this actuator should move in ~1mm increments.

For my purpose I need the actuator to only have a maximum movement of 1.0 inches and move in ~1mm increments. This can't be done with the servo.write command, only with pulses.

I believe microseconds goes in increments of 4. 0, 4, 8, 12, etc. So 1000 µS / 4 = 250 increments = 8 inches / 250 = 0.032 inches per increment. About 1/32 inch, about 0.813mm.

outsider:
I believe microseconds goes in increments of 4. 0, 4, 8, 12, etc. So 1000 µS / 4 = 250 increments = 8 inches / 250 = 0.032 inches per increment. About 1/32 inch.

I'm sorry but your response isn't making much sense to me. Please provide a code sample so that I can clearly see how that would be relevant to making this actuator work the way I need it. I have already stated that I tried using smaller increments with microseconds with unsuccessful results. This actuator (brand new and not DOA) will not move in a 1/32 inch increment using microseconds so I need help getting this to work using millis and pulses, as described previously.

Thanks,
Laggy

Try increasing writeMicroseconds() in increments of 4 with this test sketch:

/*
 Try this test sketch with the Servo library to see how your
 ESC responds to different settings, type a speed (1000 - 2000)
 in the top of serial monitor and hit [ENTER], start at 1500
 and work your way toward 1000 4 micros at a time, then toward
 2000. 
*/
#include <Servo.h>
Servo esc;

void setup() {
  // initialize serial:
  Serial.begin(9600); //set serial monitor baud rate to match
  esc.writeMicroseconds(1500);
  esc.attach(9);
  prntIt();
}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int speed = Serial.parseInt();
    speed = constrain(speed, 1000, 2000);
    esc.writeMicroseconds(speed);
    prntIt();
  }
}
void prntIt()
{
  Serial.print("microseconds =  ");
  Serial.println(esc.readMicroseconds());
}

Thank you. When starting at 1500 and going down, below are the results.
VALUE MOVEMENT (mm approximate)
1500 N/A
1496 1.0
1492 0.5
1488 1.4
1484 0.8
1480 0.9
1476 No movement
1472 No movement
1468 No movement
1464 No movement
1460 No movement
End of this test

When starting at 1500 and going higher, results below
1504 No movement
1508 No movement
1512 No movement
1516 No movement
1520 No movement
1524 No movement
1528 No movement
1532 6.0mm

Is it possible to not use microseconds and instead just use the pulses? The 1ms and 2ms pulses work reliably for continuous movement. It would be nice to get rid of the delays and replace them with millis, like in the BWoD examples. Just not sure how to structure that since there would be many delays.

Thanks,
Laggy

You would have to rip out or bypass the nice servo circuit inside the actuator to do what you ask.

Try this...

Starting from 1500, say you want to move to 1508. Write 1600, then delay(2), then write 1508. Experiment with different inputs and different delays. I suspect 2ms will be too small.

It seems like a cheap actuator. For $500 USD and up, you can get good ballscrew actuators that might meet your specification.