Go Down

Topic: [Problemão] Comunicação entre vários arduinos (com Xbee) sem erros - Roteamento (Read 5270 times) previous topic - next topic

jpensk

Boas senhores,

É um imenso prazer participar desse Forum e estou com um baita problema:

Tenho 6 arduinos + xbee (esses em modo end device) + 1 xbee coordenador em um UartSbee, para receber os dados.

Quando coloco apenas um kit (arduino + xbee) para conversar com o coordenador, recebo as tags corretamente, dentro do X-CTU [Terminal]. Porém quando coloco dois ou mais há a sobreposição de tags (lembro que cada arduino tem sua programação diferente) e dessa forma todos mandam a informação ao mesmo tempo p/ o Coordenador e vira uma grande bagunça.

O que pergunto: Como fazer com que cada kit comunique no tempo correto sem que haja essa sobreposição de informação devido ao envio de dados ao mesmo tempo entre meus vários arduinos + xbee's?

Aguardo respostas urgentes! Não sei como prosseguir! Help-me!!!






Wagner Sartori Junior

Preciso saber melhor seu ambiente para tentar ajudar.

Qual XBee está usando, Series 1 ou 2?
Os XBee's end device estão funcionando com modo API ou apenas como serial transparente?
O XBee coordinator está como API ou serial transparente?

Se estiver tudo com serial transparente e vc setou em todos os end-devices os DL/DH(destination low/high) para o coordinator e o coordinator está também como transparente, você não vai ter como saber quem enviou aqueles dados e vai virar uma zona.

jpensk

Salve Salve!!!

Vamos lá.

Todos estão em modo API. Tenho arduinos com sensores de corrente e temperatura e outros vou acionar relés! O projeto vai ser bacana! Interessante!

Em cada Arduino, tenho tags diferentes, tipo (IA1, IA2... corrente do kit1, corrente do kit 2, etc). Porém quando ligo na rede, eles mandam para meu coordenador, só que ao invés de ser p.ex [IA1=10], [IA2=5], [IA3=8].... etc acontece mais ou menos assim [IA1=[IA2=10]IA[3=]8....

Todos enviam, mas um acaba "comendo" a tag do outro, pois o envio não é realizado de forma ordenada....

Tá osso!!!


Wagner Sartori Junior

Vamos por partes. Seus XBee's são os recomendados(Series 2) para este tipo de projeto e estão em modo API o que também vai facilitar resolver isto.

Tudo leva a crêr que é alguma coisa no software. O XBee recebe e joga tudo direitinho no TX(DOUT), e ele não encavala a recepção. O que "pode" acontecer é de receber muita coisa e você não conseguir ler, assim o buffer enche e ele começa a esvaziar(ou seja você perde o pacote). O modo API do XBee tem checksum, ou seja, ele não tem como "corromper" ou "encavalar".

Se você testou cada arduino individualmente e o seu coordinator recebe corretamente me faz acreditar que o código no coordinator está fazendo alguma coisa errada. Portanto verifique o código de onde está seu coordinator. Se estiver usando threads tome o cuidado de sincroniza-las quando necessário para não gerar um deadlock ou algum race condition.

Hardware:
Você tem um schema ou alguma documentação de hardware do seu projeto?

Pelo que entendi(me corrija por favor) você tem alguns arduinos com shield XBee e sensores de corrente(quantos???), sensores de temperatura(quantos???). Você tem outros arduinos com shield XBee que tem relés ligados neles(quantos???).

Software:
Você está usando nos arduinos a lib http://code.google.com/p/xbee-arduino/?
O seu coordinator está ligado em um PC? Se for, em que linguagem está desenvolvendo e qual lib está usando ou fez na mão?

Se der para postar o código em algum lugar como github ou mesmo pastebin, iria ajudar.

jpensk

Vamos lá, por partes:

Vamos chamar de kit um conjunto arduino+xbee+sensores.

No Kit1, Kit2 e Kit3 tenho monitoramento de corrente e temperatura. No Kit 4 monitoramento de temperatura e acionamento de 4 relés (via placa externa, com transistores).

O meu coordenador está espetado diretamente o PC através de um UartSbee pela porta USB (FTDI serial) e recebo os dados para teste através do X-CTU (Terminal). Com isso funcionando, monto depois meu supervisório. Não há nada de programação nesse ponto. É o xbee "cru" somente recebendo de todos.

A atualização de leitura dos sensores está em 50ms (abaixo o código). Estou usando modo API em todos eles, pois quando estava usando modo AT no meu supervisório demorava demais atualizar as tags.

Desculpe a ignorância, mas não sei o que são os "threads".

Quanto ao hardware do meu projeto propriamente dito, tenho somente o arduino UNO, com uma placa externa com resistores (para os sensores) e o xbee pendurado no Arduino.

Como seria, por exemplo, a realização de um "request" do coordenador para que cada um responda no seu tempo correto, sem que haja aquele embaraço de informações. Ou ainda, existe uma forma mais fácil de resolver?

Abaixo o código:

#include <math.h>

#define TEMPERATURA_ADC 1
#define CORRENTE_ADC    0
#define BAT_ADC         7

#define blinkLed 8

#define BAUDRATE 9600

void sendXbeeTxAPI(byte address64bits[], byte divisor, int valor, int latency_ms, boolean typeTransmission);

   float pad = 9805;                       //valor resistencia do divisor de tensão
                                       
   float thermr = 10000;   float Temp;
   
   long previousMillis = 0;
   long previousMillis2 = 0;
   
   long interval = 100;
   
   //For analog read
   double value;

   //Constants to convert ADC divisions into mains current values.
   double ADCvoltsperdiv = 0.0032;
   double VDoffset = 2.4476; //Initial value (corrected as program runs)

   //Equation of the line calibration values
   double factorA = 15.2; //factorA = CT reduction factor / rsens
   double Ioffset = -0.08;
     
   //Constants set voltage waveform amplitude.
   double SetV = 127;

   //Counter
   int i=0;

   int samplenumber = 1000;

   //Used for calculating real, apparent power, Irms and Vrms.
   double sumI=0.0;

   int sum1i=0;
   double sumVadc=0.0;

   double Vadc,Vsens,Isens,Imains,sqI,Irms;
   double apparentPower;
   
void setup()
{
  pinMode(blinkLed, OUTPUT);
  Serial.begin(BAUDRATE); 
}

void loop()
{
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval) {
     
      previousMillis = currentMillis;
     
      byte address64bits[] = {0x00, 0x13, 0xA2, 0x00, 0x40, 0x6C, 0xBC, 0xC5};
      int latency_ms = 50;
     
      //trata dado temperatura e envia pacote API para coordenador
      byte divisor = 'T';
      int valor = Temp;
      sendXbeeTxAPI(address64bits, divisor, valor, latency_ms, true);
     
      //trata dado corrente e envia pacote API para coordenador
      divisor = 'I';
      valor = Irms;
      sendXbeeTxAPI(address64bits, divisor, valor, latency_ms, true);
     
      //trata dado tensão bateria e envia pacote API para coordenador
      divisor = 'B';
      analogReference(INTERNAL);//referencia de tensão interna 1.1v no Atmega328
      delay(20);
      valor = analogRead(7);
      analogReference(DEFAULT);
      delay(20);     
      sendXbeeTxAPI(address64bits, divisor, valor, latency_ms, true);
     
      }
     
   corrente();
   temperatura();
 
}

void temperatura(){ 
  value = analogRead(TEMPERATURA_ADC);
 
  long Resistance;   
 
  Resistance=((1024 * pad / value) - pad);
  Temp = log(Resistance);
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;     
}

void corrente(){

   value = analogRead(CORRENTE_ADC);
   //Summing counter
   i++;
   //Voltage at ADC
   Vadc = value * ADCvoltsperdiv;
   //Remove voltage divider offset
   Vsens = Vadc-VDoffset;
   //Current transformer scale to find Imains
   Imains = Vsens;                 
   //Calculates Voltage divider offset.
   sum1i++; sumVadc = sumVadc + Vadc;
   if (sum1i>=1000) {VDoffset = sumVadc/sum1i; sum1i = 0; sumVadc=0.0;}
   //Root-mean-square method current
   //1) square current values
   sqI = Imains*Imains;
   //2) sum
   sumI=sumI+sqI;
   if (i>=samplenumber)
   { 
      i=0;
      //Corrente em mA
      Irms = 100*factorA*sqrt(sumI/samplenumber)+Ioffset;
                   
      apparentPower = Irms * SetV;
       
      sumI=0.0;

   }
}

void sendXbeeTxAPI(byte address64bits[], byte divisor, int value, int latency_ms, boolean typeTransmission)
{
  if(value > 9999)
  return;
 
  if (typeTransmission)
  {
      byte unidade = value%10+0x30;
      value /= 10;     
      byte dezena = value%10+0x30;
      value /= 10;
      byte centena = value%10+0x30;
      value /= 10;     
      byte milhar = value%10+0x30;
     
      //Inicializa pacote API
      //0x7E inicia pacote
      Serial.print(0x7E ,BYTE);
      //Tamanho pacote MSB
      Serial.print(0x00 ,BYTE);
      //Tamanho pacote LSB
      Serial.print(0x16 ,BYTE);
      //Frame ID (0x10: transmissão mensagem)
      Serial.print(0x10 ,BYTE);
      //Sem retorno de resposta
      Serial.print(0x00 ,BYTE);
      //64 bits address
      Serial.print(address64bits[0] ,BYTE);
      Serial.print(address64bits[1] ,BYTE);
      Serial.print(address64bits[2] ,BYTE);
      Serial.print(address64bits[3] ,BYTE);
      Serial.print(address64bits[4] ,BYTE);
      Serial.print(address64bits[5] ,BYTE);
      Serial.print(address64bits[6] ,BYTE);
      Serial.print(address64bits[7] ,BYTE);
      //16 bit MY
      //Se desconhecido, MY: 0xFFFE
      Serial.print(0xFF ,BYTE);
      Serial.print(0xFE ,BYTE);
      //Opcções de envio
      Serial.print(0x00 ,BYTE);
      Serial.print(0x00 ,BYTE);
      //Pacote de mensagem
      Serial.print('[' ,BYTE);
      Serial.print(divisor ,BYTE);
      Serial.print(':' ,BYTE);
      Serial.print(milhar ,BYTE);
      Serial.print(centena ,BYTE);
      Serial.print(dezena ,BYTE);
      Serial.print(unidade ,BYTE);
      Serial.print(']' ,BYTE);
      //Soma do checksum
      long sum = 0x10 +
                 address64bits[0] +
                 address64bits[1] +
                 address64bits[2] +
                 address64bits[3] +
                 address64bits[4] +
                 address64bits[5] +
                 address64bits[6] +
                 address64bits[7] +
                 0xFF + 0xFE +
                 '[' + divisor + ':' +
                 milhar + centena + dezena + unidade + ']';
                 
      Serial.print(0xFF - (sum & 0xFF) ,BYTE);
  }
 
  if (!typeTransmission)
  {
      byte valueHighBit = value >> 8 & 0xFF;
      byte valueLowBit  = value & 0xFF;
     
      //Inicializa pacote API
      //0x7E inicia pacote
      Serial.print(0x7E ,BYTE);
      //Tamanho pacote MSB
      Serial.print(0x00 ,BYTE);
      //Tamanho pacote LSB
      Serial.print(0x14 ,BYTE);
      //Frame ID (0x10: transmissão informação)
      Serial.print(0x10 ,BYTE);
      //Sem retorno de resposta
      Serial.print(0x00 ,BYTE);
      //64 bits address
      Serial.print(address64bits[0] ,BYTE);
      Serial.print(address64bits[1] ,BYTE);
      Serial.print(address64bits[2] ,BYTE);
      Serial.print(address64bits[3] ,BYTE);
      Serial.print(address64bits[4] ,BYTE);
      Serial.print(address64bits[5] ,BYTE);
      Serial.print(address64bits[6] ,BYTE);
      Serial.print(address64bits[7] ,BYTE);
      //16 bit MY
      //Se desconhecido, MY: 0xFFFE
      Serial.print(0xFF ,BYTE);
      Serial.print(0xFE ,BYTE);
      //Opcções de envio
      Serial.print(0x00 ,BYTE);
      Serial.print(0x00 ,BYTE);
      //Pacote de mensagem
      Serial.print('[' ,BYTE);
      Serial.print(divisor ,BYTE);
      Serial.print(':' ,BYTE);
      Serial.print(valueHighBit ,BYTE);
      Serial.print(valueLowBit ,BYTE);

      Serial.print(']' ,BYTE);
      //Soma do checksum
      long sum = 0x10 +
                 address64bits[0] +
                 address64bits[1] +
                 address64bits[2] +
                 address64bits[3] +
                 address64bits[4] +
                 address64bits[5] +
                 address64bits[6] +
                 address64bits[7] +
                 0xFF + 0xFE +
                 '[' + divisor + ':' +
                 valueHighBit + valueLowBit + ']';
                 
      Serial.print(0xFF - (sum & 0xFF) ,BYTE);     
  }
 
      //digitalWrite(8, HIGH);
      //delay(latency_ms);
      //digitalWrite(8, LOW);

jpensk

Em tempo:

Para entender melhor: Esquecendo os sensores e a programação, como seria uma forma simples de envolver vários kits comunicando corretamente ao coordenador? Como seria a configuração?

Wagner Sartori Junior

Entendi melhor agora.

Quanto ao código, aqui no forum, tem umas tags [ code ], [ /code ]. Retire o espaço e coloque seu código entre estas tags. Ele vai melhorar a legibilidade do código e deixar seu post limpo.

Está tudo correto no hardware. Eu vi que vc escreveu o código do modo API no arduino(0x7E, ...). Isto tem seus prós e contras mas acho que está complicando o negócio. Você pode baixar uma lib pronta que já faz tudo para vc poder enviar ou receber as coisas do XBee no arduino sem se preocupar com checksum, etc... Se chama xbee-arduino e pode ser baixado em http://code.google.com/p/xbee-arduino/. Olha os exemplos que vem junto que os códigos de envio e/ou recepção já estão lá prontos.

Agora o que realmente não entendi é que o seu XBee Coordinator está ligado no PC com modo API e você está recebendo os dados PLAIN-TEXT(você consegue ler na tela do X-CTU certo?) ao invés de receber os bytes da API no X-CTU(que é ilegível). Pode estar aí o problema.

jpensk

Boa Boa!!!

Então, consigo ler no terminal do X-CTU sim, normalmente. Mas é porque não está conectado agora, mas meu Coordenador deve estar em AT se não me engano. Posso verificar.

Quando ao uso do Código, sou novo no Forum, por isso as mancadas.

Onde exatamente tem as rotinas no google code que você cita? Isso que você diz é para facilitar o algoritmo ou tem a ver exatamente com o problema que estou tendo de receber tags "sobrepostas" dos vários kits? Melhor dizendo, precisaria de uma rotina com request e Ack para saber se todos estão enviando corretamente? Mas ainda: Como seria feito esse request usando apenas o coordenador com um UartSbee espetado na usb do pc sem o uso do microcontrolador? A ficha aqui ainda não caiu....

Há ainda alguma configuração especial dentro do X-CTU para os diversos Xbee's instalados na minha planta para otimizar a rede?

Como já disse antes, sou iniciante na "parada", mas agradeço muito a colaboração que vem dado...

Obrigado!

Wagner Sartori Junior

Você é de SP capital?

As mancadas são normais, só estou tentando te ensinar as boas práticas.

Por partes novamente.

Arduinos:
O link que te passei do google code, é uma library XBee para o arduino pronta. Leia mais aqui: http://www.arduino.cc/en/Hacking/Libraries. Você instala ela(é só descompactar basicamente) e reiniciar a IDE do Arduino. Ela tem diversas funções já prontas para facilitar sua vida quando precisa se comunicar via XBee's usando a API dele. Como eu já disse, olhe os exemplos que vem junto com a library.

Coordenador:
Seu coordenador então está em AT. Bom, esta não é a melhor maneira de fazer isto e eu nunca fiz assim. Acho que você deveria colocar ele em API e por ser um "re-flash" de firmware e configuração, vc vai precisar reprogramar todos os seus end points para entrar na nova rede que o coordenador vai criar.

Com ele no modo API, você vai precisar desenvolver um software no PC, que vai abrir a porta serial(UartSbee com o coordenador) e "decifrar" os pacotes que chegam. Eu geralmente uso python e um módulo chamado python-xbee(http://code.google.com/p/python-xbee/).

Minha conta no github tem diversos projetos usando ambos arduino-xbee e python-xbee: https://github.com/trunet/

Enfim, você vai precisar ler um pouco para entender o que está fazendo.

jpensk

Opa! Sou de Vitória-ES.

Quanto ao uso das bibliotecas no Arduino IDE já sei utilizar. Vou descarregar na pasta para uso já!

Quanto ao software do PC. Até então, com somente 1 kit comunicando corretamente estava usando o Visual Studio C#, que já tem uma rotina que abre a porta serial e lê os dados corretamente. Esse python é um software específico? Roda em Windows?

Com os end points em API e o coordenador em AT é praticamente inviável o desenvolvimento no Visual Studio... creio eu... ou seja, voltei a estaca zero!

Vou tentar aumentar um pouco mais a literatura e postarei novamente em breve. Muito obrigado por enquanto! Bom final de semana! Nos falamos ainda...

Wagner Sartori Junior

Python é uma linguagem de programação como o C# que você está usando e roda em windows tranquilamente. Vai uma curva de aprendizado razoável para trocar o C# por python.

Nada te impede de fazer em C#, entretanto desconheço módulos/libraries prontas para lidar com a API do XBee nesta linguagem o que deve dificultar e aumentar o tempo para ter um código mínimo funcional.

Pode até ser que o coordenador em AT funcione, mas eu pessoalmente nunca fiz desta maneira e não consigo pensar em nada do que pode estar gerando este comportamento de "encavalar" que você descreveu.

jpensk

Beleza!!!

Então, resumo da ópera: Se não fosse esse problema de "encavalar" os dados, o projeto estaria pronto...

O que tá pegando são todos enviando dados ao mesmo tempo... mas vou ler melhor o que você me passou e tentar alguma solução. Estou há dias já com esse problema.

Amanhã retorno com alguma novidade.

Pergunta básica: No seu ponto de vista, mesmo vendo essa programação e a configuração que te passei, não era para estar havendo essa "sobreposição", mesmo sem request/ack do coordenador? O próprio Xbee sozinho não se encarregaria disso?

Abraço,




Wagner Sartori Junior

O coordenador mesmo em AT, ele usa API. Só que ele te cospe os dados que chegam diretamente no DOUT.

Qualquer XBee só manda ACK quando o frame_id de quem está mandando os dados é > 0(está no datasheet).

Você já tentou aumentar o tempo de sleep/delay de 50ms para algo 1 segundo e ver se o problema permanece? Você realmente precisa destes dados tão rápido quanto 50ms?


jpensk

Na verdade esse tempo de 50ms é exagerado mesmo! É mais para o teste que estava fazendo no Visual C#.

Vou mudar o tempo de atualização para 1s e verificar, mas mesmo assim todos tendem a enviar (ou há grande chance) de enviarem ao mesmo tempo...


Go Up