Go Down

Topic: Servo Speed Control (Read 405 times) previous topic - next topic

kelvin8

Code: [Select]
Hi I am trying to implement a servo speed control. It uses a potentiometer to vary the speed during the sweep function. I am having a problem though.
The speed varies on it's first sweep but on it's return, it goes back to its original speed.
I think the problem is in the loop.

[code#include <Servo.h>

Servo myservo;  // create servo object to control a servo
                // a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop()
{
     // scale it to use it with the servo (value between 0 and 180)

  for(pos = 0; pos < 90; pos += val)  // goes from 0 degrees to 180 degrees
  {   
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 1, 30);    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(400);                       // waits 15ms for the servo to reach the position
  }

    for(pos = 60; pos < 180; pos += val)  // goes from 0 degrees to 180 degrees
  { 
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 1, 30);    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(700);                       // waits 15ms for the servo to reach the position
  }

  for(pos = 180; pos>=1; pos-= val)     // goes from 180 degrees to 0 degrees
  {   
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 1, 30);   
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(400);                       // waits 15ms for the servo to reach the position
  }

  delay(2000);
}

lar3ry

Looks like the code works here. Here's what I did to test.
Commented out all references to servo.
Made a fixed value for val.
Used Serial.println() instead of myservo.write
Run this code, open the Serial Monitor. change val to some values between 0 and 1023, and see what you are generating for servo positions.

You'll probably want to add something after each for loop to position the servo to where you actually want it.

Code: [Select]

//#include <Servo.h>

//Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup() {
  //  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin ( 19200 );
}

void loop() {
  // scale it to use it with the servo (value between 0 and 180)

  for(pos = 0; pos < 90; pos += val)  // goes from 0 degrees to 180 degrees
  {   
    val = 500;
    //    val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 1, 30);    // in steps of 1 degree
    //    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    Serial.println(pos);
    delay(400);                       // waits 15ms for the servo to reach the position
  }
Serial.println("---");
  for(pos = 60; pos < 180; pos += val)  // goes from 0 degrees to 180 degrees
  { 
    val = 500;
    //    val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 1, 30);    // in steps of 1 degree
    //    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    Serial.println(pos);
    delay(400);                       // waits 15ms for the servo to reach the position
  }
Serial.println("---");
  for(pos = 180; pos>=1; pos -= val)     // goes from 180 degrees to 0 degrees
  {   
    val = 500;
    //    val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 1, 30);   
    //    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    Serial.println(pos);
    delay(400);                       // waits 15ms for the servo to reach the position
  }
Serial.println("-xxx-");
  delay(10000);
}
There are 10 kinds of people in the world,
those who understand binary, and those who don't.

kelvin8

Thanks as soon as i get access to my servo motor again i'll try it.

I just want to ask why you made the fixed value for val?

lar3ry

I made it a fixed value for testing purposes. I didn't feel the need to wire up a pot to a pin, inorder to see what was happening in the code. I tried a few different values, and as the value in val gets larger, the steps get bigger.

Another (perhaps better way) to change the speed would be to map a delay variable (let's call it delayTime ) to the analog pin read value,  and use that in the delay. you could map 0-1023 to 1=700, for example, then pass the start point and end point to a function that contains your servo commands. You might also want to pass a step value that is faiirly low, and use that in the for loop, to prevent large steps with delays between them.

There are 10 kinds of people in the world,
those who understand binary, and those who don't.

enanthate

Can't you just put delay(potvalue) in the loop? Or am I missing something here?

kelvin8

Yes increasing and decreasing the delay in the sweep mode  via the potentiometer was my initial idea but i had difficulties writing a test code for that.

enanthate

#6
Oct 29, 2013, 11:19 pm Last Edit: Oct 30, 2013, 12:23 am by enanthate Reason: 1

Yes increasing and decreasing the delay in the sweep mode  via the potentiometer was my initial idea but i had difficulties writing a test code for that.


I will try to write a full code later (in a hurry at the moment), for test.
Anyhow, the idea is:

Code: [Select]

for(.....value++) {
myservo.Write(value);
  potvalue = readpot;
  delay(potvalue); // Map value using map().
}


EDIT: Sorry, forgot one important detail. Added to the code now.

kelvin8

Thanks the full code will be really helpful.

lar3ry


Yes increasing and decreasing the delay in the sweep mode  via the potentiometer was my initial idea but i had difficulties writing a test code for that.


Here's a bit of test code. You'll notice that I generalized the problem into a function that is called with start position, stop position, and step size. The Serial.println(0 calls that are commented as  // myServo.write(...); can be simply replaced with that call to the servo.write, in order to test the actual speeds.

The map function maps to a minimum of 15 ms delay, and you should probablt tailor that value to your own minimum time to wait for arrival, our step size will have a bearing on what it should map to.

Here's the test code. Run it, fire up the Serial Monitor, and have a look at the results. Serial.print will take up some time, so once you're convinced the function works, you should probably test with the servos.

Code: [Select]
#include <Servo.h>

//Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int potpin = 0;  // analog pin used to connect the potentiometer
int val = 0;    // variable to read the value from the analog pin
int currentPos = 0;

void setup() {
  //  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin ( 19200 );
  Serial.println(currentPos);  // myServo.write(toPos);
}

void loop() {
  moveto ( currentPos, 90, 1 );
  Serial.println("---");
  moveto ( currentPos, 60, 1 );
  Serial.println("---");
  moveto ( currentPos, 180, 1 );
  Serial.println("---");
  moveto ( currentPos, 0, 3);
  Serial.println("---");
  moveto ( currentPos, 0, 1 );
  Serial.println("-xxx-");
  delay(10000);
}

void moveto ( int fromPos, int toPos, int stepSize) {
  int delayTime = map( val, 0, 1023, 15, 700);
  if ( fromPos != toPos ) {
    if (fromPos < toPos) {
      for ( int i = fromPos; i < toPos; i += stepSize ) {
        Serial.println(i);     // myServo.write(toPos);
        delay( delayTime );
      }
      Serial.println( toPos ); // myServo.write(toPos);
      delay(15);
    }
    else {
      for ( int i = fromPos; i > toPos; i -= stepSize ) {
        Serial.println(i);   // myServo.write(i);
        delay( delayTime );
      }
      Serial.println( toPos ); // myServo.write(toPos);
      delay(15);
    }
  }
  else {
    Serial.println( fromPos );
  }
  currentPos = toPos;
}

There are 10 kinds of people in the world,
those who understand binary, and those who don't.

enanthate


Thanks the full code will be really helpful.


I wrote a new code. Given that I currently don't actually have a potmeter, I had to set "val" manually and test this using Serial.println(pos). Please test and give feedback, it should work... :)

Code: [Select]

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int potpin = A0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {

  for(pos=0;pos<=180;pos++) {
    myservo.write(pos);
    val = map(analogRead(potpin), 0, 1023, 0, 100); // Change value "100" if higher delay is necessary.
    delay(val);
  }
  for(pos=180;pos>=0;pos--) {
    myservo.write(pos);
    val = map(analogRead(potpin), 0, 1023, 0, 100); // Change value "100" if higher delay is necessary.
    delay(val);
  }
}


Let me know.

kelvin8

Thanks it finally worked out in varying the speed of the servo.
This was the final code and it was a brilliant idea to map the position of the pot to the delay variable.

Code: [Select]
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
                // a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int potpin = A0;  // analog pin used to connect the potentiometer
int val;        // variable to read the value from the analog pin

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin (9600);
}


void loop()
{
  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    val = map(analogRead(potpin), 0, 1023, 0, 50);
    Serial.println(val);
    delay(val);                       // waits 15ms for the servo to reach the position
  }
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
  {                               
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
   val = map(analogRead(potpin), 0, 1023, 0, 50);
  Serial.println(val);
    delay(val);                       // waits 15ms for the servo to reach the position
  }
} /code]

PaulS

Quote
This was the final code and it was a brilliant idea to map the position of the pot to the delay variable.

The map() function is effectively dividing the analogRead() value by 40. One division operation is faster than what map(0 actually does.

Of course, speed is not an issue when you are also using Serial.print() and delay() in the loops. But, you should be aware that there are faster ways to achieve nearly the same result, when speed IS important.

kelvin8

Sorry i didn't understand that. I thought that the function of analog map was to convert the steps of the potentiometer (0, 1023) to a digital state (1, 40). Could u explain a bit more please.

PaulS

Quote
I thought that the function of analog map

"analog map"?

The purpose of the map() function is to convert values in one range to another range. When the start of each range is the same, the result is simply a division operation dividing the from upper limit (1023) by the to upper limit (50). Since 1023/50 is 40, dividing the analogRead() value by 40 is faster than map().

Go Up