Trying out sketch for forward acceleration on robot.

Hello,
Was trying different ways to code for a linear increase (and later decrease) in acceleration.
Doing this so I don't get an abrupt start or stop (hard on the motors).

I was wondering if I'm getting close with this small sketch:

#include <Servo.h>

Servo myservoThrottle;         // Initialize servos
Servo myservoSteering;

const int neutralThrottle = 1500;
const int maxThrotThresh = 1700;

int currentThrottle;


void setup()
{	
  myservoThrottle.attach(53, 1000, 2000);  // Attach servos throttle and steering
  myservoSteering.attach(52, 1000, 2000);
}


void loop()
{

  moveForward();
  //...
  //...  

}



void moveForward() 
{
  myservoThrottle.write(neutralThrottle);
  {
    //int i = currentThrottle;
    for(int i = 1500; i < maxThrotThresh; i += 10)

      myservoThrottle.write(i);
  }
}

Thomas

  {
    //int i = currentThrottle;
    for(int i = 1500; i < maxThrotThresh; i += 10)

      myservoThrottle.write(i);
  }

Useless curly braces outside the for loop. None around the body of the for loop. That is not generally considered best practices.

Now, ask your self how long does it take to execute the Servo::write() function? Then, multiply that very small time by the number of iterations of loop, to determine exactly how hard you are stomping the accelerator.

The answer is "pretty darn hard".

In other words, with no delay in that method, there is no smooth acceleration. In fact, the compiler is likely to optimize away the whole thing, and the useless function call. You need some kind of delay to make the function useful.

And, of course, we don't recommend the use of delay(). Using millis() and keeping track of the last time you changed speeds is better.

Which means that you need to call that function quite often, and most of the time it needs to do nothing (certainly no for loop).

So, I'd have to say no, you are not barking up the right tree. I'd almost say that it wasn't even a tree you were barking at.

PaulS:

  {

//int i = currentThrottle;
    for(int i = 1500; i < maxThrotThresh; i += 10)

myservoThrottle.write(i);
  }



Useless curly braces outside the for loop. None around the body of the for loop. That is not generally considered best practices.

Now, ask your self how long does it take to execute the Servo::write() function? Then, multiply that very small time by the number of iterations of loop, to determine exactly how hard you are stomping the accelerator.

The answer is "pretty darn hard".

In other words, with no delay in that method, there is no smooth acceleration. In fact, the compiler is likely to optimize away the whole thing, and the useless function call. You need some kind of delay to make the function useful.

And, of course, we don't recommend the use of delay(). Using millis() and keeping track of the last time you changed speeds is better.

Which means that you need to call that function quite often, and most of the time it needs to do nothing (certainly no for loop).

So, I'd have to say no, you are not barking up the right tree. I'd almost say that it wasn't even a tree you were barking at.

Thanks Paul,
I tried another way using the do-while loop and had better results (sort of hehe).
I got a nice smooth increase in acceleration but it went to full throttle instead of leveling out at my max. throttle threshold.
I'll see if I can dig the code out from my overun desktop :slight_smile: and post back.

Btw, do you have any suggestions on doing this?

t

I am sorry if this is the wrong forum for this question. I am a newbie. I have 2 servos and want to control them ultimately through a web interface to pan tilt a web camera. I am trying to follow the instruction of this website http://blog.aus10.org/?p=102 but to no avail. She talks about uploading code and then being able to control the servos via the serial monitor. I don't know what commands to use. Could you please at least point me in the right direction. I am very confused. I tried contacting the author of the webpage but she won't get back to me. Also how do you create a new post. I was told there is a "new topic" button but I'm unable to find it.
Thanks so much for any help you can provide me!!

Shawn.

Thanks so much for any help you can provide me!!

How does your post relate, in any way, to the thread you tacked it onto the end of?

I was told there is a "new topic" button but I'm unable to find it.

Go to the section you want to post in. In the top right corner there is the "new topic" button next to the "mark read" and "notify" buttons. You may want to read some tutorials on how to do simple things in the arduino environment such as uploading code. There are some good tutorials here Arduino Playground - HomePage

thomas3120:
I tried another way using the do-while loop and had better results (sort of hehe).
I got a nice smooth increase in acceleration but it went to full throttle instead of leveling out at my max. throttle threshold.
I'll see if I can dig the code out from my overun desktop :slight_smile: and post back.

This is not a problem that really calls for while loops and so on.

I think the key concept is that you have a target speed and an actual speed. The target speed can be changed arbitrarily by outside forces at any time. The actual speed is controlled by the Arduino. At regular intervals the Arduino compares the actual and target speeds and moves the actual speed towards the target speed. The 'blink without delay' example sketch shows you how to carry out processing at regular intervals - here, instead of blinking an LED, you would update the speed. The acceleration characteristics would be defined by how frequently you updated the speed, and how much you updated it by.

PeterH:

thomas3120:
I tried another way using the do-while loop and had better results (sort of hehe).
I got a nice smooth increase in acceleration but it went to full throttle instead of leveling out at my max. throttle threshold.
I'll see if I can dig the code out from my overun desktop :slight_smile: and post back.

This is not a problem that really calls for while loops and so on.

I think the key concept is that you have a target speed and an actual speed. The target speed can be changed arbitrarily by outside forces at any time. The actual speed is controlled by the Arduino. At regular intervals the Arduino compares the actual and target speeds and moves the actual speed towards the target speed. The 'blink without delay' example sketch shows you how to carry out processing at regular intervals - here, instead of blinking an LED, you would update the speed. The acceleration characteristics would be defined by how frequently you updated the speed, and how much you updated it by.

Thanks Peter,
I tried incorporating blink without delay into my accelThrottle sketch.
I'm still unsure what to do about this part in Blink without delay:

if(ledState == LOW)
ledState = HIGH;
else
ledState = LOW;

Here is what I have so far:

#include <Servo.h>

Servo myservoThrottle;         // Initialize servos
Servo myservoSteering;

unsigned long actualSpeed =micros();
unsigned long targetSpeed =micros();

long  interval =micros();

int neutralThrottle = 1500;
int maxThrotThresh = 1700;


void setup()
{	
  myservoThrottle.attach(53, 1000, 2000);  // Attach servos throttle and steering
  myservoSteering.attach(52, 1000, 2000);
}


void loop()
{

  moveForward();
  //...
  //...  

}



void moveForward() 
{
  interval =50;
  targetSpeed =1700;
  if(targetSpeed = actualSpeed += interval)
  {  
    myservoThrottle.write(actualSpeed);  /* ..or should I use myservoThrottle.write(targetSpeed); 
      since targetSpeed = actualSpeed += interval*/
  }
}

Or something along these lines...

void moveForward() 
{
  interval =50;
  targetSpeed =1700;
  if(targetSpeed - actualSpeed > interval)
  {  
    actualSpeed = targetSpeed; 
    myservoThrottle.write(targetSpeed);

  }
}

Just had another question that came to mind...
Should the contents in my 'moveFoward' function:

void moveForward() 
{
  interval =50;
  targetSpeed =1700;
  if(targetSpeed - actualSpeed > interval)
  {  
    actualSpeed = targetSpeed; 
    myservoThrottle.write(targetSpeed);

  }
}

Be inside of the main loop (void loop)?

t

thomas3120:
Or something along these lines...

void moveForward() 

{
  interval =50;
  targetSpeed =1700;
  if(targetSpeed - actualSpeed > interval)
  { 
    actualSpeed = targetSpeed;
    myservoThrottle.write(targetSpeed);

}
}

No, that's not really what I had in mind - I was thinking of something more like this:

int actualSpeed = 0; // the speed the motor is currently running at
int targetSpeed = 0; // the speed we want the motor to be running at
unsigned long lastSpeedUpdateTime = 0;
const unsigned long SPEED_UPDATE_INTERVAL = 10; // ms

void setSpeed(int requiredSpeed)
{
    targetSpeed = requiredSpeed;
}

void handleAcceleration()
{
    unsigned long now = millis();
    if(now - lastSpeedUpdateTime > SPEED_UPDATE_INTERVAL)
    {
        // time to check the motor speed again
        if(actualSpeed < targetSpeed)
        {
            // accelerating
            actualSpeed++;
            myservoThrottle.write(actualSpeed);
        }
        else if(actualSpeed > targetSpeed)
        {
            // deccelerating
            actualSpeed--;
            myservoThrottle.write(actualSpeed);
        }
        else
        {
            // motor is already at the target speed - no action required
        }
        lastSpeedUpdateTime = now;
    }
}

void loop()
{
    handleAcceleration();
    ... etc
}

Somewhere in your code you would call setSpeed() to set the required motor speed - you only need to do that when you want the speed to change. Then loop() calls handleAcceleration() repeatedly, and that accelerates the motors smoothly towards the target speed.

PeterH:
No, that's not really what I had in mind - I was thinking of something more like this:

int actualSpeed = 0; // the speed the motor is currently running at

int targetSpeed = 0; // the speed we want the motor to be running at
unsigned long lastSpeedUpdateTime = 0;
const unsigned long SPEED_UPDATE_INTERVAL = 10; // ms

void setSpeed(int requiredSpeed)
{
    targetSpeed = requiredSpeed;
}

void handleAcceleration()
{
    unsigned long now = millis();
    if(now - lastSpeedUpdateTime > SPEED_UPDATE_INTERVAL)
    {
        // time to check the motor speed again
        if(actualSpeed < targetSpeed)
        {
            // accelerating
            actualSpeed++;
            myservoThrottle.write(actualSpeed);
        }
        else if(actualSpeed > targetSpeed)
        {
            // deccelerating
            actualSpeed--;
            myservoThrottle.write(actualSpeed);
        }
        else
        {
            // motor is already at the target speed - no action required
        }
        lastSpeedUpdateTime = now;
    }
}

void loop()
{
    handleAcceleration();
    ... etc
}




Somewhere in your code you would call setSpeed() to set the required motor speed - you only need to do that when you want the speed to change. Then loop() calls handleAcceleration() repeatedly, and that accelerates the motors smoothly towards the target speed.

Thanks for steering me in the right direction Peter,
I had a question on 'setSpeed'
This seems to be a command for a stepper motor: Stepper: setSpeed(rpms)
Should I change this to something like: speedSet() ?

t

Here is my full Jarvis sketch to date.
(also thanks to Peter)

Let me know how it looks...still not sure how to incorporate the speedSet() function.
Would I still need to possibly add functions for:
moveForward()
moveBackward()
moveLeft()
moveRight()
moveToNeutral()

Seems like handleThrottAccel() and handleSteerAccel() calculate much of throttle and steering values...
?

// full Jarvis robot sketch
//
//
//
// Update 17Dec12
//
#include <Servo.h>
#include <Stepper.h>

// PING sensors x4:
#define N_PINGS 4
const byte pingPins [N_PINGS] = {22, 23, 24, 25};   // PING pins
const int minRanges [N_PINGS] = {14, 14, 26, 12};  // Thresholds for PING sensors

// Initialize servos
Servo myservoThrottle;         
Servo myservoSteering;
Servo myservoSwitch;  

// speed values in microseconds
int neutralThrottle = 1500;
int neutralSteering = 1500;
int maxThrotThresh = 1650;  
int minThrotThresh = 1350;
int maxSteerThresh = 1650;
int minSteerThresh = 1350; 

int actualSpeed = 0; // the speed the motor is currently running at
int targetSpeed = 0; // the speed we want the motor to be running at
unsigned long lastSpeedUpdateTime = 0;
const unsigned long SPEED_UPDATE_INTERVAL = 50; // microseconds

// Stepper motor:
const int stepsPerRevolution = 200;  /* change this to fit the number of steps per revolution
 for your motor */
// initialize the stepper library on the motor shield
Stepper myStepper(stepsPerRevolution, 12,13); 
// give the stepper motor control pins names:
const int pwmA = 3;
const int pwmB = 11;
const int brakeA = 9;
const int brakeB = 8;
const int dirA = 12;
const int dirB = 13;
int leftStep = 1;
int rightStep = -1;


// PIR motion sensors x2:
// The digital pins connected to the PIR sensors
const int leftPirPin = 26;    
const int rightPirPin = 27;


void setup()
{	
  Serial.begin(9600);
  myservoThrottle.attach(53, 1000, 2000);  // Attach servos throttle and steering
  myservoSteering.attach(52, 1000, 2000);
  myservoSwitch.attach(50, 1000, 2000);  // Attach servo for aut/man switch
  pinMode(leftPirPin, INPUT);
  pinMode(rightPirPin, INPUT);
  /* Set the PWM and brake pins so that the direction pins 
    can be used to control the stepper motor: */
  pinMode(pwmA, OUTPUT);
  pinMode(pwmB, OUTPUT);
  pinMode(brakeA, OUTPUT);
  pinMode(brakeB, OUTPUT);
  digitalWrite(pwmA, HIGH);
  digitalWrite(pwmB, HIGH);
  digitalWrite(brakeA, LOW);
  digitalWrite(brakeB, LOW);
  // set the motor speed (for multiple steps only):
  myStepper.setSpeed(15);
}





void loop()
{
  calcPingSensors();
  handleThrottAccel();
  handleSteerAccel();
  //... etc
  

}





unsigned long calcPingSensors()
{
  int range [N_PINGS];
  for (int i = 0; i < N_PINGS; ++i) {
    range [i] = ping(pingPins [i]);
    delay(5);
  }  

  for (int i = 0; i < N_PINGS; ++i) {
    Serial.print(range [i]);
    Serial.print(" ");
  }  
  Serial.println("inches");
  //delay(1000);
}


long ping(int pin)
{
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
  delayMicroseconds(2);
  digitalWrite(pin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pin, LOW);
  pinMode(pin, INPUT);

  return (microsecondsToInches(pulseIn(pin, HIGH)));
}

long microsecondsToInches(long microseconds)
{
  return microseconds / 74 / 2;
}






void speedSet(int requiredSpeed)
{
  targetSpeed = requiredSpeed;
}



void handleThrottAccel()
{
  unsigned long now = micros();
  if(now - lastSpeedUpdateTime > SPEED_UPDATE_INTERVAL)
  {
    // time to check the motor speed again
    if(actualSpeed < targetSpeed)
    {
      // accelerating
      actualSpeed++;
      myservoThrottle.write(actualSpeed);
    }
    else if(actualSpeed > targetSpeed)
    {
      // deccelerating
      actualSpeed--;
      myservoThrottle.write(actualSpeed);
    }
    else
    {
      // motor is already at the target speed - no action required
    }
    lastSpeedUpdateTime = now;
  }
}



void handleSteerAccel()
{
  unsigned long now = micros();
  if(now - lastSpeedUpdateTime > SPEED_UPDATE_INTERVAL)
  {
    // time to check the motor speed again
    if(actualSpeed < targetSpeed)
    {
      // accelerating
      actualSpeed++;
      myservoSteering.write(actualSpeed);
    }
    else if(actualSpeed > targetSpeed)
    {
      // deccelerating
      actualSpeed--;
      myservoSteering.write(actualSpeed);
    }
    else
    {
      // motor is already at the target speed - no action required
    }
    lastSpeedUpdateTime = now;
  }
}




void calcPirSensors()
{
}

Thomas

I guess that moveForward() and moveBackward() correspond to setting the speed to predefined positive and negative values, so it would make sense to implement them by a call to setSpeed(), or speedSet(), or whatever you choose to call it.