Início Etapa 2 Atividade 10
10
ETAPA 2 - MOBILE

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!

1

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

api/acelerometro.php (VS Code)
<?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();
}
?>
2

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)

acelerometro_mobile.ino (Arduino IDE)
/************************************************
 * 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);
}
3

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!

App.js (Expo Snack)
/**
 * 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. 1

    Inicie o XAMPP e crie a API

    Arquivo: api/acelerometro.php

  2. 2

    Faça upload do código no ESP32

    Instale WiFiManager e RoboCore_MMA8452Q

  3. 3

    Configure o WiFi via portal

    Conecte na rede "ESP32-Config"

  4. 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...