Toggle an LED using 2 Xbees

Hi,

What I'm trying to do is simple: toggle an LED on and off. There is the LED breadboard (slave, Leonardo), and the remote control I built, with 2 buttons (master, UNO). I'm using an Xbee on each.

Initially, when program is switched on, the LEDs on the slave are both off. When I pushed a button on the master to toggle the LEDs, I'm sending 'S' over to the slave, which then flickers the LED on/off. When I push this same button again, the LED stops toggling and turns off.

This program works about some of the time correctly. Basically, I can get it to toggle on / off, but it is not 1:1 (or 100%) reliable. It's like 1:2

For example, I push the button once, and it flickers. I push it again, and nothing. Again and nothing. Again, and it turns off.

Any ideas where I'm missing something?

/*****

* This is test code to make the LED blink
  when a button is pushed by the master.
  
  When it is on, the LED will flicker.
  
  When the button is pushed again, the LED will turn off.
  

*****/
int ledPin = 23;      // LED is connected to pin 23, STATUS
int ledPin2 = 22;     // yellow LED, flickering LED

bool autonomous_code = false;  // default
int auto_code = -1;          // default

int incomingByte;      // a variable to read incoming serial data into

void setup() 
{
  Serial1.begin(9600);           // set up Serial library at 9600 bps

pinMode(ledPin, OUTPUT);    // Set the LED pin as output
pinMode(ledPin2, OUTPUT); 

}

void loop() 
{

   if (Serial1.available() > 0)   // see if there's incoming serial data:
    {
      incomingByte = Serial1.read(); // read the oldest byte in the serial buffer:
  
      
        if (incomingByte == 'F')  // test button
          {
           digitalWrite(ledPin, HIGH);   // turn LED on          
           delay(10);
           digitalWrite(ledPin, LOW);   // turn LED on          
            
          } 
          
        else if (incomingByte == 'S')  // autonomous mode button. toggle flickering LED
          {
           // digitalWrite(ledPin, HIGH);   // turn LED on
            auto_code = (auto_code * (-1));
                            
              if (auto_code > 0)  // turn autonomous code ON
            {
                 autonomous_code = true;     // return to autonomous code
                 //digitalWrite(ledPin2, HIGH);   // turn LED on
                 }
                 
               else
                 {
                   autonomous_code = false; 
                   digitalWrite(ledPin2, LOW);    // turn LED off
                 }
                 
                 
          }
            
     }

else         
        {
      //      digitalWrite(ledPin, LOW);    // turn LED off
     //       digitalWrite(ledPin2, LOW);    // turn LED off
        }
      
if (autonomous_code == true)  // do autonomous code
{
    digitalWrite(ledPin2, HIGH);
    delay(50);
    digitalWrite(ledPin2, LOW);
    delay(50);
   
}


}

you can certainly simplify...

else if (incomingByte == 'S')  // autonomous mode button. toggle flickering LED
    {
      // digitalWrite(ledPin, HIGH);   // turn LED on
      auto_code = (auto_code * (-1));
      if (auto_code > 0)  // turn autonomous code ON
      {
        autonomous_code = true;     // return to autonomous code
        //digitalWrite(ledPin2, HIGH);   // turn LED on
      }
      else
      {
        autonomous_code = false; 
        digitalWrite(ledPin2, LOW);    // turn LED off
      }
    }

try:

    else if (incomingByte == 'S')  // autonomous mode button. toggle flickering LED
    {
      autonomous_code = !autonomous_code;
      digitalWrite(ledPin2, autonomous_code ? HIGH : LOW);    // turn LED on or off
    }

you can debug this by putting S or F into your serial monitor

make sure it does what you want that way, then try the Xbee

int ledPin = 23;      // LED is connected to pin 23, STATUS
int ledPin2 = 22;     // yellow LED, flickering LED
bool autonomous_code = false;  // default
unsigned long lastTime;
//
void setup() 
{
  Serial1.begin(9600);           // set up Serial library at 9600 bps
  pinMode(ledPin, OUTPUT);    // Set the LED pin as output
  pinMode(ledPin2, OUTPUT); 
}
//
void loop() 
{
  if (Serial1.available() > 0)   // see if there's incoming serial data:
  {
    int incomingByte = Serial1.read(); // read the oldest byte in the serial buffer:
    if (incomingByte == 'F')  // test button
    {
      digitalWrite(ledPin, HIGH);   // turn LED on          
      delay(500);// 10milliseconds is short, debug with longer so you can see it flash
      digitalWrite(ledPin, LOW);   // turn LED off          
    } 
    else if (incomingByte == 'S')  //toggle flickering LED
    {
      autonomous_code = !autonomous_code;
      digitalWrite(ledPin2, autonomous_code == true ? HIGH : LOW);//Do you even need this?
    }   
  }
  if (autonomous_code == true)  // do autonomous code
  {
    if (millis() - lastTime >= 50UL)
    {
      digitalWrite(ledPin2, !digitalRead(ledPin2));
      lastTime += 50UL;
    }
  }
}

Ok, I think I see what's going on now a bit more after I tried your suggestion of the serial monitor. I added to each of the "if / else" statements print outs so I could see where the code was when I pushed a button.

With this updated code, I see that when I toggle the LED (from the remote by pushing a button), I get this printout:

0 2 3 5 0 2 4 0 2 3 5 0 2 4 0 2 3 5

I think what this is showing is that while I think I'm pushing the button once quickly, it is actually sending several " button pushes". This works fine when I'm say trying to control a robot (e.g. drive forward), since it's sending the same command, but here, I really just need 1 button push to really mean that. Not sure how to modify this to make sure it doesn't get multiple readings...

/*****

* This is test code to make the LED blink
  when a button is pushed by the master.
  
  When it is on, the LED will flicker.
  
  When the button is pushed again, the LED will turn off.
  

*****/
int ledPin = 23;      // LED is connected to pin 23, STATUS
int ledPin2 = 22;     // yellow LED, flickering LED

bool autonomous_code = false;  // default
int auto_code = -1;          // default

int incomingByte;      // a variable to read incoming serial data into

void setup() 
{
  Serial1.begin(9600);           // set up Serial library at 9600 bps

pinMode(ledPin, OUTPUT);    // Set the LED pin as output
pinMode(ledPin2, OUTPUT); 

}

void loop() 
{

   if (Serial1.available() > 0)   // see if there's incoming serial data:
    {
      incomingByte = Serial1.read(); // read the oldest byte in the serial buffer:
      Serial.println("0");
      
        if (incomingByte == 'F')  // test button
          {
           digitalWrite(ledPin, HIGH);   // turn LED on          
           delay(10);
           digitalWrite(ledPin, LOW);   // turn LED on
           Serial.println("1")   ;       
            
          } 
          
        else if (incomingByte == 'S')  // autonomous mode button. toggle flickering LED
          {
           // digitalWrite(ledPin, HIGH);   // turn LED on
            auto_code = (auto_code * (-1));
            Serial.println("2");
                            
              if (auto_code > 0)  // turn autonomous code ON
            {
                 autonomous_code = true;     // return to autonomous code
                 //digitalWrite(ledPin2, HIGH);   // turn LED on
                 Serial.println("3");
                 }
                 
               else
                 {
                   autonomous_code = false; 
                   digitalWrite(ledPin2, LOW);    // turn LED off
                   Serial.println("4");
                 }
                 
                 
          }
            
     }

else         
        {
      //      digitalWrite(ledPin, LOW);    // turn LED off
     //       digitalWrite(ledPin2, LOW);    // turn LED off
        }
      
if (autonomous_code == true)  // do autonomous code
{
    digitalWrite(ledPin2, HIGH);
    delay(50);
    digitalWrite(ledPin2, LOW);
    delay(50);
    Serial.println("5");
   
}


}

so, the remote is sending a stream of digits, not just one...

you can look for the one you want:

if (Serial1.available())
  {
    int myInt = Serial1.read();
    if (myInt = 5)
    {
      //do something
    }
  }

so, the remote is sending a stream of digits, not just one...

Sort of. I output the incomingByte to the Serial monitor, and get 5-6 '83's in a row, which is the dec ASCII char for the letter 'S'. This means that each time I push the button, effectively, the letter 'S' is getting sent 5-6 times. This is making the program do unwanted things, because it's basically telling the program to toggle on / off many times in a row.

I tried to put a timer loop on it so that it can't get in there if it previously accessed this part of the program less than "x" time ago. That is not exactly working.

Here is what I tried. Note that millis() gives the output in 100, so 100, 200, 300, etc. each time it is called.

void loop() 
{
millis(); // timer


   if (Serial1.available() > 0)   // see if there's incoming serial data:
    {
      incomingByte = Serial1.read(); // read the oldest byte in the serial buffer:
       Serial.println("0");
      
      Serial.println(incomingByte);
      
        if (incomingByte == 'F')  // test button
          {
           digitalWrite(ledPin, HIGH);   // turn LED on          
           delay(10);
           digitalWrite(ledPin, LOW);   // turn LED on
           Serial.println("1")   ;       
            
          } 
          
        else if ((incomingByte == 'S') && (abs(millis() - clock_grab > 1)))  // autonomous mode button. toggle flickering LED
          {
            clock_grab = millis();
            auto_code = (auto_code * (-1));
            Serial.println("2");
                            
              if (auto_code > 0)  // turn autonomous code ON
            {
                 autonomous_code = true;     // return to autonomous code
                 Serial.println("3");
                 }
                 
               else
                 {
                   autonomous_code = false; 
                   digitalWrite(ledPin2, LOW);    // turn LED off
                   Serial.println("4");
                 }

Ok, I fixed it!

It was getting all of these multiple sends of 'S', so what I tried doing was not filtering it on the slave side, but rather I added a 200ms delay after the 'S' button was pushed on the master RC side . When I used the serial monitor on the slave, it then showed only 1 instance coming through for 'S' per button push.

I originally had the delay only at 20 ms, but that apparently was too small.

Thanks for you help - it led me to try out some different ideas and got it working now 100% per toggle!

[quote author=project science link=topic=257765.msg1824048#msg1824048 date=1406732961] Ok, I fixed it!

It was getting all of these multiple sends of 'S', so what I tried doing was not filtering it on the slave side, but rather I added a 200ms delay after the 'S' button was pushed on the master RC side . When I used the serial monitor on the slave, it then showed only 1 instance coming through for 'S' per button push.

I originally had the delay only at 20 ms, but that apparently was too small.

Thanks for you help - it led me to try out some different ideas and got it working now 100% per toggle! [/quote]

You don't need ANY delays on the sender. What you DO need is to look at the state change detection example. Send a value only when the switch BECOMES pressed.