1

I'm not sure why this has been so difficult for me, but I'm trying to control the acceleration of a 10v DC motor with an Arduino UNO and an L298n H-Bridge. Using a 12v regulated power supply to power the motor

For the life of me, I can't get a smooth acceleration/deceleration for this. I want the motor to move back and forth with a potentiometer, slowing down as it reaches the '0' and '10' positions. This works, but it's not very smooth

const byte motorUp      = 4;
const byte motorDown    = 5;
const byte motorPWM     = 6;

const int speed1 = 85;
const int speed2 = 92;
const int speed3 = 100;
const int speed4 = 110;
const int speed5 = 130;
const int speed6 = 190;

int state = 0;

const byte wiper        = A0; //Position of fader relative to GND (Analog 0)
double faderMax = 0; //Value read by fader's maximum position (0-1023)
double faderMin = 0; //Value read by fader's minimum position (0-1023)
byte motorSpeed = 255;  // Raise if the fader is too slow (0-255)
byte tolerance  = 10;  // Raise if the fader is too shaky (0-1023)

void setup() {
  Serial.begin(250000);
  pinMode(motorDown, OUTPUT);
  pinMode(motorUp, OUTPUT);
  pinMode(motorPWM, OUTPUT);
  analogWrite(motorPWM, motorSpeed);
  calibrateFader(); }

void calibrateFader() {
  digitalWrite(motorUp, HIGH);
  analogWrite(motorPWM, 155);
  delay(300);
  digitalWrite(motorUp, LOW);
  faderMax = analogRead(wiper) - tolerance;
  digitalWrite(motorDown, HIGH);
  analogWrite(motorPWM, 155);
  delay(300);
  digitalWrite(motorDown, LOW);
  faderMin = analogRead(wiper) + tolerance;
  delay(2500); }

void loop () {
  moveMotorUp();}

void moveMotorUp() {
  while (analogRead(A0) <= 100) {
    analogWrite(motorPWM, speed1);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 100) && (analogRead(A0) <= 200)) {
    analogWrite (motorPWM, speed2);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 200) && (analogRead(A0) <= 300)) {
    analogWrite (motorPWM, speed3);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 300) && (analogRead(A0) <= 400)) {
    analogWrite (motorPWM, speed4);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 400) && (analogRead(A0) <= 500)) {
    analogWrite (motorPWM, speed5);
    digitalWrite (motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 500) && (analogRead(A0) <= 600)) {
    analogWrite (motorPWM, speed6);
    digitalWrite (motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 600) && (analogRead(A0) <= 700)) {
    analogWrite (motorPWM, speed5);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
   while ((analogRead(A0) > 700) && (analogRead(A0) <= 800)) {
    analogWrite (motorPWM, speed4);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 800) && (analogRead(A0) <= 900)) {
    analogWrite (motorPWM, speed3);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while ((analogRead(A0) > 900) && (analogRead(A0) <= 1000)) {
    analogWrite (motorPWM, speed2);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW); }
  while (analogRead(A0) > 1000) {
    analogWrite (motorPWM, speed1);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW);
    moveMotorDown(); } }

void moveMotorDown() {

  while (analogRead(A0) > 1000) {
    analogWrite(motorPWM, speed1);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 900) && (analogRead(A0) <= 1000)) {
    analogWrite (motorPWM, speed2);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 800) && (analogRead(A0) <= 900)) {
    analogWrite (motorPWM, speed3);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 700) && (analogRead(A0) <= 800)) {
    analogWrite (motorPWM, speed4);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 600) && (analogRead(A0) <= 700)) {
    analogWrite (motorPWM, speed5);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 500) && (analogRead(A0) <= 600)) {
    analogWrite (motorPWM, speed6);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 400) && (analogRead(A0) <= 500)) {
    analogWrite (motorPWM, speed5);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 300) && (analogRead(A0) <= 400)) {
    analogWrite (motorPWM, speed4);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 200) && (analogRead(A0) <= 300)) {
    analogWrite (motorPWM, speed3);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 100) && (analogRead(A0) <= 200)) {
    analogWrite (motorPWM, speed2);
    digitalWrite (motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while ((analogRead(A0) > 10) && (analogRead(A0) <= 100)) {
    analogWrite(motorPWM, speed1);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW); }
  while (analogRead(A0) <= 10) {
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW);
    moveMotorUp(); } }

I hope it's simpler than this - Any ideas? Thanks

3
  • You have a nice infinitely recursive pair of functions there. You're going to run out of stack space if you leave that running for a while. – Majenko Jun 22 at 15:22
  • It seemed really inefficient to me as well. Know of any libraries that have acceleration? I'm wishing I could find something like the AccelStepper library for stepper motors. Unfortunately I'm limited to a DC motor this time. – zRockafellow Jun 22 at 15:24
  • @zRockafellow There are multiple libraries that provide value interpolations between values with various mechanisms (e.g., Ramp). Anything that can be done with recursion can be done without it--it's more likely you mean to have a state machine. – Dave Newton Jun 22 at 15:28
2

I think you need to think a little differently. Instead of "Move it at this speed until you get to here" you need to think more along the lines of "Where am I? Where do I want to get to? How far away is it?"

Basically the further you have to go the faster you want to go. The closer you get to your target value the slower you want to go.

Simply put - you want to convert the distance between your current and target positions into a proportional speed.

Take one variable: the target value that you want to get to. Take one reading: the current location of the fader. Subtract one from the other.

Take the sign of the result - that defines what direction you want the motor to turn in. Take the "absolute" (abs(...)) value of the result - that is the distance you are away from your target. Divide that absolute value by a speed factor to keep it within the range of your PWM, or lower if you want to go slower. Set the speed of the motor to that result.

So if you want to get to 0 and you are currently reading 1000 from the fader then:

  • Difference = 0 - 1000 = -1000
  • Sign is negative, so set direction to "down".
  • Distance is abs(-1000), or 1000.
  • Divide by 4 (max ADC is 1023, max PWM is 255 - 1023/4 = 255) = 250
  • Set speed to 250

Then a moment later you may be reading 738 from the ADC - so this time:

  • Difference = 0 - 738 = -738
  • Sign is negative, so set direction to "down".
  • Distance is abs(-738), or 738.
  • Divide by 4 (max ADC is 1023, max PWM is 255 - 1023/4 = 255) = 184
  • Set speed to 184

Keep doing that until you get to your target value (or within a certain tolerance of it) at which point you stop and wait for a new target value to be selected (or automatically change the target value as per your sweep demo - if 0 then set to 1023. If 1023 then set to 0).

This method then allows you to go directly to any value you choose with a deceleration as it approaches that target.

1
  • Hi Majenko, Thanks for the details! I've been trying to wrap my head around how to implement PID control into this project. I'm still not sure how to set it up though. I tried following your instructions, but you lost me at "Take the sign of the result" – zRockafellow Jun 22 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.