sábado, 25 de agosto de 2012

Novos Módulos a caminho

Esse mês de agosto fiz mais duas compras no dealextreme, dessa vez pedi alguns componentes uteis que as fezes são chatos de encontrar, e quando encontra tem um valor absurdo.
www.dealextreme.com
Conectores USB(20), foi R$5,45:

Outra compra, foi um modulo de GSM, que foi R$116,00, caro mas acho que vai valer a pena o investimento, estou com varios projetos na cabeça para utilizar ele. Dentre esse projetos um de redirecionar chamadas para diferentes chips de acordo com a operadora, mas isso é para o futuro .....


Outra coisa bem legal que comprei também foi esse pequeno modulo de recarga de baterias, pretendo usar ele no projeto do seguidor solar, e assim que receber ele olhar os componentes,que deve ser coisa bem simples e reproduzir para outros projetos.

Para o mês de Setembro já tenho minha lista de compras:

Com finalidade de elevar o nível dos projetos:

Touch Sensor colorido para projetos futuros:

Câmera VGA para microcontroladores: 

Acelerômetro de 3 eixos: 
E por ultimo modulo GPS:

Com o mudulo de GPS+Cartão SD+Acelerômetro, quero fazer o seguinte, colocar no meu carro e fazer um caminho bem comum que faço toda semana, assim vou pegar os dados do acelerômetro, a posição no GPS e salvar no cartão SD, fazer alguns gráficos e mostrar o quanto horrível são as ruas de BH.







quarta-feira, 22 de agosto de 2012

Reiniciando computador remotamente

Esse poste é uma atualização do Arduino com Ethernet Shield lendo Twitter
O projeto sofreu varias modificações, num total de 8 versões do script para chegar em uma versão beta, esta em fase de testes, estou deixando rodar 24/7, quero que fique a prova de falhas, que rode meses sem parar mesmo que algum erro ocorra, para isso tive que ir modificando com calma e testando.

Eu tentei adicionar suporte a captura de logs pelo cartão SD, essa placa de ethernet possui entrada para cartão, mas infelizmente ele compartilha o mesmo canal de comunicação com o microcontrolador(SPI), então para utilizar o ethernet em conjunto com o cartão SD, eu teria que desligar e ligar via software cada um antes de utilizar, por exemplo para gravar uma informação no cartão SD, teria que desligar a comunicação ethernet, e ligar a do cartão, logo depois de gravar os dados, desligar o cartão SD e ligar a ethernet, e assim suscetivamente. Isso causa muitas falhas por problemas de delay e perda de informação. A melhor solução que achei foi utilizar o software RealTerm, que comunica com a porta serial e salva os logs em um arquivo txt no computador, e uma coisa boa desses logs é que vem com data e horário atualizados pelo computador, usando o cartão SD teríamos que utilizar outro modulo de relógio em tempo real RTC.

Alem de fazer os logs foi implementando em conjunto com o client de leitura de twitter, um client servidor de webpage http, esse cliente mostrava as informações atuais em relação ao funcionamento do circuito, mas infelizmente comprometia boa parte da memoria do microcontrolador, alem de aumentar consideravelmente o numero de falhas do programa.

Uma outra ideia implementada foi a seguinte, anteriormente o IP era fixo, você gravava ele no código, e ele funcionaria com aquele IP para sempre, o problema é que entrando em outras redes a configuração de distribuição de IP pode ser diferente, assim o programa não consegue pegar um IP valido e comunicar com a rede. A solução foi a seguinte, o script agora tem cadastrados IP, gatway,subnet e MAC, ao iniciar o código ele utiliza apenas o código MAC e tenta pegar o resto das informações via DHCP, assim quem fornece o IP é o modem/roteador/switch que controla a rede, com posse desse IP vem uma coisa bem legal, que demorou uma semana para implementar mas que valeu a pena. Sempre ao ligar o circuito ele pega um IP e envia pelo twitter, isso mesmo alem de ler o twitter toda vez ao iniciar ele envia o IP atual que ele esta utilizando, isso se torna muito útil, caso no futuro com tempo implemente o servidor webhttp para rodar no Arduino ou para qualquer aplicação remota.

Com essas modificações feitas, passamos para faze de testes, com vários códigos de debug.
No final cheguei a uma versão que esta rodando a 2 dias e estou acompanhando, fazendo diferentes tipos de conexão via ponte de rede/roteador.

Esse é o código final vou entrar um pouco em detalhes:


/*
  Twitter Client

 Esse sketch conecta ao Twitter usando um Ethernet shield. Ele vasculha o XML
 retornado, e procura por <text>esse é um tweet</text>

 O Twitter a ser lido não pode ter nenhum dado anterior postado(pode ser preferencial
 mente deixado status como ultimo post), lembrando que sempre ao executar um comando,
 deletar logo apos. Se o circuito for ligado e ter dado antigo ele vai executar, mas
 se ja estiver ligado e possuir dado que não foi apagado ele não vai executar nenhuma
 ação.

 Ideal que o circuito fique conectado direto a um switch ou modem, em conexão de ponde
 de rede pode ter perdas de sinal

 **ATENÇÃO**
O pedido de leitura de tweets NÃO pode exceder 150 por hora
para chegar: http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=remopte
<error>
Rate limit exceeded. Clients may not make more than 150 requests per hour.
</error>

 Circuito:
 * Ethernet shield ligado nos pinos 10, 11, 12, 13

por Vinicius R.
VRO Projetos
viniciusro@gmail.com
*/

#include <SPI.h>
#include <Ethernet.h>
#include <Twitter.h>
Twitter twitter("770703602-72ou4uHkg6Qefg622WdQKAXkN7s35f5QCLJrqYTO");

byte mac[] ={0xDE,0xAD,0xBF,0xEF,0xFE,0xED};
byte ip[] ={192,168,0,15};
byte gateway[] ={192,168,0,1};
byte subnet[] ={255,255,255,0};
EthernetClient client;
const unsigned long tempoRefrescamento = 60000;
char nomeServidor[] = "api.twitter.com";
boolean pedidos;
unsigned long tempoUltimaTentativa = 0;          
String  linhaAtual = "";            
String  tweet = "";                
String  tweetAnterior = "";
boolean lendoTweet = false;  
const int reiniciar_XXX = 8;
const int reiniciar_YYY = 7;

union IPAddressConverter
{
  uint32_t ipInteger;
  uint8_t  ipArray[4];
};

void setup()
{
  pinMode(reiniciar_XXX, OUTPUT);
  pinMode(reiniciar_YYY, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(4, OUTPUT);
  digitalWrite(4,LOW);
  linhaAtual.reserve(256);
  tweet.reserve(150);
  Serial.begin(9600);
  Serial.println("Tentando pegar um IP usando DHCP:");
  if (!Ethernet.begin(mac))
    {
     Ethernet.begin(mac,ip,gateway,subnet);
    }
  Serial.print("Meu IP:");
  Serial.println(Ethernet.localIP());
  enviaIP();
  conectandoServidor();
}

void loop()
{
  if (client.connected())
  {
    if (client.available())
    {
      char inChar = client.read();
      linhaAtual += inChar;
      if (inChar == '\n')
      {
        linhaAtual = "";
      }
      if (linhaAtual.endsWith("<text>"))
      {
        lendoTweet = true;
        tweet = "";
      }
      if (lendoTweet)
      {
        if (inChar != '<')
        {
          tweet += inChar;
        }
        else
          {
          lendoTweet = false;
          Serial.println(tweet);
          Serial.print("Tweet anterior: ");
          Serial.println(tweetAnterior);
          while(tweet==tweetAnterior)
            {
              break;
            }    
            if(tweet==">reiniciar .XXX" && tweetAnterior!=tweet)
             {
               Serial.println("Reiniciando computador .XXX");
               digitalWrite(reiniciar_XXX, LOW);
               delay(1000);
               digitalWrite(reiniciar_XXX, HIGH);
               delay(1000);
               digitalWrite(reiniciar_XXX, LOW);
             }
           if(tweet==">reiniciar .YYY" && tweetAnterior!=tweet)
             {
               Serial.println("Reiniciando computador .YYY");
               digitalWrite(reiniciar_YYY, LOW);
               delay(1000);
               digitalWrite(reiniciar_YYY, HIGH);
               delay(1000);
               digitalWrite(reiniciar_YYY, LOW);
             }      
          Serial.println("");
          tweetAnterior=tweet;
          client.stop();  
          client.flush();
        }
      }
    }
  }
  else if (millis() - tempoUltimaTentativa > tempoRefrescamento)
  {
    Serial.print("Tempo de funcionamento total: ");
    Serial.print((millis()/1000)/60);
    Serial.println(" minutos");
    Serial.print("Ultima tentativa de conectar: ");
    Serial.print((tempoUltimaTentativa/1000)/60);
    Serial.println(" minutos");
    conectandoServidor();
  }
}

void conectandoServidor()
{
  Serial.println("conectando no servidor...");
  if (client.connect(nomeServidor, 80))
  {
    Serial.println("fazendo pedido de HTTP...");
    client.println("GET /1/statuses/user_timeline.xml?screen_name=remopte&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
    delay(500);
  }
   else
   {
    Serial.println("falhou ao conectar");
    client.stop();  
    delay(500);
    client.flush();
   }
  Serial.println("");
  tempoUltimaTentativa = millis();
}

void enviaIP()
{
  Serial.println("");
  Serial.println("Enviando IP atual no tweeter");
  IPAddressConverter ipAddress;
  ipAddress.ipInteger = Ethernet.localIP();
  char buf[16];
  sprintf(buf, "%d.%d.%d.%d", ipAddress.ipArray[0], ipAddress.ipArray[1], ipAddress.ipArray[2], ipAddress.ipArray[3]);
  twitter.post(buf);
  delay(5000);
  client.stop();
  client.flush();
}
A primeira coisa é conseguir um IP valido, para isso usamos  if (!Ethernet.begin(mac)) , caso não consigo um IP por DHCP, ele vai utilizar o cadastrado no código.

A função union IPAddressConverter  é para converter o formato de IP que vem em uint32_t pela função  Ethernet.localIP() em um array que em seguida é convertido para char, assim é postado no twitter utilizando a função enviaIP().

Depois que o IP é enviado o script passa a fazer leitura da rss feed do twitter em XML, vai sempre ler o ultimo IP e ver se existem alguma ação cadastrada para executar, caso não exista ele fica rodando 24/7.

Esse é o funcionamento básico, adquire IP,envia no twitter, faz leitura do twitter com tempo de refrescamento de 60 segundos e executa ação caso for cadastrada e o twitter anterior seja diferente do novo, para proteger contra eventuais erros.

Assim que aparece no terminal serial:

Tempo de funcionamento total: 948 minutos                                       
Ultima tentativa de conectar: 947 minutos                                       
conectando no servidor...                                                       
fazendo pedido de HTTP...                                                       
                                                                                
>Tweet Remote Control                                                           
Tweet anterior: >Tweet Remote Control  

Vale lembrar que para enviar o IP no twitter temos que usar a biblioteca twitter.h e cadastrar um token para o aplicativo ter acesso a sua conta de twitter.

Vou deixar em anexo também o código que quero trabalhar mais com tempo, ele possui implantado o servidor web para visualizar as informações em tempo real, mas ainda possui falhas.

/*
  Twitter Client

 Esse sketch conecta ao Twitter usando um Ethernet shield. Ele vasculha o XML
 retornado, e procura por <text>esse é um tweet</text>

 O Twitter a ser lido não pode ter nenhum dado anterior postado(pode ser preferencial
 mente deixado status como ultimo post), lembrando que sempre ao executar um comando,
 deletar logo apos. Se o circuito for ligado e ter dado antigo ele vai executar, mas 
 se ja estiver ligado e possuir dado que não foi apagado ele não vai executar nenhuma 
 ação.
 Ideal que o circuito fique conectado direto a um switch ou modem, em conexão de ponde
 de rede pode ter perdas de sinal
 **ATENÇÃO**
O pedido de leitura de tweets NÃO pode exceder 150 por hora 
para chegar: http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=remopte
<error>
Rate limit exceeded. Clients may not make more than 150 requests per hour.
</error>

 Circuito:
 * Ethernet shield ligado nos pinos 10, 11, 12, 13

por Vinicius R.
VRO Projetos
viniciusro@gmail.com

 Esse codigo é de dominio publico.

*/

#include <SPI.h>
#include <Ethernet.h>
#include <Twitter.h>
Twitter twitter("770703602-72ou4uHkg6Qefg622WdQKAXkN7s35f5QCLJrqYTO");

byte mac[] ={0xDE,0xAD,0xBF,0xEF,0xFE,0xED}; 
byte ip[] ={192,168,0,15};
byte gateway[] ={192,168,0,1};
byte subnet[] ={255,255,255,0};
EthernetServer server(80);
EthernetClient client;
const unsigned long tempoRefrescamento = 60000;  
char nomeServidor[] = "api.twitter.com";  
boolean pedidos; 
unsigned long tempoUltimaTentativa = 0;            
String  linhaAtual = "";              
String  tweet = "";                  
String  tweetAnterior = "";
boolean lendoTweet = false;    
const int reiniciar_XXX = 8;
const int reiniciar_YYY = 7;

union IPAddressConverter 
{
  uint32_t ipInteger;
  uint8_t  ipArray[4];
};

void setup() 
{
  pinMode(reiniciar_XXX, OUTPUT);
  pinMode(reiniciar_YYY, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(4, OUTPUT);
  digitalWrite(4,LOW);
  linhaAtual.reserve(256);
  tweet.reserve(150);
  Serial.begin(9600);
  Serial.println("Tentando pegar um IP usando DHCP:");
  if (!Ethernet.begin(mac)) 
    {
     Ethernet.begin(mac,ip,gateway,subnet);
    }
  Serial.print("Meu IP:");
  Serial.println(Ethernet.localIP());
  enviaIP();
  server.begin();
  conectandoServidor(); 
}

void loop()
{  
  paginaStatus();
  if (client.connected()) 
  {
    if (client.available()) 
    {
      char inChar = client.read();
      linhaAtual += inChar; 
      if (inChar == '\n') 
      {
        linhaAtual = "";
      } 
      if (linhaAtual.endsWith("<text>")) 
      {
        lendoTweet = true; 
        tweet = "";
      }
      if (lendoTweet) 
      {
        if (inChar != '<') 
        {
          tweet += inChar;
        } 
        else 
          {
          lendoTweet = false;
          Serial.println(tweet);  
          Serial.print("Tweet anterior: ");
          Serial.println(tweetAnterior);
          while(tweet==tweetAnterior)
            {
              break;
            }      
            if(tweet==">reiniciar .XXX" && tweetAnterior!=tweet)
             {
               Serial.println("Reiniciando computador .XXX");
               digitalWrite(reiniciar_XXX, LOW);
               delay(1000);
               digitalWrite(reiniciar_XXX, HIGH);
               delay(1000);
               digitalWrite(reiniciar_XXX, LOW);
             } 
           if(tweet==">reiniciar .YYY" && tweetAnterior!=tweet)
             {
               Serial.println("Reiniciando computador .YYY");
               digitalWrite(reiniciar_YYY, LOW);
               delay(1000);
               digitalWrite(reiniciar_YYY, HIGH);
               delay(1000);
               digitalWrite(reiniciar_YYY, LOW);
             }        
          Serial.println("");
          tweetAnterior=tweet;
          client.stop();    
          client.flush();
        }
      }
    }   
  }
  else if (millis() - tempoUltimaTentativa > tempoRefrescamento) 
  {
    Serial.print("Tempo de funcionamento total: ");
    Serial.print((millis()/1000)/60);
    Serial.println(" minutos");
    Serial.print("Ultima tentativa de conectar: ");
    Serial.print((tempoUltimaTentativa/1000)/60);
    Serial.println(" minutos");
    conectandoServidor();
  }
}
void conectandoServidor() 
{
  Serial.println("conectando no servidor...");
  if (client.connect(nomeServidor, 80)) 
  {
    Serial.println("fazendo pedido de HTTP...");
    client.println("GET /1/statuses/user_timeline.xml?screen_name=remopte&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
    delay(500);
  }
   else 
   {
    Serial.println("falhou ao conectar");
    client.stop();    
    delay(500);
    client.flush();
   }
  Serial.println("");
  tempoUltimaTentativa = millis();
}

void paginaStatus()
{
  delay(30);
  {
  EthernetClient client = server.available();
  if (client) 
    {
    boolean linhaAtualEmBranco = true;
    while (client.connected()) 
      {
       if (client.available()) 
         {
          char c = client.read();
          if (c == '\n' && linhaAtualEmBranco) 
            {
              client.println("HTTP/1.1 200 OK");
              client.println("Content-Type: text/html");
              client.println();
    
              client.println("<HTML>");
              client.println("<HEAD>");
              client.println("<TITLE>RemOpt - Remote</TITLE>");
              client.println("</HEAD>");
              client.println("<BODY>");
              client.println("<center>");
              client.println("<H1>RemOpt - Controle Remoto </H1>");
              client.println("</center>");
              
              client.println("<H4>Configuracao Atual:</H4>");
              client.println("Tempo de funcionamento:");
              long tempo=((millis()/1000)/60);
              client.println(tempo);
              client.println(" minuto(s)");
              
              client.println("<br>");
              client.println("Ultima tentativa de conectar: ");
              client.println((tempoUltimaTentativa/1000)/59);
              client.println(" minuto(s)");
              
              client.println("<br>");
              client.println("Meu IP: ");
              client.print(Ethernet.localIP());
              
              client.println("<br><br>");
              client.println("Ultimo Tweet: ");
              client.println(tweet);
              client.println("<br><br>");
              
              client.println("<meta http-equiv=\"refresh\" content=\"30\">");
    
          client.println("</BODY>");
          client.println("</HTML>");
          break;
            }
        if (c == '\n') 
          {
          linhaAtualEmBranco = true;
          } 
        else if (c != '\r') 
          {
          linhaAtualEmBranco = false;
          }
       }
    }
    delay(5);
    client.stop();
    }
  }
}

void enviaIP()
{
  Serial.println("");
  Serial.println("Enviando IP atual no tweeter");
  IPAddressConverter ipAddress;
  ipAddress.ipInteger = Ethernet.localIP();
  char buf[16];
  sprintf(buf, "%d.%d.%d.%d", ipAddress.ipArray[0], ipAddress.ipArray[1], ipAddress.ipArray[2], ipAddress.ipArray[3]);
  twitter.post(buf);
  delay(5000);
}

Para criar seu Token e baixar as bibliotecas entre em: http://arduino-tweet.appspot.com/


quarta-feira, 1 de agosto de 2012

Arduino Alimentando Painel Solar - Rev 2

Então dando uma continuidade e finalizando o mini projeto de do Arduino sendo Alimentado por um Painel Solar.Vou implementar no LabView a leitura dos dados em tempo real das variáveis e um banco de capacitores para manter o funcionamento mais linear, assim como dessa vez alimentar o bluetooth e o Arduino com a mesma fonte, o painel solar.

A partir do projeto original fiz algumas alterações,além de mostrar o tempo total em que a aplicação está rodando, temos o valor de tensão de entrada do painel solar, assim como valor de tensão no banco de capacitores. Adicionei essas leituras analógicas e utilizei o quebrador de String para enviar esses dados para o LabView processar.



Script:


int Vpainel      = 0;
int Vcapacitores = 0;

void setup() 
  {
    Serial.begin(9600);
  }
  
void loop() 
  {
    unsigned long tempo_atual = millis();
    Vpainel = analogRead(A0);
    Vcapacitores = analogRead(A1);
    
    Serial.print(tempo_atual);
    Serial.print(",");
    Serial.print(Vpainel);
    Serial.print(",");
    Serial.print(Vcapacitores);
    Serial.print(",");
    Serial.println("");
    
    delay(100); 
  }


Esse é o diagrama no LabView:



Imagens do banco de capacitores:


Esse vídeo mostra o funcionamento do circuito, posteriormente eu liguei o modulo bluetooth na própria alimentação do Arduino usando também o painel solar e rodou sem problemas.