domingo, 22 de octubre de 2017

Proyecto #3 ESP8266 – Manipular Modelo 3D con MPU6050 (PHP + WebGL + Three.js)

En este proyecto vamos a ver una aplicación completa de IOT (Internet de las cosas), en la que explico cómo usar un NodeMCU (ESP8266) para trasmitir mediante datagramas UDP de forma inalámbrica, la inclinación que leen los acelerómetros y los giroscopios de un MPU6050; pasando por un filtro complementario y de esa manera poder manipular un modelo 3D representado en un navegador web que sea compatible con WebGL. Para todo esto eso vamos a utilizar la IDE de Arduino, HTML5, PHP, la librería de JavaScript Three.js y varias cosas más.



mpu6050udp:

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

WiFiUDP Udp;

const char* ssid = "-----";
const char* password = "-----";
int contconexion = 0;

//Direccion I2C de la IMU
#define MPU 0x68
 
//Ratios de conversion
#define A_R 16384.0 // 32768/2
#define G_R 131.0 // 32768/250
 
//Conversion de radianes a grados 180/PI
#define RAD_A_DEG = 57.295779

//MPU-6050 da los valores en enteros de 16 bits
//Valores RAW
int16_t AcX, AcY, AcZ, GyX, GyY, GyZ;
 
//Angulos
float Acc[2];
float Gy[3];
float Angle[3];

String valores;

long tiempo_prev;
float dt;

void setup()
{
  Wire.begin(4,5); // D2(GPIO4)=SDA / D1(GPIO5)=SCL
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);

  Serial.begin(115200);
  Serial.println();

  WiFi.mode(WIFI_STA); //para que no inicie el SoftAP en el modo normal
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
  }
  if (contconexion <50) {
      //para usar con ip fija
      IPAddress Ip(192,168,1,180); 
      IPAddress Gateway(192,168,1,1); 
      IPAddress Subnet(255,255,255,0); 
      WiFi.config(Ip, Gateway, Subnet); 
      
      Serial.println("");
      Serial.println("WiFi conectado");
      Serial.println(WiFi.localIP());
  }
  else { 
      Serial.println("");
      Serial.println("Error de conexion");
  }
}

void loop()
{
      
  //Leer los valores del Acelerometro de la IMU
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); //Pedir el registro 0x3B - corresponde al AcX
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,6,true);   //A partir del 0x3B, se piden 6 registros
  AcX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
  AcY=Wire.read()<<8|Wire.read();
  AcZ=Wire.read()<<8|Wire.read();
 
  //A partir de los valores del acelerometro, se calculan los angulos Y, X
  //respectivamente, con la formula de la tangente.
  Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
  Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
 
  //Leer los valores del Giroscopio
  Wire.beginTransmission(MPU);
  Wire.write(0x43);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,6,true);   //A partir del 0x43, se piden 6 registros
  GyX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
  GyY=Wire.read()<<8|Wire.read();
  GyZ=Wire.read()<<8|Wire.read();
 
  //Calculo del angulo del Giroscopio
  Gy[0] = GyX/G_R;
  Gy[1] = GyY/G_R;
  Gy[2] = GyZ/G_R;
    
  dt = (millis() - tiempo_prev) / 1000.0;
  tiempo_prev = millis();
    
  //Aplicar el Filtro Complementario
  Angle[0] = 0.98 *(Angle[0]+Gy[0]*dt) + 0.02*Acc[0];
  Angle[1] = 0.98 *(Angle[1]+Gy[1]*dt) + 0.02*Acc[1]; 

  //Integración respecto del tiempo paras calcular el YAW
  Angle[2] = Angle[2]+Gy[2]*dt;
 
  //Mostrar los valores por consola
  valores = String(Angle[0]) + "," + String(Angle[1]) + "," + String(Angle[2]);

  //Armar los paquetes UDP  
  Udp.beginPacket("192.168.1.101", 245);
  for(int i=0; i<valores.length();i++){
    Udp.write(byte(valores[i]));  
  }
  Udp.endPacket();
  
  delay(10);
}

Uniform Server 8.9.2 Coral

a380.stl

proyecto3.zip

9 comentarios:

  1. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  2. a mi no me funciona y no tengo idea de por que, si hice todo como en el viedo, creo que al momento de cambiar las ips sobretodo en la fija veo que tu tienes al final .180 de donde sacaste el 180?

    ResponderEliminar
    Respuestas
    1. La IP fija si define según tu red. El 180 lo elegí yo. Si tenés dudas, borrá lo siguiente así usas IP dinámica:

      IPAddress Ip(192,168,1,180);
      IPAddress Gateway(192,168,1,1);
      IPAddress Subnet(255,255,255,0);
      WiFi.config(Ip, Gateway, Subnet);

      Eliminar
  3. Hola que tal! Muy bueno el tutorial.

    He seguido paso a paso el tutorial, exepto la seccion de conexion a red, que he usado asignacion de IP dinamica. Aqui esta el codigo:

    --------------------------------------------------
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("Netmask: ");
    Serial.println(WiFi.subnetMask());
    Serial.print("Gateway: ");
    Serial.println(WiFi.gatewayIP());
    --------------------------------------------------

    El problema es que cuando pido la paguina al servidor desde el naveador de internet, aparece el siguiente mensage de error:

    --------------------------------------------------
    Socket created Could not bind socket : [10048] Only one usage of each socket address (protocol/network address/port) is normally permitted.
    --------------------------------------------------

    Sale el mismo error usando localhost o la IP


    Me puedes ayudar. Muchas gracias.
    Saludos

    ResponderEliminar
    Respuestas
    1. Al final averigue lo que paso.

      La aplicacion Apache estaba bloqueada en el perfil Publico del firewall.

      No se lo que paso. Mi profile de red paso de privada a publica sin saberlo.

      Ahora todo funciona correctamente.

      Saludos

      Eliminar
  4. El trabajo que ha realizado en este proyecto ha sido inspirador para realizar mi proyecto. Muchas gracias.

    ResponderEliminar
  5. Buenos días muchas gracias por su gran trabajo.
    He seguido todos sus pasos, y funciona perfectamente.
    Solo un tema, la deriva estoy utilizando mpu9250 con magnetómetro pero si dejo el sitema quieto, el comienza a girar solo no manteniendo la imagen estática.
    me puede ayudar.
    muchas gracias

    ResponderEliminar
  6. Excelente trabajo, muy claro, me costo mucho encontrar un tutorial de este tipo, y la verdad me ayudo mucho

    ResponderEliminar
  7. can admin please give access to the above files, i have requested.

    ResponderEliminar