Go Down

Topic: Controlling position of linear actuator (Read 2 times) previous topic - next topic


Feb 04, 2013, 04:55 pm Last Edit: Feb 04, 2013, 04:57 pm by Retroplayer Reason: 1
Hi all,

I am working on an animatronics project and need to control two linear actuators. The linear actuators are DC Motors connected to a gearbox and output through a leadscrew. On the shaft of the motor is an encoder wheel. Unfortunately, it is not quadrature. Only a single channel. 4 openings on the disk. Through extensive testing and experimenting, I have found the gear ratio is 1:10.

There are 4 pulses per revolution of the DC motor, 40 pulses = 1 turn of the output shaft. That translates into 5mm of linear travel. So, I am settling on 1mm resolution of control (8 pulses).

At the extremes of movement are limit switches which go low when activated. Again, the encoder is only a single channel (basically a tachometer) so I cannot derive direction or absolute position from it.

So, I have devised a plan to track the position using the limit switches and pulses using interrupts:

Code: [Select]
void CountLR(){
//Rightmost position = 64
//Leftmost position = 0

// 8 pulses per 1mm of travel. Count every 8 pulses for 64 positions
if (RevLR == 8){
    RevLR=0;  //if pulses = 8, resent revolution counter
//if moving Left to Right, increase position
if (Dir == LU && digitalRead(L_LIM) == 1){
  }//Else if moving Right to Left, count down
else  if (DirLR ==RD && digitalRead(R_LIM) == 1){

if(digitalRead(R_LIM) == 0){
  if(digitalRead(L_LIM) == 0){

This snippet is activated by the interrupt on an encoder count. I have it ignoring counting until it has been triggered 8 times. Depending on the direction variable which is kept track of in code, it will count up or down. If it hits a limit switch, it will reset the min and max count to a fixed number. This is needed because the count is not always exactly the same (off only by a few.) So I constrain it to 0 to 64.

I have written code to move to a position. I will paste what I have in the next post.


Here is the code to move to an absolute position:

Code: [Select]

void MoveLR(int pos){

if (pos == CURRPOS[8]){

else if (pos > CURRPOS[8]) {

      while (pos != [CURRPOS[8]){





else if (pos < CURRPOS[8]) {

      while (pos != CURRPOS[8]) {






This works, but it's ugly. I am basically calling a step function which turns on the motors, delays, then stops to check the encoder pos again. And repeats until pos == currpos. It triggers on the position match, but of course the motor overshoots by quite a bit. some overshoot is ok, but we are talking actually stopping at position 16 when it is suppose to be 32 for example.

The larger project will not really have enough PWM to control all of the motors (10 motors total, but 8 of them use potentiometers for feedback), and the original controller didn't seem to use PWM either.

So, I am trying to figure out how to control the position cleanly without using PWM. Is this possible? Hopefully I included enough information. If not, just ask. If I can get something steady, I will be posting it up for posterity for others to use in similar situations. I know motor control is one of the most commonly asked questions.

I have only a little control over the design itself because I am modifying existing hardware and want to keep it as stock as possible, so simply using a servo is not an option. In fact, the end application here is to turn all of the motors into servos and provide a 10 servo serial servo controller interface to the end-user (compatible to Mini-SSC II.) Again, all code will be released to the public when completed.



Feb 05, 2013, 12:36 am Last Edit: Feb 05, 2013, 12:37 am by Retroplayer Reason: 1
I was just investigating that. I may have to go that route. I guess I am a bit stubborn. I don't see how they are using PWM in the original application since the motor signals are all connected to latches. I almost wonder if they are actually just sending pulse widths (not PWM) directly (meaning turning the motors on for a certain length of time, then off.) When I was first experimenting with these, I found there was actually a pretty good correlation between pulse widths and position. For example, I was moving the head to one limit switch, then moving it to center with a 400ms pulse and it would land in the center every time. That would mean that they are using the position information to determine the direction to move and a pulse width based on how far off it is.

Honestly, for this application, it really doesn't need to 'hold' the position, because there is no load on the motors when they are not moving, with the exception of the mouth and eyebrows which spring back when power is removed. However, these both move from a centered position. I think they were just meant to spring one way or the other quickly and let it return to nuetral on it's own.

However, doing it this way is a hack and makes my ultimate code much less useful for other projects.


Linear actuators with position feedback use internal sliding pots. If the travel distance isn't too long, sliding pots might be used external to the actuators you have.
Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   8)

Go Up