Problemas de dessincronização de dados Arduino Xbee+Computador Xbee

Olá pessoal!
Eu estou a desenvolver um projeto onde tenho de enviar dados de 30 em 30 segundos de um Arduino ligado a um Xbee para um Xbee ligado à porta série do meu portátil. Por sua vez no portátil através de um programa feito no processing recebo os dados na porta série e coloco-os em gráfico. Acontece que após ter deixado o projeto rolar durante a noite ao analisar os dados recebidos no processing deu para ver que a sua qualidade não era a melhor, pois por vezes havia dessincronização dos dados recebidos pelo xbee ligado ao pc, como podem ver de seguida:

04-07-2012 19:51 0,321 73,9 51,8 0,033 1
04/07/152 00:�:48,6 0,033 4 7 12 19
04-07-2012 19:54 0,274 63,1 44,1 0,034 1
...
04/07/12 20,26:�:� 7 12 20 36 0
04-07-2012 20:36 NaN 48,1 0,065 NaN 7
04/07/12 230:00,265:60,066 NaN 7 12 20 38
04-07-2012 20:40 0,271 62,3 43,6 0,068 1

Segundo consigo perceber ele não obedece à sequência de valores que implementei, sendo que muitas das vezes salta.
Em relação ao problema ele só pode estar relacionado com o Xbee pois estou a usar um cartão sd no arduino para armazenar os dados recolhidos e neste caso está tudo bem...
Em relação à configuração dos Xbees estão usando ambos o modo AT, sendo um o router e outro o coordenador.
Em relação ao código não estou usando nada diretamente ligado ao xbee, pelo que apenas imprimo os valores na porta série do arduino/xbee e os recolho pela porta série do computador.
Acredito que no código vou ter de implementar outra estratégia ou utilizar o modo API, mas gostava que alguém me pudesse dar umas dicas, ou então dizer onde posso encontrar projetos semelhantes...

Que baud rate estas a utilizar?
Tenta baixar o baud para os 9600 caso o tenhas mais elevado e por uma questao de teste coloca os perto um do outro.

Estou a usar ambas as condições...
Será que é por ter tantos dados? Estava a pensar utilizar o modo API ou então colocar um caracter diferente À frente de cada valor enviado, de forma a tentar solucionar o problema. Que achas?

Sem ver o código apenas podemos comentar que há algo estranho na ligação das XBee.

Como escrever no cartão provavelmente é feito numa chamada bloqueante, é provável que esses dados estejam sempre correctos. Escrever na porta série, não é bloqueante e pode haver alguma coisa no teu programa que bloqueie a porta série (é difícil, mas nunca se sabe) ou o que é mais provável, que o buffer esteja a ser corrompido com dados a mais ou algo do género. Já experimentaste enviar menos dados à mesma frequência ou os mesmos dados a uma frequência menor?

Podes colocar aqui parte do código ou o código completo?

Este é o código completo do Arduino que está a recolher os dados e a enviar posteriormente para o Xbee ligado ao meu computador, onde o processing recolhe os mesmos dados e os reproduz em gráficos...

#include <Wire.h>  //I2C library
#include <SD.h>    //SD library
#define DS1307_ADDRESS 0x68 //RTC library

byte zero = 0x00; //workaround for issue #527 (RTC variable)

//definition of pin on Arduino board
const int PIR1 = 2;
const int PIR2 = 3;
const int LED = 5;
const int pinPot = A0;
const int CS_pin = 4;  
const int pow_pin = 8; 

//Motion Detection Variables
int val1 = 0;             //PIR1 value
int val2 = 0;             //PIR2 value
int reading = 0;          //US value
int oldreading = 0;       //oldUS value
int count = 0;            //counter to keep LED tu 
int calibrationPIR = 0;  //calibration time of PIR sensors
int presence_state = 0; //sets initial value of presence as 0, without presence




const int numberOfSamples = 1185;   

//Callibration Constants
const int Vrms = 230; 
const float PF = 0.70;//set an average Power Factor value

//CR Magnetics CR31000-3000 CT parameters
const float CT_BURDEN_RESISTOR  = 180; 
const float CT_TURNS     = 3000;

/*YHDC SCT-013-030 CT parameters
const float CT_BURDEN_RESISTOR  = 62; 
const float CT_TURNS            = 1800;*/

//Calibration coeficients
int calibrationCT = 0;  //calibration time of PIR sensors
const float ICAL = 0.96; 
int lastSampleI,sampleI; //Sample variables
float lastFilteredI, filteredI; //Filter variables
float sqI, sumI;  //Power calculation variables
float Irms; //Useful value variables
float apparentPower,realPower;
float kilowattHour;

unsigned long last_kwhTime;
unsigned long kwhTime;  

//Real Time Clock Variables
int second, minute, hour, weekDay, day, month,year;
  
void setup()
{
  Wire.begin();          // start the I2C bus

  Serial.begin(9600);    // open the serial port:
  
  //Definition of input/output values
  pinMode(PIR1,INPUT);
  pinMode(PIR2,INPUT);
  pinMode(LED,OUTPUT);
  pinMode(pinPot,INPUT);
  pinMode(CS_pin, OUTPUT); 
  pinMode(pow_pin, OUTPUT);
   
  digitalWrite(pow_pin, HIGH);  

  //Initialize Card
  if (!SD.begin(CS_pin))
  {
      Serial.println("Card Failure");
      return;
  }
  //Serial.println("Card Ready");
  
  //Read the Configuration information (COMMANDS.txt)
  File logFile = SD.open("SMEP_SD.csv", FILE_WRITE);
  if (logFile)
  {
    String header = "day-month-year hour:minute:second;Irms (A);Apparent Power (W);Real Power (W);Energy (kWh);Presence";
    logFile.println(header);
    logFile.close();
    Serial.println(header);    
  }
  else
  {
    Serial.println("Could not read command file.");
    return;
  }  
}

void loop()
{ 
  runRTC();  
  passiveIR();
  ultrasonic();  
  presence(); 
 
  if(second == 0  || second == 30 ){ //condition to run functions  
                                         //only from 30 to 30 seconds   
    printDate();
    consumption();
 
   if( calibrationPIR < 1 ){ 
 
    presence_state=0;
    calibrationPIR++;
   }   
    Serial.println(presence_state);
    
    File logFile = SD.open("SMEP_SD.csv" , FILE_WRITE);
    if (logFile)
    {//print to micro SD card
    logFile.print(day);
    logFile.print("/");      
    logFile.print(month);
    logFile.print("/");    
    logFile.print(year);
    logFile.print(" ");
    logFile.print(hour);
    logFile.print(":"); 
    logFile.print(minute);
    logFile.print(":"); 
    logFile.print(second);
    logFile.print(";");    
    logFile.print(Irms,3);
    logFile.print(";"); 
    logFile.print(apparentPower,1);
    logFile.print(";"); 
    logFile.print(realPower,1);
    logFile.print(";"); 
    logFile.print(kilowattHour,3);
    logFile.print(";");
    logFile.println(presence_state);

    logFile.close();
    }

    else
    {
      Serial.println("Couldn´t open log file");
    }
    presence_state=0;    
  }
  delay (500);  //set a delay to avoid the print on serail port of two lines of values
}

void passiveIR()
{    
  val1 = digitalRead(PIR1);
  val2 = digitalRead(PIR2);
  delay (200); 
}

void ultrasonic()
{
  // step 1: instruct sensor to read centimeters
  Wire.beginTransmission(112); 
                               
                              
  Wire.write(byte(0x00));      
  Wire.write(byte(0x51));     
                              
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen
  delay(70);                   // datasheet suggests at least 65 milliseconds

  // step 3: instruct sensor to return a particular echo reading
  Wire.beginTransmission(112); // transmit to device #112
  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
  Wire.endTransmission();      // stop transmitting

  // step 4: request reading from sensor
  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    oldreading = reading;
    reading = Wire.read();    // receive high byte (overwrites previous reading)
    reading = reading << 8;   // shift high byte to be high 8 bits
    reading |= Wire.read();   // receive low byte as lower 8 bits
  }

  delay(25);                 // wait before next reading:
}

void presence()
{  
 //the follow condition memorizes if there was a motion during the 30seconds and print it
 int f = reading - oldreading; 
 
  if((val1 == LOW) || (val2 == LOW) || (f > 15)){
    presence_state=1;    
    digitalWrite(LED,HIGH);
  }
  
  else{
    digitalWrite(LED,LOW);
  }    
}
  
void consumption()
{   

  for (int n=0; n < numberOfSamples; n++)
  {    

    lastSampleI = sampleI;     //Used for current offset removal
    
    lastFilteredI = filteredI; //Used for voltage offset removal 
    
    //sampleI = map(analogRead(pinPot),0,1023,0,30);    
     sampleI = analogRead(pinPot);  
     
    //Apply digital high pass filters to remove 2.5V DC offset (centered on 0V)    
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);
       
   
   //Root-mean-square method current
    //1) square current values
    sqI = filteredI * filteredI;
    //2) sum
    sumI += sqI;
  }
    
  //Calculation of the root of the mean of the current squared (rms)
  //Calibration coeficients applied.   
  //Calculated ratio constants
  ///I_Ratio=(CT_Turns / CT_BR)* (5V/1024)*ICA
  float I_RATIO = CT_TURNS / CT_BURDEN_RESISTOR * 5 / 1024 * ICAL;  
  Irms = I_RATIO*sqrt(sumI / numberOfSamples); 
  
  //condition to avoid when there's no current the code 
  //prints a current value due to resolution of ADC
  
  if(Irms <0.3 || calibrationCT < 1 ){
  Irms=0.000;    
  Serial.print(Irms,3);
  Serial.print(';'); 
 
  // Calculate power values 
  apparentPower = Vrms * Irms; 
  realPower = PF * apparentPower; 
  
  Serial.print(apparentPower,1);
  Serial.print(';');
  Serial.print(realPower,1);
  Serial.print(';');   
  
  // Calculate running total kilowatt hours 
  // This value will reset in 50 days  
  last_kwhTime = kwhTime;
  kwhTime = millis();
  kilowattHour += (realPower / 1000) * ((kwhTime - last_kwhTime) / 3600000.0);
  Serial.print(kilowattHour,3);
  Serial.print(';');  
  // Reset sample totals 
  sumI = 0;
  calibrationCT++; 
  }
  else{
  //if(Irms >= 0.14 && calibrationCT >= 1 ){ 

  Serial.print(Irms,3);
  Serial.print(';'); 
 
  // Calculate power values 
  apparentPower = Vrms * Irms; 
  realPower = PF * apparentPower; 
  
  Serial.print(apparentPower,1);
  Serial.print(';');
  Serial.print(realPower,1);
  Serial.print(';');   
  
  // Calculate running total kilowatt hours 
  // This value will reset in 50 days  
  last_kwhTime = kwhTime;
  kwhTime = millis();
  kilowattHour += (realPower / 1000) * ((kwhTime - last_kwhTime) / 3600000.0);
  Serial.print(kilowattHour,3);
  Serial.print(';');  
  // Reset sample totals 
  sumI = 0;
  calibrationCT++; 
  }
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void runRTC(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  day = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
  }
  

void printDate(){

  Serial.print(day);
  Serial.print(";");
  Serial.print(month);
  Serial.print(";");
  Serial.print(year);  
  Serial.print(";");
  Serial.print(hour);
  Serial.print(";");
  Serial.print(minute);
  Serial.print(";");
  Serial.print(second);
  Serial.print(";");

}

Em relação ao processing estou napplets, mas aqui fica a parte principal do código onde são tratados os dados recebido na porta série a partir do xbee

 import napplet.*;
import processing.serial.*;
Serial port;

PrintWriter dadosSMEP;

int count;
//variables to receive on serial port
float yeartime, monthtime, daytime; 
float hourtime, minutetime, secondtime, oldsecondtime ;
float presvalue, oldpresvalue; 
float Irms;
float apparentPower,realPower;
float kilowattHour;
float timeX;  //Calculates the total time, using the time function of processing necessary to use on graphs Xaxis

//Size of the window
int plotX=1150, plotY=800;
//Dimension of each graph window
int plotgwX=575, plotgwY=312;
//plotmw means the height of the main window
int plotmwY=176;

//
color bgc=color(0, 153, 0); //backgroung color of each window
color graphc=color(#4D4D4A);//graph line color
color textc=color(255);     //text color on graph label

PFont plotFont; //font used in each graph

void setup() {

  
  size(plotX,plotY);
  
  // Print a list of the serial ports, for debugging purposes:
  println(Serial.list());
 
  // Open whatever port is the one you're using.
  port = new Serial(this,"COM14", 9600);
  // don't generate a serialEvent() unless you get a newline character:
  port.bufferUntil('\n');
  
  NAppletManager nappletManager = new NAppletManager(this);

  //define the initial points of each window created in our sketch 
  nappletManager.createNApplet("Irms", 0, 0);
  nappletManager.createNApplet("RealPower", width/2, 0);
  nappletManager.createNApplet("kWh", 0, plotgwY);  
  nappletManager.createNApplet("Presence", width/2, plotgwY);
  nappletManager.createNApplet("MainWindow", 0, height-plotmwY);
 
  plotFont = createFont("SansSerif", 20);
  textFont(plotFont);
  
  //setup the text file to be created with descrition of several parameters
  dadosSMEP = createWriter("dadosSMEP.csv");
  dadosSMEP.print("Date");
  dadosSMEP.print(";");      
  dadosSMEP.print("Irms");  
  dadosSMEP.print(";");  
  dadosSMEP.print("Apparent_Power");  
  dadosSMEP.print(";");  
  dadosSMEP.print("Real_Power");  
  dadosSMEP.print(";");
  dadosSMEP.print("kWh");  
  dadosSMEP.print(";"); 
  dadosSMEP.println("Presence");
  
} 


void draw() {
  background(0, 153, 0);
  timeX=60.0*minutetime+secondtime+hourtime*3600.0; //Calculates the total time, using the time function of processing  
                                              //necessary to use on graphs Xaxis   

  //convert the float number to integer
  String intyeartime = nf(yeartime, 2,0); 
  String intmonthtime = nf(monthtime, 2,0);
  String intdaytime = nf(daytime, 2,0); 
  String inthourtime = nf(hourtime, 2,0); 
  String intminutetime = nf(minutetime, 2,0);
  String intsecondtime = nf(secondtime, 2,0); 


  if(secondtime != oldsecondtime){//just print if the time change using second from Arduino Time
    
  //print the data received from Arduino on the text file
  dadosSMEP.print(intyeartime+"/"+intmonthtime+"/"+intdaytime+" "+inthourtime+":"+intminutetime+":"+intsecondtime);
  dadosSMEP.print(";");   
  dadosSMEP.print(Irms);
  dadosSMEP.print(";");  
  dadosSMEP.print(apparentPower);
  dadosSMEP.print(";");
  dadosSMEP.print(realPower);
  dadosSMEP.print(";");
  dadosSMEP.print(kilowattHour);
  dadosSMEP.print(";");  
  dadosSMEP.println(presvalue);
  
  dadosSMEP.flush();
  }
  oldsecondtime = secondtime;
}
 
void mousePressed() 
{
  println("Coordinates: " + mouseX +"," + mouseY);
}

void serialEvent(Serial port)
{
  String input = port.readStringUntil('\n');//le o que chega a porta ate ao enter para importar as variaveis do arduino    
 
  /*para isto e necessario que no sketch do arduino as variaveis sejam imprimidas com Serial.print(variavel)
  e seguidas de virgula ou seja outro Serial.print(",").Sendo que a ultima variavel a registar e imprimida com
  Serial.println(variavel) */
                                                                                      
  if (input != null)//se a string contiver algo
  {
    input = trim(input); // limpa a string de espaços vazios que não sejam necessários
    // The data is split into an array of Strings with a comma or asterisk as a delimiter and converted into an array of integers.
    float [] infos =float (split(input, ";")); //preenche uma matriz com as variaveis importadas sendo que as diferentes variaveis vao para locais diferentes da matriz infos [0],infos [1]...
 
    if (infos.length >=11) //11 e o numero de variaveis que importo do arduino "ainda nao percebi bem porque e' necessario este if"
    {
      daytime = infos [0];
      monthtime = infos [1];      
      yeartime = infos [2];
      hourtime = infos [3];
      minutetime = infos [4];
      secondtime = infos [5];
      Irms = infos [6];
      apparentPower = infos [7];
      realPower = infos [8];
      kilowattHour = infos [9];
      presvalue = infos [10]; //presence value
    }
  }
}

Espero que possa ajudar e desculpa a possível estrutura do código mas foi o meu primeiro projeto nesta área :slight_smile: