Pages: [1]   Go Down
Author Topic: Remember servo position after detach()  (Read 701 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi guys,

I am having a bit of trouble with making a servo stop. I have made some code which detaches a servo after input from a distance sensor.
The servo stops moving, but when I attach the servo again it 'catches up' with the loop (I hope this is understandable). However, I want the servo to remember its last position before detach and start the program again from there.
Is there a simple way to do this?

This is the code:
Code:
#include <Servo.h>


 
Servo servolaag;  // 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 IRpin = 1;  // analog pin for reading the IR sensor
int distance = 0;
int servoPin = 2;
int ledPin = 5;

void setup()
{
  servolaag.attach(2);  // attaches the servo on pin 2 to the servo object
  Serial.begin(9600); // start the serial port
  pinMode(servoPin, OUTPUT);
}
 
 
void loop()

{
 
 
 
  for(pos = 0; pos < 180; pos += 1)                // goes from 0 degrees to 180 degrees
  {                                                // in steps of 1 degree
    servolaag.write(pos);              // tell servo to go to position in variable 'pos'
    delay(30); 
       
 if (analogRead(IRpin) <= 500 && analogRead(IRpin) >= 300){
    analogWrite (ledPin, 0);
    servolaag.detach();
 }

else if (analogRead (0) == 0 ||  analogRead (0)<= 299){
   analogWrite (ledPin, 255);
   servolaag.attach(2);
}
                           
 



  }

 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
  {                               
    servolaag.write(pos);              // tell servo to go to position in variable 'pos'
    delay(30); 
   
    if (analogRead(IRpin) <= 500 && analogRead(IRpin) >= 300){

    analogWrite (ledPin, 0);
    servolaag.detach();
 }

else if (analogRead (0) == 0 ||  analogRead (0)<= 299){
   analogWrite (ledPin, 255);
   servolaag.attach(2);
 
}   

}

 
Logged

Central Europe
Offline Offline
Edison Member
*
Karma: 6
Posts: 1220
Use the Source, Luke.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

When you call detach, the refreshing of the servo stops and it wont hold the position any more. So far, so good.

When you call attach, the servo will move to the position it is set to, which by default is some kind of middle position at 1500 microseconds. If you don,t like this, call writeMicroseconds() before calling attach(). Write would work too, but you might not have set the high and low parameter correctly so the mapping from degree to microseconds might not be correct.

In short, a servo doesn't need to be attached to write to it, but the position will only be applied once the servo is attached too.

That should resolve your problem.

However if you would like to know in what position the servo currently is because it was moved manually while detached, you're out of luck. I can't think of a way to get this information.

Korman
« Last Edit: May 28, 2011, 03:09:41 pm by Korman » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Korman is right, after detach every info is gone.

There exist - expensive-  servo's that can remember their position.  You can make one yourself by extending the axis of the servo and connect it to a potmeter, which can be read by analogRead(). You need to create a lookup table or formula but it can be done. Given that a normal potmeter uses 270 degrees of which you only use 180 (?) you get a 2/3 range on the analogRead() something like 0..680  (multiply by 10 divide by 38) => 0..180 approx.

Furthermore you could remember the position of the Servo in a local var and when you attach again write this value again (a wrapperfunction around attach/detach?)

my 2 cents,
Rob
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

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

Quote
I have made some code which detaches a servo after input from a distance sensor.
Why do you think it is necessary to detach the servo? You could leave the servo attached, and simply not write a new position, if the sensor value is in range.

The purpose of the for loops is unclear.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok thank you for you help so far!

I have looked into hacking the servo by adding a potmeter, but perhaps this is not necessary at this time. Due to total noobism with coding (the code could probably be written with only half the size and clutter), detaching the servo was for me the way the program worked to some extend.

If I would leave the servo attached how should I code this the easiest?
Logged

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

Quote
how should I code this the easiest?
Start with a clear description of the requirements for the program. What it looks now like you are trying to do is to have the servo wave back and forth unless something is within some range of the sensor.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, this is exactly what it should do  smiley-razz
Logged

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

Quote
Well, this is exactly what it should do
Using the blink with delay example, you should be able to revise the code you have to move the servo to the next position, when the required time has elapsed.

When you have done this, it will be easy to "move the servo to the next position, when the required time has elapsed, unless something is in front of the sensor".

Start with moving the servo through its full range, without using delay. Then, add code to read the sensor value, and an if statement to move, or not, based on the sensor reading.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I finally managed to do it using a 'break' in a loop. Not the prettiest code, but posted below anyways. Thank you guys so much for you help and tips!

Code:
#include <Servo.h>


 
Servo servo;  // 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 IRpin = 1;  // analog pin for reading the IR sensor
int servoPin = 2;



void setup()
{
  servo.attach(2);  // attaches the servo on pin 2 to the servo object
  Serial.begin(9600); // start the serial port
  pinMode(servoPin, OUTPUT);
}
 
 
void loop()

{   

  for(pos = 0; pos < 180; )  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
     for (analogRead (IRpin) == 0 ;  analogRead (IRpin)<= 299; pos +=1)
     {
    servo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15); 
 Serial.println(pos);    // waits 15ms for the servo to reach the position
 if (pos > 180)
 {
   break;
   }
  }
}
   
   
   
    for(pos = 180; pos>0; )     // goes from 180 degrees to 0 degrees
  {                               
      for (analogRead (IRpin) == 0 ;  analogRead (IRpin)<= 299; pos -=1)
      {
    servo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15); 
 Serial.println(pos);   
if (pos < 0)
{
 break;
   }
  }
}
}
Logged

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

Code:
for (analogRead (IRpin) == 0 ;  analogRead (IRpin)<= 299; pos +=1)
The first part of the for loop is an assignment section. You are not assigning anything. Your loop will compare the value of analogRead() to 0. Regardless of whether it is true or false, the loop will execute.

The second part defines the while part of the loop. The loop executes as long as the while part is true.

The third part defines what happens at the end of the loop. In this case pos is incremented.

You are breaking out of the inner for loop when pos gets to 180, if the sensor reading is 300 or greater.

I don't think that is even close to good code.

What you should do is something like this:
Code:
unsigned long lastMove = 0;
int pos = 0;
int dir = 1;

void loop()
{
   int sensVal = analogRead(IRpin);
   if(sensVal < 300 || sensVal > 500) // Nothing is in range, so move the servo
   {
       unsigned long currTime = millis();
       if(currTime - lastMove > 100) // 100 milliseconds between moves
       {
          if(dir > 0)
          {
             if(pos < 180)
                pos++;
             else
                dir = -1;
          }
          else
          {
             if(pos > 0)
                pos--;
             else
                dir = 1;
          }
          servo.write(pos);
          lastMove = currTime;
       }
   }
}

This tests that there is nothing in the desired range of the sensor. If there is, nothing happens.

If there isn't, it tests that it is time to move the servo. If it isn't, nothing happens. If it is, the position is incremented if is is less than 180 and incrementing. Otherwise it is decremented, if it is greater than 0. Then, the servo is moved to that position, and the time of the move is recorded.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Damn that looks way more logical and works like a charm. Since I would never had come up with this, its time for me to get a good book for mastering the basics  smiley-roll-blue. Thanks a million PaulS!
Logged

Pages: [1]   Go Up
Jump to: