Servo Reading IR Sensor

Currently working on a project using a few DC motors, a Servo and an IR sensor.

I am trying to get a Servo to be controlled via IR sensor once I reach a certain destination. The IR sensor needs to tell the Servo to move a desired position once it sees a hole in a rotating disk and the voltage is lower than a specified amount. As of now the code I have works, but not exactly how I want it. The servo does not immediately react when the hole passes the IR sensor and that is what I need.

Any help would be much appreciated!

The following is the code I have at the moment, and the bolded portion is the area I sure the error is.

#include <Wire.h>
#include <Adafruit_MotorShield.h>

#include <Servo.h>

Servo Servo9;

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

// Select which 'port' , M3
Adafruit_DCMotor *Motor1 = AFMS.getMotor(3);

// Attach the switch to pin 3 - make it a constant so it can't be changed
const int motor_switch = 3;

// Selct which 'port' motor goes in
Adafruit_DCMotor *Motor2 = AFMS.getMotor(1);

void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Motor Running via Switch Input");

AFMS.begin(); // create with the default frequency 1.6KHz

//configure the motor_switch as an input and enable the internal pull-up resistor
pinMode(motor_switch, INPUT_PULLUP);

// Set the speed to maximum
// The speed won't change, so we can define it in setup
Motor1->setSpeed(150);

// Set the speed to maximum
// The speed won't change, so we can define it in setup
Motor2->setSpeed(200);

Serial.begin(9600);
Servo9.attach(9);
Servo9.write(175);

}

void loop() {
// While the button is held down, run the motor
while(!digitalRead(motor_switch))

Serial.println("Button Pressed. Running motor...");
// Set the direction of the motor to FORWARD
// The direction won't change, so we can define it in setup
Motor1->run(FORWARD);

// Delay for 4350 ms before checking the swtich again
delay(4790);
// if the button is not pressed, stop the motor
Motor1->run(RELEASE); // Stop the motor

// Delay for 5000 ms before checking the swtich again
delay(4000);

{
int value=analogRead(0);

// print out the raw value that was read:
Serial.print("The raw analog reading was ");
Serial.println(value);

// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = value * (5.0 / 1023.0);
Serial.print("This corresponds to an analog votlage of ");
Serial.print(voltage);
Serial.println("V");

{ if (voltage > 1.5){
** Serial.println("servo closed position.");**
** Servo9.write(175);**
** delay(100);**
}
** else if (voltage < 1.5) {**
** Serial.println("servo open position.");**
** Servo9.write(50);**

}

{
// Set the direction of the motor to BACKWARDS
Motor1->run(BACKWARD);

// Delay for 1000 ms before checking switch again
delay(1155);

// if the button is not pressed, stop motor
Motor1->run(RELEASE); // Stop motor

// Delay for 1000 ms before checking switch again
delay(1000);

// Motor 1 activated, dropping beacon cage down
Motor2->run(BACKWARD);

// Motor 2 drop delay
delay(3610);

// if the button is not pressed, stop motor
Motor2->run(RELEASE); // Stop motor

// Delay for 1000 ms then wait until data center is reached
delay(1000);

// Continue direction of the motor BACKWARDS
Motor1->run(BACKWARD);

// Delay for 3000 ms before checking switch again
delay(2430);

// if the button is not pressed, stop motor
Motor1->run(RELEASE); // Stop motor

// Delay for 5000 ms before checking switch again
delay(2000);

// Motor 2 activated, lifts cage at data center
Motor2->run(FORWARD);

// Delay cage lift
delay(3610);

// Motor 2 function ends completely
Motor2->run(RELEASE); // Stop motor

// Delay time between end motor 2 and beginning of motor 1 movement
delay(1000);

// Continue direction of motor BACKWARDS
Motor1->run(BACKWARD);

// Delay for 1500 ms before checking switch again
delay(1170);

// if the button is not pressed, stop motor
Motor1->run(RELEASE); // Stop motor

// Delay for 10000 ms before checking switch again
delay(10000);
}}} }

I have some real doubts that you know what you are talking about. Your thread title suggests that you think a servo can read an IR sensor. That is not bloody likely.

Then, you say "The IR sensor needs to tell the Servo to move a desired position". Well, there is no way in hell that the IR sensor can tell the servo to do anything.

  // While the button is held down, run the motor
  while(!digitalRead(motor_switch))


 
   Serial.println("Button Pressed. Running motor...");

You said that the sensor was an IR device. Why is that connected to a pin named motor_switch? How do you press an IR sensor?

  // Delay for 1000 ms before checking switch again
  delay(1155);

The comment is rubbish. That is NOT what the code is doing.

How the hell do you expect the Arduino to instantly sense when the IR beam is no longer interrupted or is now interrupted when you stuff your head in the sand for so much of the time?

Exactly ONE } goes on a line.

I have not looked at your code in detail because it is so badly laid out, but I note that it is littered with delay()s during which nothing will happen. Could that be a problem ?

Your code would be easier to read if you Auto Formatted it in the IDE and posted it in code tags as described in read this before posting a programming question which I assume that you have read.

I'd say the Problem is a little higher in the program...

delay(4000);

If the hole passes the sensor while the CPU is twiddling it's thumbs waiting for four seconds, how could it react immediately?

What are you trying to accomplish with the "{" after the delay?

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you post a picture of your project so we can see what you are trying to achieve?

Thanks.. Tom... :slight_smile:

Ya got me... don't really no what I'm talking about when it comes to coding for arduino. This is a school project and we were given a Sparkfun Inventors Kit along with an 2 DC motors and an IR sensor. We spent maybe 2 weeks learning how to code for this project and I have no previous knowledge for this type of stuff so you don't have to tell me I'm shit at this. Trust me, I already know. Also I apologize for not putting the coding in the correct formatting.

Anyways, for those who are willing look past my apparent insult to this community, your help will not go unappreciated. A little background of the project..

We have built a 'robot', basically a small 'car' made of a wooden frame and 4 wheels, that is driven by one of the DC motors. We have a PVC pipe attached the top of the car and is horizontal to the ground. This pipe extends out the front of the car and has another PVC pipe attached to it, this one is perpendicular to the ground.

This perpendicular pipe holds ping pong balls via servo motor with an attached arm that prevents the balls from falling out. The IR sensor is also attached to this perpendicular pipe. So if you are still with me :slight_smile: I'm getting closer to the point.

This robot must activate via pushbutton start, travel a small distance, around 15 inches, to a cylinder that has a rotating top plate with a hole on the outer edge. I am trying to get the the IR sensor to read when the hole is positioned directly under it, activate the servo and allow the ping pong balls to drop into the hole.

This is the Whole point! I need to get the ping pong balls to drop in that hole in order to score the max points.

There is a little more to this project after this, but I don't want to bore you all too much and will leave it to that. Attached should be an animated sketch of the of what the playing grounds look like. The rotating cylinder is called the inner zone on the picture.

Thanks for any help you may provide

// Include the necessary libraries for the motor shield
// You should include all three below anytime you're using the motor-driver shield
#include <Wire.h>
#include <Adafruit_MotorShield.h>
 #include <Servo.h> 

 Servo Servo9;

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

// Select which 'port' M1, M2, M3 or M4. In this case, M3
Adafruit_DCMotor *Motor1 = AFMS.getMotor(3);

// Attach the switch to pin 3 - make it a constant so it can't be changed
const int motor_switch = 3;

// Selct which 'port' motor goes in
Adafruit_DCMotor *Motor2 = AFMS.getMotor(1);


void setup() {
  Serial.begin(9600);        // set up Serial library at 9600 bps
  Serial.println("Motor Running via Switch Input");

  AFMS.begin();  // create with the default frequency 1.6KHz
 
  //configure the motor_switch as an input and enable the internal pull-up resistor
  pinMode(motor_switch, INPUT_PULLUP);

  // Set the speed to maximum
  // The speed won't change, so we can define it in setup
  Motor1->setSpeed(150);

  // Set the speed to maximum
  // The speed won't change, so we can define it in setup
  Motor2->setSpeed(200);

  Servo9.attach(9);
  Servo9.write(175);

  
}

void loop() {
  // While the button is held down, run the motor
  while(!digitalRead(motor_switch))


 { 
   Serial.println("Button Pressed. Running motor...");
      // Set the direction of the motor to FORWARD
      // The direction won't change, so we can define it in setup
      Motor1->run(FORWARD);
      
      // Delay for 4790 ms before checking the swtich again
      delay(4790);
    // if the button is not pressed, stop the motor
  Motor1->run(RELEASE); // Stop the motor
  
  // Delay for 5000 ms before checking the swtich again
  delay(6000);
  }
  {
    int value=analogRead(0);

  // print out the raw value that was read:
  Serial.print("The raw analog reading was ");
  Serial.println(value);
  
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = value * (5.0 / 1023.0);
  Serial.print("This corresponds to an analog votlage of ");
  Serial.print(voltage);
  Serial.println("V");

   if (voltage < 1.5) {
    Serial.println("servo stop position.");
    Servo9.write(30);
   }
  else if (voltage > 1.6) {
    Serial.println("servo stop position");
    Servo9.write(175);
  }
  
  // Set the direction of the motor to BACKWARDS
Motor1->run(BACKWARD); 

  // Delay for 1000 ms before checking switch again
  delay(1155);

  // if the button is not pressed, stop motor
    Motor1->run(RELEASE); // Stop motor

    // Delay for 1000 ms before checking switch again
    delay(1000);

  // Motor 1 activated, dropping beacon cage down
  Motor2->run(BACKWARD);

  // Motor 2 drop delay
  delay(3610);

  // if the button is not pressed, stop motor
  Motor2->run(RELEASE); // Stop motor

  // Delay for 1000 ms then wait until data center is reached
  delay(1000);

  // Continue direction of the motor BACKWARDS
  Motor1->run(BACKWARD);

  // Delay for 3000 ms before checking switch again
  delay(2400);

  // if the button is not pressed, stop motor
  Motor1->run(RELEASE); // Stop motor

  // Delay for 5000 ms before checking switch again
  delay(5000);

  // Motor 2 activated, lifts cage at data center
  Motor2->run(FORWARD);

  // Delay cage lift
  delay(2400);

  // Motor 2 function ends completely
  Motor2->run(RELEASE); // Stop motor

  // Delay time between end motor 2 and beginning of motor 1 movement
  delay(1000);

  // Continue direction of motor BACKWARDS
  Motor1->run(BACKWARD);

  // Delay for 1500 ms before checking switch again
  delay(1200);

  // if the button is not pressed, stop motor
  Motor1->run(RELEASE); // Stop motor

  // Delay for 10000 ms before checking switch again
  delay(10000);


 }}

I can get the servo and IR sensor to react how I want it by itself, but as soon as I add this code with the coding that controls the two DC motors something is getting out of whack

 #include <Servo.h> 

 Servo Servo9;
 
 void setup()
{
  Serial.begin(9600);
  Servo9.attach(9);
}


void loop()
{
  int value=analogRead(0);

  // print out the raw value that was read:
  Serial.print("The raw analog reading was ");
  Serial.println(value);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = value * (5.0 / 1023.0);
  Serial.print("This corresponds to an analog votlage of ");
  Serial.print(voltage);
  Serial.println("V");

   if (voltage > 1.75) {
    Serial.println("servo stop position.");
    Servo9.write(175);
   }
       else if (voltage < 1.75) {
     Serial.println("servo open position.");
     Servo9.write(50); }

    }

Are you by any chance using analogWrite() to control the motors ? If so, which PWM pins are the motors connected to ? If you read Servo - Arduino Reference you will see that use of the Servo library and PWM on some pins at the same time is not possible.

I'm using analog pin A0 for IR sensor and the servo is attached on digital pin 9. I'm also using a motor shield with its' own motor ports for the DC motors.

You said earlier that I have too many delays. How would I get the motor to stop running and start up again in a few seconds without using a delay? Is it possible to activate the DC motor by an IR value reading?

I'm also using a motor shield with its' own motor ports for the DC motors.

Are you using analogWrite() in your program ?

To avoid problems with delay() causing a program to stall and/or become unresponsive the normal technique is to use millis() for timing and let loop() run freely. Save the millis() value when a timing period starts, then each time through loop() check its value again to see whether the required interval has passed. If so then act on it. If not then go round loop() again reading inputs, or whatever you need to do.

This is often referred to as the BlinkWithoutDelay principle named after the example with that name in the IDE.

   if (voltage > 1.75) {
    Serial.println("servo stop position.");
    Servo9.write(175);
   }
       else if (voltage < 1.75) {

What should happen if the voltage is exactly 1.75?

Why was it necessary to convert the analog reading to a voltage? Why couldn't this pair of if statements used the raw reading, instead?

When the voltage is exactly 1.75, the servo should stay in the starting position. Once the voltage is less than 1.75 I want the servo to move from that start position(175) to (50).

I'm converting the analog reading to voltage because i think it's a bit easier to determine distances.

Also, not using analogWrite(). However I do use analogRead().. Sorry if these questions are very basic, I'm not very experienced with this.

PaulS:

   if (voltage > 1.75) {

Serial.println("servo stop position.");
    Servo9.write(175);
  }
      else if (voltage < 1.75) {



What should happen if the voltage is exactly 1.75?

Why was it necessary to convert the analog reading to a voltage? Why couldn't this pair of if statements used the raw reading, instead?

UKHeliBob:
Are you using analogWrite() in your program ?

To avoid problems with delay() causing a program to stall and/or become unresponsive the normal technique is to use millis() for timing and let loop() run freely. Save the millis() value when a timing period starts, then each time through loop() check its value again to see whether the required interval has passed. If so then act on it. If not then go round loop() again reading inputs, or whatever you need to do.

This is often referred to as the BlinkWithoutDelay principle named after the example with that name in the IDE.

Thelenpum, exactly what do you mean when you say "The servo does not immediately react when the hole passes the IR sensor"?

Is the Thing sitting there watching the disk spin for several seconds before even attempting to drop the ball in the hole, or does it drop it at (more or less) the right time, but sometimes misses the hole? Is it dropping too early or too late?

In the original post, you said: "The IR sensor needs to tell the Servo to move a desired position once it sees a hole in a rotating disk and the voltage is lower than a specified amount."

Checking for the hole is done by
int value=analogRead(0);
float voltage = value * (5.0 / 1023.0);

Detecting the hole is done by
if (voltage < 1.75)

And dropping the ball is done by
Servo9.write(50); }

Have I understood everything right so far?

I'm converting the analog reading to voltage because i think it's a bit easier to determine distances.

That is nonsense, since the distance between the sender and the receiver never changes. At least, if I understand your setup it doesn't.

The question about analogWrite() was because that function does PWM, using a timer. The Servo library also uses a timer. Since there are a limited number of timers, using the Servo library disables PWM on some pins. If you are expecting the use analogWrite() on those pins, you will be disappointed when the only speeds you get are stopped and balls-to-the-wall.