Question on servo/motor decrease speed until stopped using 'for' loop?

Hello,
Starting to write some code to control 2 motors through a motor driver (accepts RC pulse widths of 1000uS to 2000uS).
I'm using the servo.h library, so using degrees (0 to 180, with 90 being neutral or stop).
Angles < 90 are speeds in reverse and angles > 90 are speeds going fowards.

Using variables: angleThrottle and angleSteering to store the values in degrees.

I know I can stop them completely (hard stop) by:

int servoStop()
{
  myservoThrottle.write(90);
  myservoSteering.write(90);
}

I'm trying to find the best way in my servoStop() function to slow the motors down (maybe increments of 10 degrees) to fully stop.
Let's say I set the throttle to a foward speed of 50% (angle is 135 degrees set in angleThrottle). Then I make a call to the servoStop() function to stop the motors but with an 11.1% slowdown (10 degree increments).

Would the 'for' loop be my best option for this?

int servoStop()
{

  for (int i=angleThrottle; angleThrottle < 90; i += 10)
  {
    myservoThrottle.write(i);
  }
}

Thomas

In principle, that'll do what you want for angles less than 90. In practice, that loop will execute so fast that it'll be just the same as your hard stop version. The easy solution is to use the delay function, but this will make other parts of your code unresponsive while you're stopping. If that isn't ok, you will need to look at state machines and the blink without delay example.

wildbill:
In principle, that'll do what you want for angles less than 90. In practice, that loop will execute so fast that it'll be just the same as your hard stop version. The easy solution is to use the delay function, but this will make other parts of your code unresponsive while you're stopping. If that isn't ok, you will need to look at state machines and the blink without delay example.

Thanks for the reply Bill.
Yeah, I was thinking I would have to add an 'if' command...

if(angleThrottle < 90){

//...
}

//or

if(angleThrottle > 90){

//...
}

The blink without delay sketch is starting to haunt me...everything I try, I get sent back to it hehe :slight_smile:

About the fast execution...
What about adding something like this:
rate = 1000mS/10°
1 second per 10 degree increment, decrement to get to the 90° neutral point?

..or using the map() command?

t

I'd be more inclined to step it by single degrees and delay for 100ms for each - I'd expect it to be smoother, if that matters.

wildbill:
I'd be more inclined to step it by single degrees and delay for 100ms for each - I'd expect it to be smoother, if that matters.

Thanks Bill.
I got it working with the 100mS delay. Very smooth slow down, stops but keeps looping(starts up for a 1/2 second then the smooth slowdown...over and over).

int servoStop()
{
  int angle;

  for (angle = angleThrottle; angle > 90; angle -= 1) 
  {
    delay(100);

    myservoThrottle.write(angle);
  } 
}

I'd use a variable to hold the actual speed being output, and another variable to hold the target speed, and an unsigned long recording the value of millis() last time you changed the actual speed.

Use the technique demonstrated in 'blink without delay' to adjust the output speed periodically. At each adjustment, move the output speed towards the target speed. It is up to you to decide what what interval you want to make these changes, and whether you're going to make a constant small adjustment (resulting in a linear change in speed) or a proportional adjustment (resulting in an exponential change in speed).

If you are interested in more sophisticated behaviour then there are various control algorithms you can use which would enable you to simulate inertia and control the acceleration/decelleration etc.

If you do this right, your code will not include any calls to delay().

PeterH:
I'd use a variable to hold the actual speed being output, and another variable to hold the target speed, and an unsigned long recording the value of millis() last time you changed the actual speed.

Use the technique demonstrated in 'blink without delay' to adjust the output speed periodically. At each adjustment, move the output speed towards the target speed. It is up to you to decide what what interval you want to make these changes, and whether you're going to make a constant small adjustment (resulting in a linear change in speed) or a proportional adjustment (resulting in an exponential change in speed).

If you are interested in more sophisticated behaviour then there are various control algorithms you can use which would enable you to simulate inertia and control the acceleration/decelleration etc.

If you do this right, your code will not include any calls to delay().

Thanks Peter,
I'll start a new sketch and try what you said.

In my current sketch I was finally able to stop motion.
Inputting angles in the throttle works great but when I try inputting angles for the steering, it takes several seconds to start the motors and several seconds to turn them off. The steering is differential.
Not sure if it has to do with the 'pulseIn' command for the auto/manual toggle or something else...

Here's the full sketch I was working on...(disregard the PING sensor data)

/*Main program on the Arduino Mega2560 with auto/manual toggle switch to control robot 
 with ultrasonic PING sensors, PIR sensors...
 */
//
//
//
#include <Servo.h>
#include <Stepper.h>
#include <KitchenSink.h>


#define N_PINGS 4
const byte pingPins [N_PINGS] = {22, 23, 24, 25};   //These are the pins for the 4 Ping ultrasonic sensors
const int minRanges [N_PINGS] = {16, 16, 24, 18};   // for later. These are the thresholds in inches for the ping sensors (when to stop when object detected)


unsigned int duration;   

Servo myservoThrottle;   // create servo object to control throttle
Servo myservoSteering;  // create servo object to control steering


int autManToggle = 50;  // auto manual toggle switch on pin 50
int angleThrottle;    // variable to store the servo throttle angle position
int angleSteering;    // variable to store the servo steering angle position


void setup()
{

  Serial.begin(9600);
  //Setup toggle auto/man Switch as an Input:  
  pinMode(autManToggle, INPUT);

  myservoThrottle.attach(52, 1000, 2000);   // attaches throttle servo on pin 52 to servo object  (min. 1000uS and max. is 2000uS).
  myservoSteering.attach(53, 1000, 2000); // attaches steering servo on pin 53 to servo object  (min. 1000uS and max. is 2000uS).
}


void loop()
{
  duration = pulseIn(autManToggle, HIGH);
  {
    if(duration > 1700)
    {
      servoStop();   
      // had to add these below to stop looping on and off
      angleThrottle = 90;  
      angleSteering = 90;
    }
    else
    {

      calcThrottle();
      calcSteering();
    }
  }
}



int calcThrottle()
{
  myservoThrottle.write(angleThrottle);
  angleThrottle = 130;
  //...
  //...
}


int calcSteering()
{
  myservoSteering.write(angleSteering);
  angleSteering = 90;
  //...
  //...
}


int servoStop()
{
  int angle;

  for (angle = angleThrottle; angle > 90; angle -= 1) 
  {
    delay(100);

    myservoThrottle.write(angle);
  } 
}

t