Go Down

Topic: simple two position servo (Read 3814 times) previous topic - next topic

Apr 21, 2011, 05:13 pm Last Edit: Apr 23, 2011, 06:39 pm by tomswell Reason: 1
hello: Im a total newb trying to get my first servo sketch working and have spent hours without result desired. I've messed with may examples using potentiometers with success but seem to fail using fixed position attempts. Any assitance will be most appreciated.


ADDENDUM:
great hints provided caused me to start by declaring myservo object & experimenting with  myservoWrite(values) to determine servo limits
then added logic & additional led
successful sketch below  :)


Code: [Select]
//two position servo
#include <Servo.h>
#define SENSOR 5
int IRvalue = 0;
Servo myservo;  // create servo object
void setup()
{
  pinMode (2 , OUTPUT); // "sensor active" LED 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  myservo.writeMicroseconds(600);// assure servo starts in correct position
  delay(400);
  // Serial.begin(9600); used to see actual SENSOR values
}

void loop()
{

  IRvalue = analogRead (SENSOR)/100;// look at sensor and pause
  // Serial.print("IRvalue ="); // text
  // Serial.println(IRvalue);// IRvalue with line feed

  if (IRvalue < 8){ // sensor normally 10
    digitalWrite(2,HIGH); // light up led indicating sensor activated
  }
  else{
    digitalWrite(2,LOW); // no sense active
  }

  delay(1000);// delay before action

  if (IRvalue < 7) {                  //sensor output went below 10
    myservo.writeMicroseconds(2400);  // tell servo to go to  active position in'
    delay(200);                       // wait for the servo to reach the position
    myservo.writeMicroseconds(600);              // tell servo to return to passive position
    delay(100);
  }
}[code]
[/code]

johnwasser

You don't use digitalWrite() for the servo pin.  Use myservo.write(position-in-degrees) or myservo.writeMicroseconds(pulse-width-in-microseconds).  Be warned that pulse widths below 1000 or above 2000 may cause the servo to jam against its internal stop.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

zoomkat

Quote
Any assitance will be most appreciated.


Try stating what you are trying to do for best help.
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

#3
Apr 21, 2011, 11:20 pm Last Edit: Apr 21, 2011, 11:23 pm by GordonMcComb Reason: 1
The Part 3 (from the ArdBot series in SERVO Magazine) example code shows attaching and detatching. Get it here:

http://www.robotoid.com/servomag/

Simplify your tests by initially including only the servo code. The example "exercises" a servo from one end to the other.

A couple of things about your code:

1. When you create a new servo object its position gets set to 90 (or 1500 microseconds). You can change the initial position with servo.write. You don't have to attach it first.

2. Be sure you delay long enough to the next statement for the servo to transit where you want it to go.

3. You need to re-read the value of your IR pin each time in the loop. You have it as:

if (IRval == HIGH)

which only checks what you put into the IRval previously, outside the loop. Since the variable will never change your servo will not move.

4. You don't need to set servo pins as OUTPUTs, as the class does that implicitly.

5. When in idle mode standard (non-converted) servos don't consume a lot of current. One good use of the detach method is when you have servos converted to continuous rotation. By detatching the servo won't creep, which can be the case if their center points drifts from the usual 1500 usec.

thanks for support
successful result posted within first message :)

I'm still experimenting but here's an example of having a servo momentarily going more or less full rotation on event;
I'm now fooling with timing ...  include a counter that increments with each (IR_value<7)= servo action ...   after (x) main loop cycles ...  blink counter().... occasionally report how many times servo was actuated


Quote



//two position servo
#include <Servo.h>
#define SENSOR 5
int IRvalue = 0;
Servo myservo;  // create servo object
void setup()

  pinMode (2 , OUTPUT); // "sensor active" LED 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  myservo.writeMicroseconds(600);// assure servo starts in correct position
  delay(400);
  // Serial.begin(9600); used to see actual SENSOR values


void loop()

  delay (4000);
  IRvalue = analogRead (SENSOR)/100;// look at sensor and pause
  // Serial.print("IRvalue ="); // text
  // Serial.println(IRvalue);// IRvalue with line feed

  if (IRvalue < 8){ // sensor normally 10  delay(2000);// delay before action
    delay(200);

    digitalWrite(2,HIGH); // light up led indicating sensor activated
  }
  else{
    delay (200);
    digitalWrite(2,LOW); // no sense active
  }


  if (IRvalue < 7) {                  //sensor output went below 10
    delay(2200);                       // wait for the servo to reach the position
    myservo.writeMicroseconds(3400);  // tell servo to go to  active position in'
    delay(1200);                       // wait for the servo to reach the position
    myservo.writeMicroseconds(600);              // tell servo to return to passive position
    delay(100);
  }
}












Good to know you're having success. Just a couple of points about the code.

You've duplicated the lines

Code: [Select]
delay(200);

twice within the if block. You might want to delete these and have just one, right after you've read the IR value. These kinds of consolidations can make the code easier to track as you try different values.

You have some extremely long delays waiting for the servo to transit. Are these really necessary or are you adding additional waiting time for demonstration purposes? Example: you have one specifying a delay of over two seconds

Code: [Select]
delay(2200);

Following this is a servo position value that looks extraordinarily out-of-bounds for most any servo:

Code: [Select]
myservo.writeMicroseconds(3400)

What kind of servo is this? Standard, sail winch, something else?

Some servos will accept out-of-bound limits to prevent internal damage, and I wonder if yours is doing that, giving you a false impression of the usec values you should be using. A more common lower and upper limit is along the lines of 650 us to 2400 us, and even these are outside some brands of servos.

zoomkat

I think if one digs into the servo library files there are default high and low values set there.
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

#8
May 04, 2011, 06:33 pm Last Edit: May 04, 2011, 06:40 pm by GordonMcComb Reason: 1
I'm having trouble visualizing your setup if what you're doing is trying to close a bait trap after the rat has come all the way in.

First thing I'd do is replace the IR sensor, which can be be unreliable, with a force sensitive resistor like this one:

http://www.sparkfun.com/products/9376

Place the sensor right at the bait. Connect it between 5V and Gnd in series with a resistor (play with the value of the resistor to get good sensitivity for the weight of the average ravenous rat; start with perhaps 100k and go from there). Connect the output to an analog pin. (For a hookup example use a photoresistor circuit; the concept is exactly the same -- you are converting a resistance to a voltage.)

In the setup() function, set up your servo object, rotate the servo to open the trap, and detach it. If you don't the slight "throbbing" of the servo will cause the rat to run away.

In the loop() function wait for the value to drop to indicate the rat is at the bait. Then close the trap in one swift move.

In pseudocode

Code: [Select]

setup() {
 define Servo object
 attach object to servo pin
 rotate servo to open trap
 delay one second for full transit
 detach servo
}

loop {
 read analog input
 is rat on sensor? {
    re-attach servo
    rotate to close trap
    return;
 }
}


The LED code you can add later. I'd not worry about the arc of the servo; rather define the values you need to open and close the trap door. Depending on the mechanics you may not need anything close to the full 180-200 degree arc of the servo.

In any case, you don't really need delays beyond the first one. Be sure to keep the servo attached (energized) after the trap has been sprung, or work up a locking mechanism to keep the door shut.

Anyway, this is how I envision a rat trap might be set up.

-- Gordon


#9
May 05, 2011, 03:07 pm Last Edit: May 05, 2011, 03:13 pm by tomswell Reason: 1
essentially the trap is a half open cylinder that flips over rapidly dumping creature into bucket. Sort of a tumbling funhouse barrel. The advantage of this design is the minimal load on the servo even with a good sized creature chowing down in the trough.
The digital sensor is a Sharp GP2Y0D805Z0F from Pololu that I have I have watched closely and it's output seems very consistent. The primary concern is assuring a consistent delay prior to activating servo. Since I added counter that consistency has diminished. So I'm thinking of driving a couple of seven segment LEDs as opposed to pulsing count output.

The GP2Y0D80's are more consistent than the older style, and they update at about 300 Hz, giving better accuracy.

As these aren't expensive, even on the breakboard boards that Pololu provides, have you considered using two? One for when the rat enters, and one when it's at the feeding area. You could use the two to pretty much eliminate any false triggers, and it (I would think) avoid the problems of having to use a delay.

In any case, a simple delay when the sensor hits its trigger point ought to do it. You shouldn't have to use the counter. Simply:

Code: [Select]

read IR sensor
is rat there? {
  delay(nnn);
  rotate servo
  return;
}


The nnn for delay is whatever you want to make it. A couple seconds perhaps? So delay(2000); will give a two second delay once the IR sensor has detected said rat.

-- Gordon

johnwasser


I'm toying with thoughts of storing (total_counts) where as (count) would be cleared with reset or battery change.  I'm guessing that it would be not be worth having small aux battery to preserve memory ... or the inclusion additional no volatile ram ( if that's even possible.)


You could use the built-in EEPROM to save values while power is off.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

tastewar


Thanks for your interest ... component count / cost is part of design decision making. I posted under programming a question about nested If statements and I think I'll go with that approach:
Code: [Select]

// to test to test if IRvalue <3 still persists over time to avoid false triggering

if (IRvalue < 3) {                                         //sensor output went low  TRIGGERED
    delay (6000);                                         // wait a  while for validation that rattie is munching
                                                              // may include pot value for easy adjustment in final build
    if (IRvalue < 3) {                                    //sensor output still low
       myservo.writeMicroseconds(1200);         // tell servo to go to active position
       delay(1200);                                      // wait for the servo to flip over open cylinder in trough 180°
       myservo.writeMicroseconds(600);          // tell servo to return to passive position
       count=count+1;                                  //tally time validated event
       serial print (count);                            //  thru Max7219 & twin 8 segment leds     
}
    } // ... loop again

I'm toying with thoughts of storing (total_counts) where as (count) would be cleared with reset or battery change.  I'm guessing that it would be not be worth having small aux battery to preserve memory ... or the inclusion additional no volatile ram ( if that's even possible.)



Sorry, I may be missing something here, but without re-establishing IRvalue again (e.g.
Code: [Select]

IRvalue = analogRead (SENSOR)/100

What's the point in recomparing it to 3??

#13
May 09, 2011, 11:55 pm Last Edit: May 09, 2011, 11:57 pm by GordonMcComb Reason: 1

if (IRvalue < 3) {                                         //sensor output went low  TRIGGERED
   delay (6000);                                         // wait a  while for validation that rattie is munching
...


I assume you're posting code fragments, which makes it a bit hard to follow. But in any case, you're testing for (IRvalue < 3) twice, one right after the other. You only need one, unless you're re-establishing IRvalue with a new reading.

Maybe your rats are slower eaters than the ones that bother our house, but in six seconds ours will have gone in, got the food, and run back out. Remember that because of the way the delay statement works for those six seconds the Arduino is a hung process, and doesn't do anything else.

Here's where you may want to delay for 500 or 1000 milliseconds at a time, each time re-reading the input to check if the rat is still eating. Assuming 1000 delays, you'd repeat that loop six times. You still have a six second total delay, but each second you're re-reading the input and can more quickly act upon a change.

-- Gordon


The reassessment of ir value is to prevent servo action if value does not persist after delay.


The code you posted doesn't re-read the I/O pin, so the value in the IRvalue variable will not have changed between the two if statements. (This is a common mistake in Arduino programming, treating the variable that holds an I/O value the same as the I/O itself.)

If you're posting code fragments, and merely left out the part where you re-read the pin, it's best to include all the relevant code. Otherwise it's not possible to see how the sketch will work.

-- Gordon

Go Up