terça-feira, 11 de novembro de 2014

Octopus Soil Moisture Sensor Brick


An important variable to be monitored and controlled in your garden is the soil moisture level. I decided to use the Octopus Soil Moisture Sensor Brick, that can be found at http://www.elecfreaks.com/ for about U$ 5,00.


Octopus Soil Moisture Sensor Brick - Image Source www.elecfreaks.com

I have a very strict control over soil moisture in the environment of the test, and after 36 hours of usage, the data acquired was not reflecting reality, as shown at the graphic below:


Only five days after installed the data dropped to 0, and the sensor was completly wasted:



The problem was related to the sensor waste:



I do not recomend the usage of this sensor in continuous mode. A very good article (in Portuguese), that show how you can build your own soil moisture sensor, can be found at https://ncaio.wordpress.com/

segunda-feira, 10 de novembro de 2014

Creating a digital filter - Smoothing analog input values

If you wanna eliminate noise from your analog inputs, or have smooth variation in reads, you can implement a digital filter following this example:

 int ldrSensor = 2;  
 float rawValue = 0;  
 float withFilter = 0;  
 float variation = 0;  
 float smoothCoeficient = 0.1;  
 void setup()  
 {  
  Serial.begin(9600);  
  rawValue = analogRead(ldrSensor);  
  withFilter = rawValue;  
 }  
 void loop()  
 {  
  rawValue = analogRead(ldrSensor);  
  variation = rawValue - withFilter ;  
  withFilter = withFilter + variation * smoothCoeficient ;  
  Serial.print(int(rawValue));  
  Serial.print(" ");  
  Serial.println(int(withFilter));  
 delay(50);  
 }  

If you set lower smoothCoeficient value, slower will be the changes in your filtered values.

Data output example:

 656 656  
 656 656  
 657 656  
 657 656  
 656 656  
 657 656  
 657 656  
 656 656  
 656 656  
 657 656  
 656 656  
 657 656  
 656 656  
 657 656  

When you have a smoothCoeficient of 0.1, means that only 10% of the last variation will be inserted into filtered value. You may need to change this value to fit your needs.

Making your arduino sketch support multiple languages

So you have an LCD attached to your arduino, and want to support multiple languages?

Let me show you how i solved this problem:

Inside your library folder, create a folder called languages. Inside this folder, save the file below as languages.h

 typedef enum Language  
 {  
    pt_br,  
    en_en  
 };  
 typedef enum Sentences  
 {  
    HELLO,  
    GOODBYE  
 };  

And the following code as languages.c

 char* pt_br[] = {"Olá","Tchau"};  
 char* en_en[] = {"Hello","Goodbye"};  
 char** languages[2] = {pt_br,en_en};  

This code shows you how to use the library


 #include <languages.h>  
 Language current_language;  
 extern char** languages[2];  
 void setup()   
 {  
  Serial.begin(9600);  
  current_language=pt_br; //pt_br, en_en  
 }  
 void loop()   
 {  
  Serial.println(languages[current_language][HELLO]);  
  Serial.println(languages[current_language][GOODBYE]);  
  if (current_language == pt_br)  
  {  
   current_language = en_en;  
  }  
  else  
  {  
   current_language = pt_br;  
  }  
  delay(1000);  
 }  

Let me know if you have suggestions on how to improve this.


terça-feira, 7 de outubro de 2014

Identificando a porta serial em que o Arduino está conectado (Linux/Python)

Uma boa maneira de se comunicar com o Arduino é utilizar a interface serial (USB) que acompanha alguns modelos. A vantagem, se comparado com shields de comunicação sem fio ou ethernet, é que não é necessário comprar nenhum módulo adicional. A desvantagem é que você precisará ter um computador próximo (limite de 3 metros do padrão USB). Uma outra desvantagem, é que toda vez que se conectar, o Arduino irá reiniciar. Dependendo da aplicação, é recomendável fazer um Daemon que se conecte apenas uma vez.

Se você deseja escrever um script para se conectar ao Arduino, um problema frequente é que o nome da porta serial pode se alterar com eventuais reinícios do dispositivo.

Adaptei o código, a partir de um post que encontrei no stackoverflow.com. O código postado lá é genérico, e pode ser utilizado para vários sistemas operacionais.

O código abaixo irá se conectar à primeira porta /dev/ttyACM encontrada.


 #! /usr/bin/python  
 import serial  
 import time  
 import re  
 import os,sys  
 import glob  
 import serial  
 def serial_port():  
   #http://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python  
   if sys.platform.startswith('win'):  
     ports = ['COM' + str(i + 1) for i in range(256)]  
   elif sys.platform.startswith('linux'):  
     ports = glob.glob('/dev/tty[A-Za-z]*')  
   elif sys.platform.startswith('darwin'):  
     ports = glob.glob('/dev/tty.*')  
   else:  
     raise EnvironmentError('Plataforma nao suportada')  
   result = ""  
   for port in ports:  
     try:  
       s = serial.Serial(port)  
       s.close()  
       prog = re.compile('^/dev/ttyACM[0-9]')  
       if prog.match(port):  
         return port  
     except (OSError, serial.SerialException):  
       pass  
 ser = serial.Serial(serial_port(), 9600, timeout=1)  
 print "Conectado a " + serial_port()  

sexta-feira, 29 de agosto de 2014

Aferição de um relógio antigo utilizando Arduino

Como postagem inicial deste despretencioso blog, apresento um projeto para regular e aferir um antigo relógio analógico de pêndulo. Da marca brasileira DIMEP, ele é do modelo "500 dias", mas sem o calendário de dia do mês e da semana que havia em alguns outros que também levaram este nome. Encontrei uma referência indicando que o nome é relativo ao tempo de duração da bateria. Existe também uma variação "TAGUS 500 dias", o qual leva estampado em seu mostrador um pitoresco mapa mundi com o polo sul ao centro, utilizado para facilitar a verificação de diferença entre fusos horários.


Relógio DIMEP Tagus 500 dias
Relógio DIMEP 500 dias com o qual executamos o projeto
 O relógio apresentava problemas e passou por uma manutenção. Após o procedimento, desejava verificar com que precisão estava funcionando, e também regular pois o período do braço pode ser alterado através de uma peça rosqueável (rating nut) que fica na ponta do pêndulo. Durante uma semana, percebi que ele adiantou aproximadamente 10 minutos, entretanto qualquer alteração, demandaria mais um grande intervalo para perceber o resultado.

Minha primeira dúvida neste projeto, era sobre a confiabilidade do arduino para medir um intervalo de tempo em milisegundos. Escrevi um pequeno sketch que apenas contabilizava o tempo de um delay(1000) e imprimia o resultado na tela. Este método pode ser questionado pois tanto para gerar o delay quanto para fazer a medição estou utilizando a mesma função millis(), ou seja, o resultado deveria ser sempre o mesmo, certo? Eu também pensei que sim... Este teste pode ser feito apenas com a placa do arduino, sem utilizar nenhum componente ligado a ela. Abaixo o código utilizado para medir o tempo.


 unsigned long inicio,fim,duracao;   
 void setup()  
 {  
  Serial.begin(9600);  
 }   
 void loop()  
 {  
  inicio=millis();  
  delay(1000);  
  fim=millis();  
  duracao=fim-inicio;  
  Serial.println(duracao);  
 }  

O resultado para 30 segundos foi:

6 amostras com 999 ms
8 amostras com 1001 ms
16 amostras com 1000 ms
Média de 1000,066 ms

A conclusão é que para uma leitura individual, pode haver erro de um ms para mais ou para menos, mas na média o erro está abaixo do décimo de milésimo (talvez bem mais abaixo se considerarmos uma amostragem maior). Algum especialista no assunto consegue explicar esta flutuação nas leituras do delay()? 

O projeto foi realizado utilizando:

- 1 Arduino Mega 2560 Rev 3.
- 1 resistor de um megaohm (1MΩ).
- 1 sensor piezoelétrico
Esquema de fiação do arduino:


Esquema de fiação no fritzing

Utilizei uma fita adesiva para posicionar o sensor no final do curso do pêndulo, de maneira que houvesse apenas um toque muito leve (veja na figura abaixo).



Ao analisar os dados gerados pelo sensor (ver figura abaixo), o eixo X representa uma amostra a cada 2 ms, e o eixo Y a pressão sobre o sensor, observei que a contabilização do tempo deveria ser apenas entre os primeiros toques no sensor, e os seguintes já deveriam ser considerados como intervalo do pêndulo. Ao pressionar o sensor entre os dedos, você facilmente faz ele chegar até 1024, ou seja, o valor 15 apresentado no gráfico, é um toque muito leve.





Código para medição do intervalo:


 const int kSensor = A1; //pino em que esta conectado o sensor  
 const int threshold = 500; //limite para desconsiderar os valores, apos o primeiro toque  
 int sensorReading = 0;  
 int count = 0;   
 unsigned long start, finished, elapsed, avg, total;  
 void setup()  
 {  
  Serial.begin(9600);  
  total=0;  
 }  
 void loop()  
 {  
  sensorReading = analogRead(kSensor);  
  start = millis();  
  elapsed=start-finished;   
  if ((sensorReading != 0) and (elapsed >threshold))  
  {  
     count = count + 1;  
     start = millis();  
     elapsed=start-finished;      
     total = total + elapsed;  
     avg = total / count;  
     finished = millis();  
     Serial.print("Ultimo: ");   
     Serial.print(elapsed);  
     Serial.print(" Media: ");      
     Serial.print(avg);  
     Serial.print(" Ticks: ");      
     Serial.print(count);  
     Serial.println();  
  }  
 }  
Resultado:



De média 996 que era anteriormente consegui mudar para 999 ms.

Reconheço que a melhor maneira seria utilizar algum sensor com o qual não houvesse  toque, para evitar interferência do sistema de medição. 

Como sugestão para um projeto futuro , fica a sugestão para utilizar um LDR e um feixe de luz, pois não haveria influência no pêndulo.
O projeto não é pioneiro, encontrei um já executado aqui.


Para não perder a oportunidade de um trocadilho na conclusão, relógio que atrasa não adianta pra nada!