Stopping dc motors gradually

Hi, we have been trying to program a gradual start and stop codes for our wheelchair. Our design uses two BTS7960 drivers which is controlled by an Arduino Uno. We've already been able to create a part of the code which, when we tried, is actually working. But our concern is, how do we make a line of code for the smooth stop without having different codes for when the dc motors are moving clockwise and counterclockwise. Does anyone here have an idea?

Here's our code:

const int ENA_PIN = 10; // the Arduino pin connected to the EN1 pin L298N
const int IN1_PIN = 5; // the Arduino pin connected to the IN1 pin L298N
const int IN2_PIN = 6; // the Arduino pin connected to the IN2 pin L298N

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pins as outputs.
  pinMode(ENA_PIN, OUTPUT);
  pinMode(IN1_PIN, OUTPUT);
  pinMode(IN2_PIN, OUTPUT);
  
  //clockwise
  digitalWrite(IN1_PIN, HIGH);
  digitalWrite(IN2_PIN, LOW);

  for (int speed = 0; speed <= 255; speed++) {
    analogWrite(ENA_PIN, speed); // control the speed
    delay(10);
  }

  delay(1000); // rotate at maximum speed 1 seconds in clockwise direction

  
  //"cw" stop (temporary)
  //dapat maging general yung code for 'stop'
  digitalWrite(IN1_PIN, HIGH);
  digitalWrite(IN2_PIN, LOW);
  
  for (int speed = 255; speed >= 0; speed--) {
    analogWrite(ENA_PIN, speed); // control the speed
    delay(10);
  }
  
  delay(1000); // stop motor for 1 second
  
  
  //counter clockwise
  digitalWrite(IN1_PIN, LOW);
  digitalWrite(IN2_PIN, HIGH);

  for (int speed = 0; speed <= 255; speed++) {
    analogWrite(ENA_PIN, speed); // control the speed
    delay(10);
  }
  
  delay(1000); // rotate at maximum speed 1 seconds in counter clockwise direction

  
  //"ccw" stop (temporary)
  //dapat maging general yung code for 'stop'
  digitalWrite(IN1_PIN, LOW);
  digitalWrite(IN2_PIN, HIGH);
  
  for (int speed = 255; speed >= 0; speed--) {
    analogWrite(ENA_PIN, speed); // control the speed
    delay(10);
  }
  
  delay(1000); // stop motor for 1 second
}

// the loop function runs over and over again forever
void loop() {
  
}

Motor speed can not be controlled easily, it depends on many factors.

What do you mean by "smooth stop"? Reduce power input gradually, make the motor run free, or brake by shorting the motor?

Apologies for the confusion, what I mean by that is to gradually stop the motion of the dc motor. When stopping the dc motor, the speed of its motion decreases until it fully stops.

Then you have to measure the motor speed, what should be done anyhow, and take the appropriate means to reduce the motor speed over time.

what about a function that has direction and speed arguments and called repeatedly from where ever you want to control the the motor.

it could gradually change the speed of the motor (via a PWM) value. it would keep track (static vairables) of the current speed and direction and only change the speed either by some increment. it can increment at different rates depending on in/decreasing

(yes, it would need to force the speed to zero before changing direction and then incrementing it to the specified speed.

it would return a 1 if the current speed matches the target speed.

it could also change the direction but only after the speed reaches zero, again only returning 1 when it reaches the specified speed and direction.

1 Like

consider

byte PinSpd = 10;
byte PinDir = 11;

enum { For = LOW, Rev = HIGH };
const int SpdInc = 10;

char s [80];

// -----------------------------------------------------------------------------
int
motor (
    int dir,
    int spd )
{
    static int _dir;
    static int _spd;

    if (_dir != dir)  {
        if (0 != _spd)
            spd = 0;
        else  {
            _dir = dir;
            sprintf (s, " %s: dir %d", __func__, _dir);
            Serial.println (s);

            digitalWrite (PinDir, _dir);
        }
    }

    int dSpd = spd - _spd;
    if (0 ==  dSpd && _dir == dir)
        return 1;

    if (SpdInc > abs(dSpd))
        _spd += dSpd;
    else
        _spd += _spd < spd ? SpdInc : -SpdInc;

    sprintf (s, " %s: dir %d, spd %4d", __func__, _dir, _spd);
    Serial.println (s);

    analogWrite (PinSpd, _spd);
    delay (100);

    return 0;
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);
    pinMode (PinSpd, OUTPUT);
    pinMode (PinDir, OUTPUT);
    digitalWrite (PinDir, For);

    while (! motor (For, 255))
        ;

    while (! motor (Rev, 100))
        ;
}

void
loop (void)
{
}

perhaps not obvious in the above code is that when the motor speed is brought to zero when the direction changes and it then gradually increased

This is controlling the ENABLE pin. It will reduce power to zero regardless of which direction the motor is going.

Is there some kind of user input for controlling speed? Like a joystick? In that case, I would use a timer to sample the input and use a rate limit on how fast the output will change. For example:

// Joystick steering of DC motors
// Example sketch by John Wasser

const byte XPotPin = A0;  // Left-Right control
const byte YPotPin = A1;  // Forward-backward throttle

const int PWM_LIMIT = 255;
const int DEAD_ZONE = 10;
const int YAW_SENSITIVITY = 100;
const unsigned long ControlInterval = 10; // 100 samples per second.

#define RATE_LIMITING 1 // 1 for enable, 0 = no rate limit

#if RATE_LIMITING
int PreviousLeftSpeed = 0;
int PreviousRightSpeed = 0;
#endif

void setup()
{
  // Set pin modes on motor pins
}

void LeftMotorSetSpeedForward(byte speed)
{
  // Set motor pins to run the motor forward at the specified speed
  (void) speed;
}

void LeftMotorSetSpeedBackward(byte speed)
{
  // Set motor pins to run the motor backward at the specified speed
  (void) speed;
}

void RightMotorSetSpeedForward(byte speed)
{
  // Set motor pins to run the motor forward at the specified speed
  (void) speed;
}

void RightMotorSetSpeedBackward(byte speed)
{
  // Set motor pins to run the motor backward at the specified speed
  (void) speed;
}

void loop()
{
  static unsigned long previousMillis = 0;
  if (millis() - previousMillis >= ControlInterval)
  {
    int speedInput = analogRead(YPotPin); // Forward/Reverse
    int yawInput = analogRead(XPotPin); // Left/Right turn

    // map 'speed' to the range -PWM_LIMIT (backward), +PWM_LIMIT (forward)
    speedInput = map(speedInput, 0, 1023, -PWM_LIMIT, PWM_LIMIT);
    yawInput = map(yawInput, 0, 1023, -YAW_SENSITIVITY, YAW_SENSITIVITY);

    // Put in dead zones
    if (speedInput > -DEAD_ZONE && speedInput < DEAD_ZONE)
      speedInput = 0;
    if (yawInput > -DEAD_ZONE && yawInput < DEAD_ZONE)
      yawInput = 0;

    int leftSpeed = speedInput + yawInput;
    int rightSpeed = speedInput - yawInput;

    // neither motor can go faster than maximum speed
    leftSpeed = constrain(leftSpeed, -PWM_LIMIT, PWM_LIMIT);
    rightSpeed = constrain(rightSpeed, -PWM_LIMIT, PWM_LIMIT);

#if RATE_LIMITING
    int leftDelta = leftSpeed - PreviousLeftSpeed;
    if (leftDelta > 0)
      leftSpeed = PreviousLeftSpeed + 1;
    else if (leftDelta < 0)
      leftSpeed = PreviousLeftSpeed - 1;
    PreviousLeftSpeed = leftSpeed;

    int rightDelta = rightSpeed - PreviousRightSpeed;
    if (rightDelta > 0)
      rightSpeed = PreviousRightSpeed + 1;
    else if (rightDelta < 0)
      rightSpeed = PreviousRightSpeed - 1;
    PreviousRightSpeed = rightSpeed;
#endif

    if (leftSpeed < 0)
      LeftMotorSetSpeedBackward(-leftSpeed);
    else
      LeftMotorSetSpeedForward(leftSpeed);

    if (rightSpeed < 0)
      RightMotorSetSpeedBackward(-rightSpeed);
    else
      RightMotorSetSpeedForward(rightSpeed);
  }
}
1 Like

HI @kurisoo

welcome to the arduino-forum.

The BTS7960 -chip itself is a high-current half-bridge.
I'm pretty sure that you are using a module that has two BTS7960-half-bridges connected together to form a full H-bridge-driver


connecting two BTS7960-chips together can be done in different ways
So it is very very important to have the datasheet of your particular BTS7960-module

You should not rely on assumptions.
I suspect that your code already relies on assumptions as you are using the code

to make the motor stop.
Usually such two inputs like "IN1", "IN2" are used for setting up the direction CW or CCW but not for stopping the motor.

but my assumption might be wrong. So the next step is to post the manual or at least a picture of your BTS7960-driver-module and a link where you have bought the driver

best regards Stefan

This does not stop the motor but establishes a direction. Stopping means the same low or high driver pair enabled for braking and keeping the motor stopped. Full H-bridges often control one half with the inverse selection signal, so that the direction can be given by a single direction control signal.

and @StefanL38 , see OPs code using ENA_PIN to slow speed to stop

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.