Go Down

Topic: Newbie having trouble with IR remote servo project (Read 6233 times) previous topic - next topic

carl1864

I'm trying to be able to move a servo to predefined positions with an IR remote, but I'm having trouble understanding part of the IR programming.  I'm using the IR library by Ken Shirriff.  But here is the biggest problem I am facing so far.

I have searched all over the place, but cannot seem to find any good reference to the commands or code that are available to use.  What I mean by that is, say compared to the servo library, I can find reference to what functions are available for the servos such as myservo.write(), myservo.read(), myservo.attach(), etc.  However I have been unable to find any similar reference for the IR library.  The only commands I found are ones I've attempted to reverse engineer from the examples, and being a newbie, I have found trying to reverse engineer these IR examples to be much more difficult.  If i had a reference to what commands were available, and the correct format to use them in it would be much easier.

-----------------------------------------
Here is the work in progress code that I have so far........

#include <IRremote.h>
#include <Servo.h>
int RECV_PIN = 11;
Servo myservo;   // create servo object to control a servo

int position1;   //servo position 1
int position2;   //servo position 2
int position3;   //servo position 3

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
 position1 = 0;    //default servo positon 1
 position2 = 90;   //default servo position 2
 position3 = 179;  //default servo position 3
 Serial.begin(9600);
 irrecv.enableIRIn(); // Start the receiver
 myservo.attach(9);  // attaches the servo on pin 9
 myservo.write(position3);   //start the servo out at position 3
}

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

----------------------------------------

Now I used the example IRrecvDemo in order to map the buttons of my NEC remote.  For example button one gave me FFA25D, button 2 gave me FF629D, button 3 gave me FFE21D.  But i'm unsure of the correct code to link them, so that pressing button 1 will cause myservo.write(position1).  

Also, I copied all the IR code from the example, and I'm unsure if the serial portions, such as "Serial.begin(9600);" and "Serial.println(results.value, HEX);", are necessary.  Can that stuff be taken out?  Isn't that only necessary if I'm wanting to view the data with the serial monitor?

Thanks for the help.  Eventually what I want it to do is have 3 different buttons for 3 different servo positions.  Then have an up and a down button that move the servo 1 degree at a time in either direction.  Then have 3 storage buttons (so that I can basically program the main 3 servo positions by using the up and down buttons to move the servo exactly where i want it, and press the corresponding store button to store that as position 1, 2, and 3).  Then finally I will want to store those 3 values in eeprom so that I won't have to redo them every time the power is turned off.

AltairLabs

so your
Code: [Select]
  Serial.println(results.value, HEX);
is printing a unique value for every button?  Then you have everything, jus write code that commands the servo depending on results.value is.  A case statement might be good here.

http://arduino.cc/en/Reference/SwitchCase

carl1864

I'm still a bit confused how to correctly do so.  I've tried all sorts of ways to use those hex values.  Stuff like
if (results.value  == FFA25D) {myservo.write(position1);},   or
if (results.value  == (FFA25D, HEX)) {myservo.write(position1);}
but all I get is compiling errors.

I tried loading the IR recieve example again, but deleted the "HEX" out of the part Serial.println(results.value, HEX);  . This gave different values out of the serial monitor, still unique to each button, such as button 1 is 16753245.  would I have better luck coding with these values rather than the hex values?

also, is there any benefit to using the "case statements", rather than a bunch of "if" statements for each button?  Or will both work equally well?  I only ask because I've learned if statements, but haven't learned case statements yet.

carl1864

Just an update, I spent another couple hours trying to figure out this cryptic code and I am completely lost.  I've been trying if statements, switch case statements, and many other variations, and I am completely lost at this point.

Here are a few more pieces of code I've tried which failed to work.

(irrecv.decode(&results));
 if (results.value == 16753245) {
   myservo.write(position1);
 }
irrecv.resume(); // Receive the next value
 if (results.value == 16736925) {
   myservo.write(position2);
 }
irrecv.resume(); // Receive the next value
 if (results.value == 16769565) {
   myservo.write(position3);
 }
irrecv.resume(); // Receive the next value

-----------------------------------------





(irrecv.decode(&results));
 if (results.value == 16753245) {
   myservo.write(position1);
   irrecv.resume(); // Receive the next value
 }
 if (results.value == 16736925) {
   myservo.write(position2);
   irrecv.resume(); // Receive the next value
 }
 if (results.value == 16769565) {
   myservo.write(position3);
   irrecv.resume(); // Receive the next value
 }






-----------------------------------------------------



void loop() {
switch (irrecv.decode(&results)) {
   case 16753245:    
     myservo.write(position1);
     irrecv.resume(); // Receive the next value
     break;
   case 16736925:    
     myservo.write(position2);
     irrecv.resume(); // Receive the next value
     break;
   case 16769565:    
     myservo.write(position3);
     irrecv.resume(); // Receive the next value
     break;
   case 16761405:
     current = myservo.read();
     myservo.write(current++);
     irrecv.resume(); // Receive the next value
   
}



}

I know I've probably got the format wrong or the wrong syntax or something, but I've been searching all over the place, and tinkering with this for hours, and can't seem to get it right.  Can anyone go back through this post any help me figure out how to do this, and/or correct my mistakes?

Big Oil

This worked for my type of remote:
unsigned long codeValue;
You can look at it in your serial monitor like this:

codeValue = results.value;
 Serial.println(codeValue);

And maybe use an if statement based on those values:

 if (codeValue == 59 || codeValue == 2107){ // menu
 digitalWrite(13, HIGH);
 delay(100);
 digitalWrite(13, LOW);  
 }

carl1864

That's similar to what I've been trying.  But I also tried that and it causes something strange to happen, that I don't understand.  If you look at this code, it always gives what seems like an accurate value for whatever button I press.

if (irrecv.decode(&results)) {
   Serial.println(results.value);


However when I made a change and defined "long codeValue;", and then did "codeValue = results.value;", and then "Serial.println(codeValue);", it gives me a completely different number, and is very inconsistent.

That makes no sense to me, if codeValue = results.value, I should be able to use them interchangeabley and get the same result right?  That's not what's happening.  I'm lost right now.

Big Oil

codeValue gives you a different number every time you press the same button on the remote?

carl1864

#7
Jan 18, 2011, 03:09 am Last Edit: Jan 18, 2011, 03:11 am by carl1864 Reason: 1
Actually I just got that particular thing working, producing consistent results, I think I might have put a == instead of an =, but when I've been experimenting with other variable replacement, bizarre things happen that don't make sence, like why does...

Serial.println(results.value, HEX);

give different results than

   codeValue = (results.value, HEX);
   Serial.println(codeValue);

They should be identical, yet the second one doesn't work at all, only gives me the #16 on every button.

PS: I still lost on getting this switch case statement to work, I posted the code above, think I'm doing it wrong, missing a colon or space, or something.

Big Oil

codeValue == 16 for every button you press?  
Maybe the IR library isn't working with that remote.

You can look at this thread, it might help.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1284904455

carl1864

Well I've spent a bunch of time juggling stuff around, and although there are parts I still don't quite understand, I almost have everything working except for one bug.  Here is the code, I'll explain the bug below.
-------------------------------------

#include <IRremote.h>
#include <Servo.h>
int RECV_PIN = 11;
Servo myservo;   // create servo object to control a servo

int position1;   //servo position 1
int position2;   //servo position 2
int position3;   //servo position 3
int codeValue;   //the code from the remote
int current;     //keeps track of current servo position

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
 position1 = 0;    //default servo positon 1
 position2 = 90;   //default servo position 2
 position3 = 179;  //default servo position 3
 Serial.begin(9600);
 irrecv.enableIRIn(); // Start the receiver
 myservo.attach(9);  // attaches the servo on pin 9
 myservo.write(position3);   //start the servo out at position 3
}

void loop() {
 if (irrecv.decode(&results)) {
   codeValue = results.value;
   switch (codeValue) {
   case 16753245:    
     myservo.write(position1);
     current = position1;
     break;
   case 16736925:    
     myservo.write(position2);
     current = position2;
     break;
   case 16769565:    
     myservo.write(position3);
     current = position3;
     break;
   case 16761405:
     ++current;
     myservo.write(current);
   case 16748655:
     --current;
     myservo.write(current);
   case 16712445:
     current += 10;
     myservo.write(current);
   case 16754775:
     current -= 10;
     myservo.write(current);
   case 16720605:    
     myservo.write(0);
     current = 0;
     break;
   case 16769055:    
     myservo.write(179);
     current = 179;
     break;
   case 16738455:    
     position1 = current;  //stores current position as servo position 1
     break;
   case 16750695:    
     position2 = current;
     break;
   case 16756815:    
     position3 = current;
     break;
 }
irrecv.resume(); // Receive the next value
}
}


------------------------------------------
The problem is with this section of code, I've read it over and over and just can't figure out why it doesn't work.

case 16761405:
     ++current;
     myservo.write(current);
   case 16748655:
     --current;
     myservo.write(current);
   case 16712445:
     current += 10;
     myservo.write(current);
   case 16754775:
     current -= 10;
     myservo.write(current);

What it is supposed to do is a allow to be able to increase/decrease the servo position from wherever its at 1 or 10 degrees at a time.  The current position is always monitored by the "current" variable (as far as I know it seems to be working fine in the rest of the code), so I thought that adding/subtracting the correct # from the current value, and then writing current to the servo should work, but they generally either do nothing, or cause the servo to go all the way to 0.  I've also tried it a slightly different way with slightly different syntax like this.

     current = ++current;
     myservo.write(current);
   case 16748655:
     current = --current;
     myservo.write(current);
   case 16712445:
     current = current += 10;
     myservo.write(current);
   case 16754775:
     current = current -= 10;
     myservo.write(current);

but it still isn't working.


AWOL

#10
Jan 18, 2011, 08:59 am Last Edit: Jan 18, 2011, 09:01 am by AWOL Reason: 1
Some of those constants are not representable as 'int' on the Arduino.
Try adding the suffix 'L', thusly:
case 164563L:

Also, your case statements need 'break's,otherwise you'll just execute all of the cases, one after the other.

(and please use the code # icon in the editor when posting code.)
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

carl1864

AWOL: Thanks so much for the help, I was indeed missing breaks on each of those statements.  Should have known, but somehow I was so focussed thinking the current += type statemtnes were somehow wrong, that it had me looking in the wrong place for the problem.

As far as adding the suffix L, does that change any number to a "long"?  I've gone through all the ladyada tutorials, read the whole arduino notebook, most of the ASKmanual (still going through it), and also cruised the website, and had never known that you can do that.  Thats the main reason I'm struggling so much, although many things are documented well, I keep running into a few little things that aren't.

In any case, since all the other buttons worked without the "L", so I actually continued on the trend and didn't use it.  Your right, that number is higher than an "int", so it in theory shouldn't work, but I'm guessing that maybe they are all just rolling over, but always rolling over to the consistent value.

Anyways right now everything is almost done, just need to implement eeprom storage and it will be good.  I plan on posting some sort of tutorial or something when I'm done to help other newbies trying to do the similar thing.

AWOL

#12
Jan 18, 2011, 09:34 pm Last Edit: Jan 18, 2011, 10:24 pm by AWOL Reason: 1
You're right - the switch selector is an int, but the case constants are not.
You need to be more consistent, and check exactly what type the decode function returns.
Unfortunately, it's an undesireable side-effect of the Arduino's suppression of warnings.

Quote
As far as adding the suffix L, does that change any number to a "long"?  I've gone through all the ladyada tutorials, read the whole arduino notebook

Re: Constant type modifiers:
http://arduino.cc/en/Reference/IntegerConstants

Code: [Select]
if (irrecv.decode(&results)) {
  codeValue = results.value;
  switch (codeValue) {


Here, 'codeValue' is declared as an 'int', but a look at the declaration of 'decode_results' says that 'value' is an 'unsigned long', so assigning 'results.value' to 'codeValue' would normally generate a warning about this being a narrowing cast.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

carl1864

I've almost got everything working, but I'm trying to fix one bug.  Luckily I think I know the culprit.  It seems as though my "current" variable, is able to exceed above and below the servo limits of 0 and 179.  For example say the servo is at 5 degrees, and I push my button to decrease by 10 degrees, well the value goes below 0 (I'm guessing to -5), and ends up causing issues with it not going to, or saving the right position.

Is there a way to perhaps define the "current" variable to limit it to between 0 and 179?  So that if you do try and for example have it at 175 and add 10, it will automatically know to make it 179 since that's the max defined variable?

I was thinking I could possibly use some "if" statements, like inbetween these 2 lines of code.....

Code: [Select]
     current += 10;  //moves servo 10 degrees
     myservo.write(current);

.... I could put
if (current > 179) {current = 179;}

I think that would effectively set limits if I put it in all the right places, but I'm trying to figure out if there is a better way to do it.

Big Oil

http://arduino.cc/en/Reference/UnsignedChar
The unsigned char datatype encodes numbers from 0 to 255.

For something like 179 you would have to code it yourself, good job.

Go Up