xBee Breaks Arduino Comms

I am trying to get a Pi and Arduino Mega to communicate via xBee.

Pi has xBee Explorer USB on it (ttyUSB0)

Arduino has xBee Arduino Shield on it

1)My code works if I plug the mega directly into the Pi and use ttyACM0 (as long as shield is removed from arduino)

  1. If I put my xBee Arduino shield on the Mega and switch my code to use ttyUSB0, the Pi receives blank lines.

  2. If take the xBee from the arduino shield and put it on another explorer USB on my computer, I can communicate directly with the Pi. So I know the Pi works.

This leads me to the following question:

What do I need to do to make the Mega communicate with the xBee? I have the shield switch set to UART. I also, on a whim, tried using an xBee Explorer Regulated and manually pinning it to the Mega with the same result.

I feel this may be related to the fact that serial by USB does not work with the shield plugged in. The Pi cannot communicate direct unless i remove the shield, I also cannot program the arduino without removing the shield.

https://lh3.googleusercontent.com/vWnwQ … 62-h821-no

https://lh3.googleusercontent.com/Mvc-9 … 12-h821-no

https://lh3.googleusercontent.com/282PT … 60-h821-no

Shield is standard Sparkfun xBee Arduino shield. I manually wired it to Serial3 instead of Serial, and it’s working, albeit laggy,

Here is the Arduino code, followed by the Pi Code.

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

unsigned long previousMillis = 0;
long interval = 2000; 
unsigned long currentMillis = 0;

      // variables to hold the parsed data
int Joy1X = 0;
int Joy1Y = 0;
int Joy2X = 0;
int Joy2Y = 0;
int Joy3X = 0;
int Joy3Y = 0;
int Sw1 = 0;
int Sw2 = 0;
int Sw3 = 0;
int Sw4 = 0;

String sentCommand = "";
String call = "KF5RVR ";
String start = "{";
String last = "}";
String comma = ",";

boolean newData = false;
boolean firstContact = false;
boolean waitingForReply = false;

int RangeLF = 0;
int RangeRF = 0;
int RangeLR = 0;
int RangeRR = 0;
int AccelX = 0;
float AccelX_abs;
int AccelY = 0;
float AccelY_abs;
int AccelZ = 0;
float AccelZ_abs;
int roll = 0;
int pitch = 0;

// input string from Robot: {255,255,255,255,255,255,255}
// output string to robot: {100,100,100,100,100,100,1,1,1,1}

//========================================================================

void setup() {
    pinMode(13,OUTPUT);
    pinMode(A0,INPUT);
    pinMode(A1,INPUT);
    pinMode(A2,INPUT);
    pinMode(A3,INPUT);
    pinMode(A4,INPUT);
    pinMode(A5,INPUT);
    
    digitalWrite(13,LOW);
  
    Serial3.begin(4800);
    Serial.begin(9600);
    establishContact();
}

void loop() {
    currentMillis = millis();
    recvWithStartEndMarkers();
    
    if (newData == true) {
        
        //Serial.print("Received: ");
        //Serial.println(receivedChars);
        
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
        waitingForReply = false;
    } else{
        if ((Serial3.available() == 0) && (!waitingForReply)){
          transmitControlValues();
          waitingForReply = true;
        }
    }
    
    WarningLights();
}

//========================================================================

void establishContact() {
  while (Serial3.available() <= 0) {
    Serial3.println('A');   // send a capital A
    delay(1000);
  }
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '{';
    char endMarker = '}';
    char rc;

    while (Serial3.available() > 0 && newData == false) {
        rc = Serial3.read();
        if (rc == 'C') {
//            //transmitControlValues();
//            //waitingForReply = true;
//            break;
            Serial3.flush();
            Serial3.println('A');
            break;
          }
//        previousMillis = currentMillis;

        if (firstContact == false){
           if (rc == 'B'){
                Serial3.flush();
                firstContact = true;
                                                    //Serial.println("First Contact Made");
           }
        } else {
          if (recvInProgress == true) {
              
              if (rc != endMarker) {
                  receivedChars[ndx] = rc;
                  ndx++;
                  if (ndx >= numChars) {
                      ndx = numChars - 1;
                  }
              }
              else {
                  receivedChars[ndx] = '\0'; // terminate the string
                  recvInProgress = false;
                  ndx = 0;
                  newData = true;
                  previousMillis = currentMillis;
              }
          } else if (rc == startMarker) {
              recvInProgress = true;
          }
        } 
    }
}

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    RangeLF = atoi(strtokIndx);  // convert this part to an integer
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    RangeRF = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL,",");      // this continues where the previous call left off
    RangeLR = atoi(strtokIndx);  // convert this part to an integer
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    RangeRR = atoi(strtokIndx);     // convert this part to an integer
        
    strtokIndx = strtok(NULL,",");     // this continues where the previous call left off
    AccelX = atoi(strtokIndx);  // convert this part to an integer
    AccelX_abs = ((float)AccelX / 1000) * 9.8;
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    AccelY = atoi(strtokIndx);     // convert this part to an integer
    AccelY_abs = ((float)AccelY / 1000) * 9.8;

    strtokIndx = strtok(NULL,",");      // this continues where the previous call left off
    AccelZ = atoi(strtokIndx);  // convert this part to an integer
    AccelZ_abs = ((float)AccelZ / 1000) * 9.8;

    roll = atan2(AccelY_abs,AccelZ_abs) * 57.3;
    pitch = atan2( -1*AccelX_abs , sqrt((AccelY_abs*AccelY_abs)+(AccelZ_abs*AccelZ_abs))) * 57.3;
}

void showParsedData() {
    Serial.println("");
    Serial.println(currentMillis);
    Serial.print("RangeLF ");
    Serial.println(RangeLF);
    Serial.print("RangeRF ");
    Serial.println(RangeRF);
    Serial.print("RangeLR  ");
    Serial.println(RangeLR);
    Serial.print("RangeRR ");
    Serial.println(RangeRR);
    Serial.print("AccelX ");
    Serial.println(AccelX);
    Serial.print("AccelX_abs ");
    Serial.println(AccelX_abs);
    Serial.print("AccelY  ");
    Serial.println(AccelY);
    Serial.print("AccelY_abs  ");
    Serial.println(AccelY_abs);
    Serial.print("AccelZ ");
    Serial.println(AccelZ);
    Serial.print("AccelZ_abs ");
    Serial.println(AccelZ_abs);
    Serial.print("Roll  ");
    Serial.println(roll);
    Serial.print("Pitch ");
    Serial.println(pitch);
}

void transmitControlValues() {
    Joy1X = analogRead(A0);
    Joy1Y = analogRead(A1);
    Joy2X = analogRead(A2);
    Joy2Y = analogRead(A3);
    Joy3X = analogRead(A4);
    Joy3Y = analogRead(A5);
    Sw1 = 0;
    Sw2 = 1;
    Sw3 = 0;
    Sw4 = 1;
    

  /*sentCommand = '{' + Joy1X + ',' + Joy1Y + ',';
    sentCommand += Joy2X + ',' + Joy2Y + ',';
    sentCommand += Joy3X + ',' + Joy3Y + ',';
    sentCommand += Sw1 + ',' + Sw2 + ',';
    sentCommand += Sw3 + ',' + Sw4 + '}';*/

    sentCommand = call + start + Joy1X + comma + Joy1Y + comma;
    sentCommand += Joy2X + comma + Joy2Y + comma;
    sentCommand += Joy3X + comma + Joy3Y + comma;
    sentCommand += Sw1 + comma + Sw2 + comma;
    sentCommand += Sw3 + comma + Sw4 + last;

                                                              //Serial.println("Transmitting:");
    Serial3.println(sentCommand);
                                                              //delay(5000);
    
}

void WarningLights(){
    
    if(currentMillis - previousMillis > interval){
      // Illuminated when linked
      digitalWrite(13, LOW);
    } else {
      // turned off when comms lost
      digitalWrite(13, HIGH);
    }

    if (AccelX > 300){
      //X angle greater than 30% (2.9 m/s2)
      digitalWrite(25,HIGH);
    } else {
      digitalWrite(25,LOW);
    }

    if (AccelY > 300){
      //Y angle greater than 30% (2.9 m/s2)
      digitalWrite(26,HIGH);
    } else {
      digitalWrite(26,LOW);
    }

    if (AccelZ < 900){
      //Z angle less than 90% (8.82 m/s2)
      digitalWrite(27,HIGH);
    } else {
      digitalWrite(27,LOW);
    }
  
}

Here is the Python3 code from the Pi.

It seems the comms are averaging about 6 tenths of a second to parse completely, when unregulated- it tends to push in batches of 3 comms at a time. My math says that at 4800 bps, it should be taking less than 3 tenths of a second. As a result, I have set the program to pause for half a second simply to make the speed of comms more predictable.

Should I bump the rate up to 9600? The plan is to have the xBee’s up to 1000 feet apart, and they are 63mw series 2 Pro’s.

Video of the transmission behavior:

[https://www.youtube.com/watch?v=JFiJ6nF65QI

import serial
from time import sleep
import time
import board
import busio
import adafruit_lsm9ds1
import Adafruit_ADS1x15
import math

#port = serial.Serial("/dev/ttyAMA0", baudrate=9600, timeout=3.0)
#ser = serial.Serial("/dev/ttyACM0", baudrate=4800, timeout=3.0) #USB Serial to Arduino
ser = serial.Serial("/dev/ttyUSB0", baudrate=4800, timeout=3.0) #USB xBee

# I2C connection:
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_lsm9ds1.LSM9DS1_I2C(i2c)
adc48 = Adafruit_ADS1x15.ADS1115()
adc49 = Adafruit_ADS1x15.ADS1015(address=0x49, busnum=1)
GAIN = 1

incomingCommand = ""
prevPosInString = 0
nextPosInString = 0
joy1X = 0
joy1Y = 0
joy2x = 0
joy2Y = 0
joy3X = 0
joy3Y = 0
sw1 = 0
sw2 = 0
sw3 = 0
sw4 = 0

waitingForContact = 1
sentCommand=""
rangeLF = 0
rangeRF = 0
rangeLR = 0
rangeRR = 0
accelX = 0
accelY = 0
accelZ = 0

speedFactor = 1.0
crabSteer = 0


def driveMotors():
    if (sw1 == "1"):
        speedFactor = 0.25
        # set forward ESC to 25% of received Joy1Y
    else:
        speedFactor = 1.0
        # set forward ESC to received Joy1Y
    
    if (sw2 == "1"):
        crabSteer = 1
        # set front and rear steer to Joy1X
        # this makes all 4 tires point the same direction
    else:
        crabSteer = 0
        # set front steer servo to Joy1X
        # set rear steer servo to -1*Joy1X
        # this makes tires turn about a single point
    
    
    
def readRangeSensors():
    global rangeLF, rangeRF, rangeLR, rangeRR
    values48 = [0]*4
    values49 = [0]*4
    for i in range(4):
        values48[i] = adc48.read_adc(i, gain=GAIN)
        values49[i] = adc49.read_adc(i, gain=GAIN)
    rangeLF = values48[0]
    rangeRF = values48[1]
    rangeLR = values48[2]
    rangeRR = values48[3]


def readAccelerometer():
    global accelX, accelY, accelZ
    accelX, accelY, accelZ = sensor.acceleration
    accelX = round((accelX / 9.8) * 1000)
    accelY = round((accelY / 9.8) * 1000)
    accelZ = round((accelZ / 9.8) * 1000)
    magX, magY, magZ = sensor.magnetic
    gyroX, gyroY, gyroZ = sensor.gyro
    temp = sensor.temperature

while waitingForContact:
    x = ser.read()
    print(x)
    if ( x.decode() == 'A' ):
            ser.write(b'B')
            print('B')
            waitingForContact = 0
    else:
        ser.write(b'C')
        print('C')
        sleep(0.500)

while True:
    
    driveMotors()
    readRangeSensors()
    readAccelerometer()
    
    if(ser.inWaiting() == 0):
        sleep(0.500) #4800 bps = 600 bytes per second @ 42 bytes per comm = 0.071 per comm
    
    while(ser.inWaiting() > 0):
        sleep(0.002) #4800 bps = 600 bytes per second @ 42 bytes per comm = 0.071 per comm
        incomingCommand = str(ser.readline())
        print("in: " + incomingCommand[0:-2])
        
#        print incomingCommand.find("A")
        
        if(incomingCommand.find("A") > -1):
            ser.write(b'B')
            print('B')
            ser.flush()
            sleep(0.250)
#            incomingCommand = str(ser.readline())
        
#        incomingCommand = incomingCommand[1:-3]
#        print("revised1: " + incomingCommand)

        if(len(incomingCommand) > 15):
        
            prevPosInString = 0
            
            nextPosInString = incomingCommand.find("{")
            incomingCommand = incomingCommand[nextPosInString+1:-6]
            prevPosInString = nextPosInString
            print("revised: " + incomingCommand)
        
            nextPosInString = incomingCommand.find(",")
    #        print "index1: %s" % (nextPosInString,)
            joy1X = incomingCommand[prevPosInString:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index2: %s" % (nextPosInString,)
            joy1Y = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index3: %s" % (nextPosInString,)
            joy2X = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index4: %s" % (nextPosInString,)
            joy2Y = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index5: %s" % (nextPosInString,)
            joy3X = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index6: %s" % (nextPosInString,)
            joy3Y = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index7: %s" % (nextPosInString,)
            sw1 = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index8: %s" % (nextPosInString,)
            sw2= incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index9: %s" % (nextPosInString,)
            sw3 = incomingCommand[prevPosInString+1:nextPosInString]
            prevPosInString = nextPosInString
            
            nextPosInString = incomingCommand.find(",",prevPosInString+1)
    #        print "index10: %s" % (nextPosInString,)
            sw4 = incomingCommand[prevPosInString+1:]
            prevPosInString = nextPosInString
            
    #        print(joy1X)
    #        print(joy1Y)
    #        print(joy2X)
    #        print(joy2Y)
    #        print(joy3X)
    #        print(joy3Y)
    #        print(sw1)
    #        print(sw2)
    #        print(sw3)
    #        print(sw4)

        if (ser.inWaiting() == 0):
            sentCommand = "KF5RVR {" + str(rangeLF) + "," + str(rangeRF) + "," + str(rangeLR) + "," + str(rangeRR) + "," + str(accelX) + "," + str(accelY) + "," + str(accelZ) + "}"
            sentCommand = sentCommand
            ser.write(sentCommand.encode())
            print("out: " + sentCommand)
            print("")
            
        # End Serial Comms
    # End While True
# Start Rest Of Code Here
    
    
ser.close()

](https://www.youtube.com/watch?v=JFiJ6nF65QI)