Acelerômetro Mobile 🎮📱
Monitore a orientação e movimento do ESP32 em tempo real no celular!
🎯 Objetivo desta atividade
Criar um app que mostra a orientação 3D do ESP32 em tempo real, com um indicador visual tipo nível de bolha e detecção de movimento. O ESP32 usa WiFiManager para configuração automática de WiFi!
🏗️ Como funciona?
MMA8452Q
Acelerômetro
ESP32
WiFiManager
API PHP
Servidor
App
Nível 3D
📚 Conceitos Importantes
Eixos X, Y, Z
X: Inclinação lateral (esquerda/direita)
Y: Inclinação frente/trás
Z: Força da gravidade (≈1.0 quando plano)
Nível de Bolha
Indicador visual que mostra se a placa está nivelada. A "bolha" se move conforme você inclina o ESP32!
Backend - API PHP
Editar no VS Code
A API recebe os dados X, Y, Z do acelerômetro e detecta movimento automaticamente.
📁 Onde criar: Salve em
C:\xampp\htdocs\iot\api\acelerometro.php
<?php
/**
* API para dados do Acelerômetro MMA8452Q
*/
// CORS Headers
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
header("Content-Type: application/json");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
$arquivo = __DIR__ . '/acelerometro_dados.json';
// Inicializar arquivo
if (!file_exists($arquivo)) {
file_put_contents($arquivo, json_encode([
'x' => 0, 'y' => 0, 'z' => 1,
'movimento' => false,
'timestamp' => time()
]));
}
// GET: Retorna dados atuais
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$dados = json_decode(file_get_contents($arquivo), true);
echo json_encode([
'success' => true,
'x' => $dados['x'] ?? 0,
'y' => $dados['y'] ?? 0,
'z' => $dados['z'] ?? 1,
'movimento' => $dados['movimento'] ?? false
]);
exit();
}
// POST: Recebe dados do ESP32
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$dados = json_decode(file_get_contents('php://input'), true);
if (isset($dados['x'], $dados['y'], $dados['z'])) {
// Detecta movimento automaticamente
$movimento = (abs($dados['x']) > 0.3 ||
abs($dados['y']) > 0.3 ||
abs($dados['z'] - 1) > 0.2);
$novosDados = [
'x' => floatval($dados['x']),
'y' => floatval($dados['y']),
'z' => floatval($dados['z']),
'movimento' => $movimento,
'timestamp' => time()
];
file_put_contents($arquivo, json_encode($novosDados));
echo json_encode(['success' => true]);
} else {
http_response_code(400);
echo json_encode(['error' => 'Campos obrigatórios']);
}
exit();
}
?>
ESP32 - Código com WiFiManager
Upload via Arduino IDE
📶 WiFiManager: Na primeira vez, conecte na rede
"ESP32-Config" com senha
"12345678" para configurar seu WiFi.
⚠️ Bibliotecas necessárias:
• WiFiManager (por tzapu)
• RoboCore_MMA8452Q (pelo Library Manager)
/************************************************
* ACELERÔMETRO MOBILE - ESP32 + MMA8452Q
*
* Envia dados X, Y, Z para visualização no app.
* Usa WiFiManager para configuração automática!
*
* Bibliotecas necessárias:
* - WiFiManager (por tzapu)
* - RoboCore_MMA8452Q
***********************************************/
#include <WiFiManager.h> // Configuração automática de WiFi
#include <HTTPClient.h> // Para requisições HTTP
#include "RoboCore_MMA8452Q.h" // Biblioteca do acelerômetro
// ========== CONFIGURAÇÕES ==========
// ALTERE PARA O IP DO SEU COMPUTADOR!
const char* URL_API = "http://192.168.1.100/iot/api/acelerometro.php";
// Pino do botão para resetar WiFi
const int PINO_BOTAO = 4;
// Cria o objeto do acelerômetro
MMA8452Q acel;
void setup() {
Serial.begin(115200);
pinMode(PINO_BOTAO, INPUT);
// Inicializa o acelerômetro
acel.init();
Serial.println("Iniciando WiFiManager...");
// ========== WiFiManager ==========
// Cria o objeto WiFiManager
WiFiManager wm;
// Se o botão estiver pressionado no boot, reseta WiFi
if (digitalRead(PINO_BOTAO) == LOW) {
Serial.println("⚠️ Resetando configurações WiFi...");
wm.resetSettings();
}
// Timeout de 3 minutos para configurar
wm.setConfigPortalTimeout(180);
// Tenta conectar. Se falhar, abre portal de configuração
// Portal: rede "ESP32-Config" com senha "12345678"
bool conectou = wm.autoConnect("ESP32-Config", "12345678");
if (conectou) {
Serial.println("✅ WiFi conectado!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("❌ Falha na conexão! Reiniciando...");
ESP.restart();
}
}
void loop() {
// Verifica conexão WiFi
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi desconectado! Reiniciando...");
ESP.restart();
}
// Faz a leitura do acelerômetro
acel.read();
float x = acel.x;
float y = acel.y;
float z = acel.z;
Serial.print("📐 X: ");
Serial.print(x, 2);
Serial.print(" | Y: ");
Serial.print(y, 2);
Serial.print(" | Z: ");
Serial.println(z, 2);
// Envia para a API via POST
HTTPClient http;
http.begin(URL_API);
http.addHeader("Content-Type", "application/json");
// Monta o JSON com os 3 eixos
String json = "{\"x\":" + String(x, 3) +
",\"y\":" + String(y, 3) +
",\"z\":" + String(z, 3) + "}";
int httpCode = http.POST(json);
if (httpCode == 200) {
Serial.println("✅ Dados enviados!");
} else {
Serial.print("❌ Erro HTTP: ");
Serial.println(httpCode);
}
http.end();
// Aguarda 200ms (5 leituras por segundo)
delay(200);
}
App Mobile - Nível de Bolha
Programar em snack.expo.dev
Este código cria um nível de bolha virtual que mostra a orientação da placa ESP32 em tempo real. A bolha se move conforme você inclina a placa!
⚠️ Importante: Altere a variável URL_API
para o IP do seu computador!
/**
* Acelerômetro Mobile - Nível de Bolha
* Tutorial do Prof. Reginaldo
*/
import React, { useState, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
Dimensions
} from 'react-native';
// ⚠️ ALTERE PARA O IP DO SEU COMPUTADOR!
const URL_API = 'http://192.168.1.100/iot/api/acelerometro.php';
const { width } = Dimensions.get('window');
const NIVEL_SIZE = width - 80;
const BOLHA_SIZE = 40;
export default function App() {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const [z, setZ] = useState(1);
const [movimento, setMovimento] = useState(false);
const [erro, setErro] = useState(null);
// Buscar dados da API
const buscarDados = async () => {
try {
const resposta = await fetch(URL_API);
const dados = await resposta.json();
if (dados.success) {
setX(dados.x);
setY(dados.y);
setZ(dados.z);
setMovimento(dados.movimento);
setErro(null);
}
} catch (e) {
setErro('Erro ao conectar');
}
};
// Atualiza 5 vezes por segundo
useEffect(() => {
buscarDados();
const intervalo = setInterval(buscarDados, 200);
return () => clearInterval(intervalo);
}, []);
// Calcula posição da bolha
const bolhaX = (NIVEL_SIZE / 2) + (x * NIVEL_SIZE / 2) - (BOLHA_SIZE / 2);
const bolhaY = (NIVEL_SIZE / 2) + (y * NIVEL_SIZE / 2) - (BOLHA_SIZE / 2);
// Limita a bolha dentro do círculo
const limitedX = Math.max(0, Math.min(NIVEL_SIZE - BOLHA_SIZE, bolhaX));
const limitedY = Math.max(0, Math.min(NIVEL_SIZE - BOLHA_SIZE, bolhaY));
// Determina se está nivelado
const nivelado = Math.abs(x) < 0.1 && Math.abs(y) < 0.1;
return (
<View style={styles.container}>
<Text style={styles.titulo}>📐 Nível de Bolha</Text>
<Text style={styles.subtitulo}>Incline o ESP32 para ver a bolha se mover</Text>
// Círculo do nível
<View style={styles.nivelContainer}>
<View style={styles.nivel}>
// Linhas de referência
<View style={styles.linhaCentroH} />
<View style={styles.linhaCentroV} />
// Bolha
<View style={[
styles.bolha,
{
left: limitedX,
top: limitedY,
backgroundColor: nivelado ? '#22c55e' : '#ef4444'
}
]} />
</View>
</View>
// Status de nivelamento
<View style={[styles.statusBox, {
backgroundColor: nivelado ? '#22c55e20' : '#ef444420',
borderColor: nivelado ? '#22c55e' : '#ef4444'
}]}>
<Text style={[styles.statusTexto, {
color: nivelado ? '#22c55e' : '#ef4444'
}]}>
{nivelado ? '✓ Nivelado' : '✗ Inclinado'}
</Text>
</View>
// Valores dos eixos
<View style={styles.valoresContainer}>
<View style={styles.valorBox}>
<Text style={[styles.valorLabel, {color: '#ef4444'}]}>X</Text>
<Text style={styles.valor}>{x.toFixed(2)}</Text>
</View>
<View style={styles.valorBox}>
<Text style={[styles.valorLabel, {color: '#22c55e'}]}>Y</Text>
<Text style={styles.valor}>{y.toFixed(2)}</Text>
</View>
<View style={styles.valorBox}>
<Text style={[styles.valorLabel, {color: '#3b82f6'}]}>Z</Text>
<Text style={styles.valor}>{z.toFixed(2)}</Text>
</View>
</View>
// Alerta de movimento
{movimento && (
<View style={styles.alertaMovimento}>
<Text style={styles.alertaTexto}>⚠️ MOVIMENTO DETECTADO!</Text>
</View>
)}
{erro && (
<Text style={styles.erro}>⚠️ {erro}</Text>
)}
<Text style={styles.rodape}>Tutorial do Prof. Reginaldo</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#0f172a',
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
titulo: {
fontSize: 24,
fontWeight: 'bold',
color: '#22d3ee',
marginBottom: 4,
},
subtitulo: {
fontSize: 14,
color: '#64748b',
marginBottom: 20,
},
nivelContainer: {
marginBottom: 20,
},
nivel: {
width: NIVEL_SIZE,
height: NIVEL_SIZE,
borderRadius: NIVEL_SIZE / 2,
backgroundColor: '#1e293b',
borderWidth: 3,
borderColor: '#334155',
position: 'relative',
overflow: 'hidden',
},
linhaCentroH: {
position: 'absolute',
left: 0,
right: 0,
top: '50%',
height: 1,
backgroundColor: '#475569',
},
linhaCentroV: {
position: 'absolute',
top: 0,
bottom: 0,
left: '50%',
width: 1,
backgroundColor: '#475569',
},
bolha: {
position: 'absolute',
width: BOLHA_SIZE,
height: BOLHA_SIZE,
borderRadius: BOLHA_SIZE / 2,
},
statusBox: {
paddingHorizontal: 24,
paddingVertical: 10,
borderRadius: 12,
borderWidth: 1,
marginBottom: 20,
},
statusTexto: {
fontSize: 16,
fontWeight: 'bold',
},
valoresContainer: {
flexDirection: 'row',
gap: 20,
marginBottom: 20,
},
valorBox: {
backgroundColor: '#1e293b',
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 12,
alignItems: 'center',
minWidth: 80,
},
valorLabel: {
fontSize: 14,
fontWeight: 'bold',
marginBottom: 4,
},
valor: {
fontSize: 18,
color: '#fff',
fontWeight: 'bold',
},
alertaMovimento: {
backgroundColor: '#fef3c720',
borderColor: '#f59e0b',
borderWidth: 1,
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 12,
marginBottom: 10,
},
alertaTexto: {
color: '#f59e0b',
fontWeight: 'bold',
},
erro: {
color: '#ef4444',
fontSize: 14,
marginBottom: 10,
},
rodape: {
position: 'absolute',
bottom: 30,
color: '#475569',
fontSize: 12,
},
});
🧪 Testando o Sistema
-
1
Inicie o XAMPP e crie a API
Arquivo: api/acelerometro.php
-
2
Faça upload do código no ESP32
Instale WiFiManager e RoboCore_MMA8452Q
-
3
Configure o WiFi via portal
Conecte na rede "ESP32-Config"
-
4
Teste o app - incline a placa!
A bolha verde se move em tempo real
🎉 Parabéns! Você criou um nível de bolha digital com visualização em tempo real no celular!
📝 Teste seus Conhecimentos
Quiz Gamificado
Responda às perguntas para ganhar XP!
Carregando quiz...