Go Down

Topic: Xbees not playing nice with eachother (Read 397 times) previous topic - next topic

Soffer

Would appreciate some knowledgeable advice here.
MY project consists of a "Sender" arduino (nano) carrying a S1 xbee, and a "Receiver" arduino (Uno) carrying S1 as well.
Most of the data traffic is nano ->uno, but in 2 specific cases on the receiver code (Rewind and Play cases) I need to send back a confirmation to the sender and make it turn an LED down. Now the thing is, it sometimes works and sometimes doesn't and I can't see any logic to this. Maybe I'm overflowing the Xbee modules? Maybe I'm doing some basic thing all wrong?
Really need some help here and attaching the codes.

Sender:
Code: [Select]
#include <OneButton.h>

// Movement of Optical encoder is translated to moving stepper
//



//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;

int lastEncoded = 0;
int encoderValue = 0;

int lastencoderValue = 0;
int lastMSB = LOW;
int lastLSB = LOW;

//LEDs
#define realTimeLED 12      //Real Time LED
#define playLED 9          //PLay LED
#define inLED 11            //In LED
#define outLED 10           //Out LED

// Setup OneButton
OneButton realTimebutton(A4, true);
OneButton playButton (A1, true);
OneButton inButton (A3, true);
OneButton outButton (A2, true);

//Values for focus points
volatile int inPoint = 0;
volatile int outPoint = 3000;

//Values for calibrating lens and motor
int lowEnd = 0;
int highEnd = 3000;

//Blink without delay
int ledState = LOW;
long previousMillis = 0;
int ledInterval = 75;

boolean rClickedOnce = false;
boolean rLongPress = false;
boolean pClickedOnce = false;

//Value for sendFunction - to send over Xbee
int value;

//value for variable speed - to send over Xbee
int valToRemap;
int encoderValToRemap;

//Value to recieve from 2nd Xbee: when "play" or "rewind" has finished"
int dataReceive;

//Modes
int mode;
#define RealTime 1
#define Stop 2
#define REWIND 3
#define PLAY 4
#define LENSCALIB 5


void setup(){
 Serial.begin(115200);

 //Pinmodes
 pinMode (realTimeLED, OUTPUT);
 pinMode (playLED, OUTPUT);
 pinMode (inLED, OUTPUT);
 pinMode (outLED, OUTPUT);
 pinMode(encoderPin1, INPUT);
 pinMode(encoderPin2, INPUT);

 digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
 digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

 //call updateEncoder() when any high/low changed seen
 //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
 //attachInterrupt(0, updateEncoder, CHANGE);
 //attachInterrupt(1, updateEncoder, CHANGE);

 //Attach Click to Buttons
 realTimebutton.attachClick(Click);
 playButton.attachClick(ClickPlay);
 inButton.attachClick(ClickIn);
 outButton.attachClick(ClickOut);

 //Attach Press to Real Time for calibrating lens and motor
 realTimebutton.attachPress(rPress);

}

void loop(){
 
 int MSB = digitalRead(encoderPin1); //MSB = most significant bit
 int LSB = digitalRead(encoderPin2); //LSB = least significant bit
 
 //only if changed value
 if(lastMSB != MSB || lastLSB != LSB){
   updateEncoder(MSB, LSB);
 }
   
 // keep watching the push buttons:
 realTimebutton.tick();
 playButton.tick();
 inButton.tick();
 outButton.tick();

 //This was meant in order to signal "sender" arduino when the action
 //on other side (play/rewind) is done. Currently does not work
 if (Serial.available())
 {
   dataReceive = Serial.read();
   if (dataReceive == 1)
   {
     pClickedOnce = false;
     digitalWrite(playLED, LOW);
   }  
 }
}


void updateEncoder(int MSB, int LSB){
 lastMSB = MSB;
 lastLSB = LSB;
 

 int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
 int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
 {
   encoderValue ++;
  /* if (encoderValue>highEnd)
     encoderValue = highEnd;*/
     //Serial.println(encoderValue);
   // This is a function so as to be able to to use the data
   // in 2 different ways: 1/as encoder value
   // 2/as speed value for play/rewind
   // depending on state of switches.
   sendFunction (1);

 }
 if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
 {
   encoderValue --;
   /*if (encoderValue<lowEnd)
     encoderValue = lowEnd;*/
     //Serial.println(encoderValue);

   // This is a function so as to be able to to use the data
   // in 2 different ways: 1/as encoder value
   // 2/as speed value for play/rewind
   // depending on state of switches.
   sendFunction(2);
 }

 lastEncoded = encoded; //store this value for next time

}


//4 Buttons Click Functions
void Click() {
 digitalWrite(playLED, LOW);
 if (rClickedOnce == false )
 {
   rClickedOnce = true;
   digitalWrite(realTimeLED, HIGH);
 }
 else
 {
   digitalWrite(realTimeLED, LOW);
   rClickedOnce = false;
 }
}

void ClickPlay () {
 //terminate realtime in case it wasn't stopped
 if (pClickedOnce == false)
 {
   pClickedOnce = true;
   rClickedOnce = false;  
   digitalWrite(realTimeLED, LOW);
   digitalWrite(playLED, HIGH);
   Serial.write(4);
 }
 else
 {
   pClickedOnce = false;
   digitalWrite(playLED, LOW);
 }
}

void ClickIn () {
 // Saving In
 if (rClickedOnce == true)                      
 {
   Serial.write (3);
   inPoint = encoderValue;
   //Serial.println (inPoint);  
   blinkMark (inLED);
 }
 //Saving Low End of encoderVal
 // else if (rLongPress == true) {
 // lowEnd = encoderValue;
 //Serial.print ("lowEnd = ");
 //Serial.println (lowEnd);
 //}
 //blinkMark (inLED);
}

void ClickOut() {
 //Saving Out
 if (rClickedOnce == true)
 {
   Serial.write (5);
   outPoint = encoderValue;
   //Serial.println (outPoint);  
   blinkMark (outLED);
 }  

 /*outPoint = stepper.currentPosition();
  encoderOut = encoderValue;          //saved for variable speed
  Serial.print ("Out Point = ");
  Serial.println (encoderOut);
 
  else if (rLongPress ==true) {
  highEnd = encoderValue;
  Serial.print ("highEnd = ");
  Serial.println (highEnd);
  }
  blinkMark (outLED);*/
}

// Press Function - calibrating lens and stepper
// not tried yet.
void rPress() {
 if (rLongPress == false) {
   Serial.println ("Lens Limit");
   rLongPress = true;
   highEnd = 4000;
   lowEnd = 0;
   mode = LENSCALIB;
 }
 else {
   mode = Stop;
 }
}

int blinkFunction (int y)   // Blink without delay
{

 unsigned long currentMillis = millis ();
 if (currentMillis - previousMillis>ledInterval)
 {
   previousMillis = currentMillis;
   if (ledState == LOW)
     ledState = HIGH;
   else
     ledState = LOW;
   digitalWrite (y, ledState);
 }
}

int blinkMark (int y)
{
 boolean b = HIGH;
 for (int i=0;i<6;i++)
 {
   digitalWrite(y, b);
   delay(75);
   b=!b;
 }
}

int sendFunction(int value)
{
 // 1/Send encoder value to move stepper
 if (rClickedOnce == true)
   Serial.write (value);

 else if (pClickedOnce == false)
   {
   // 2/Send remapped value to change speed of stepper    
  encoderValToRemap = encoderValue;
 
  if (inPoint<outPoint)
     {
     if (encoderValToRemap< inPoint)
       encoderValToRemap = inPoint;

     if (encoderValToRemap>outPoint)
       encoderValToRemap = outPoint;    
     }
   else
     {
  if (encoderValToRemap>inPoint)
    encoderValToRemap = inPoint;
   
  if (encoderValToRemap<outPoint)
    encoderValToRemap = outPoint;
     }
  //Serial.println (encoderValToRemap);
   
 
   //remap value to ba able to send bytes
   valToRemap = focusSpeed(encoderValToRemap);
   }
}

int focusSpeed (int valToRemap)
{
 //remapped value sent to "receiving" arduino to change stepper speed
 //during play/rewind.
 // currently after some revolutions of encoder Xbees stop communicating until reset.
 valToRemap = map(valToRemap, inPoint, outPoint, 10, 30);
 //Serial.print ("valToRemap");
 //Serial.println (valToRemap);
 Serial.write (valToRemap);
}


Soffer

Receiver Code:
Code: [Select]
// Movement of Optical encoder is translated to moving stepper

#include <AccelStepper.h>

//encoder/motor/driver setup
int easyDriverMicroSteps = 2;
int rotaryEncoderSteps = 75;
int motorStepsPerRev = 200;

int MinPulseWidth = 50; //too low and the motor will stall, too high and it will slow it down

int easyDriverStepPin = 4;
int easyDriverDirPin = 5;
int enablePin = 6;

volatile long encoderValue = 0;
int dataReceive = 0;
long lastencoderValue = 0;

//Values for focus points
int inPoint;
int outPoint;

//value for variable speed
int speedValue = 1000;
int mappedSpeed;

int mode;
#define Rewind 1
#define Play 2
// Stop mode is meant to enable Xbee receive changes in speed
// in values 0-255, remap to 200-100 and reyrn to Play/Rewind.
// currently not working.
#define Stop 3


AccelStepper stepper(1, easyDriverStepPin, easyDriverDirPin);

//Sleep Function - to diable ED when not active
long previousMillis = 0;
int sleepTimer = 5000;

void setup(){
  Serial.begin(115200);

  stepper.setMinPulseWidth(MinPulseWidth);
  stepper.setMaxSpeed(speedValue);             //variable to later determine speed play/rewind
  stepper.setAcceleration(100000);
  stepper.setSpeed(50000);

  pinMode(enablePin, OUTPUT);
}

void loop(){
  stepper.run();
  if (Serial.available()>0)
  {
    digitalWrite (enablePin, LOW);
    previousMillis = millis();
    dataReceive = Serial.read();
    //function to sort data reveived and action.
    dataSort ();
    //take care of variable speed
    speedValue = 1000;
    stepper.setMaxSpeed(speedValue);
    int stepsPerRotaryStep = (motorStepsPerRev * easyDriverMicroSteps) / rotaryEncoderSteps;
    stepper.moveTo(encoderValue * stepsPerRotaryStep);
  }
  else
  {
    //Stepper sleep after 5sec of no data
    unsigned long currentMillis = millis ();
    if (currentMillis - previousMillis>sleepTimer)
    {
      digitalWrite (enablePin, HIGH);
    }
  }

  switch (mode)
  {

  case Stop:
   /* if (Serial.available()>0)
      dataSort(); */
   
    break;
   
  case Rewind:
    //take care of variable speed
    stepper.setMaxSpeed(speedValue);
    stepper.moveTo(inPoint);
    stepper.run();
    //Serial.println ("Rcase");
    if(stepper.currentPosition()==inPoint)
    {
     
       
       Serial.write (1); 
     
    mode=Stop;
    }
   
    break;

  case Play:
    //take care of variable speed
    stepper.setMaxSpeed(speedValue);
    stepper.moveTo(outPoint);
    stepper.run();
    //Serial.println ("Pcase");
    if(stepper.currentPosition()==outPoint)
    {
     
       Serial.write (1);
     
     mode=Stop;
    }
    break;
  }
}

//Sort the received data and decide action
void dataSort()
{
  if (dataReceive == 3)
  {
    inPoint = stepper.currentPosition();
    Serial.print ("inpoint = ");
    Serial.println (inPoint);
  }
  else if (dataReceive == 5)
  {
    outPoint = stepper.currentPosition();
    Serial.print ("outpoint = ");
    Serial.println (outPoint);
  }
  else if (dataReceive == 1)
  {
    encoderValue ++;
    Serial.println(dataReceive);
  }
  else if (dataReceive == 2)
  {
    encoderValue --;
    Serial.println(dataReceive);
  }
  else if (dataReceive == 4)
  {
    //function to make Play or Rewind
    defineDirection();
  }
  else
    //Checking is data can be received indeed for changing speed.
    //currently after some revolutions of encoder Xbees stop communicating until reset.
    Serial.println (dataReceive);

}

void defineDirection()
{
  if (stepper.currentPosition()!=inPoint)
  {
    Serial.println ("REWIND");
    mode = Rewind;
  }
  else if (stepper.currentPosition() == inPoint)
  {
    Serial.println ("PLAY");
    mode = Play;
  }
}

void stepperMove ()
{
  stepper.run();
  int stepsPerRotaryStep = (motorStepsPerRev * easyDriverMicroSteps) / rotaryEncoderSteps;
  stepper.moveTo(encoderValue * stepsPerRotaryStep);
}

PaulS

It appears as though you are sending debug data from one XBee to the other. I can't see why you are doing that. It appears as though you think that the XBee know which serial port data is for it to broadcast and which serial data is for the Serial Monitor. This is not the case. If the XBee is connected to pins 0 and 1, you can't debug your application using Serial.

Soffer

Hey Paul.
By "sending debug data" you mean the Serial.print?
Am I wrong in assuming that "Serial.write" goes to Xbee and "Serial.print" goes to pc?
If this is so - in the specific cases where it goes wrong, I do not have any of this mix up.

Receiver - In this instance sends a confirmation:
Code: [Select]
case Play:
    //take care of variable speed
    stepper.setMaxSpeed(speedValue);
    stepper.moveTo(outPoint);
    stepper.run();
    //Serial.println ("Pcase");
    if(stepper.currentPosition()==outPoint)
    {
     Serial.write (1);
     
     mode=Stop;
    }
    break;

Sender - In this loop waits for confirmation and needs to act
Code: [Select]
if (Serial.available())
  {
    dataReceive = Serial.read();
    if (dataReceive == 1)
    {
      pClickedOnce = false;
      digitalWrite(playLED, LOW);
    } 
  }

PaulS

Quote
Am I wrong in assuming that "Serial.write" goes to Xbee and "Serial.print" goes to pc?

I'm afraid that you are.

Soffer


Quote
Am I wrong in assuming that "Serial.write" goes to Xbee and "Serial.print" goes to pc?

I'm afraid that you are.

Would you care to elaborate? Or point to a right way of doing this?
And as for for my 2nd question - " in the specific cases where it goes wrong, I do not have any of this mix up."
Please help me out here - I'm searching all around for some info and not in this forum or Rob Faludi's site do I find any.

PaulS

Quote
Would you care to elaborate?

There is one serial port. Serial.write() and Serial.print() are two ways of sending data to the serial port. They are not ways of directing data to one device listening to the serial port versus the other device.

There should only be one device (either the PC and the Serial Monitor application or the XBee.

If you need two serial ports, you either need different hardware (like a Mega with 4 hardware serial ports) or different software (SoftwareSerial, to create a software port).

Soffer


Quote
Would you care to elaborate?

There is one serial port. Serial.write() and Serial.print() are two ways of sending data to the serial port. They are not ways of directing data to one device listening to the serial port versus the other device.

There should only be one device (either the PC and the Serial Monitor application or the XBee.

If you need two serial ports, you either need different hardware (like a Mega with 4 hardware serial ports) or different software (SoftwareSerial, to create a software port).

Thank you Paul. This actually means that once I run my code w/o being connected to the PC, and w/o Serial.write this should work. This - if I understand correctly - is good news. Thank you very much for clearing this out.
If on the other hand I'm missing something again - please let me know.

Go Up