controlling servo with sensors

I am working on a piece where I need to hook up 7 servo motors to the arduino (each rotating at a different speed, some in one direction, others in the other) but basically an on/off with a motion sensor. I am using a full rotation servo.

I amusing an infrared sensor but the servo is still moving (awkwardly and jerky) when not sensing motion, but then runs as normal.
Here is the code I am using (right now, I am only at 1 servo – trying to get the sensor right first) :

#include <Servo.h>

Servo myservo;
int potPin = 0; //analog pin used to connect the sensor
int ledPin = 9; //select pin for the servo
int val = 0; //variable to read the value from the analog pin
void setup()
{
myservo.attach(9); //set up the servo as usual
pinMode(ledPin, OUTPUT); //variable to store the value coming from the sensor
Serial.begin(9600); //for watching the speeds in the serial monitor
}

void loop() {
val = analogRead(potPin); // read the value from the sensor
val = map(val,0,600,0,255);
if (val>80) digitalWrite(ledPin, HIGH); //turn the ledPin on

else if (val<80) digitalWrite(ledPin, LOW); //turn the LedPin off

Serial.println(val);
delay(10);

}

– any suggestions?

amusing an infrared sensor

I tried that once but couldn't even get a giggle out of it.

if (val>80) digitalWrite(ledPin, HIGH); //turn the ledPin on
 
  else if (val<80) digitalWrite(ledPin, LOW);  //turn the LedPin off

Not your problem I don't think but what happens of val == 80?

the servo is still moving

What servo, there's no code to control one.


Rob

Do you mean have the val ==80 for HIGH? or LOW?
In the code, the pinMode sets the ledPin as output - so I am sending the info read by the sensor to the digital pin 9 or servo.

If 80 is your trip point you don't need two tests and the way it is written when val == 80 nothing happens.

if (val>80) digitalWrite(ledPin, HIGH); //turn the ledPin on
 
  else digitalWrite(ledPin, LOW);  //turn the LedPin off

In the code, the pinMode sets the ledPin as output - so I am sending the info read by the sensor to the digital pin 9 or servo.

Writing a single HIGH or LOW to a servo won't cause it to move properly, but it might jerk as you are saying, especially when the sensor val is hovering around 80.

Servos need a constant pulse stream.

Look up the servo library functions


Rob

thanks - I'll work with this and see what happens - I appreciate the help!

One other thought, the reason that I am using the HIGH / LOW is that I want when someone is in front of the sensor, I want the servos to move, when they are away from the sensor, I want the servos to stop.
In looking at the servo library, there is the detach option which I am wondering if I can define the HIGH and LOW to attach and detach.
Or if I can just list myservo.write instead of the digital write when the sensor reaches the required val.
I'm going to try it but as always, input is greatly appreciated.
W

Something like,

#define CW 1
#define CCW -1

[glow]setup [/glow]() {
   servo.write (90); // to start at mid position

}

int angle = 0;
int direction = CW;

if (val < 80)  { // I assume < 80 means someone is close
    servo.write (angle);
    angle += direction;
    if ( angle <= 0) direction = CW;
    if ( angle >= 180) direction = CCW;
    delay (10); // maybe, depends on how fast you want it to move

}

If no one is near the servo will stay at the last position. When someone gets close it will start moving back and forth.

You can also play with the CW and CCW values to increase the step size.

EDIT: changed loop to setup.


Rob

thanks! will try

I finally got it to work with one servo - now I need to add the other 6.
Here is what worked:
#include <Servo.h>

Servo myservo;
int potPin = 0; //analog pin used to connect the sensor
int ledPin = 9; //select pin for the servo
int val = 0; //variable to read the value from the analog pin
void setup()
{
myservo.attach(9); //set up the servo as usual

pinMode(ledPin, OUTPUT); //variable to store the value coming from the sensor
Serial.begin(9600); //for watching the speeds in the serial monitor
}

void loop() {
val = analogRead(potPin); // read the value from the sensor
val = map(val,0,1023,0,179);
if (val>79) myservo.writeMicroseconds(0); //set servo to mid-point

else if (val<80) myservo.writeMicroseconds(1500); //set servo to mid-point

Serial.println(val);
delay(10);

}

I just realised you're using continuous servos.

Anyway I don't think

writeMicroseconds(0);

is valid, it's supposed to be between 1000 and 2000.

And there's no need for two tests as I said before

[glow]if (val>79)[/glow] myservo.writeMicroseconds(0);  [glow]//set servo to mid-point[/glow] 
  else [glow]if (val<80)[/glow] myservo.writeMicroseconds(1500);  [glow]//set servo to mid-point[/glow]

that implies there's a third option which there isn't. A person is either close (<80) or they aren't. Once you've determined the first there's no need to test for the second.

And the comments can't both be right.

Anyway, to do mutiple servos create an array and do something like the following

#include <Servo.h>

#define N_SERVOS 7

Servo myservos[N_SERVOS];

int potPin = 0; //analog pin used to connect the sensor
int val = 0;  //variable to read the value from the analog pin
void setup()
{
 myservos[0].attach(9); // use whatever pins are right
 myservos[1].attach(9); 
 myservos[2].attach(9); 
 myservos[3].attach(9); 
 myservos[4].attach(9); 
 myservos[5].attach(9); 
 myservos[6].attach(9); 
 
 Serial.begin(9600); //for watching the speeds in the serial monitor
}

void loop() {
val = analogRead(potPin);    // read the value from the sensor
 val = map(val,0,1023,0,179);
  if (val>79) {
    for (int i = 0; i < N_SERVOS; i++)
      myservos[i].writeMicroseconds(1500);  
  } else { 
    for (int i = 0; i < N_SERVOS; i++)
      myservos[i].writeMicroseconds(1000); 
  } 

 
 Serial.println(val);
delay(10); 

}

This compiles but I've never used the servo object before so have no idea if it will work, can't see why not though.


Rob

Hey Rob - thanks for your post - I have been busy installing another art installation and am just getting back to this now. I had taken a class where we were instructed to use the if else formula and you are right about the comments (I was just cutting and pasting)
I'll let you know if it works - thanks again - W

No problems, I'll probably be out of touch for the next week or so, hopefully that code will at least get you started.


Rob

First things first:

  • LEDPin (pin 9) is given to a servo, and then you steal it as a regular digital output. Pick one, you can't have both.
  • Graynomads example code has an array of servo's, all of which attached to pin9, they each need their own pin (which isn't used in any pinmode calls).
  • Your 'servos' need to be controlled exclusively through the servo objects, that means no digitalwrites or so. Read the documentation about the library, turning a servo off isn't done with detach... (thats for making the arduino oblivious to the servo, which isn't the same as turning it off), this is likely accomplished through the servo.writemicroseconds with a value that you'll have to determine through experimentation (as in, just fill in a number and see if it'll stop the servo).
  • As Graynomad has tried to explain at least twice.. an if statement looks at the first 'if' first. If it meets the criteria stated in it, it will do the code associated with it. If it doesn't meet it, it will see what you put for its else... this means that the else parts is ignored if the first part of the if is run. This means that your 'if - else if' is less efficient than a simple 'if - else', the second check isn't needed.. as it is effectively the opposite of the original if check.

Hope this helped!

You may need to state what the "full rotation servo" is that ypu are using. There are "normal"servos that normally only have ~180deg of rotation and can move to specific locattions, and "continous rotation "servos that have been modified to act like gear motors, that can contionously rotate round and round.

I am using a full rotation servo motor from sparkfun ROB-09347. I can get it to run the way I want with 1 servo but not more than that but only using the code I listed before as working.
I understand that everyone says I only need an if and not the else if but no matter what I try, the servo keeps spinning when there is not movement in front of the center withe the exception of putting in the else if.
The problem is that I can't figure out what and where to duplicate so I can run more than one servo.

I am confused as all the code I find say that more servos can be run but they only list one as an example on pin 9.
I tried "stealing" as mentioned above by running pin 9 to the breadboard and connecting more than 1 servo to it but that didn't work. I am confused as to how to define the 7 servos. I have tried all the versions suggested as well as those listed in the library but am not having any luck - any other suggestions? I am open to them all.
thanks

You should post up your code for using more than one servo (some things in your previously posted code look strange to me). I assume you are using only one sensor which will provide the input for what is sent to the individual servos. Probably best to make some test code where you send a simulated sensor value from the serial monitor to the arduino for testing the multiple servo setup, then when that works, switch to the sensor input.

everyone has said this is weird, but this is the only thing that worked - but only with 1 servo:
#include <Servo.h>

Servo myservo;
int potPin = 0; //analog pin ued to connect the sensor
int ledPin = 9; //select pin for the servo

int val = 0; //variable to read the value from the analog pin
void setup()
{
myservo.attach(9); //set up the servo as usual

pinMode(ledPin, OUTPUT); //variable to store the value coming from the sensor
Serial.begin(9600); //for watching the speeds in the serial monitor
}

void loop() {
val = analogRead(potPin); // read the value from the sensor
val = map(val,0,1023,0,179);
if (val>79) myservo.writeMicroseconds(0); //set servo to mid-point

else if (val<80) myservo.writeMicroseconds(1500);

Serial.println(val);
delay(10);

}

This is my latest attempt with the multiple servos:
#include <Servo.h>

#define N_SERVOS 7

Servo myservos[N_SERVOS];

int potPin = 0; //analog pin used to connect the sensor
int val = 0; //variable to read the value from the analog pin
void setup()
{
myservos[0].attach(9); // use whatever pins are right
myservos[1].attach(8);
myservos[2].attach(7);
myservos[3].attach(6);
myservos[4].attach(5);
myservos[5].attach(3);
myservos[6].attach(3);

Serial.begin(9600); //for watching the speeds in the serial monitor
}

void loop() {
val = analogRead(potPin); // read the value from the sensor
val = map(val,0,1023,0,179);
if (val>79) {
for (int i = 0; i < N_SERVOS; i++)
myservos*.writeMicroseconds(0); *

  • }else if (val<80) {*
  • for (int i = 0; i < N_SERVOS; i++)*

_ myservos*.writeMicroseconds(1500);_
_
}_
Serial.println(val);
delay(10);
_
} *_
I am only using 1 sensor.

I read this a couple times and I don't think this question has been answered. Are you connecting the servos to the Arduino directly? Or are you using some sort of transistor in between.

myservos[i].writeMicroseconds(0);

Is zero allowed?
[edit]oops, someone already said that.[/edit]

I have tried both to connect the servos directly to the arduino and to the breadboard. and to the other comment, my understanding is that 0 is a number. Please correct me if I am wrong.