Varying Servo Rotation Limit

Hi I have a servo pan camera base and i'm trying to do something interesting.

The servo does a sweep from 0 to 180 degrees. My aim is to use two potentiometers to vary that level of rotation. The servo's limit is 180 degrees so it can't rotate farther than that but i want to be able to decrease the rotation to say from 40 o 100 degrees.

I modified a code with the servo sweep that was able to compile but when i attached it to the pots and the servo, it sweeps as i want but i didn't recognise any real change in the limit of rotation.

This is the code i had running:

#include <Servo.h> 
Servo myservo;

int potpin1 = 0;    //analog input pin A0
int potpin2 = 1;    //analog input pin A1

int pos1;          //variable to store servo minimum position
int pos2;          //variable to store servo maximum position

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("testing position variable servo");
}

void loop()
{
  pos1 = analogRead(potpin1);
  pos1 = map(pos1, 0, 1023, 1, 150);
  pos2 = analogRead(potpin2);
  pos2 = map(pos2, 0, 1023, 30, 180);
  
  for(pos1 = 0; pos1 < 180; pos1 += 1)    // goes from 0 degrees to 180 degrees
  {                                      // in steps of 1 degree
    myservo.write(pos1);                // tell servo to go to position in variable pos1
    delay(15);
    
  }
  for(pos2 = 180; pos2>=1; pos2 -= 1)    // goes from 180 degrees to 0 degrees
  {
    myservo.write (pos2);                // tell servo to go to position in variable pos2
    delay(15);
  }
}
/code]

I believe i might have made some mistakes with the pos1 and pos2. Thanks if anyone has any idea on this or any alternative methods for this particular issue.

I think what you're doing is ignoring the pos1 and pos2 values as mapped after you read the pots and still then varying the sweeps from 0 to 180.

So what you might try is to read and map the pots as you have but call them say "minPos" and "maxPos", but then use those as the limits in the fors as in:

for(pos1 = minPos; pos1 < maxPos; pos1 += 1)

I jus tried doing that i was not able to declare pos1 or pos2 as anything.

In my earlier code pos1 and pos2 were the positions of the pot but i changed them to minPos and maxPos as you suggested

What do i declare pos1 and pos2 as being?

#include <Servo.h> 
Servo myservo;

int potpin1 = 0;    //analog input pin A0
int potpin2 = 1;    //analog input pin A1

int minPos;          //variable to store servo minimum position
int maxPos;          //variable to store servo maximum position

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("testing position variable servo");
}

void loop()
{
  minPos = analogRead(potpin1);
  minPos = map(minPos, 0, 1023, 1, 150);
  maxPos = analogRead(potpin2);
  maxPos = map(maxPos, 0, 1023, 30, 180);
  
  for(pos1 = minPos; pos1 < maxPos; pos1 += 1)    // goes from 0 degrees to 180 degrees
  {                                      // in steps of 1 degree
    myservo.write(pos1);                // tell servo to go to position in variable pos1
    delay(15);
    
  }
  for(pos2 = maxPos; pos2>=minPos; pos2 -= 1)    // goes from 180 degrees to 0 degrees
  {
    myservo.write (pos2);                // tell servo to go to position in variable pos2
    delay(15);
  }
}

There is a thread on the forum with quite a similar code, you could understand it from there. Search next time :wink:
http://forum.arduino.cc//index.php?topic=196144.msg1447997#msg1447997

If this does not help you, I can try to write the full code for you.
Try first, as this is a good way to learn.

Edit : Your for-loops make no sense. If you use pos1 in the first loop, you have to use the same in the next loop. The second loop is waiting for pos2 = 180, but that will never happen, as only pos1 will be 180.

What do i declare pos1 and pos2 as being?

int pos1;
int pos2;
You don't need them tho. You have only one servo? Use pos1 to write the value for it, remove pos2.

Sorry, I'm bored so I figured I might as well write the code. Try to see what changes I made, didn't put any text in it.

UNTESTED, might be some bugs in there!

#include <Servo.h> 
Servo myservo;

int potpin1 = 0;    //analog input pin A0
int potpin2 = 1;    //analog input pin A1

int minPos;          //variable to store servo minimum position
int maxPos;          //variable to store servo maximum position
int pos1 = 0;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("testing position variable servo");
}

void loop()
{
  minPos = map(analogRead(potpin1), 0, 1023, 0, 180);
  maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  pos1 = minPos;

  for(pos1 = minPos; pos1 <= maxPos; pos1 += 1)    // goes from 0 degrees to 180 degrees
  {                                      // in steps of 1 degree
    myservo.write(pos1);                // tell servo to go to position in variable pos1
    delay(15);
    maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  }
  maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  pos1 = maxPos;
  for(pos1 = maxPos; pos1 >= minPos; pos1 -= 1)    // goes from 180 degrees to 0 degrees
  {
    myservo.write (pos1);                // tell servo to go to position in variable pos2
    delay(15);
    minPos = map(analogRead(potpin1), 0, 1023, 0, 180);
  }
}

You now have 2 pot-meters - potpin1 is controlling minPos, potpin2 is controlling maxPos. Why not just use one pot-meter to control both?

EDIT : Edited the code just a bit.

Thanks that really helped a lot but i just have a question.

Why did you use the analogRead function for min and max Position twice?

kelvin8:
Why did you use the analogRead function for min and max Position twice?

I'm glad it worked.

Because when the servo goes from maxPos to minPos, say this takes about 3 seconds. In this time, you might adjust the minPos. This would not affect the second loop. The reason for this is that when a for-loop starts, the void loop() is "stopping", and only the for-loop is running again and again until it's broken. Therefor, since the first for-loop takes a little time, I added that analogRead to get fresh values for for-loop number 2.

Notice that I also put analogRead inside the loop, this is to affect when the loop will stop(if this wasn't inside the for-loop, the value would not change even if you turn your pot-meter. The command needs to be executed in order to read and set the current pot-meter value). You can change both values during the loops.

Edit: Sorry for such a long text to explain this simple thing, my english is only limited.

Thanks that's really good. I'll try it out on monday when i have access to some potentiometers but thanks again.

I have a question related to this.
Could you do an analogRead as one of your parameters in the for loop?

for example:

for (int i = 0; i <= analogRead(potPin); i++){
   myServo.write(i);
  delay(15);
}

Wouldnt that change the value of the end of the for loop on the fly?

Wouldnt that change the value of the end of the for loop on the fly?

At the cost of reading the potentiometer on every pass of the loop, yes. Don't forget that you can't (successfully) write all the values to the servo that analogRead() can return.

Thats what I meant, actually. I think it would be interesting to be able to change the limits of a for loop on the fly.

I dont have any use for this, but its an interesting idea.

Hi still had some problems using the code above. What i got was the servo working as some sort of the knob function with the two pots.
There is no constant sweep and so both servos don't work to either increase or decrease the rotation limit

Hi still had some problems using the code above.

You turn one pot. Something happens. You turn the other pot. Something else happens. "That didn't work" doesn't cut it. Details, man, details.

Basically pot 1 is meant to assume the minimum limit of the servo rotation (lets say 0)

Pot2 is meant to assume the maximum limit of the servo rotation (in this case 180)

The aim is to start a sweep movement but within the limit the pots allow.
The servo sweeps from 0 to 180 continuously and as the pots are turned it doesn't rotate past that limit the pot decides.

So if pot 1 creates a variable position saying 20 degrees and pot2 creates one saying 80 degrees. The servo sweeps from 20 to 80 degrees continuously until changed.

The code above does compile but what happens is that both servos create a position for the servo resulting in sort of a knob movement. So when u rotate the pot the servo arm follows the rotation. Its meant to create the limit of rotation.

You need to post the code you are talking about. I would be using something like this:

for(int pos = analogRead(lowerLimitPotPin)/6; pos < analogReadUpperLimitPotPin/6; pos++)
{
   Servo.write(pos);
   delay(thumbTwiddlingTime);
}

with a similar loop for the sweep back.

This is the code

[code#include <Servo.h> 
Servo myservo;

int potpin1 = 0;    //analog input pin A0
int potpin2 = 1;    //analog input pin A1

int minPos;          //variable to store servo minimum position
int maxPos;          //variable to store servo maximum position
int pos1 = 0;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("testing position variable servo");
}

void loop()
{
  minPos = map(analogRead(potpin1), 0, 1023, 0, 180);
  maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  pos1 = minPos;

  for(pos1 = minPos; pos1 <= maxPos; pos1 += 1)    // goes from 0 degrees to 180 degrees
  {                                      // in steps of 1 degree
    myservo.write(pos1);                // tell servo to go to position in variable pos1
    delay(15);
    maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  }
  maxPos = map(analogRead(potpin2), 0, 1023, 0, 180);
  pos1 = maxPos;
  for(pos1 = maxPos; pos1 >= minPos; pos1 -= 1)    // goes from 180 degrees to 0 degrees
  {
    myservo.write (pos1);                // tell servo to go to position in variable pos2
    delay(15);
    minPos = map(analogRead(potpin1), 0, 1023, 0, 180);
  }
}

I think the issue might be the analog mapping

Have you tried something like below? Also, you probably should print the servo commands to the serial monitor to see what the code output is.

int minPos;          //variable to store servo minimum position
int maxPos;          //variable to store servo maximum position
int pos1 = 90;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("testing position variable servo");
}

void loop()
{
  minPos = map(analogRead(potpin1), 0, 1023, 0, 90);
  maxPos = map(analogRead(potpin2), 0, 1023, 90, 180);
  //pos1 = minPos;

Hi yes i was able to try that idea but the servo still acts as if the potentiometers are running the knob control code.

I tried using the serial print and got the values of the potentiometer correctly but i'm still not able to understand why the servo does not sweep between both angles.

I don't think you posted a schematic of your setup... might be time to do that so we can see exactly how it hangs together.

Modified sweep test code to set the upper and lower servo positions (big delay and 5 deg. changes for testing). I don't have a servo to test this with, so YMMV. Use the serial monitor to see the position output.

// zoomkat modified sweep 11-04-13

#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
int pos = 90; // servo start position between up and dn
int dn = 40; // servo lower limit
int up = 140; // servo upper limit

void setup() 
{ 
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
} 
 
 
void loop() 
{ 
  for(pos > dn; pos < up; pos += 5)  // dn and up set servo limits 
  {                                   
    Serial.println(pos);  // for serial monitor viewing
    myservo.write(pos);   // tell servo to go to position in variable 'pos' 
    delay(150);           // waits 150ms for the servo to reach the position 
  } 
  for(pos < up; pos >dn; pos-=5)     // dn and up set servo limits 
  {                                
    Serial.println(pos);
    myservo.write(pos);     // tell servo to go to position in variable 'pos' 
    delay(150);             // waits 150ms for the servo to reach the position 
  } 
}