Acceleration/Deceleration using a standard DC motor & optical linear encoder?

Hey everyone, finally decided to make an account after a long time of lurking and finding what I needed through searches.

I'm trying to figure out if acceleration and deceleration can be acheived with the use of a standard DC motor and an optical linear encoder from an old printer? If not, I could just use the stepper motors that I have but I'd prefer not to since I can know perciesly where the trolley is at on the slide rod with an encoder.

Any help for feedback would be greatly appreciated!

Thanks!

You should give a bit more detail of your application e.g. what are you moving and why, and where trolleys and slide rods come into it.

I am not sure why you think steppers will not give you an accurate position. As long as you don't accelerate or decelarate so hard that you cause the motor to skip then step counting will give an accurate position.

Knowing the mass you are trying to move and the accelerations you require will allow you to calculate momentum and so size motors.

Sorry for leaving details out, my bad.

I'm looking to move a cup of liquid, so not that heavy, back and forth between drink dispensers. I'll be using the printer slide rod and trolley assembely pretty much as is. The reason I wanted to know if I could do it with the DC motor is because that's how it's setup now and wouldn't take any modification at all.

I'm not opposed to using a stepper and I really doubt that I'd have to worry about skipping steps seeing as I can't really accelerate a cup of liquid that fast in the first place. I was just looking for as little modification as possible but it won't be that bad. I'll add a switch at the end to signal home and call for it after ever drink made. Simple enough I think?

Thanks for the speedy reply!

A cup of liquid might not be that heavy but it will have a lot more mass than the print assembly the motor presently shifts. It might be an idea to attach a weight similar to a full cup to the printer and see if the motor struggles (watch you don't damage it).

I cannot think of any reason why the DC motor should not work provided it is powerful enough, but there are people on the list who know a lot more about motors than I do. Do you have a spec. for the motor you have?

I don't see why you couldn't use a linear encoder for position sensing and use that to provide feedback for a closed loop controller for a DC motor. That would give you precise control over acceleration, speed and position.

If the physical characteristics of the moving assembly are consistent then you may even be able to get away with just a couple of limit switches - using a predefined PWM profile to define the acceleration and deceleration curves with deceleration triggered by the limit switches.

If it's possible to consider changes to the mechanical setup, you could even use a crank to control the movement which would inherently define the range of the movement and provide smooth acceleration and deceleration using a constant motor speed.

If the physical characteristics of the moving assembly are consistent then you may even be able to get away with just a couple of limit switches - using a predefined PWM profile to define the acceleration and deceleration curves with deceleration triggered by the limit switches.

I agree that this might be possible as I have done something similar. One snag would be what happens if the cup is not filled, or only partially filled, with liquid for some reason. You might want to experiment on how accurately the device would position when the cup is full and empty.

Hi I am using a printer to somewhat do the same thing. To control the DC motor i have a SN754410NE and using the Arduino to read the encoder. The problem i have is i tell the printer head to move 1500 units to the right and turn off the DC motor, but the printer head will over shoot because it cant stop instantly. The more weight you add to the head the harder its going to be. A stepper motor would have a better chance but you could lose a step or two. Any ideas for code? ie making it Acceleration/Deceleration when it gets close to 1500 units. I dont think the you can control Acceleration/Deceleration with the SN754410NE.

(making a useless machine with 10 switches)

Thanks

The problem i have is i tell the printer head to move 1500 units to the right and turn off the DC motor, but the printer head will over shoot because it cant stop instantly. The more weight you add to the head the harder its going to be. A stepper motor would have a better chance but you could lose a step or two.

You should not try and stop instantly even with a stepper motor. Taking account of the mass you are moving you should accelerate and decelearate it. With a stepper would would ramp the frequency of steps up and down, bringing the mass to a controlled halt at a precise location without skipping steps.

I think there is even an AccelStepper library which manages stepper acceleration/deceleration for you.

Slowman223:
I dont think the you can control Acceleration/Deceleration with the SN754410NE.

Yes you can. Use PWM to vary the motor torque and braking force. For example, try setting the PWM to max(255, distance_units_to_go/K) where K is a constant you can experiment with. To get more accurate positioning and speed control, use PID controller software.

Yes i forgot about the pwm. I have played around with AccelStepper library. Do you know of a Library to control a DC motor Acceleration/Deceleration with the SN754410NE. I am using 3 pins to control the DC motor. Pin 8 = on/off Pin 9 and 10= Direction (10 = HIGH and 9= LOW is Clockwise, 10 = LOW and 9 = HIGH is Anticlockwise)

I dont know how to control the Acceleration/Deceleration with a DC motor.

Thanks

I presume you have pin 8 driving the EN pin and pins 9, 10 driving the A inputs. You just need to PWM pin 9 or pin 10 while keeping the other one LOW. Reducing the PWM will reduce both the torque (hence the acceleration) and the speed that the motor eventually reaches. So to accelerate/decelerate smoothly, just ramp the pwm up/down smoothly.

Im getting some where.

I need to move 1500 Units. I have set a Acceleration from 0 to 500 units but dont know how to Deceleration from 1000 to 1500. DistanceAcc is the number on the encoder. DcMotorDir1 driving the A inputs DcMotorDir2 driving the A inputs DcMotorOn EN pin

int DcMotorAcc = map(DistanceAcc, 0 , 500, 125, 255);

if (digitalRead(Switch1) == HIGH && (LastSwitch1) == LOW) { digitalWrite(DcMotorDir1, LOW); analogWrite(DcMotorDir2, DcMotorAcc); digitalWrite(DcMotorOn, HIGH); }

Ideas?

if (digitalRead(Switch1) == HIGH && (LastSwitch1) == LOW) {
    digitalWrite(DcMotorDir1, LOW);
    if (DistanceAcc < 500)
    {
       int DcMotorAcc = map(DistanceAcc, 0, 500, 125, 255);
       analogWrite(DcMotorDir2, DcMotorAcc);
    }
    else if (DistanceAcc > 1000)
    {
       int DcMotorAcc = map(DistanceAcc, 1000, 1500, 255, 50);
       analogWrite(DcMotorDir2, DcMotorAcc);
    }
    else
    {
       analogWrite(DcMotorDir2, 255);
    }
    digitalWrite(DcMotorOn, HIGH);
    }

Thanks for that :) works great Also this is the code i used for the encoder

#define encoderI 2
#define encoderQ 3 

volatile int count;
void setup()
{
Serial.begin(9600);
count=0;
pinMode(encoderI, INPUT);
pinMode(encoderQ, INPUT); attachInterrupt(0, handleEncoder, CHANGE);

}

void loop()
{
Serial.println(count);
delay(10);
}

void handleEncoder()
{
if(digitalRead(encoderI) == digitalRead(encoderQ))
{ count++;
}
else
{ count--;
}

}

Hello, although I am warned that this is an old topic I’m giving it a try. I see in this topic that acceleration/deceleration of DC motors can be done in code via map() and I wander if anybody can give me any clue how to implement it in my code? As of now, I am controlling the voltage that motors are receiving manually via potentiometer:

speedA = analogRead (potPin1) / 4;
speedB = analogRead (potPin2) / 4;

I’d like to keep the above code if it is possible so I can “fine-tune” the final speed of each motor manually via potentiometer. Perhaps this is not necessary? Anyway, below is my entire code:

#define DEBUG
unsigned long currentMillis = 0;

unsigned long pauseA = 5000;
unsigned long pauseB = 5000;

unsigned long timerA = 0;
unsigned long timerB = 0;

const int potPin1 = A2;
const int potPin2 = A3;

const int ledPin1 = A4;
const int ledPin2 = A5;

//int limitPin1 = 4;
//int limitPin2 = 2;

const int trigPin1 = 5;
const int echoPin1 = 6;
const int trigPin2 = 10;
const int echoPin2 = 7;

int duration1 = 0;
int distance1 = 0;
int duration2 = 0;
int distance2 = 0;

int speedA = 0;
int speedB = 0;

//flags

byte motorA_Running = true;
byte motorB_Running = false;

byte sensorA_Running = true;
byte sensorB_Running = false;

byte timerA_Running = false;
byte timerB_Running = false;

void setup() {
  Serial.begin (9600);
  pinMode(trigPin1, OUTPUT);
  pinMode(echoPin1, INPUT);

  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);

  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);

  //pinMode(limitPin1, INPUT);
  //pinMode(limitPin2, INPUT);

  // Setup Channel A
  pinMode(12, OUTPUT); // Direction A pin
  pinMode(3, OUTPUT); // PWM A pin
  pinMode(9, OUTPUT); // Brake A pin

  // Setup Channel B
  pinMode(13, OUTPUT); // Direction B pin
  pinMode(11, OUTPUT); // PWM B pin
  pinMode(8, OUTPUT);  // Brake B pin
}

void loop(){
currentMillis = millis();
speedA = analogRead (potPin1) / 4;
speedB = analogRead (potPin2) / 4;

#ifdef DEBUG
    Serial.print(currentMillis);
    Serial.print("  | A: ");
    Serial.print(timerA);
    Serial.print("  | B: ");
    Serial.print(timerB);
#endif

if (timerA_Running == true){
   if ((unsigned long)(currentMillis - timerA) >= pauseA) {
      motorA_Running = true;
      timerA_Running = false;
   }
 }

if (timerB_Running == true){
   if ((unsigned long)(currentMillis - timerB) >= pauseB) {
       motorB_Running = true; 
       timerB_Running = false;
   }
}

if (sensorA_Running == true){
      sensorA();
}

 if (sensorB_Running == true){
      sensorB();
}

if (motorA_Running == true){
  digitalWrite(12, HIGH);
  analogWrite(3, speedA);
  digitalWrite(ledPin2, LOW);
} else {
  analogWrite(3, 0);  
}

if (motorB_Running == true){
  digitalWrite(13, HIGH);
  analogWrite(11, speedB);
  digitalWrite (ledPin1, LOW);
} else {
  analogWrite(11, 0);
}

#ifdef DEBUG
  Serial.println("\n");
#endif
}

// loop end

void sensorA(){ // If distance is less than 10cm the motor A should stop > pauseA > turn motor B on. 
  digitalWrite (trigPin1, HIGH);
  delayMicroseconds (10);
  digitalWrite (trigPin1, LOW);
  duration1 = pulseIn (echoPin1, HIGH);
  distance1 = (int) ( (duration1 / 2.0)  /  29.1);

  if (distance1 < 10) {
    digitalWrite (ledPin1, HIGH);
    motorA_Running = false;
    TurnOnTimerB();
    sensorA_Running = false;
    sensorB_Running = true;
  }
}

void sensorB(){ // If distance is less than 10cm the motor B should stop > pauseB > turn motor A on.
    digitalWrite (trigPin2, HIGH);
    delayMicroseconds (10);
    digitalWrite (trigPin2, LOW);
    duration2 = pulseIn (echoPin2, HIGH);
    distance2 = (int) ( (duration2 / 2.0)  /  29.1);
    
    if (distance2 < 10) {
      digitalWrite (ledPin2, HIGH);
      motorB_Running = false;
      TurnOnTimerA();
      sensorB_Running = false;
      sensorA_Running = true;
    }
}

void TurnOnTimerA() {
   timerA = currentMillis;
   timerA_Running = true;
}

void TurnOnTimerB() {
   timerB = currentMillis;
   timerB_Running = true;
}

This robot has two motors (A and B) which turn only in one direction, i.e. when motor A is on motor B is off and vice versa. The above code is just turning them on and off based on sensors input but I think it’s be very cool if the motors would actually gradually decelerate and accelerate instead. Any help much appreciated!