sábado, 25 de dezembro de 2010

Comunicação entre 2 Arduinos por Rádio (Final)

Software de Recepção para Comunicação entre 2 Arduinos por Rádio

Este é o software de recepção, que utiliza em parte as rotinas desenvolvidas por Maurice Ribble (30/08/2009), disponíveis em http://www.glacialwanderer.com/hobbyrobotics.

/*
Projeto:
   Transmissão de dados por RF entre duas placas Arduino

Objetivos:
   Experimentar a transmissão de dados por RF entre duas placas Arduino
   Experimentar os módulos de transmissão e recepção de RF
   Estabelecer os fundamentos para futuras experiências envolvendo controle remoto
  
Componentes:
   2 Placas Arduino Duemilanove com ATmega328
   1 módulo transmissor de RF de 315 MHz
   1 módulo receptor de RF de 315 MHz

Autor: Karl Heinz Benz
Data: 23/12/2010
Correções, sugestões e nova documentação devem ser enviadas a karlbenz@terra.com.br
Licenciamento: Atribuição-Uso não-comercial-Compartilhamento pela mesma licença 3.0 Brasil
http://creativecommons.org/licenses/by-nc-sa/3.0/br/

Utilização do pacote de software desenvolvido por:
   Maurice Ribble
   30/08/2009
   http://www.glacialwanderer.com/hobbyrobotics
*/

// Módulo de RECEPÇÃO

#define LED_PIN     13

void setup()
{
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  Serial.begin(1200);  // Hardware suporta até 2400, mas 1200 fornece maior alcance.
}

void loop()
{
  Serial.println(readUInt(true));
  digitalWrite(LED_PIN, HIGH);
  delay(50);
  digitalWrite(LED_PIN, LOW);
}

// Maurice Ribble
// 30/08/2009
// http://www.glacialwanderer.com/hobbyrobotics
// This does some error checking to try to make sure the receiver on this one way RF
//  serial link doesn't repond to garbage

#define NETWORK_SIG_SIZE 3

#define VAL_SIZE         2
#define CHECKSUM_SIZE    1
#define PACKET_SIZE      (NETWORK_SIG_SIZE + VAL_SIZE + CHECKSUM_SIZE)

// The network address byte and can be change if you want to run different devices in proximity to each other without interfearance
#define NET_ADDR 5

const byte g_network_sig[NETWORK_SIG_SIZE] = {0x8F, 0xAA, NET_ADDR};  // Few bytes used to initiate a transfer

// Receives an word over the RF network
word readUInt(bool wait)
{
  int pos = 0;          // Position in the network signature
  word val;             // Value of the unsigned int
  byte c = 0;           // Current byte
 
  if((Serial.available() < PACKET_SIZE) && (wait == false))
  {
    return 0xFFFF;
  }
 
  while(pos < NETWORK_SIG_SIZE)
  {
    while(Serial.available() == 0); // Wait until something is avalible
    c = Serial.read();

    if (c == g_network_sig[pos])
    {
      if (pos == NETWORK_SIG_SIZE-1)
      {
        byte checksum;

        while(Serial.available() < VAL_SIZE + CHECKSUM_SIZE); // Wait until something is avalible
        val      =  Serial.read();
        val      += ((unsigned int)Serial.read())*256;
        checksum =  Serial.read();
       
        if (checksum != ((val/256) ^ (val&0xFF)))
        {
          // Checksum failed
          pos = -1;
        }
      }
      ++pos;
    }
    else if (c == g_network_sig[0])
    {
      pos = 1;
    }
    else
    {
      pos = 0;
      if (!wait)
      {
        return 0xFFFF;
      }
    }
  }
  return val;
}

Comunicação entre 2 Arduinos por Rádio (II)

Software de Transmissão para Comunicação entre 2 Arduinos por Rádio

Este é o software de transmissão, que utiliza em parte as rotinas desenvolvidas por Maurice Ribble (30/08/2009), disponíveis em http://www.glacialwanderer.com/hobbyrobotics.

/*
Projeto:
   Transmissão de dados por RF entre duas placas Arduino

Objetivos:
   Experimentar a transmissão de dados por RF entre duas placas Arduino
   Experimentar os módulos de transmissão e recepção de RF
   Estabelecer os fundamentos para futuras experiências envolvendo controle remoto
  
Componentes:
   2 Placas Arduino Duemilanove com ATmega328
   1 módulo transmissor de RF de 315 MHz
   1 módulo receptor de RF de 315 MHz

Autor: Karl Heinz Benz
Data: 23/12/2010
Correções, sugestões e nova documentação devem ser enviadas a karlbenz@terra.com.br
Licenciamento: Atribuição-Uso não-comercial-Compartilhamento pela mesma licença 3.0 Brasil
http://creativecommons.org/licenses/by-nc-sa/3.0/br/

Utilização do pacote de software desenvolvido por:
   Maurice Ribble
   30/08/2009
   http://www.glacialwanderer.com/hobbyrobotics
*/

// Módulo de TRANSMISSÃO

#define NETWORK_SIG_SIZE 3

#define VAL_SIZE         2
#define CHECKSUM_SIZE    1
#define PACKET_SIZE      (NETWORK_SIG_SIZE + VAL_SIZE + CHECKSUM_SIZE)

// The network address byte and can be change if you want to run different devices in proximity to each other without interfearance
#define NET_ADDR 5

void setup()
{
  Serial.begin(1200);  // Hardware suporta até 2400, mas 1200 fornece maior alcance.
}

int sensorPin = A0;    // Entrada conectada ao pino central do potenciômetro
int sensorValue = 0;

void loop()
{

  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);   
  writeUInt(sensorValue); // Put any number you want to send here
  delay(100); // Debounce button
}

const byte g_network_sig[NETWORK_SIG_SIZE] = {0x8F, 0xAA, NET_ADDR};  // Few bytes used to initiate a transfer

// Sends a word over the RF network
void writeUInt(word val)
{
  byte checksum = (val/256) ^ (val&0xFF);
  Serial.write(0xF0);  // This gets reciever in sync with transmitter
  Serial.write(g_network_sig, NETWORK_SIG_SIZE);
  Serial.write((byte*)&val, VAL_SIZE);
  Serial.write(checksum); //CHECKSUM_SIZE
}

sexta-feira, 17 de dezembro de 2010

Comunicação entre 2 Arduinos por Rádio (I)

Você construiu aquele carrinho com dois motores controlados por um Arduino (ou por qualquer outro controlador, não vamos limitar o mundo ao Arduino) acoplado a um joystick. Tudo funciona bem, os motores aceleram e desaceleram, virando a haste do joystick para a esquerda o motor esquerdo diminui a rotação, e assim por diante. Aí você faz o carrinho andar sobre a mesa, prá frente e prá trás, e se dá conta do óbvio: a abominável fiapeira que une o carrinho ao Arduino, à fonte de alimentação, ao joystick. Qual a solução? Claro, dois Arduinos - um servindo como interface com o mundo externo (joystick, potenciômetros, chaves e outros dispositivos de controle) e o outro com a função de controlar os motores e outros atuadores do tal carrinho - e os dois Arduinos, claro, conectados por alguma comunicação sem fio.

Complicado? Não, muito simples e barato. Pode-se utilizar dois módulos XBee, mas o preço seria inconveniente e não há necessidade de uma tecnologia tão sofisticada. A alternativa (disponível no mercado nacional) é o uso de Módulos de RF de 315 MHz - um módulo é transmissor e o outro é receptor. A comunicação é unidirecional, não havendo, portanto, a possibilidade de envio da informação de eventuais sensores localizados no carro robótico para a placa de interface com o mundo externo. Futuramente abordarei a transmissão bidirecional.

Na foto, o módulo pequeno é o transmissor e o módulo maior é o receptor. Mais dados técnicos no site da Sparkfun. Existem diversos fabricantes e diversos revendedores no Brasil. Também exitem módulos que operam em outras freqüências, como 299, 418 e 433.92 MHz. O preço? Quase todos os módulos custam cerca de R$ 8,00 cada.

As características principais desta solução são:
  • Comunicação em um único sentido;
  • Alcance máximo de cerca de 150 metros;
  • Preço baixíssimo;
  • Grande geração de ruído, que necessita de um filtro (de software) para funcionar de forma conveniente;
  • Velocidade de transmissão: 2400 bps (embora alguns módulos funcionem a 4800 bps).
Há diversos artigos abordando esta solução:
Projeto
A proposta deste projeto é simples: um Arduino deve transmitir a outro o valor obtido a partir da leitura de um potenciômetro (de 0 a 1023).

O diagrama esquemático do transmissor é:

Já o receptor está abaixo representado:

    quarta-feira, 15 de dezembro de 2010

    Mais portas para o Arduino

    À primeira vista, um Arduino Duemilanove ou Uno (chip ATmega328) tem uma infinidade de portas: 6 entradas analógicas e 14 entradas/saídas digitais, das quais 6 podem ser saídas PWM, o que parece suficiente para a maioria das aplicações imagináveis. Muitas vezes, no entanto, sentiremos falta de alguma entrada analógica a mais - como no caso de haver necessidade de conectar 8 potenciômetros ou sinais analógicos quaisquer - ou de alguma entrada digital - por exemplo, se precisarmos conectar um LCD (que utiliza 6 pinos digitais) e mais um monte de chaves liga-desliga; por fim, haverá situações em que necessitaremos de alguma(s) entrada(s) analógica(s) e de alguma(s) entrada(s)/saída(s) digital(is) a mais.

    Existem 2 soluções: o uso de outro processador, como o Arduino Mega, que utiliza o chip ATmega2560, com 16 pinos de entrada analógica e 54 entradas/saídas digitais (dos quais 14 podem ser saídas PWM). É uma alternativa tecnicamente correta, mas bastante mais cara.

    E existe a alternativa mais barata, mas que envolve um pouco mais de esforço no projeto: o uso de multiplexadores. Um multiplexador é um circuito combinacional com várias entradas e uma única saída, mais um conjunto de entradas de controle que permitem selecionar qual entrada é conectada diretamente à saída. Um multiplexador pode ser digital (lida somente com sinais digitais, como o 74LS151) e analógico (os sinais de entrada e o de saída possuem níveis analógicos, mas os pinos de seleção são digitais), como o CD4051.

    Por exemplo, no multiplexador digital de 8 bits citado - o 74LS151, temos 8 entradas digitais (valores binários 0 ou 1) e somente uma saída digital; exitem 3 pinos de seleção (porque 2 na potência 3 = 8).

    Assim como existem multiplexadores, também existem os demultiplexadores (digitais e analógicos), com uma entrada única e diversas saídas, e que igualmente contam com um circuito de controle que seleciona qual entrada é conectada à saída. Para maiores esclarecimentos, consulte a Wikipedia.

    O Playground do Arduino possui uma solução interessante para conectar 8 sinais analógicos (no caso, potenciômetros) a uma única entrada analógica do Arduino, com a utilização de um chip 4051 (multiplexador analógico de 8 canais). No caso, são utilizados 3 pinos digitais do ATmega328 para selecionar qual das 8 entradas será conectada à saída do multiplexador, e portanto a uma entrada analógica do próprio microcontrolador. Também há um circuito que ilustra a utilização de um multiplexador digital, no caso o 74LS151.

    Em todos os casos, o microcontrolador deve fazer uma varredura (normalmente seqüencial) em todas as portas, lendo o valor que consta na saída do multiplexador e, obviamente, "sabendo" qual circuito está sendo lido naquele instante.

    À medida que mais e mais portas vão sendo conectadas aos multiplexadores, também necessitaremos de mais saídas lógicas para selecionar cada porta individualmente, o que poderá trazer novo problema - a falta de disponibilidade de portas digitais.

    Uma alternativa é a utilização de um contador hexadecimal (por exemplo, o 74LS93) para selecionar uma porta do multiplexador. Neste caso, bastará 1 (uma) saída digital para incrementar o contador.


    Se quisermos sofisticar um pouco, poderemos acrescentar mais uma saída para ressetar o contador, e eventualmente uma terceira para decrementar (neste caso, teríamos de utilizar um contador bidirecional, como o 74LS193, que ainda possui outros recursos - por exemplo, pode ser carregado com um valor inicial).

    terça-feira, 14 de dezembro de 2010

    Robôs x Computadores (Final)

    Este artigo é, em parte, baseado no livro Robot Programming - A Practical Guide to Behavoir-Based Robotics, de Joseph L. Jones (embora não seja mera tradução).

    Planos x Oportunidades
    Um programa de computador, tipicamente, executa um plano: as coisas acontecem em uma seqüência pré-definida, as interações com o ambiente são determinísticas, as informações fornecidas pelo usuário pertencem a domínios claramente limitados. Os resultados são previsíveis, e (mediante um certo esforço) todas as situações de erro podem ser previstas e devidamente tratadas.

    Já um robô ("dispositivo eletromecânico ou biomecânico, que conecta sensores a atuadores de uma maneira inteligente, dotado de alguma forma de movimento e responsável por executar alguma tarefa controlada") necessita ser oportunista. Por exemplo, se a bateria do robô estiver com pouca carga, ele deverá dirigir-se de volta à sua base para recarregá-la. Se, no entanto, ele estiver trabalhando próximo à base e ainda restar uma tarefa a realizar, ele poderá postergar a recarga. Um algoritmo pouco flexível poderá obrigar o robô a realizar muitos deslocamentos desnecessários de volta à base, gastando sua preciosa energia justamente na recarga da mesma. Já um algoritmo mais evoluído poderá fornecer ao mesmo robô mais autonomia e fazer com que o mesmo dispenda menos tempo nos procedimentos de recarga.

    Degradação Elegante
    Como já dito anteriormente, um bom programa de computador, utilizado corretamente e com os dados adequados, sempre exibirá resultados corretos e adequados. Um computador corretamente utilizado tem um comportamento tipicamente previsível e determinístico.

    Um robô depende de componentes mecânicos, elétricos, hidráulicos. Um robô convive com o mundo físico, poeira, água, tombos, calor e frio, e assim por diante. Sensores não são plenamente confiáveis, motores não dão respostas plenamente confiáveis, e o processamento das informações provenientes de inúmeros sensores não confiáveis, por vezes transmitindo informações contraditórias, nos leva inevitavelmente a resultados incertos e não determinísticos. Em função desta realidade complexa, o programa de controle de um robô precisa ser capaz de uma "degradação elegante" na presença de sensores defeituosos e erráticos - basicamente, um robô não pode simplesmente bloquear e emitir uma enigmática mensagem de erro, e esperar que "alguém faça alguma coisa", mas precisa ter um comportamento que ainda lhe permita manter o seu próprio controle.