Help with IR Remote

I'm really new to Arduino and recently completed my first project (thanks to someones help on this forum). Now I'm trying to modify my project to be controlled via remote. I purchased the IR Control Kit from Sparkfun. The newbie in me thought I could just substitute the pushbutton with IR codes. After some research I realized I couldn't and have been experimenting with the code. Basically what the code is supposed to do is control 5 servos, one at a time, at the push of a button. I would also like it to power on and off. I looked at various posts/articles and pieced together something that complies but doesn't really work :confused: Here is what I currently have. I can also post the original push button code if needed. Is there someone that can lend a hand?

#include <IRremote.h>
#include <Servo.h>

const int DebounceDelay = 100; //milliseconds
const int irReceiverPin = 2; //was "button". where reciever is connected to
const int ledPin = 13;
int press1 = 0;
int press2 = 0;
int press3 = 0;
int press4 = 0;
int press5 = 0;

IRrecv irrecv(irReceiverPin); //create an IRrecv object
decode_results decodedSignal; //stores results from IR detector
IRsend irsend;

unsigned long Power = 0xD827; // Power key
unsigned long A_Key = 0xF807; //A Key
unsigned long B_Key = 0x7887; //B Key
unsigned long C_Key = 0x58A7; //C Key
unsigned long UP = 0xA05F; //Up Key
unsigned long Down = 0x00FF; //Down Key
unsigned long Left = 0x10EF; //Left Key
unsigned long Right = 0x807F; //Right Key
unsigned long Circle = 0x20DF; //Circle Key
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;


void setup()
{ 
  Serial.begin(9600);
  irrecv.enableIRIn(); //start the receiver object
  
  pinMode(irReceiverPin, INPUT_PULLUP);
  servo1.attach(3);
  servo1.write(0);
  digitalWrite(irReceiverPin, HIGH);
  
  pinMode(irReceiverPin, INPUT_PULLUP);
  servo2.attach(4);
  servo2.write(0);
  digitalWrite(irReceiverPin, HIGH);
  
  pinMode(irReceiverPin, INPUT_PULLUP);
  servo3.attach(5);
  servo3.write(0);
  digitalWrite(irReceiverPin, HIGH);
  
  pinMode(irReceiverPin, INPUT_PULLUP);
  servo4.attach(6);
  servo4.write(0);
  digitalWrite(irReceiverPin, HIGH);
  
  pinMode(irReceiverPin, INPUT_PULLUP);
  servo5.attach(7);
  servo5.write(0);
  digitalWrite(irReceiverPin, HIGH);
}

void loop(){

   while(digitalRead(irReceiverPin) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  if(decodedSignal.value == Circle)
  servo1.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(irReceiverPin) == LOW) {
    //do nothing while we wait for the button to be released
 
  }
  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(irReceiverPin) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  if(decodedSignal.value == Circle)
  servo2.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(irReceiverPin) == LOW) {
    //do nothing while we wait for the button to be released
  
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(irReceiverPin) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  if(decodedSignal.value == Circle)
  servo3.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(irReceiverPin) == LOW) {
    //do nothing while we wait for the button to be released
 
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(irReceiverPin) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  
  if(decodedSignal.value == Circle)
  servo4.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(irReceiverPin) == LOW) {
    //do nothing while we wait for the button to be released
  
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(irReceiverPin) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  if(decodedSignal.value == Circle)
  servo5.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(irReceiverPin) == LOW) {
    //do nothing while we wait for the button to be released

irrecv.resume();
}
}

Which hardware timers do your IR and servo libraries use? Better not be the same one. By the way, have you tested the servos and IR separately, with known good example sketches?

yes the servo and the ir transmitter have been tested separately and they work. Also I believe the IR is using timer2 and servo timer1.

Could you either post or link to your original 5 servo code? I think it would help us understand the desired behaviour.

Edit: After looking at the code, I think it would be more helpful if you posted the original IR code.

I'm pretty sure you do NOT want to read from the IR pin like this.

while(digitalRead(irReceiverPin) == LOW)

The IR pin is receiving a series of pulses which the IR library decodes. You want to compare the received code against your list of expected codes.

I see you do have an example of comparing the received IR code with an expected value here:

if(decodedSignal.value == Circle)

Post the IR code and bet we can get you started.

Edit again:

Does the IR example have you set the IR pin like this?

  pinMode(irReceiverPin, INPUT_PULLUP);

If it does, there isn't a need to set it more than once. If the IR example you have doesn't do this at all, you shouldn't either.

The IR pin is not a button.

Original working code with push button

#include <Servo.h>

const int DebounceDelay = 100; //milliseconds
int button = 2;
int press1 = 0;
int press2 = 0;
int press3 = 0;
int press4 = 0;
int press5 = 0;

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;

void setup()
{
  pinMode(button, INPUT_PULLUP);
  servo1.attach(3);
  servo1.write(0);
  digitalWrite(button, HIGH);
  
  pinMode(button, INPUT_PULLUP);
  servo2.attach(4);
  servo2.write(0);
  digitalWrite(button, HIGH);
  
  pinMode(button, INPUT_PULLUP);
  servo3.attach(5);
  servo3.write(0);
  digitalWrite(button, HIGH);
  
  pinMode(button, INPUT_PULLUP);
  servo4.attach(6);
  servo4.write(0);
  digitalWrite(button, HIGH);
  
  pinMode(button, INPUT_PULLUP);
  servo5.attach(7);
  servo5.write(0);
  digitalWrite(button, HIGH);
}

void loop(){
   while(digitalRead(button) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  servo1.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(button) == LOW) {
    //do nothing while we wait for the button to be released
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(button) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  servo2.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(button) == LOW) {
    //do nothing while we wait for the button to be released
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(button) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  servo3.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(button) == LOW) {
    //do nothing while we wait for the button to be released
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(button) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  servo4.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(button) == LOW) {
    //do nothing while we wait for the button to be released
  }

  delay(DebounceDelay);  //wait long enough for a stable HIGH
  while(digitalRead(button) == HIGH) {
    //do nothing while we wait for the button to be pushed
  }
  servo5.write(90);
  
  delay(DebounceDelay);  
  while(digitalRead(button) == LOW) {
    //do nothing while we wait for the button to be released
}
}

DuaneDegn:
Edit again:

Does the IR example have you set the IR pin like this?

  pinMode(irReceiverPin, INPUT_PULLUP);

If it does, there isn't a need to set it more than once. If the IR example you have doesn't do this at all, you shouldn't either.

The IR pin is not a button.

My example doesn't set the IR pin like that. I just assumed I could replace the button function with the IR Receiver Pin signal. Again that was the newbie in me trying to just replace everything. I put "button" on the comments to remind me where I edited the code, so I could go back and undo renaming "button".

Arrays can make your life a lot easier.

Your original button/servo code could be written like this:

#include <Servo.h>

const int BUTTON_PIN = 2;
const byte SERVOS_IN_USE = 5;
const byte SERVO_PIN[] = {3, 4, 5, 6, 7};
Servo myServo[SERVOS_IN_USE];

void setup()
{
  for (int i = 0; i < SERVOS_IN_USE; i++)
  {
    myServo[i].write(0);
    myServo[i].attach(SERVO_PIN[i]);
  }

  pinMode(BUTTON_PIN, INPUT_PULLUP);

}

void loop()
{
  for (int i = 0; i < SERVOS_IN_USE; i++)
  {
    while (digitalRead(BUTTON_PIN) == HIGH)
    {
      //do nothing while we wait for the button to be pushed
    }
    myServo[i].write(90);
    delay(DebounceDelay);
    while (digitalRead(button) == LOW)
    {
      //do nothing while we wait for the button to be released
    }
  }
}

This is one of those things that takes a while to sink in. You want to be aware of when there are repetitive sections of code and try to figure out ways these sections can be converted to some sort of loop or function.

With the code in a loop, it's easier to modify. Here's my guess at converting it to use a button from an IR remote.

#include <IRremote.h>
#include <Servo.h>

const int DebounceDelay = 100; //milliseconds
const int IR_PIN = 2;
const byte SERVOS_IN_USE = 5;
const byte SERVO_PIN[] = {3, 4, 5, 6, 7};

IRrecv irrecv(IR_PIN); //create an IRrecv object
decode_results decodedSignal; //stores results from IR detector
IRsend irsend;

unsigned long Circle = 0x20DF; //Circle Key
Servo myServo[SERVOS_IN_USE];

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); //start the receiver object
  for (int i = 0; i < SERVOS_IN_USE; i++)
  {
    myServo[i].write(0);
    myServo[i].attach(SERVO_PIN[i]);
  }
}

void loop()
{
  for (int i = 0; i < SERVOS_IN_USE; i++)
  {
    do
    {
      if (irrecv.decode(&decodedSignal))
      {
        Serial.println(decodedSignal.value, DEC); // print resultat fra TV Remote i serial vinduet
        irrecv.resume();
      }
    } while (decodedSignal.value != Circle); // keep checking until the circle button is pressed
    myServo[i].write(90);
  }
}

I haven't tested either of these programs.

I uploaded the code you posted and nothing happens except now my servo is making a buzzing sound and is vibrating slightly.

mightymel:
I uploaded the code you posted and nothing happens except now my servo is making a buzzing sound and is vibrating slightly.

I neglected to add some of the setup code.

I added the lines:

  Serial.begin(9600);
  irrecv.enableIRIn(); //start the receiver object

Hopefully that will get things to work.

The new code didn't change anything. Servo is still buzzing. It looks like it is receiving the signal because the LED light on the Arduino is blinking whenever I press the circle button.

mightymel:
The new code didn't change anything. Servo is still buzzing. It looks like it is receiving the signal because the LED light on the Arduino is blinking whenever I press the circle button.

Is there any output to the terminal?

Do you see any missing setup code?

You have IR code which works? If you post the IR code you have we can compare it to the code I posted.

It looks like these two lines in setup()

   myServo[i].write(0);
    myServo[i].attach(SERVO_PIN[i]);

should be swapped so the attach comes first.

Well the IR code I used, I kinda pieced together. I started using this code from the examples thinking I could get some inspiration. I also found a post on instructables that modified the same code but its only for one servo and it rotates it left and right. I tested it and it works but the servo buzzes when it reaches its stopping point going clockwise. It doesn't look like the code you posted but maybe it could work???

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

// Written by: Mohamed Soliman
// This code is for controlling servo motor with IR remote control
// When clicking at any of two buttons the motor is toggling between the rotation and stop

#include <IRremote.h>      //must copy IRremote library to arduino libraries
#include <Servo.h>
#define plus 0x10EF10EF   //clockwise rotation button
#define minus 0x10EF807F  //counter clockwise rotation button

int RECV_PIN = 2;       //IR receiver pin
Servo servo1;
int val;                //rotation angle
bool cwRotation, ccwRotation;  //the states of rotation

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  servo1.attach(3);     //servo pin
  servo1.write(0);
}

void loop() 
{
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value

    if (results.value == plus)
    {
      cwRotation = !cwRotation;      //toggle the rotation value
      ccwRotation = false;         //no rotation in this direction
    }

    if (results.value == minus)
    {
      ccwRotation = !ccwRotation;   //toggle the rotation value
      cwRotation = false;            //no rotation in this direction
    }
  }
  if (cwRotation && (val != 90))  {
    val++;                         //for colockwise button
  }
  if (ccwRotation && (val != 0))  {
    val--;                         //for counter colockwise button
  }
  servo1.write(val);
  delay(20);          //General speed
}

I switched them, nothing changed

In this case it doesn't matter since if write isn't used before attach the servo will move to zero degrees. Generally it does matter since most people don't want the servo to start at the extreme position. If you want the servo to start in the center than you'd use:

   myServo[i].writeMicroseconds(1500);
    myServo[i].attach(SERVO_PIN[i]);

This prevents the servos from slamming from one position to another as they're started. I think it's safe to say you want to use "write" before "attach" when initializing servos.

mightymel:
yes the servo and the ir transmitter have been tested separately and they work.

What code did you use to test the IR?

DuaneDegn:
Is there any output to the terminal?

How about this slightly modified version of your last post as a starting point to spin the servos in turn when the plus key is pressed?

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

// Written by: Mohamed Soliman
// This code is for controlling servo motor with IR remote control
// When clicking at any of two buttons the motor is toggling between the rotation and stop

#include <IRremote.h>      //must copy IRremote library to arduino libraries
#include <Servo.h>
#define plus 0x10EF10EF   //clockwise rotation button
#define minus 0x10EF807F  //counter clockwise rotation button

int RECV_PIN = 2;       //IR receiver pin


const int numServos = 5;      // # of servos
const int firstServoPin = 3;  // attached to consecutive pins
int servoIdx = 0;            // index of servo to spin when button pressed
Servo servos[numServos];      // servo objects

Servo servo1;
int val;                //rotation angle
bool cwRotation, ccwRotation;  //the states of rotation

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  // create servo objects
  for(int i=0; i < numServos; i++)
  {
    servos[i].attach(firstServoPin+i);
    servos[i].write(0);

    //  servo1.attach(3);     //servo pin
    //  servo1.write(0);

  }
}

void loop()
{
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value

      if (results.value == plus)
    {
      // if more servos to spin
      if( servoIdx < numServos ) 
      {
        // spin servo and increment index
        servos[servoIdx++].write(90);
        delay(20);          //General speed

      }

    }

  }

  /*
    {
   cwRotation = !cwRotation;      //toggle the rotation value
   ccwRotation = false;         //no rotation in this direction
   }
   
   if (results.value == minus)
   {
   ccwRotation = !ccwRotation;   //toggle the rotation value
   cwRotation = false;            //no rotation in this direction
   }
   }
   if (cwRotation && (val != 90))  {
   val++;                         //for colockwise button
   }
   if (ccwRotation && (val != 0))  {
   val--;                         //for counter colockwise button
   }
   servo1.write(val);
   delay(20);          //General speed
   */
}

That's very similar to what I was thinking. It's better to leave the 'resume()' until after the action completes though, and also since these actions are only wanted to happen once, it's good to check for that first, I reckon.
Still, your's was so similar that I'm only posting mine now because I already went to the trouble of writing it and don't want to waste it. :smiley:
This is my (untested) version:-

#include <IRremote.h>
#include <Servo.h>

const unsigned long Power = 0xD827;     // Power key
const unsigned long A_Key = 0xF807;     //A Key
const unsigned long B_Key = 0x7887;     //B Key
const unsigned long C_Key = 0x58A7;     //C Key
const unsigned long UP = 0xA05F;        //Up Key
const unsigned long Down = 0x00FF;      //Down Key
const unsigned long Left = 0x10EF;      //Left Key
const unsigned long Right = 0x807F;     //Right Key
const unsigned long Circle = 0x20DF;    //Circle Key

const byte NUM_SERVOS = 5;

const byte irReceiverPin = 2;
const byte servoPin[5] = {3, 4, 5, 6, 7};

bool done = false;
byte servoIndex = 0;

Servo currentServo[NUM_SERVOS];
IRrecv irrecv(irReceiverPin); //create an IRrecv object
decode_results decodedSignal; //stores results from IR detector

void setup()
{
    for (byte index = 0; index < NUM_SERVOS; index++)
    {
        currentServo[index].write(0);
        currentServo[index].attach(servoPin[index]);
    }
    Serial.begin(9600);
    irrecv.enableIRIn(); //start the receiver object
}

void loop()
{
    while (done == false)
    {
        if(irrecv.decode(&decodedSignal))
        {
            Serial.println(decodedSignal.value, HEX);
            if(decodedSignal.value == Circle)
            {
                currentServo[servoIndex].write(90);
                servoIndex++;
                if(servoIndex == NUM_SERVOS)
                    done = true;
            }
            irrecv.resume();
        }
    }
}

Edit: Of course, my version is based on the assumption that this is all the program has to do, based on the code originally presented. If other IR codes have to be handled afterwards, it would need rearranging slightly.

Thank you Blue Eyes. Your code worked!! And everyone else who has posted, thank you as well. I'm still getting a buzzing from one of the servos. Why is that? Also how would you incorporate a "power" function? That is another thing I have been looking for but have found NOTHING on. Not even a mention of it.

mightymel:
Thank you Blue Eyes. Your code worked!! And everyone else who has posted, thank you as well. I'm still getting a buzzing from one of the servos. Why is that?

Servos don't necessarily handle 0 and 180. Usually a little less in each direction. I'd say that one or more of your servos probably can't quite reach the "0" position.

Also how would you incorporate a "power" function? That is another thing I have been looking for but have found NOTHING on. Not even a mention of it.

What do you want the "power" function to do?
You could handle the "POWER" button and 'detach()' the servos maybe? (That stops pulses being sent to them.)

OldSteve:
What do you want the "power" function to do?
You could handle the "POWER" button and 'detach()' the servos maybe? (That stops pulses being sent to them.)

It would be nice to be able to power the board on and off with the remote. Originally this project was for a play and it will be onstage, powered by a 9v battery. The power button would just be convenient so I wouldn't have to unplug the battery to reset the servos to the starting position for each performance. Does that make sense? Or is there an easier method I'm overlooking?