Pages: [1]   Go Down
Author Topic: Servo Speed Control  (Read 328 times)
0 Members and 1 Guest are viewing this topic.
London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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);
}
Logged

Saskatchewan, Canada
Offline Offline
Edison Member
*
Karma: 49
Posts: 1389
Coding Geezer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//#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);
}
Logged

London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Saskatchewan, Canada
Offline Offline
Edison Member
*
Karma: 49
Posts: 1389
Coding Geezer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Norway
Offline Offline
Jr. Member
**
Karma: 1
Posts: 71
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Norway
Offline Offline
Jr. Member
**
Karma: 1
Posts: 71
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
for(.....value++) {
 myservo.Write(value);
  potvalue = readpot;
  delay(potvalue); // Map value using map().
}

EDIT: Sorry, forgot one important detail. Added to the code now.
« Last Edit: October 29, 2013, 06:23:11 pm by enanthate » Logged

London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks the full code will be really helpful.
Logged

Saskatchewan, Canada
Offline Offline
Edison Member
*
Karma: 49
Posts: 1389
Coding Geezer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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;
}
Logged

Norway
Offline Offline
Jr. Member
**
Karma: 1
Posts: 71
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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... smiley

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 = 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.
Logged

London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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]
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

London
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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().
Logged

Pages: [1]   Go Up
Jump to: