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 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?
#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
}
}
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".
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);
}
}
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.
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
}
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:
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.
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.
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?