complex program adaptation, cant get IR to work

Hi,

I am working on a plate and ball balancing toy. I found a very good wiki describing the build and it included some code. The code included was set up to use a wii nunchuk. I would like to use a white ir controller I found on the net. I copied the code mostly and removed the portions that used the nunchuk, I also added some LEDs and the start of the code for the ir using many examples that were unrelated. I set up a short interrupt routine to wait for ir input but it doesn't put the button code in a variable. I want it to store the button push code so it can use it in a switch loop. So 2 things need to happen with the ir. it needs to store the button push code, then use that code to change the way the program balances the ball. There are 5 places for it to balance the ball, and in each spot when it balances I want it to light the corresponding LED. then if you use the channel button, it needs to count the times its pressed to cycle through a switch loop to set a trajectory for the ball to roll. I dont expect anyone to write the code for me, but I am at the limit of my small programming knowledge. any help would be appreciated. the entire code is listed below. I plan to eventually make a sell a kit for these, so the code will be ever evolving I hope and always available. Im just making the mechanics and putting it together in a kit for those who cant do the mechanical side. I tried to use code tags but upload wouldn't accept it due to size.


bkk.txt (11.1 KB)

I would like to help you, but when a question is posted as a solid block of text all in one multi line paragraph my eyes glaze over and I move on.

sorry here is simple question statement

I know the nano is receiving ir, but it is not recording the button push in the variable LastButtonValue

///KONTROLA STABILITY////
 while(Stable==125)//if is stable
 { //still measure actual postiion
      attachInterrupt(digitalPinToInterrupt(interruptPin), IRinput, CHANGE);  //reattach interrupt
//      IRinput();
      setDesiredPosition();  
      detachInterrupt(interruptPin);// stop interrupt for calculations
 
    TSPoint p = ts.getPoint();
     Input=(p.x * convertX);  //read X
      Input1=(p.y * convertY); //read Y
    if(Input<Setpoint-2 || Input>Setpoint+2 || Input1>Setpoint1+2 || Input1<Setpoint1-2  ) //if ball isnt close to setpoint
    {
      servo1.attach(ServoX); //again attach servos
      servo2.attach(ServoY);
      digitalWrite(LedID,LOW);
      Stable=0; //change STABLE state
    }
    
  }//end of STABLE LOOP
  

}//loop end

////////////////////////Functions////////////////// 

//get IR input
void IRinput() {
       irrecv.resume(); // Receives the next value from the button you press
while (irrecv.decode(&results)); {   //decodes the infrared input
      Serial.println(results.value);   // turn off and on to print value for trouble shooting  
   if (results.value == RepeatValue){
       LastButtonValue = LastButtonValue;
}
   else 
{
       LastButtonValue = results.value;
      Serial.println(LastButtonValue); // turn off and on to print value for trouble shooting
}}

//if CH is pressed, increment up until 5 which doesnt exist so resets to 1

/* if (LastButtonValue == IRButtonCH) {  // if CH is pushed
    CHButtonCounter++; //Ch button counter is incremented
 } //end if
 if (CHButtonCounter >= 5); { //reset to first case from last case
    CHButtonCounter = 0;  //re-starts at first shape case
//    LastButtonValue = 0;
 } //end if
*/         
}

You have not posted the whole program but you appear to be printing in an ISR, Interrupts are disabled when in an ISR. Serial uses interrupts so all bets are off as to whether it will work.

Is LastButtonValue declared volatile ? If not then it should be as its value is changed by the ISR

Why do you keep attaching the interrupt ? Is once not enough ?
Same question for attaching the servos

Hi,

I am working on a plate and ball balancing toy.
I found a very good wiki describing the build and it included some code.
The code included was set up to use a wii nunchuk.
I would like to use a white ir controller I found on the net.
I copied the code mostly and removed the portions that used the nunchuk, I also added some LEDs and the start of the code for the ir using many examples that were unrelated.
I set up a short interrupt routine to wait for ir input but it doesn't put the button code in a variable.
I want it to store the button push code so it can use it in a switch loop.
So 2 things need to happen with the ir.
It needs to store the button push code, then use that code to change the way the program balances the ball.
There are 5 places for it to balance the ball, and in each spot when it balances I want it to light the corresponding LED. then if you use the channel button, it needs to count the times its pressed to cycle through a switch loop to set a trajectory for the ball to roll.
I dont expect anyone to write the code for me, but I am at the limit of my small programming knowledge.
Any help would be appreciated.
The entire code is listed below.
I plan to eventually make a sell a kit for these, so the code will be ever evolving I hope and always available.
I'm just making the mechanics and putting it together in a kit for those who cant do the mechanical side.
I tried to use code tags but upload wouldn't accept it due to size.

Sorry but I had to spread it out to read.
Tom.. :slight_smile:

BKK:
I know the nano is receiving ir, but it is not recording the button push in the variable LastButtonValue

Have you written a short program to learn how to receive the IR data and update a variable? If not, that should be your first step.

...R

UKHeliBob:
You have not posted the whole program but you appear to be printing in an ISR, Interrupts are disabled when in an ISR. Serial uses interrupts so all bets are off as to whether it will work.

Is LastButtonValue declared volatile ? If not then it should be as its value is changed by the ISR

Why do you keep attaching the interrupt ? Is once not enough ?
Same question for attaching the servos

OK, I see, the printing was something I added to troubleshoot. I will remove it

the whole program is in the first post in the text file. it was too big for the code block to post.

LastButtonValue is declared as volatile

the ball balancing portion turns the servos on and off, I thought it was so that when it finds a stable position it will turn off the servo since the idea is to react to an imbalance or a push on the ball it needs to also be able to immediately turn on and react. also since it does run on battery I would like them to be off if it is not doing anything

my understanding on interrupts is you don't want to have it running while calculations are being made and so I set the ISR up with the interrupt activated before the ISR call then after the return so it wouldn't interfere with calculations of the stability loop

here is the entire stability loop.

void loop() {


  while(Stable<125) //REGULATION LOOP
  {
   TSPoint p = ts.getPoint();   //measure pressure on plate
   if (p.z > ts.pressureThreshhold) //ball is on plate
   {  
      servo1.attach(ServoX); //connect servos
      servo2.attach(ServoY); 
      attachInterrupt(digitalPinToInterrupt(interruptPin), IRinput, CHANGE);  //reattach interrupt look for change in signal
//      IRinput();
      setDesiredPosition();  
      detachInterrupt(interruptPin);// stop interrupt for calculations
      noTouchCount = 0;  //timer value for ball not present
      TSPoint p = ts.getPoint(); // measure actual position 
      Input=(p.x * convertX);  // read and convert X coordinate
      Input1=(p.y * convertY); // read and convert Y coordinate
      
          if((Input>Setpoint-2 && Input<Setpoint+2 && Input1>Setpoint1-2 && Input1<Setpoint1+2))//if ball is close to setpoint
          {
              Stable=Stable+1; //increment STABLE
              digitalWrite(LedID,HIGH);  // if its stable lights led 9
                 
          }
          else
          {
              digitalWrite(LedID,LOW);   //if not stable turns off led 9
          }
       myPID.Compute();  //action control X compute
       myPID1.Compute(); //   action control  Y compute   
    
  }
   else //if there is no ball on plate
  {
    noTouchCount++; //increment no touch count

    if(noTouchCount == 75) 
    {
     noTouchCount++; 
     Output=95; //make plate flat
     Output=95;
     servo1.write(Output + AdjustXservo); 
     servo2.write(Output1 + AdjustYservo);
     digitalWrite(LedID,HIGH);
    }
    if(noTouchCount == 150) //if there is no ball on plate longer
    {
     servo1.detach(); //detach servos
     servo2.detach();     
   
    }
  }
  servo1.write(Output + AdjustXservo);//control
  servo2.write(Output1 + AdjustYservo);//control 
//  Serial.print(Setpoint);   Serial.print(",");  Serial.print(Setpoint1);  Serial.print(",");  Serial.print(Input);Serial.print(","); Serial.println(Input1); 
//   Serial.println(CHButtonCounter);     // turn off and on to print value for trouble shooting, plot output to see representation of control
}
////END OF REGULATION LOOP///
  
  servo1.detach();//detach servos
  servo2.detach();
  
 ///KONTROLA STABILITY////
 while(Stable==125)//if is stable
 { //still measure actual postiion
      attachInterrupt(digitalPinToInterrupt(interruptPin), IRinput, CHANGE);  //reattach interrupt
//      IRinput();
      setDesiredPosition();  
      detachInterrupt(interruptPin);// stop interrupt for calculations
 
    TSPoint p = ts.getPoint();
     Input=(p.x * convertX);  //read X
      Input1=(p.y * convertY); //read Y
    if(Input<Setpoint-2 || Input>Setpoint+2 || Input1>Setpoint1+2 || Input1<Setpoint1-2  ) //if ball isnt close to setpoint
    {
      servo1.attach(ServoX); //again attach servos
      servo2.attach(ServoY);
      digitalWrite(LedID,LOW);
      Stable=0; //change STABLE state
    }
    
  }//end of STABLE LOOP
  

}//loop end

here is a video to see how it works now.

BKK Ball and Plate

the ball balancing portion turns the servos on and off, I thought it was so that when it finds a stable position it will turn off the servo since the idea is to react to an imbalance or a push on the ball it needs to also be able to immediately turn on and react. also since it does run on battery I would like them to be off if it is not doing anything

If you leave the servos attached they will react more quickly when required. Also, if you leave them attached the servo will hold its current position if anything tries to disturb it. Have you measured the current consumption of a servo attached and not attached to establish whether there is a significant difference ?

my understanding on interrupts is you don't want to have it running while calculations are being made

That is true when calculations take more than one instruction cycle to avoid the calculation being interrupted, but the usual way of doing that is to disable/enable interrupts not to detach and attach them.

HI,
You haven't answered post #5.

Have you written code JUST to deal with IR, so you can make sure it works?

Tom.... :o :o

TomGeorge:
HI,
You haven't answered post #5.

Have you written code JUST to deal with IR, so you can make sure it works?

Tom.... :o :o

yes, it is a good path forward, Im reading up on it, but I am not finding many examples of ir code stored in a variable, but I am looking

UKHeliBob:
If you leave the servos attached they will react more quickly when required. Also, if you leave them attached the servo will hold its current position if anything tries to disturb it. Have you measured the current consumption of a servo attached and not attached to establish whether there is a significant difference ?
That is true when calculations take more than one instruction cycle to avoid the calculation being interrupted, but the usual way of doing that is to disable/enable interrupts not to detach and attach them.

I have not hooked it up to measure draw, but what I found is that they buzz when parked.

The disturbance reaction has not been an issue at all, it reacts instantly even with the servos detached. I will have a meter on the battery soon to see if I can determine battery life, up to now I have been powering it through a USB port off the computer.

I detached them but I think I meant to disable as you point out, I will research and implement disable/enable instead thanx.
When I had it running before the loop and didnt turn it on and off, it did not receive ir. with the attach/detach in the position in the loop it is now, I see the ir flickering the rcv led, so I was continuing with that strategy.

BKK:
yes, it is a good path forward, Im reading up on it, but I am not finding many examples of ir code stored in a variable, but I am looking

Post the test program you have written and tell us what it actually does and what you want it to do that is different.

...R

same issue, I just get scrolling "0"

///Libraries///
#include <IRremote.h>                   // insert IRremote.h library

// IR pin connection
#define IRPin 2 // D2 IR Receiver output on D2 interrupt 1 pin

//IR Remote button codes
#define IRButtonCH 16736925
#define IRButton1 16724175
#define IRButton3 16743045
#define IRButton5 16726215
#define IRButton7 16728765
#define IRButton9 16732845
#define RepeatValue 4294967295  //value broadcast by remote when button is held down

//baud rate
#define BaudRate 9800  //was 115200

//position variables
volatile int CHButtonCounter = 0 ;   // was 1 counter for the number of ch button presses volatile because it is in interrupt routine
volatile int LastButtonValue = 0;     // previous state of the button, holds value so it can compare if the remote button is held down volatile because it is in interrupt routine


// IR Remote
IRrecv receiver(IRPin);                 //define IR PIN for infrared receiver
volatile decode_results results;                  //define variable results to save the result of infrared receiver added volatile because it is interrupt routine

void setup()
{

//IR receiver
  receiver.enableIRIn();                      //Boot infrared decoding
  pinMode(IRPin, INPUT);                    // set pin to receive
  
  Serial.begin(BaudRate);

} //end setup

void loop() {
  
receiver.resume(); // Receives the next value from the button you press

//get IR input    

 (receiver.decode(&results)); {   //decodes the infrared input
      Serial.println(results.value);   // turn off and on to print value for trouble shooting  
   if (results.value == RepeatValue){
       LastButtonValue = LastButtonValue;
       
} //if end

   else 
   
{
       LastButtonValue = results.value;
      Serial.println(LastButtonValue); // turn off and on to print value for trouble shooting
} //end else
} //end loop
} //end all

Your scattered code formatting makes it hard to follow the program flow. Use a standard indentation to clearly show the code blocks. Never put more than one statement per line. Place any brackets by themselves on a separate line. Use blank lines sparingly, no more than one at a time. Before posting the code, use Ctrl-T in the IDE to reformat the code in a standard format, which makes it easier for us to read.

sorry, this is my 2nd full program. I like having everything annotated for my memory, here it is cleaned up didn't know about control T, thanx

///Libraries///
#include <IRremote.h>

// IR pin connection
#define IRPin 2

//IR Remote button codes
#define IRButtonCH 16736925
#define IRButton1 16724175
#define IRButton3 16743045
#define IRButton5 16726215
#define IRButton7 16728765
#define IRButton9 16732845
#define RepeatValue 4294967295

//baud rate
#define BaudRate 9800  //was 115200

//position variables
volatile int CHButtonCounter = 0;
volatile int LastButtonValue = 0;

// IR Remote
IRrecv receiver(IRPin);
volatile decode_results results;

void setup()
{
  //IR receiver
  receiver.enableIRIn();
  pinMode(IRPin, INPUT);
  Serial.begin(BaudRate);

}

void loop()
{
  receiver.resume();
  (receiver.decode(&results));
  {
    unsigned int value = results.value;
    if (value == RepeatValue)
    {
      LastButtonValue = LastButtonValue;
    }
    else
    {
      LastButtonValue = value;
      Serial.println(LastButtonValue);
    }
  }
}

Aren't you supposed to check to see whether anything has been received before you decode it? You have a set of braces that does nothing. Perhaps you think it does something.

What is this mess?

  (receiver.decode(&results));
  {

I stepped back a little farther and modified the ir demo included in the software download. So with this code, I get the reaction I want except that the value it returns is completely different. Not sure why but seems like if I just modify the values for the buttons this will work.

sorry about the code above. I think I moved the if and left everything else, then moved the bracket to its own line......

#include <IRremote.h>

//position variables
volatile int CHButtonCounter = 0;
volatile int LastButtonValue = 0;


int RECV_PIN = 2;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  // In case the interrupt driver crashes on setup, give a clue
  // to the user what's going on.
  Serial.println("Enabling IRin");
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");
}

void loop() {
  if (irrecv.decode(&results)) {
    LastButtonValue = results.value;
    Serial.println(LastButtonValue);
    irrecv.resume(); // Receive the next value
  }
  delay(100);
}

this prints button one as "12495" where the other IR demo prints it as "16736925"

Because LastButtonValue is an int, it can't contain a number as large as 16736925.

what do I declare to get the full number?

the code below is doing what I want. It stores the short number and ignores the repeat. So if I can get the full number I should be good to insert it into my main program

#include <IRremote.h>

//position variables
volatile int CHButtonCounter = 0;
volatile int LastButtonValue = 0;
#define RepeatValue -1

int RECV_PIN = 2;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  // In case the interrupt driver crashes on setup, give a clue
  // to the user what's going on.
  Serial.println("Enabling IRin");
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");
}

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == RepeatValue)
    LastButtonValue = LastButtonValue;
    else
    LastButtonValue = results.value;
    Serial.println(LastButtonValue);
    irrecv.resume(); // Receive the next value
  }
  delay(100);
}