Sistema de olfato artificial com Arduino + NodeMCU

Um Sistema olfativo artificial tem uma matriz de sensores que sofrem mudança de resistência quando algum composto volátil é detectado. A informação, traduzida pelos sensores como mudanças de resistência, é adquirida para depois ser processada e, então, a amostra é classificado. O processo de funcionamento do sistema olfativo é mostrado abaixo. Uma aplicação do sistema para reconhecimento de vinhos pode ser vista aqui.

eos2

Neste post, é apresentado um sistema de aquisição de dados para sistemas de olfato artificial usando o Arduino Uno para capturar sinais de um conjunto de seis sensores de gás que compõem a matriz de sensoreamento (mais detalhes sobre sensores de gás aqui), bem como a conexão pela porta serial com o NodeMcu ESP 8266 para publicação da informação coletada dos sensores na nuvem via MQTT.

img_20161201_230055

Matriz de sensoreamento construída com sensores MQ-3, MQ-4 e MQ-6 (dois de cada)

Funcionamento

Cada um dos seis sensores de gás são conectados as portas analógicas do Arduino Uno. O Arduino foi programado para realizar o processo de coleta dos voltagens em três etapas como mostradas na figura abaixo.

diagram-page-1-1

1. Fase de concentração. Antes do início desta fase, a amostra é colocada na câmara de concentração. Ao iniciar o processo, que demora três minutos, a amostra fica na câmara fechada pelas válvulas solenóides controladas pelo Arduino. O objetivo da fase é conseguir que sejam liberados os voláteis que serão levados ate a câmara de sensoriamento na seguinte etapa 2.

2. Fase de medida. No início desta etapa o Arduino envia o valor lógico para as portas configuradas como saídas digitais encargadas de ativar os relés que governam as válvulas solenóides e a bomba de ar. Neste caso são ligadas a bomba de ar e abertas as válvulas solenoides que controlam o fluxo de voláteis na câmara de concentração e na câmara de medições. Simultaneamente, o processo de envio dos dados coletados dos seis sensores é feito pela porta serial comunicando o Arduino com o NodeMcu do qual são aproveitadas as vantagems e funcionalidades para publicar informação via MQTT. O tempo estimado nesta etapa é de dois minutos.

3. Fase de Limpeza. Precisa-se  limpar as duas câmaras (concentração e medição) para o início de um novo ciclo de medição. Para isso, a bomba injeta ar limpo nas câmaras tendo as válvulas abertas com o objetivo de ter fluxo dos gases para fora das mesmas. O tempo nesta etapa é de dois minutos.

Finalmente, o NodeMCU envia os dados recebidos pela porta serial ao broker MQTT que, por sua vez, entrega esta informação às aplicações inscritas no tópico que realizarão as tarefas de processamento e classificação ou regressão. O esquema abaixo ilustra a ligação dos principais componentes do sistema olfativo.

blank-diagram-page-1-4
Diagrama esquemático da conexão Arduino-Node Mcu

Captura de tela do aplicativo celular com os dados enviados por meio do protocolo MQTT para o aplicativo Android MQTT Dashboard para observação.

screenshot_2016-12-01-23-40-01 screenshot_2016-12-01-23-39-28

Códigos:

Os códigos para execução no Arduino e no NodeMcu estão disponibilizados a seguir.

Código usado no Node-MCU:


#code for Node MCU
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266HTTPClient.h>
#include <string.h>
extern "C"{
#include "user_interface.h"
}
const char* ssid = "Network-name"; //Wifi conection name
const char* password = "password"; //Wifi conection password
const char* mqtt_server = "mqtt(server).com"; //Url MQTT Server
const char* clientID = "nodemcu"; //ID MQTT Client
const char* topic0 = "configuration"; //Instance
const char* topic1 = "sensor1"; //Instance
const char* topic2 = "sensor2"; //Instance
const char* topic3 = "sensor3";
const char* topic4 = "sensor4";
const char* topic5 = "sensor5";
const char* topic6 = "sensor6";
const char* mqttuser = "USER"; //Instance user authorized
const char* mqttpass = "password"; //Instance password
const int port = 00000; //Number MQTT port (unencrypted)
WiFiClient TempClient;
PubSubClient mqttclient(TempClient);
const int LED = D4;
String data_received="";
char cadena[4];
void sendMQTT(char topic);
byte to_receive(void);
byte check_data;
void setup()
{
Serial.begin(38400);
pinMode(LED, OUTPUT); // Pin digital 5 como salida
//Wifi configuration
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
//MQTT configuration
mqttclient.setServer(mqtt_server, port);
mqttclient.setCallback(callback);
}
void loop()
{
if (!mqttclient.connected()) {
mqtt_connection();
}
if (Serial.available())
{
to_receive();
if (data_received=="s1")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic1, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
if (data_received=="s2")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic2, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
if (data_received=="s3")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic3, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
if (data_received=="s4")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic4, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
if (data_received=="s5")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic5, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
if (data_received=="s6")
{
check_data==LOW;
check_data=to_receive();
if (check_data==HIGH) {
mqttclient.publish(topic6, cadena);
Serial.flush();
if (check_data==HIGH) digitalWrite(LED, LED^1);
}
}
}
}
byte to_receive(void)
{
float var1;
Serial.flush();
delay(5);
data_received="";
data_received = Serial.readStringUntil('\n');
data_received.toCharArray(cadena, 4);
var1 = strtod (cadena, NULL);
if (var1>=0.0 && var1<=5.0) return HIGH;
else return LOW;
}
void mqtt_connection() {
while (!mqttclient.connected()) {
if (mqttclient.connect(clientID,mqttuser,mqttpass)) {
bool subscribe(String topic1, uint8_t qos = 0);
} else {
delay(1000);
}
}
}
//Optional, not used here
void callback(char* topic, byte* payload, unsigned int length) {
char conf[33];
for (int i=0;i<length;i++) {
conf[i]=(char)payload[i];
}
}

Código usado no Arduino:


//Serial communication between ARDUINO and/or node MCU – Program of Master
// RODRIGUEZ-GAMBOA, JUAN C. & ALBARRACIN-ESTRADA, E. SUSANA
// – E-MAIL: {juan.gamboa,eva.susana}@ufrpe.br
// Libraries
#include <string.h>
#include "TimerOne.h"
const byte button = 2; // Digital pin when is wired the button
const int led=13;
const int gas_S1=A0;
const int gas_S2=A1;
const int gas_S3=A2;
const int gas_S4=A3;
const int gas_S5=A4;
const int gas_S6=A5;
const int air_pump=12;
const int valve1=9;
const int valve2=10;
const int valve3=11;
String data_received="";
char var[8];
float time_conf=0;
float sensor1;
float sensor2;
float sensor3;
float sensor4;
float sensor5;
float sensor6;
int state=0;
int meter=0;
int time_state1=10;
int time_state2=20;
int time_state3=10;
bool button_status = false;
bool timeout=false;
bool flag=false;
void configuration(void);
bool send_data(float number);
void to_receive(void);
void tCallback (void) { timeout=true;}
void push_button(void) {
button_status=true;
delay(100);
if (flag==false) {
flag=true;
state=1;
meter=0;
}
}
void setup()
{
Serial.begin(38400); //Open serial port communication
attachInterrupt(digitalPinToInterrupt(button),push_button,FALLING);
Timer1.initialize(333333);
Timer1.attachInterrupt(tCallback);
pinMode(led, OUTPUT);
pinMode(air_pump, OUTPUT);
pinMode(valve1, OUTPUT);
pinMode(valve2, OUTPUT);
pinMode(valve3, OUTPUT);
}
void loop()
{
if (timeout)
{
meter++;
if (state==2)
{ timeout=false;
read_sensor();
}
timeout=false;
}
if (flag==true && state!=0 && meter==0)
{
configuration();
delay(1000);
}
if (state!=0 && meter!=0)
{
switch (state)
{
//gas concentration
case 1:
if ((meter/3)>=time_state1)
{ state=2;
meter=0;
}
break;
case 2:
if ((meter/3)>=time_state2) {
state=3;
meter=0;
}
break;
case 3:
if ((meter/3)>=time_state3) {
state=4;
flag=false;
meter=0;
}
break;
}
}
}
void read_sensor(void)
{
sensor1=analogRead(gas_S1)*5.0/1024.0;
String fild="s1";
send_data(sensor1,fild);
delay(40);
sensor2=analogRead(gas_S2)*5.0/1024.0;
fild="s2";
send_data(sensor2,fild);
delay(40);
sensor3=analogRead(gas_S3)*5.0/1024.0;
fild="s3";
send_data(sensor3,fild);
delay(40);
sensor4=analogRead(gas_S4)*5.0/1024.0;
fild="s4";
send_data(sensor4,fild);
delay(40);
sensor5=analogRead(gas_S5)*5.0/1024.0;
fild="s5";
send_data(sensor5,fild);
delay(40);
sensor6=analogRead(gas_S6)*5.0/1024.0;
fild="s6";
send_data(sensor6,fild);
}
void configuration(void)
{
switch (state)
{
//gas concentration
case 1:
Serial.println("Gas concentration");
digitalWrite(air_pump,LOW);
digitalWrite(valve1,LOW);
digitalWrite(valve2,LOW);
digitalWrite(valve3,HIGH);
break;
//measurement
case 2:
Serial.println("Measurement");
digitalWrite(valve3,LOW);
digitalWrite(air_pump,HIGH);
digitalWrite(valve1,HIGH);
digitalWrite(valve2,HIGH);
break;
//purge
case 3:
Serial.println("Purge");
digitalWrite(air_pump,HIGH);
digitalWrite(valve1,HIGH);
digitalWrite(valve2,HIGH);
digitalWrite(valve3,HIGH);
break;
case 4:
Serial.println("Measurement finished");
digitalWrite(air_pump,LOW);
digitalWrite(valve1,LOW);
digitalWrite(valve2,LOW);
digitalWrite(valve3,LOW);
flag=false;
state=0;
break;
}
}
bool send_data(float number, String fild)
{
dtostrf(number,2,2, var);
Serial.flush();
char cadena[4];
fild.toCharArray(cadena,4);
Serial.write(cadena);
Serial.write('\n');
delay(1);
Serial.flush();
Serial.write(var);
Serial.write('\n');
delay(5);
Serial.flush();
digitalWrite(led,HIGH);
return true;
}
void to_receive(void)
{
Serial.flush();
delay(5);
if (Serial.read()=="conf")
{
data_received="";
data_received=Serial.read();
char cadena[4];
data_received.toCharArray(cadena,4);
time_conf = strtod(cadena,NULL);
}
}

Publicidade

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s