sábado, 25 de febrero de 2017

Implementación de un Paso de Peatones con Sensores Inteligentes de Bajo Coste. Parte VI

Sistema Software
Software nodo terminal
En el siguiente diagrama de estados se muestra el funcionamiento de los nodos terminales.



La misión de los nodos terminales de alertar de la existencia de un peatón, por eso los dos macro-estados son PEATON y NO PEATON. 
La acción asociada al macro-estado PEATON es encender el led y la acción asociada al macro-estado NO PEATON es apagar el led.
Las variables de las que dependen las transicciones entre estados son:
  • ESTADO: variable estado que identifica lo que detecta el sistema sensorial, su valor puede ser COCHE, PEATON o NADA
  • ESTADO_OTHERS: variable ESTADO que resume el estado real del resto de nodos terminales, su valor puede ser PEATON o NADA
  • TIEMPO_NOPEATON: tiempo que ha pasado desde la última vez que se detectó un peatón, puede haberlo detectado el propio nodo o cualquiera del resto. 
A partir de lo anteriormente descrito se concluye que un sistema formado por múltiples nodos terminales actuarán de manera coordinada, de tal forma que cuando al menos un nodo detecte la presencia de un peaton él y el resto de nodos enciendan sus led. Mientras que, en el caso de que ninguno detecte algún peatón, todos permanecerán con los leds apagados.
   
El código completo se encuentra en el siguiente enlace:
Código Arduino 

 Funcionamiento del Sistema

En el siguiente video se explica el comportamiento del sistema con un solo nodo terminal.


 <<Anterior

Implementación de un Paso de Peatones con Sensores Inteligentes de Bajo Coste. Parte V

Sistema Software

Software nodo terminal
 La comunicacion con el servidor MQTT consistirá en recoger los eventos que son enviados por el broker y en el caso de algun evento corresponda con PEATON, se encenderá el led. Además en caso de que el nodo detecte uun peaton emitirá dicho evento.
A continuacion se muestra el código correspondiente al cliente MQTT implementado en los nodos terminales

#include <PubSubClient.h>
#include <ESP8266WiFi.h>

#define OUT_LED D4
 #define NADA 0
#define PEATON 1
#define COCHE 2

 //EDIT THESE LINES TO MATCH YOUR SETUP
#define MQTT_SERVER "192.168.0.5"
//"test.mosquitto.org"
const char* ssid = "Vodafone6717";
const char* password = "MMCDQCPIYODWPL";
//D9 en la parte de arduino y GPIO2 por detras
char* lightTopic = "PASOPEATONES";
  int ESTADO_OTHER=NADA;
  double instante_ESTADO_OTHER;

 ///////////////////////////////////////////////////////////////////////////
 ///////////////////////VARIABLES TIEMPO PEATON////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 double instante_peaton;
 double MAX_PEATON = 4000;
 double instante_evento;
 double MAX_ENVIO_EVENTO=2000;
 double MAX_LED_ENCENDIDO=4000;


 ///////////////////////////////////////////////////////////////////////////
 ///////////////////////FUNCIONES Y OBJETOS ESP8266/////////////////////////
 //////////////////////////////////////////////////////////////////////////

//Definicion de la funcion callback del cliente MQTT
 void callback(char* topic, byte* payload, unsigned int length);
//Funcion que convierte una direccion mac a string
 String macToStr(const uint8_t* mac) {
  String result;
  for (int i = 0; i < 6; ++i) {
    result += String(mac[i], 16);
    if (i < 5) {
      result += ':';
    }
  }
  return result;
}

//VARAIABLES CONEXIÓN A LA RED Y AL SERVIDOR MQTT
 WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);
void callback(char* topic, byte* payload, unsigned int length) {
  /*String topicStr = topic;
  Serial.println("Callback update.");
  Serial.print("Topic: ");
  Serial.println(topicStr);*/
  if (payload[0] == 'P') {
    ESTADO_OTHER=PEATON;
    instante_ESTADO_OTHER=millis();
    Serial.println("Evento peaton recibido");
  }
}

//FUNCION DE CONEXION A LA RED
 void reconnect() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to "); 
    Serial.println(ssid);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println(""); 
    Serial.println("WiFi connected");  
  }
  if (WiFi.status() == WL_CONNECTED) {
    while (!client.connected()) {
      Serial.print("Attempting MQTT connection...");
      String clientName;  
      clientName += "esp8266-";  
      uint8_t mac[6];  
      WiFi.macAddress(mac); 
      clientName += macToStr(mac);
      if (client.connect((char*) clientName.c_str())) {
        Serial.print("\tMTQQ Connected");   
        client.subscribe(lightTopic);
        }
        else {
          Serial.println("\tFailed.");
          abort();
        }
      }
    }
  }

//FUNCION DE INICIALIZACION PRINCIPAL
void setup() {
  Serial.begin(115200); delay(100);
  WiFi.begin(ssid, password);
  reconnect();
  delay(2000);
  ///////////////////////////////////////////////////////////////////////////
  ////////////////////INICIALIZACION EVENTO PEATON///////////////////////////
  //////////////////////////////////////////////////////////////////////////
  instante_peaton=millis();
  pinMode(OUT_LED, OUTPUT);
  digitalWrite(OUT_LED,LOW);
  instante_evento=millis();
}

 int last_state=NADA;
//FUNCION BUCLE PRINCIPAL
void loop() {
  if (!client.connected() && WiFi.status() == 3) {
      reconnect();
    }
   client.loop();     
  ////////////ACCIONES POST FUZZY////////////
  if(ESTADO!=last_state){
    last_state=ESTADO;
    Serial.println("Cambio de estado");
    if(ESTADO==NADA){
       Serial.println("NADA");
    }else if(ESTADO==PEATON){
       Serial.println("PEATON");
    }else if(ESTADO == COCHE){
       Serial.println("COCHE");
    }
  }
  double tiempo_evento=millis()-instante_evento;
  if(ESTADO==PEATON && tiempo_evento > MAX_ENVIO_EVENTO){
    instante_evento=millis();
    Serial.println("ENVIO EVENTO");
    client.publish(lightTopic, "P");
    //emitir peaton
  }
  if((ESTADO_OTHER==PEATON && ((millis()-instante_ESTADO_OTHER)<MAX_LED_ENCENDIDO))|| ESTADO==PEATON){
    digitalWrite(OUT_LED, HIGH);
    //Serial.println("ENCENDER LED");
    instante_peaton=millis();
  }
  double tiempo_peaton=millis()-instante_peaton;
  if(tiempo_peaton>MAX_PEATON){
    //Serial.println("APAGAR LED");
    digitalWrite(OUT_LED, LOW);
  }
}


<<Anterior 







 

Implementación de un Paso de Peatones con Sensores Inteligentes de Bajo Coste. Parte IV

Sistema Software

Software nodo terminal

La fusión sensorial complementaria implementada trata de proporcionar una fusión de la información obtenida por el sensor de distancia, el sensor de luz y el tiempo. Esta fusión trata de determinar la presencia de un peatón, un coche o nada. Para implementarla se ha hecho uso de un sistema difuso.
Las variables de entrada son:
  • Luminosidad:
 
  • Distancia :

  • TiempoNoLuz

 Solo existirá una variable de salida llamada estado que poseera los valores PEATON, COCHE o NADA
La base de reglas es:



A continuacion se muestra el código que implementa la fusion sensorial
 #define NADA 0
#define PEATON 1
#define COCHE

int min_medida_luz = 8;                                //->valores de ejemplo
 int max_medida_luz = 913;                              //->valores de ejemplo
 int min_real_luz = 0;                                //->valores de ejemplo
 int max_real_luz = 934;                              //->valores de ejemplo

 int min_medida_distancia = 3;                                //->valores de ejemplo
 int max_medida_distancia = 13;                              //->valores de ejemplo
 int min_real_distancia = 3;                                //->valores de ejemplo
 int max_real_distancia = 13;                              //->valores de ejemplo

 int UMBRAL_LUZ=550;
 double instante_no_luz;
 double MAX_NO_LUZ = 4000;

  ///////////////////////////////////////////////////////////////////////////
  //////////////////////VARIABLES SISTEMA DIFUSO/////////////////////////////
  //////////////////////////////////////////////////////////////////////////
  double x0K1[2];
  double x1K1[2];
  double x2K1[2];
  double x3K1[2];
  double x0K2[2];
  double x1K2[2];
  double x2K2[2];
  double x3K2[2];
  double x0K3[2];
  double x1K3[2];
  double x2K3[2];
  double x3K3[2];
  int K1[8];
  int K2[8];
  int K3[8];
  int C1[8];
  double H[8];

//FUNCION QUE MAPEA LA VARIABLE DE ENTRADA CON EL RANGO DE ENTRADA EN EL RANGO DE SALIDA

double mapdouble(double x, double in_min, double in_max, double out_min, double out_max)
{
 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//FUNCION QUE EJECUTA EL SISTEMA DIFUSO 

int fuzzysystem(double E1, double E2, double E3) {
    double corte;
    for (int i = 0; i<8; i++) {
      H[i] = 2147483648; //{IniciKlizo K un m¡nimo muy grKnde}
      corte = 0;
      if ((E1 >= x0K1[K1[i]]) && (E1<x1K1[K1[i]])) { corte = (E1 - x0K1[K1[i]]) / (x1K1[K1[i]] - x0K1[K1[i]]); }
      if ((E1 >= x1K1[K1[i]]) && (E1<x2K1[K1[i]])) { corte = 1; }
      if ((E1 >= x2K1[K1[i]]) && (E1<=x3K1[K1[i]])) { corte = (E1 - x3K1[K1[i]]) / (x2K1[K1[i]] - x3K1[K1[i]]); }
      if (corte<H[i]) { H[i] = corte; }// {M¡nimo de los Kntecedentes hKstK KhorK}
      corte = 0;
      if ((E2 >= x0K2[K2[i]]) && (E2<x1K2[K2[i]])) { corte = (E2 - x0K2[K2[i]]) / (x1K2[K2[i]] - x0K2[K2[i]]); }
      if ((E2 >= x1K2[K2[i]]) && (E2<x2K2[K2[i]])) { corte = 1; }
      if ((E2 >= x2K2[K2[i]]) && (E2<=x3K2[K2[i]])) { corte = (E2 - x3K2[K2[i]]) / (x2K2[K2[i]] - x3K2[K2[i]]); }
      if (corte<H[i]) { H[i] = corte; } //{M¡nimo de los Kntecedentes hKstK KhorK}
      corte = 0;
      if ((E3 >= x0K3[K3[i]]) && (E3<x1K3[K3[i]])) { corte = (E3 - x0K3[K3[i]]) / (x1K3[K3[i]] - x0K3[K3[i]]); }
      if ((E3 >= x1K3[K3[i]]) && (E3<x2K3[K3[i]])) { corte = 1; }
      if ((E3 >= x2K3[K3[i]]) && (E3<=x3K3[K3[i]])) { corte = (E3 - x3K3[K3[i]]) / (x2K3[K3[i]] - x3K3[K3[i]]); }
      if (corte<H[i]) { H[i] = corte; }// {M¡nimo de los Kntecedentes hKstK KhorK}
    }
    double sumHM[3];
    for (int i = 0; i<3; i++) {
      sumHM[i] = 0;
    }
    for (int i = 0; i<8; i++) {
      sumHM[C1[i]] = sumHM[C1[i]] + H[i];
    }
    int resultado = NADA;
    double value = 0;
      for (int i = 0; i < 3; i++) {
        if (sumHM[i] > value) {
          resultado = i;
          value = sumHM[i];
        }
      }
    return resultado;
}

//FUNCION QUE RESTRINGE EL RANGO DE UNA VARIABLE
double constraintdouble(double x, double in_min, double in_max){
  if(x<in_min){
    return in_min;
  }else if(x>in_max){
    return in_max;
  }else{
    return x;
  }
}

 //FUNCION DE INICIALIZACION PRINCIPAL
void setup() {
  Serial.begin(115200); delay(100);
  ///////////////////////////////////////////////////////////////////////////
  ///////////////INICIALIZACION BASICA SISTEMA DIFUSO////////////////////////
  //////////////////////////////////////////////////////////////////////////
  x0K1[0] = 0;       x1K1[0] = 0;       x2K1[0] = 0.3333;  x3K1[0] = 0.6667;
  x0K1[1] = 0.3333;  x1K1[1] = 0.6667;  x2K1[1] = 1;       x3K1[1] = 1;
  x0K2[0] = 0;       x1K2[0] = 0;       x2K2[0] = 0.3333;  x3K2[0] = 0.6667;
  x0K2[1] = 0.3333;  x1K2[1] = 0.6667;  x2K2[1] = 1;       x3K2[1] = 1;
  x0K3[0] = 0;       x1K3[0] = 0;       x2K3[0] = 0.3333;  x3K3[0] = 0.6667;
  x0K3[1] = 0.3333;  x1K3[1] = 0.6667;  x2K3[1] = 1;       x3K3[1] = 1;
  K1[0] = 0; K1[1] = 1; K1[2] = 1; K1[3] = 0; K1[4] = 0; K1[5] = 0; K1[6] = 1; K1[7] = 1;
  K2[0] = 0; K2[1] = 0; K2[2] = 1; K2[3] = 1; K2[4] = 1; K2[5] = 0; K2[6] = 0; K2[7] = 1;
  K3[0] = 0; K3[1] = 0; K3[2] = 0; K3[3] = 0; K3[4] = 1; K3[5] = 1; K3[6] = 1; K3[7] = 1;
  C1[0] = 2; C1[1] = 2; C1[2] = 2; C1[3] = 2; C1[4] = 2; C1[5] = 2; C1[6] = 1; C1[7] = 0;
  min_medida_luz = medida_luz[0];
  max_medida_luz = medida_luz[n_lookup_luz - 1];
  min_real_luz = real_luz[0];
  max_real_luz = real_luz[n_lookup_luz - 1];
  UMBRAL_LUZ = (real_luz[1]+real_luz[2])/2;
  instante_no_luz=millis();
  //Configuracion etiquetas Fuzzy
  x2K3[0] = mapdouble(real_luz[1],min_real_luz,max_real_luz,0,1);
  x3K3[0] = mapdouble(real_luz[2],min_real_luz,max_real_luz,0,1);
  x0K3[1] =  mapdouble(real_luz[1],min_real_luz,max_real_luz,0,1);
  x1K3[1] = mapdouble(real_luz[2],min_real_luz,max_real_luz,0,1);
}

//FUNCION BUCLE PRINCIPAL
void loop() {
  ////////////OBTENCION TIEMPO (0,1)////////////
  if(out_luz<UMBRAL_LUZ){
    instante_no_luz=millis();
  }
  double tiempo_no_luz=millis()-instante_no_luz;
  if(tiempo_no_luz>MAX_NO_LUZ){
    tiempo_no_luz=MAX_NO_LUZ;
  }
  //////////////PRE-CALCULOS FUZZY//////////////
  double E1=mapdouble(tiempo_no_luz,0,MAX_NO_LUZ,0,1);
  double E2=mapdouble(out_distancia,min_real_distancia,max_real_distancia,0,1);
  double E3=mapdouble(out_luz,min_real_luz,max_real_luz,0,1);
  ///////////////SISTEMA FUZZY///////////////
 // Serial.println(out_distancia);
  int ESTADO=fuzzysystem(E1,E2,E3);


<<Anterior