XBee communication: snippet for when the signal is lost

Hello guys, I don’t know whether this should go to Networking forum, if so I am sorry.

I am building a RC plane using XBee S2 ZB modules. I have successfully made it upto where I can control my 2 Servos and the ESC using potentiometers thanks for Nick Gammon. My problems is this,

I don’t know how to act when the signal is lost for the receiver end. Receiver keeps doing what the last data packet it got to read. I need to

Check for signal every 500ms and try to reconnect, do this 10 times(5s wait time).
If we didn’t find signal within that time, i need to set all the values to a default possition, and kill the prop.

I have written a code to accomplish this as to my knowledge. But It doesn’t work as I want it to.

void signalLossProtocol(int attempts)
 {
   if(Serial.available()<0)
   {
     attempts++;
     delay(500);
     if(attempts<11)
       signalLossProtocol(attempts);
     else
     {
       defaults(); 
       while(1>0);//exit(0); forum advices not to do so. check if works
     }
   }
 }
 
 void loop()
 {
   if(Serial.available()>0) //>0 not needed?
     processIncomingByte(Serial.read());
   else
     signalLossProtocol(0);
 }

I have given some values from my transmitter end (from the POTs) and Killed the power for that. Servos in the Receiver is at the same possition after 5 secs also.

As I think my problem is at Serial.available() check. Isn’t it?
I need to know whether theres an way doing this using the Xbee Object?

Thanks in advance!
Bhashithe

   if(Serial.available()<0)

Shouldn’t you check for <= 0? Or just == 0?

I can’t see the point of checking for less than zero, you will never get -1 bytes in the serial buffer.

void signalLossProtocol(int attempts)
 {
   if(Serial.available()<0)
   {
     attempts++;
     delay(500);
     if(attempts<11)
       signalLossProtocol(attempts);
     else
     {
       defaults(); 
       while(1>0);//exit(0); forum advices not to do so. check if works
     }
   }
 }

I also don’t see how “attempts” will ever be greater than one. Oh wait, yes I do. You are using recursion. Why not a simple loop? eg.

void signalLossProtocol ()
 {
  for (int attempts = 0; attempts < 10; attempts++)
    {
    if (Serial.available () > 0)
      return;  // we have data
    delay (500);
    } // end of for

  defaults ();
  }

Hello, Thanks Nick!

Yes Serial.available() returns the number of characters right?

And I thought using recursion is effective in this situation(processor wise?). Well that didn’t work though.

/* RX
 * State machine
 * 2 servos, esc. extend if a rudder is needed, currently using a servo for esc as well
 */
 
 #include <Servo.h>
 
 #define laileron 11
 #define raileron 10
 #define throttle 9
 
 typedef enum{NONE,GOT_L,GOT_R,GOT_S} states;
 Servo left,right,esc;
 states state = NONE;
 unsigned int currentValue;
 
 void setup()
 {
   pinMode(13,OUTPUT);
   digitalWrite(13,LOW);
   Serial.begin(9600); //1152200 only 9600 works, check whats wrong
   state=NONE;
   left.attach(laileron);
   right.attach(raileron);
   esc.attach(throttle);
 }
 
 void processLeft(const unsigned int value)
 {
   left.write(value);
   //Serial.print(1);
   //delay(10);
 }
 
  void processRight(const unsigned int value)
 {
   right.write(value);
   //Serial.print(1);
   //delay(10);
 }
 
  void processEsc(const unsigned int value)
 {
   esc.write(value);
   //Serial.print(1);
   //delay(10);
 }
 
 void hanldlePreviousState()
 {
   switch(state)
   {
     case GOT_L:
       processLeft(currentValue);
       break;
     case GOT_R:
       processRight(currentValue);
       break;
     case GOT_S:
       processEsc(currentValue);
       break;
   }
   currentValue=0;
 }
 
 void processIncomingByte(const byte c)
 {
   if(isdigit(c))
   {
     currentValue *= 10;
     currentValue += c-'0';
   }
   else
   {
     hanldlePreviousState();
     
     switch(c)
     {
       case 'L': state=GOT_L;
         break;
       case 'R': state=GOT_R;
         break;
       case 'S': state=GOT_S;
         break;
       default: state=NONE;
     }
   }
 }
 
 void defaults()
 {
   /*left.write(90);
   right.write(90);
   esc.write(0);*/
   digitalWrite(13,HIGH);
 }
 
 /*void signalLossProtocol(int attempts)
 {
   if(Serial.available()<=0)
   {
     attempts++;
     delay(500);
     if(attempts<11)
       signalLossProtocol(attempts);
     else
     {
       defaults(); 
       while(1>0);//exit(0); forum advices not to do so. check if works
     }
   }
 }*/
 
 void signalLossProtocol ()
 {
  for (int attempts = 0; attempts < 10; attempts++)
    {
    if (Serial.available () > 0)
      return;  // we have data
    delay (500);
    } // end of for

  defaults ();
  }
 
 void loop()
 {
   if(Serial.available()>0) //>0 not needed?
     processIncomingByte(Serial.read());
   else
     signalLossProtocol();
 }
 /* TX
 * using elevons?
 * have 2 servos for 2 elevons, ignore aileron.
 */
 
#define aileron 2
#define elevon 3
#define esc 4

#define elevontrim 0
#define ailerontrim 1
#define esctrim 5

#define signalLED 13

int ailerontrimVal,elevontrimVal,aileronVal,elevonVal,esctrimVal,escVal;

void setup()
{
  Serial.begin(9600);//1152200 only 9600 works, check XBEE forum
  pinMode(signalLED,OUTPUT);
}

void loop()
{
  aileronVal = analogRead(aileron);
  aileronVal = map(aileronVal, 0, 1023, 0, 179);
  ailerontrimVal = analogRead(ailerontrim);
  ailerontrimVal = map(ailerontrimVal, 0, 1023, -25, 25);
  aileronVal = aileronVal+ ailerontrimVal;
  constrain(aileronVal, 0, 179);
  
  elevonVal = analogRead(elevon);
  elevonVal = map(elevonVal, 0, 1023, 0, 179);
  elevontrimVal = analogRead(elevontrim);
  elevontrimVal = map(elevontrimVal, 0, 1023, -25, 25);
  elevonVal = elevonVal+ elevontrimVal;
  constrain(elevonVal, 0, 179);

  escVal = analogRead(esc);
  escVal = map(escVal, 0, 1023, 0, 179);
  esctrimVal = analogRead(esctrim);
  esctrimVal = map(esctrimVal, 0, 1023, -25, 25);
  escVal = escVal+ esctrimVal;
  constrain(escVal, 0, 179);
  
  Serial.print("L");
  Serial.print(aileronVal);
  Serial.print("R");
  Serial.print(elevonVal);
  Serial.print("S");
  Serial.print(escVal);
  delay(10);
  
  /*if(Serial.available())
  {
    if(Serial.read() == 1)
      digitalWrite(signalLED,HIGH);
    else
      digitalWrite(signalLED,LOW);
  }*/
    
}

This is my whole code. Please ignore the commented parts. I am trying to work with 2 things here. What I need to accomplish now is that if i loose signal the plane should come to a default state.

I tried my recursion and your loop too. But my servos keep going at random places now, even i don’t have to push the joystick, it does go on changing its value. When I comment out the signalLossProtocol() method, it works like before. I still have a problem in the code.

Anyhow I am delaying (10ms) the Serial.print() part in the TX. At that very time we don’t have a Serial input for the RX and we wait 500ms for the next input. Could this lead to a problem?

If I don’t delay at the TX the RX doesn’t read the Serial as I need it do be.

Thanks,
Bhashithe

I'm not sure what your signalLossProtocol function is achieving except to introduce delays when they are probably not wanted.

It is very very likely there will be 10 iterations without serial data, and then you throw in a half-second delay, and potentially miss important stuff.

So If i wanted to kill my propellar and bring the servos to the default pos when ever the RX did not receive signal for 5 seconds what would I do? :astonished: :fearful:

Delaying for 500 mS is not the answer. More like, keep track (with a variable, and calling millis() ) when you last received data. If the last lot of data you got was over 5 seconds ago, kill the propellers.

   if(Serial.available()<=0)

The Serial.available() function will NEVER return a negative number. If there is nothing to read, there are 0 bytes in the buffer. There can never be a negative number of bytes in the buffer.

So, you look like a doofus testing for an impossible condition. Look smarter by doing the test right.

Oh hey Paul! :slight_smile:

Yeah I know that was pretty stupid :D. Even if i changed that to Serial.available()<=0 it presents some other problem. My servos start to act crazy.

Anyhow, If I wanted to kill the propeller if I didn’t receive signal for 5s what should I do? why does this not behave as it should?

If I wanted to kill the propeller if I didn't receive signal for 5s what should I do?

Every time you do get a "signal" (I presume you mean each time you discover that there is serial data to read), record the time.

Periodically, see if enough time has elapsed (I haven't heard from base in a while...), and panic(). Oops, I mean landSafely().

So as Nick Gammon suggested I went for a millis()?

I’d store millis() at every successfull Serial.read(). Then changed my signalLossProtocol a bit. It works quite well now :slight_smile:

 void signalLossProtocol()
 {   
   while(millis()-successfulMillis<5000)
   {
     if(Serial.available()>0)
       return;
   }
  defaults();
 }

Thanks guys, You are always here when I need help! :slight_smile:

That method is going to wait, for up to 5 seconds, for there to be serial data. I would NOT use that code on my helicopter.

I'd do something along these lines:

void loop()
{
   if(Serial.available() > 0)
   {
      x = Serial.read();
      lastReadTime = millis();
   }

   // Do something with x, if needed

   // Are we communicating?
   if(millis() - lastReadTime > NotTalkingLimit)
   {
      landSafely();
      while(true)
        ;
   }
}

Getting and using the data, and noting when data was read, is separate from determining how long it has been since there was data to read, and doing something about it if it's been too long.

Thanks paul, I've made the adjustment!

I've learned a lot!

 while(millis()-successfulMillis<5000)
   {
     if(Serial.available()>0)
       return;
   }

All that does is wait 5 seconds, in a different way.

Thankfully PaulS has explained exactly what I had in mind.

Hello guys, I have come up with anither question. I have tested the devices signal loss functionality by turning off the transmitter. Today I got to take the device out and check the range. My XBees are series 2 wire antena ones. They have promissed that it will work upto 120m. But mine works at best within 10m !

I still think that the problem is with the program. I will try to do this with easy tranfer library and let you guys know whats the out come. While I'm doing that can any one of you figure out whats the problem?

thanks bhashithe

I still think that the problem is with the program.

That you've modified since you posted.

I will try to do this with easy tranfer library

You'll be wasting your time. While there is nothing wrong with the library, using it will not improve your range.

While I'm doing that can any one of you figure out whats the problem?

If "the problem" is range, then there is likely a lot of noise in the area where the XBees are. What else is going on at the sender end? At the receiver end? In between? A picture of how the XBees are positioned would be useful, too.

What wattage are these Xbees? the 2mW ones don’t have much range even under ideal conditions - 10m sounds low though.

But mine works at best within 10m !

He doesn't define "work" here. Does the fail-safe cut in? Or something else happen?