1 Monta el sensor
Material: NodeMCU ESP8266, módulo MPU-6050 (GY-521), 4 cables dupont, ordenador, móvil y WiFi de 2,4 GHz.
| MPU-6050 | NodeMCU | Cable |
|---|---|---|
| VCC | 3V (no VIN) | rojo |
| GND | G | negro |
| SCL | D1 | naranja |
| SDA | D2 | verde |
| AD0 | G | negro |
2 Comprueba que el sensor responde
Arduino IDE, placa NodeMCU 1.0 (ESP-12E Module). Copia, sube y abre el monitor serie a 115200.
// MPU-6050 en NodeMCU ESP8266
// Sin libreria, solo Wire (I2C)
#include <Wire.h>
const int SDA_PIN = D2;
const int SCL_PIN = D1;
// Con AD0 a GND la direccion es 0x68
const uint8_t MPU = 0x68;
void setup() {
Serial.begin(115200);
delay(500);
Serial.println();
Wire.begin(SDA_PIN, SCL_PIN);
// Comprueba que el sensor responde
Wire.beginTransmission(MPU);
byte error = Wire.endTransmission();
if (error != 0) {
Serial.println("MPU no responde.");
Serial.println("Revisa el cableado.");
while (true) {
delay(1000);
}
}
// Despierta el sensor (sale de reposo)
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission();
Serial.println("MPU-6050 listo");
}
void loop() {
// Pide 14 bytes desde el registro 0x3B
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom((uint8_t)MPU,
(size_t)14, true);
int16_t ax = Wire.read() << 8
| Wire.read();
int16_t ay = Wire.read() << 8
| Wire.read();
int16_t az = Wire.read() << 8
| Wire.read();
int16_t t = Wire.read() << 8
| Wire.read();
int16_t gx = Wire.read() << 8
| Wire.read();
int16_t gy = Wire.read() << 8
| Wire.read();
int16_t gz = Wire.read() << 8
| Wire.read();
// Conversion a unidades reales
// Acel: 16384 por g (rango +-2 g)
// Giro: 131 por grado/s (+-250)
Serial.print("Acel g: ");
Serial.print(ax / 16384.0);
Serial.print(" ");
Serial.print(ay / 16384.0);
Serial.print(" ");
Serial.print(az / 16384.0);
Serial.print(" | Giro grad/s: ");
Serial.print(gx / 131.0);
Serial.print(" ");
Serial.print(gy / 131.0);
Serial.print(" ");
Serial.print(gz / 131.0);
Serial.print(" | Temp C: ");
Serial.println(t / 340.0 + 36.53);
delay(500);
}
¿Qué debería salir?
Con el sensor quieto y plano: Acel Z ≈ 1 g, X e Y ≈ 0, giro ≈ 1 °/s.
Si sale «MPU no responde», revisa el montaje del paso 1.
3 Sube el servidor web
Cambia TU_WIFI y TU_CLAVE por los de tu red (2,4 GHz). Sube el código y mira el monitor serie: saldrá la IP.
// Chisme: MPU-6050 en el movil
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
// Pon aqui tus datos (mayusculas exactas)
const char* ssid =
"TU_WIFI";
const char* password =
"TU_CLAVE";
const int SDA_PIN = D2;
const int SCL_PIN = D1;
// Con AD0 a GND la direccion es 0x68
const uint8_t MPU = 0x68;
ESP8266WebServer server(80);
// Ultimos datos leidos
float aX, aY, aZ;
float gX, gY, gZ;
float tempC;
float roll, pitch;
// Pagina web con actualizacion en vivo
const char PAGINA[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width,
initial-scale=1">
<title>MPU-6050</title>
<style>
body{text-align:center;
font-family:sans-serif}
table{margin:10px auto;
font-size:1.3em}
td{padding:4px 12px}
.caja{height:140px;
padding-top:50px}
#barra{width:220px;
height:22px;
margin:0 auto;
background:#2e7de0;
border-radius:11px;
transition:transform .2s}
#estado{color:#c0392b}
</style>
</head>
<body>
<h1>MPU-6050</h1>
<div class="caja">
<div id="barra"></div>
</div>
<p>Inclinacion (roll):
<b id="roll">-</b> grados</p>
<p>Inclinacion (pitch):
<b id="pitch">-</b> grados</p>
<table>
<tr><td>Acel X</td>
<td id="ax">-</td><td>g</td></tr>
<tr><td>Acel Y</td>
<td id="ay">-</td><td>g</td></tr>
<tr><td>Acel Z</td>
<td id="az">-</td><td>g</td></tr>
<tr><td>Giro X</td>
<td id="gx">-</td><td>grad/s</td></tr>
<tr><td>Giro Y</td>
<td id="gy">-</td><td>grad/s</td></tr>
<tr><td>Giro Z</td>
<td id="gz">-</td><td>grad/s</td></tr>
<tr><td>Temp chip</td>
<td id="temp">-</td><td>C</td></tr>
</table>
<p id="estado"></p>
<script>
function poner(id, v) {
document.getElementById(id)
.textContent = v.toFixed(2);
}
function actualizar() {
fetch("/datos")
.then(function (r) {
return r.json();
})
.then(function (d) {
poner("roll", d.roll);
poner("pitch", d.pitch);
poner("ax", d.ax);
poner("ay", d.ay);
poner("az", d.az);
poner("gx", d.gx);
poner("gy", d.gy);
poner("gz", d.gz);
poner("temp", d.temp);
document.getElementById("barra")
.style.transform =
"rotate(" + d.roll + "deg)";
document.getElementById("estado")
.textContent = "";
})
.catch(function () {
document.getElementById("estado")
.textContent = "Sin datos";
});
}
setInterval(actualizar, 300);
actualizar();
</script>
</body>
</html>
)rawliteral";
// Lee el sensor (igual que el base)
bool leerMPU() {
// Pide 14 bytes desde el registro 0x3B
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
size_t n = Wire.requestFrom(
(uint8_t)MPU, (size_t)14, true);
if (n < 14) {
return false;
}
int16_t ax = Wire.read() << 8
| Wire.read();
int16_t ay = Wire.read() << 8
| Wire.read();
int16_t az = Wire.read() << 8
| Wire.read();
int16_t t = Wire.read() << 8
| Wire.read();
int16_t gx = Wire.read() << 8
| Wire.read();
int16_t gy = Wire.read() << 8
| Wire.read();
int16_t gz = Wire.read() << 8
| Wire.read();
// Conversion a unidades reales
aX = ax / 16384.0;
aY = ay / 16384.0;
aZ = az / 16384.0;
gX = gx / 131.0;
gY = gy / 131.0;
gZ = gz / 131.0;
tempC = t / 340.0 + 36.53;
// Inclinacion a partir de la gravedad
roll = atan2(aY, aZ) * 180.0 / PI;
pitch = atan2(-aX, sqrt(aY * aY
+ aZ * aZ)) * 180.0 / PI;
return true;
}
void paginaInicio() {
Serial.println("Peticion: /");
server.sendHeader("Cache-Control",
"no-store");
server.send_P(200, "text/html",
PAGINA);
}
// Devuelve los datos en formato JSON
void datos() {
if (!leerMPU()) {
server.send(503, "text/plain",
"sin sensor");
return;
}
String j = "{";
j += "\"ax\":" + String(aX, 2) + ",";
j += "\"ay\":" + String(aY, 2) + ",";
j += "\"az\":" + String(aZ, 2) + ",";
j += "\"gx\":" + String(gX, 2) + ",";
j += "\"gy\":" + String(gY, 2) + ",";
j += "\"gz\":" + String(gZ, 2) + ",";
j += "\"temp\":" + String(tempC, 2);
j += ",\"roll\":" + String(roll, 1);
j += ",\"pitch\":" + String(pitch, 1);
j += "}";
server.sendHeader("Cache-Control",
"no-store");
server.send(200, "application/json", j);
}
// Lista las redes que ve la placa
void mostrarRedes() {
Serial.println("Buscando redes...");
int n = WiFi.scanNetworks();
Serial.print("Redes vistas: ");
Serial.println(n);
for (int i = 0; i < n; i++) {
Serial.print(i + 1);
Serial.print(") ");
Serial.print(WiFi.SSID(i));
Serial.print(" senal ");
Serial.print(WiFi.RSSI(i));
Serial.print(" dBm canal ");
Serial.print(WiFi.channel(i));
if (WiFi.SSID(i) == String(ssid)) {
Serial.print(" <-- TU RED");
}
Serial.println();
}
}
// Intenta conectar durante 20 s
bool conectarWiFi() {
Serial.print("Conectando a: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
for (int i = 0; i < 40; i++) {
if (WiFi.status() == WL_CONNECTED) {
return true;
}
Serial.print("estado ");
Serial.println(WiFi.status());
delay(500);
}
return false;
}
void setup() {
Serial.begin(115200);
delay(500);
Serial.println();
Wire.begin(SDA_PIN, SCL_PIN);
// Comprueba que el sensor responde
Wire.beginTransmission(MPU);
byte error = Wire.endTransmission();
if (error != 0) {
Serial.println("MPU no responde.");
Serial.println("Revisa el cableado.");
while (true) {
delay(1000);
}
}
// Despierta el sensor (sale de reposo)
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission();
Serial.println("MPU-6050 listo");
WiFi.persistent(false);
WiFi.disconnect(true);
delay(200);
WiFi.mode(WIFI_STA);
mostrarRedes();
if (!conectarWiFi()) {
Serial.println("NO CONECTA.");
Serial.println("Reinicio en 10 s");
delay(10000);
ESP.restart();
}
Serial.print("Conectado. IP: ");
Serial.println(WiFi.localIP());
server.on("/", paginaInicio);
server.on("/datos", datos);
server.begin();
Serial.println("Servidor listo");
}
void loop() {
server.handleClient();
}
En el móvil (misma WiFi), abre el navegador y escribe la IP, por ejemplo http://192.168.1.45. Verás los datos moverse cada 0,3 s.
4 Predice y mide
Antes de inclinar el sensor, escribe qué eje crees que marcará ≈ 1 g en cada posición. Luego míralo en el móvil.
- Plano sobre la mesa.
- De canto, apoyado en un lado.
- De pie, apoyado en el borde corto.
Ver la pista
La gravedad tira siempre hacia abajo: el eje que queda apuntando hacia arriba o hacia abajo marca ≈ 1 g (en valor absoluto). Los otros dos marcan ≈ 0.
Mide el giroscopio en reposo: con el sensor quieto debería marcar 0 °/s, pero marca ≈ 1 °/s. Es un desfase normal de fábrica.
Mira la temperatura: marca unos 39 °C. Es la del chip, no la de la habitación.
★ Si algo falla
- «MPU no responde»: aprieta los cables. Si siguen fallando, hay que soldar los pines del módulo.
- No encuentra el sensor: comprueba que SDA va a D2 y SCL a D1.
- No conecta al WiFi: tiene que ser de 2,4 GHz y con la clave bien escrita, con mayúsculas.
- La página dice «Sin datos»: mira el monitor serie y comprueba que el móvil está en la misma WiFi.
🏁 Reto final
Calibra el giroscopio: mide el valor medio con el sensor quieto y réstalo a cada lectura. ¿Marca ahora ≈ 0 °/s?
Solo funciona en tu red local y sin contraseña: cualquiera conectado a tu WiFi puede ver la página. Prototipo educativo.


