Robô Otto Ninja#


Objetivo#

Compreender, montar e programar o robô Otto Ninja, explorando conceitos de eletrônica, mecânica e programação.

Analisaremos também a evolução da plataforma com o uso do ESP32, que incorpora conectividade sem fio (Wi-Fi e Bluetooth), maior capacidade de processamento e novas possibilidades de controle e automação.

Ao longo do notebook, são apresentadas aplicações na Engenharia Civil, como o uso de sensores de distância para monitoramento de estruturas, controle de acesso em obras e automação de inspeções.


1. Introdução ao Otto Ninja#

O Otto Ninja é um robô bípede open-source capaz de andar, dançar e desviar de obstáculos. É amplamente utilizado no ensino de robótica por integrar conceitos de eletrônica, programação e mecânica de forma prática e acessível.

Otto Ninja Robot

Mais informações: ottodiy.com/ninja

Originalmente baseado em Arduino Nano, versões mais recentes utilizam o ESP32, permitindo comunicação Bluetooth e Wi-Fi, além de maior desempenho e menor custo.

O comportamento do robô é baseado em sequências coordenadas de movimentos dos servomotores, simulando locomoção bípede.


Conceitos envolvidos:#

Área

Conceito

Robótica

Locomoção bípede, cinemática

Eletrônica

Controle PWM, sensores, alimentação

Programação

C++ / Arduino IDE, lógica de controle

Comunicação

Bluetooth, Wi-Fi, IoT

Mecânica

Estrutura impressa em 3D, servos


Modos de operação:#

┌─────────────────────────────────────────┐
│           OTTO NINJA - MODOS            │
├─────────────────┬───────────────────────┤
│ Autônomo        │ Executa rotinas pré-  │
│                 │ programadas           │
├─────────────────┼───────────────────────┤
│ Manual          │ Controle via app /   │
│                 │ Bluetooth             │
├─────────────────┼───────────────────────┤
│ Reativo         │ Responde a sensores  │
│                 │ (desvio de obstáculo) │
└─────────────────┴───────────────────────┘

2. Componentes#

Versão tradicional (Arduino Nano):#

Componente

Quantidade

Função

Arduino Nano

1

Microcontrolador principal

Servo motor SG90

4

Movimentação das pernas e pés

Sensor HC-SR04

1

Detecção de obstáculos

Buzzer

1

Sons e alertas

Módulo Bluetooth (HC-05)

1 (opcional)

Controle remoto

Bateria 9V ou LiPo

1

Alimentação

Estrutura 3D impressa

1 kit

Corpo do robô


Versão atualizada (ESP32) — Recomendada:#

ESP32 DevKit Pinout

Componente

Quantidade

Vantagem

ESP32

1

Wi-Fi + Bluetooth integrados, maior CPU

Servo motor SG90

4

Mesmos servos — compatível

Sensor HC-SR04

1

Mesma funcionalidade

Buzzer

1

Saída de áudio simples

Bateria LiPo 3,7V + regulador

1

Mais compacto e eficiente


Observações:#

  1. Alimentação separada para os servos: Os servos consomem até 1A por unidade em carga. Nunca os alimente diretamente do pino 3.3V do ESP32 — use um regulador externo (ex: AMS1117 5V).

  2. GND compartilhado (Ground comum): O GND do ESP32, dos servos e do sensor deve ser conectado em um ponto comum. Sem isso, os sinais de controle PWM não funcionarão corretamente.

  3. Nível lógico do HC-SR04: O sensor opera em 5V, mas o ESP32 usa 3.3V. O pino ECHO precisa de um divisor de tensão (resistores 1kΩ e 2kΩ) ou de um módulo conversor de nível lógico.

    ESP32 (3.3V)    Divisor de tensão     HC-SR04 (5V)
         │                                     │
    ECHO ─┤──── R1(1kΩ) ──┬── R2(2kΩ) ── GND │ ECHO
         │                └── GPIO ESP32       │

3. Controle de Servomotores — Conceito de PWM#

O PWM (Pulse Width Modulation) é o sinal usado para controlar a posição de um servomotor.

A largura do pulso determina o ângulo:

  • ~1ms de pulso → 0°

  • ~1,5ms de pulso → 90° (posição central)

  • ~2ms de pulso → 180°

O período total do sinal é de 20ms (frequência de 50Hz).

Analogia com Engenharia Civil:#

Da mesma forma que um atuador hidráulico em uma ponte móvel recebe um sinal proporcional para abrir ou fechar em um ângulo específico, o servomotor responde ao sinal PWM para posicionar sua haste com precisão.

# ============================================================
# SIMULAÇÃO: Controle de Servo via PWM — Otto Ninja
# ============================================================
#
# CONTEXTO
# --------
# O Otto Ninja é um robô bípede de código aberto controlado
# por Arduino. Cada perna é movida por um servomotor, que
# recebe comandos via sinal PWM (Pulse Width Modulation).
#
# COMO FUNCIONA O PWM
# -------------------
# PWM é uma técnica de controle em que o microcontrolador
# envia pulsos elétricos periódicos. O que muda não é a
# tensão, mas a DURAÇÃO de cada pulso (largura):
#
#   Pulso curto (1.0 ms)  →  servo vai para -90°
#   Pulso médio (1.5 ms)  →  servo fica na posição central (0°)
#   Pulso longo (2.0 ms)  →  servo vai para +90°
#
# O servo lê esses pulsos ~50 vezes por segundo e ajusta
# seu eixo para o ângulo correspondente.
#
# O QUE ESTE CÓDIGO FAZ
# ---------------------
# Simula o ângulo de UMA perna do Otto ao longo de 2 segundos,
# usando uma função senoidal para gerar o movimento oscilatório
# suave (vai e volta) que produz o padrão de caminhada.
# Em seguida, converte esse ângulo no pulso PWM equivalente.
#
# APLICAÇÕES NA ENGENHARIA CIVIL
# -------------------------------
# Esse mesmo padrão oscilatório aparece em:
#   • Amortecedores ativos de pontes pênseis
#   • Atuadores de barragens com comportas automáticas
#   • Braços robóticos de inspeção estrutural
# ============================================================

import numpy as np
import matplotlib.pyplot as plt

# ------------------------------------------------------------------
# PARÂMETROS DO MOVIMENTO
# ------------------------------------------------------------------
tempo      = np.linspace(0, 2, 300)  # Eixo do tempo: 0 a 2s, com 300 amostras
amplitude  = 45                      # Amplitude da oscilação em graus
                                     # → o servo vai de -45° a +45°
frequencia = 1.5                     # Frequência em Hz (ciclos por segundo)
                                     # → 1.5 Hz = uma ida e volta completa a cada 0.67s

# ------------------------------------------------------------------
# ÂNGULO DO SERVO AO LONGO DO TEMPO
# ------------------------------------------------------------------
# A função seno produz valores entre -1 e +1.
# Multiplicar pela amplitude escala esse intervalo para [-45°, +45°].
#
# Fórmula: θ(t) = A · sin(2π · f · t)
#   A = amplitude (graus)
#   f = frequência (Hz)
#   t = tempo (s)
angulo_servo = amplitude * np.sin(2 * np.pi * frequencia * tempo)

# ------------------------------------------------------------------
# CONVERSÃO: ÂNGULO → LARGURA DE PULSO PWM
# ------------------------------------------------------------------
# Relação linear entre ângulo e duração do pulso:
#
#   pwm = 1.5  +  (ângulo / 90) × 0.5
#
# Exemplos de verificação:
#   ângulo =   0° → pwm = 1.5 + 0     = 1.50 ms  ✓ (centro)
#   ângulo = +45° → pwm = 1.5 + 0.25  = 1.75 ms  ✓ (metade do caminho para +90°)
#   ângulo = -45° → pwm = 1.5 - 0.25  = 1.25 ms  ✓ (metade do caminho para -90°)
#   ângulo = +90° → pwm = 1.5 + 0.5   = 2.00 ms  ✓ (máximo)
#   ângulo = -90° → pwm = 1.5 - 0.5   = 1.00 ms  ✓ (mínimo)
pwm_ms = 1.5 + (angulo_servo / 90) * 0.5

# ------------------------------------------------------------------
# VISUALIZAÇÃO
# ------------------------------------------------------------------
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
# sharex=True vincula o zoom/pan dos dois gráficos no eixo X

# --- Gráfico 1: Ângulo do servo ---
ax1.plot(tempo, angulo_servo, color='royalblue', linewidth=2)
ax1.axhline(0, color='gray', linestyle='--', linewidth=0.8)         # linha de referência: 0°
ax1.fill_between(tempo, angulo_servo, 0, alpha=0.1, color='royalblue')  # área sombreada
ax1.set_ylabel('Ângulo do servo (°)', fontsize=11)
ax1.set_title('Simulação de Movimento Oscilatório — Otto Ninja (Perna)', fontsize=13)
ax1.set_ylim(-60, 60)    # margem extra acima/abaixo da amplitude de ±45°
ax1.grid(True, alpha=0.3)
ax1.legend(['Ângulo'], loc='upper right')

# --- Gráfico 2: Largura de pulso PWM correspondente ---
ax2.plot(tempo, pwm_ms, color='orangered', linewidth=2)
ax2.axhline(1.5, color='gray', linestyle='--', linewidth=0.8, label='Centro (0° → 1.5 ms)')
ax2.set_ylabel('Largura do pulso PWM (ms)', fontsize=11)
ax2.set_xlabel('Tempo (s)', fontsize=11)
ax2.set_ylim(0.8, 2.2)   # margem visual acima de 2.0 ms e abaixo de 1.0 ms
ax2.grid(True, alpha=0.3)
ax2.legend(loc='upper right')

plt.tight_layout()
plt.savefig('pwm_servo.png', dpi=120, bbox_inches='tight')
plt.show()

# ------------------------------------------------------------------
# RESUMO NUMÉRICO DOS RESULTADOS
# ------------------------------------------------------------------
print(f"Amplitude de oscilação : ±{amplitude}°")
print(f"Frequência             : {frequencia} Hz  →  período = {1/frequencia:.2f} s")
print(f"Pulso PWM mínimo       : {pwm_ms.min():.2f} ms  (posição -{amplitude}°)")
print(f"Pulso PWM máximo       : {pwm_ms.max():.2f} ms  (posição +{amplitude}°)")
print(f"Pulso PWM central      : 1.50 ms  (posição 0°)")
../../_images/4f95436e60301867f13839151c70078125328bb0d1ba7432079f32720bcce1f8.png
Amplitude de oscilação: ±45°
Frequência: 1.5 Hz
Pulso PWM mínimo: 1.25 ms  (≈ 45° negativo)
Pulso PWM máximo: 1.75 ms  (≈ 45° positivo)

4. Montagem#

A montagem do Otto Ninja influencia diretamente sua estabilidade e a qualidade dos movimentos.


Etapas de montagem:#

  1. Calibração inicial dos servos: Posicione todos os 4 servos em 90° antes de fixá-los na estrutura. Erros nesta etapa resultam em desequilíbrio permanente.

  2. Fixação dos servos na estrutura: Use os parafusos M2 que vêm com os SG90. Garanta alinhamento perfeitamente paralelo.

  3. Montagem das pernas e pés: Encaixe os braços dos servos nos slots da estrutura. Evite folgas.

  4. Instalação do sensor ultrassônico: O HC-SR04 fica na “cabeça” do robô, apontado para frente.

  5. Conexão do microcontrolador: Encaixe o ESP32 na cavidade central.

  6. Organização da fiação: Prenda os fios com abraçadeiras. Fios soltos interferem no movimento.


Problemas comuns e soluções:#

Problema

Causa provável

Solução

Robô desequilibrado

Servo não estava em 90° na montagem

Desmontar e reposicionar

Tremores nos servos

Alimentação insuficiente

Usar bateria externa para os servos

Movimento irregular

Ângulos errados no código

Ajustar os valores de offset

Ruído nos movimentos

Folga mecânica

Reajustar parafusos da estrutura


5. Programação — Arduino / ESP32#

A lógica do robô baseia-se no controle dos ângulos dos servos ao longo do tempo. Cada movimento é uma sequência de posições angulares sincronizadas.

No ESP32, o controle PWM é realizado via ledc (LED Control peripheral), que permite frequência e resolução mais precisas que o analogWrite do Arduino.


Estrutura básica de um programa:#

SETUP (executa 1 vez)
  └─ Inicializar pinos dos servos
  └─ Configurar pinos do sensor HC-SR04
  └─ Posicionar servos em 90° (neutro)

LOOP (executa continuamente)
  └─ Ler sensor de distância
  └─ Decidir: andar, girar ou parar
  └─ Executar sequência de movimentos
  └─ Aguardar (delay)

Controle de Servo — Otto Ninja#

Arduino / ESP32 — C++

Exemplo básico de movimentação oscilatória de uma perna usando a biblioteca Servo.h no Arduino Nano ou ESP32.


Código-fonte#

// Controle simples de servo — Otto Ninja
#include <Servo.h>        // Importa a biblioteca de controle de servo

Servo perna_esquerda;     // Cria objeto que representa o servo físico

void setup() {
  // Associa o objeto ao pino GPIO 2 do microcontrolador
  // O pino envia o sinal PWM que controla o ângulo do servo
  perna_esquerda.attach(2);

  // Posiciona o servo em 90° (posição neutra / vertical)
  perna_esquerda.write(90);
  delay(500);             // Aguarda 500 ms para estabilizar
}

void loop() {
  perna_esquerda.write(70);   // Inclina a perna para frente
  delay(400);                 // Mantém a posição por 400 ms

  perna_esquerda.write(90);   // Retorna ao centro
  delay(400);

  perna_esquerda.write(110);  // Inclina a perna para trás
  delay(400);

  perna_esquerda.write(90);   // Retorna ao centro
  delay(400);
}

Funções principais#

Instrução

O que faz

#include <Servo.h>

Importa a biblioteca que traduz write(90) no sinal PWM correto automaticamente.

Servo perna_esq

Declara um objeto que representa um servo físico. Cada servo precisa do seu próprio objeto.

.attach(pino)

Define qual GPIO do microcontrolador enviará os pulsos PWM ao servo.

.write(ângulo)

Move o eixo do servo para o ângulo desejado — aceita valores de 0° a 180°.

delay(ms)

Pausa a execução em milissegundos, dando tempo ao servo alcançar a posição antes do próximo comando.


Mapeamento ângulo → pulso PWM#

O servo interpreta a duração do pulso elétrico recebido (~50 vezes por segundo) e posiciona o eixo no ângulo correspondente:

Ângulo

Largura do pulso

Posição

−90°

1.0 ms

extremo esquerdo

1.5 ms

centro (neutro)

+90°

2.0 ms

extremo direito

Fórmula da conversão:

\[pwm_{ms} = 1.5 + \frac{\theta}{90} \times 0.5\]

Parâmetros do exemplo#

Parâmetro

Valor

Posição central

90°

Amplitude de oscilação

±20° (70° ↔ 110°)

Tempo por passo

400 ms

Pino PWM

GPIO 2


6. Controle de Movimento — Como o Otto anda?#

O Otto Ninja tem 4 servomotores:

        [CABEÇA — HC-SR04]
              │
         ┌───┴───┐
         │ ESP32 │
         └───────┘
         │       │
    [Servo 1] [Servo 2]   ← Pernas (movimento frente/trás)
         │       │
    [Servo 3] [Servo 4]   ← Pés (equilíbrio lateral)
         │       │
       [PÉ E] [PÉ D]

Como um passo é formado:#

Instante

Servo Perna E

Servo Perna D

Servo Pé E

Servo Pé D

T=0ms

90°

90°

90°

90°

T=200ms

70° (frente)

110° (atrás)

80°

100°

T=400ms

90°

90°

90°

90°

T=600ms

110° (atrás)

70° (frente)

100°

80°

T=800ms

90°

90°

90°

90°

Conceito-chave: Movimento = sequência de ângulos + tempo (delay)

Analogia com Engenharia Civil:#

Na análise de estruturas, o conceito de deslocamento em função do tempo é fundamental. Uma ponte pênsil oscila em modos de vibração — cada modo tem uma frequência e um padrão de deslocamento específico, assim como os servos do Otto têm frequência de oscilação e amplitudes configuráveis.

# ============================================================
# SIMULAÇÃO: Sequência de movimento de um passo completo
# Visualiza a coordenação entre os 4 servos
# ============================================================

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

# Definição dos instantes de tempo (ms)
tempos = [0, 200, 400, 600, 800, 1000]

# Ângulos de cada servo ao longo do tempo
# (um passo completo de caminhada bípede)
servo_perna_E  = [90,  70, 90, 110, 90, 70]    # Perna Esquerda
servo_perna_D  = [90, 110, 90,  70, 90, 110]   # Perna Direita
servo_pe_E     = [90,  80, 90, 100, 90,  80]   # Pé Esquerdo
servo_pe_D     = [90, 100, 90,  80, 90, 100]   # Pé Direito

fig, ax = plt.subplots(figsize=(11, 5))

cores = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728']
nomes = ['Perna E', 'Perna D', 'Pé E', 'Pé D']
dados = [servo_perna_E, servo_perna_D, servo_pe_E, servo_pe_D]

for i, (nome, serie, cor) in enumerate(zip(nomes, dados, cores)):
    ax.plot(tempos, serie, marker='o', linewidth=2.5,
            color=cor, label=nome, markersize=6)

ax.axhline(90, color='gray', linestyle='--', linewidth=1, alpha=0.6, label='Neutro (90°)')
ax.set_xlabel('Tempo (ms)', fontsize=12)
ax.set_ylabel('Ângulo do servo (°)', fontsize=12)
ax.set_title('Coordenação dos 4 Servos — Um Passo Completo do Otto Ninja', fontsize=13)
ax.set_ylim(60, 120)
ax.legend(loc='upper right')
ax.grid(True, alpha=0.3)

# Destaque nas fases
for t, label in zip([0, 200, 400, 600, 800], ['Neutro', 'Passo 1', 'Neutro', 'Passo 2', 'Neutro']):
    ax.axvline(t, color='lightgray', linestyle=':', linewidth=1)
    ax.text(t + 10, 62, label, fontsize=7, color='gray')

plt.tight_layout()
plt.savefig('movimento_otto.png', dpi=120, bbox_inches='tight')
plt.show()

print(" Gráfico gerado: coordenação entre os 4 servos durante um passo")
print("\n Observe a OPOSIÇÃO de fase entre Perna E e Perna D — isso gera o deslocamento!")
../../_images/d47af8bc1d6868de3908f852a97cddc9fe9771e904cd98ac8651bfce66ef1215.png
 Gráfico gerado: coordenação entre os 4 servos durante um passo

 Observe a OPOSIÇÃO de fase entre Perna E e Perna D — isso gera o deslocamento!

7. Sensor Ultrassônico HC-SR04#

Sensores ultrassônicos como o HC-SR04 medem a distância até um objeto através do tempo de retorno de um pulso sonoro ultrassônico (40 kHz — inaudível ao ser humano).

Sensor HC-SR04


Princípio físico:#

  [TRIG]──► pulso 10µs ──► som 40kHz ──► OBJETO ──► eco ──► [ECHO]
                                                              ↓
                                           tempo eco = HIGH do pino ECHO

Fórmula: $\(d = \frac{t_{eco} \times v_{som}}{2}\)$

  • \(d\) = distância até o obstáculo (m)

  • \(t_{eco}\) = tempo do eco (s)

  • \(v_{som}\) = 343 m/s (a 20°C)

  • Divide por 2 porque o som vai e volta

Parâmetro

Valor

Alcance

2 cm a 400 cm

Precisão

± 3 mm

Tensão

5V

Frequência

40 kHz


Aplicação em Engenharia Civil — Monitoramento de Nível:#

O sensor HC-SR04 é utilizado em estações de monitoramento de nível de rios e reservatórios. Instalado sobre a lâmina d’água, calcula a distância à superfície e estima o nível. Pesquisas com Arduino e HC-SR04 mostraram precisão aceitável (erro < 4 cm) em escalas de 0 a 4 metros — aplicação diretamente relacionada ao dimensionamento de obras hidráulicas e planos de contingência para enchentes.

# ============================================================
# SIMULAÇÃO: Leitura do sensor ultrassônico HC-SR04
# ============================================================

import numpy as np
import matplotlib.pyplot as plt

# ---- Função de cálculo de distância ----
def calcular_distancia(tempo_eco_s, temperatura_C=20):
    """
    Calcula a distância a partir do tempo do eco ultrassônico.

    Parâmetros:
        tempo_eco_s  : float — duração do pulso ECHO (em segundos)
        temperatura_C: float — temperatura ambiente (afeta vel. do som)

    Retorna:
        distancia_m  : float — distância ao obstáculo em metros
        distancia_cm : float — distância em centímetros
    """
    # A velocidade do som varia com a temperatura:
    # v = 331.3 + 0.606 * T  (m/s)
    velocidade_som = 331.3 + 0.606 * temperatura_C

    distancia_m  = (tempo_eco_s * velocidade_som) / 2
    distancia_cm = distancia_m * 100
    return distancia_m, distancia_cm

# ---- Exemplos de leitura ----
print("=" * 55)
print("  LEITURAS DO SENSOR ULTRASSÔNICO HC-SR04")
print("=" * 55)

exemplos = [
    (0.00060, 20, "Obstaculo próximo"),
    (0.00290, 20, "Distância média"),
    (0.01170, 20, "Obstáculo distante"),
    (0.00290, 35, "Dia quente (35°C)"),  # efeito da temperatura
]

for t, temp, desc in exemplos:
    d_m, d_cm = calcular_distancia(t, temp)
    print(f"  {desc:<25} | t={t*1000:.2f} ms | T={temp}°C | d = {d_cm:.1f} cm")

print()

# ---- Gráfico: distância vs tempo do eco ----
tempos = np.linspace(0.0001, 0.023, 200)   # de 0.1ms a 23ms
distancias_20 = [calcular_distancia(t, 20)[1] for t in tempos]
distancias_35 = [calcular_distancia(t, 35)[1] for t in tempos]

fig, ax = plt.subplots(figsize=(9, 4))
ax.plot([t*1000 for t in tempos], distancias_20, label='T = 20°C', color='steelblue', linewidth=2)
ax.plot([t*1000 for t in tempos], distancias_35, label='T = 35°C', color='coral',    linewidth=2, linestyle='--')
ax.axhline(400, color='red', linestyle=':', linewidth=1, label='Limite máx. HC-SR04 (400cm)')
ax.axhline(2,   color='green', linestyle=':', linewidth=1, label='Limite mín. HC-SR04 (2cm)')
ax.set_xlabel('Tempo do eco (ms)', fontsize=11)
ax.set_ylabel('Distância calculada (cm)', fontsize=11)
ax.set_title('HC-SR04: Relação entre Tempo do Eco e Distância', fontsize=12)
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('sensor_distancia.png', dpi=120, bbox_inches='tight')
plt.show()

print("  Nota: a temperatura afeta a velocidade do som e, portanto, a leitura.")
print("   Em obras externas, é recomendável compensar a temperatura no cálculo.")
=======================================================
  LEITURAS DO SENSOR ULTRASSÔNICO HC-SR04
=======================================================
  Obstaculo próximo         | t=0.60 ms | T=20°C | d = 10.3 cm
  Distância média           | t=2.90 ms | T=20°C | d = 49.8 cm
  Obstáculo distante        | t=11.70 ms | T=20°C | d = 200.9 cm
  Dia quente (35°C)         | t=2.90 ms | T=35°C | d = 51.1 cm
../../_images/59734ac7a3c9d08479d788114ef007c83b59e4189a3597bcb1973c333650c6ba.png
  Nota: a temperatura afeta a velocidade do som e, portanto, a leitura.
   Em obras externas, é recomendável compensar a temperatura no cálculo.

8. Aplicações na Engenharia Civil#

Os conceitos do Otto Ninja têm paralelos diretos com sistemas utilizados na Engenharia Civil moderna:


8.1 Monitoramento Estrutural com Sensores#

Analogia: O sensor HC-SR04 do Otto detecta obstáculos a sua frente. Na Engenharia Civil, sensores ultrassônicos medem fissuras, recalques e deslocamentos em estruturas de concreto e fundações.

Aplicação Civil

Sensor

Parâmetro medido

Nível de reservatório

Ultrassônico

Lâmina d’água

Abertura de fissura

Extensômetro

Deslocamento (mm)

Recalque de fundação

LVDT / GPS

Deslocamento vertical

Vibração em pontes

Acelerômetro

Frequência natural


8.2 Robótica de Inspeção em Obras#

Robôs bípedes como o Otto inspiram robôs de inspeção capazes de caminhar sobre terrenos irregulares de obras, inspecionar dutos, verificar estruturas em altura ou entrar em ambientes confinados sem expor trabalhadores a riscos.


8.3 IoT e Monitoramento Remoto de Canteiro de Obras#

Com o ESP32, é possível replicar as funcionalidades de um sistema IoT real:

  Sensor (campo)  →  ESP32  →  Wi-Fi / MQTT  →  Dashboard Web
  ─────────────────────────────────────────────────────────────
  Nível d'água    →  ESP32  →  Internet       →  Alerta de cheia
  Temperatura     →  ESP32  →  Internet       →  Cura do concreto
  Deslocamento    →  ESP32  →  Internet       →  Alerta estrutural
# ============================================================
# SIMULAÇÃO: Monitoramento de Nível de Reservatório
# usando o mesmo princípio do sensor HC-SR04 do Otto Ninja
# ============================================================
#
# Cenário: Um ESP32 com sensor HC-SR04 está instalado na borda
# superior de um reservatório de 4 metros de altura.
# Ele mede a distância até a superfície da água a cada 30 min.
#
# Nível da água = Altura do reservatório - Distância medida
# ============================================================

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

# Parâmetros do reservatório
ALTURA_RESERVATORIO = 4.00  # metros
NIVEL_ALERTA        = 3.60  # metros (90% cheio)
NIVEL_CRITICO       = 3.80  # metros (95% cheio)

# Simulação: leituras ao longo de 24 horas (a cada 30 min)
# O nível sobe com chuva (0-12h) e estabiliza depois
horas = np.linspace(0, 24, 49)

# Curva simulada de variação do nível
nivel_agua = (
    2.0
    + 1.5 * (1 - np.exp(-horas / 6))       # Subida exponencial (chuva)
    - 0.3 * np.maximum(0, horas - 14) / 10  # Leve queda após a chuva
    + 0.05 * np.random.randn(49)             # Ruído de sensor
)
nivel_agua = np.clip(nivel_agua, 0, ALTURA_RESERVATORIO)

# Distância medida pelo sensor (HC-SR04) = Altura - Nível
distancia_sensor = ALTURA_RESERVATORIO - nivel_agua

# Detecção de alertas
em_alerta  = nivel_agua >= NIVEL_ALERTA
em_critico = nivel_agua >= NIVEL_CRITICO

# -------- Plot ---------
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(11, 7), sharex=True)

# Gráfico 1: Nível da água
ax1.fill_between(horas, nivel_agua, alpha=0.3, color='steelblue')
ax1.plot(horas, nivel_agua, color='steelblue', linewidth=2, label='Nível da água')
ax1.axhline(NIVEL_ALERTA,  color='orange', linestyle='--', linewidth=1.5, label=f'Nível de Alerta ({NIVEL_ALERTA}m)')
ax1.axhline(NIVEL_CRITICO, color='red',    linestyle='--', linewidth=1.5, label=f'Nível Crítico ({NIVEL_CRITICO}m)')
ax1.axhline(ALTURA_RESERVATORIO, color='black', linestyle='-', linewidth=1, label=f'Capacidade máxima ({ALTURA_RESERVATORIO}m)')
ax1.scatter(horas[em_critico], nivel_agua[em_critico], color='red', zorder=5, s=40, label='⚠ Alarme crítico')
ax1.set_ylabel('Nível da água (m)', fontsize=11)
ax1.set_title('🏗️ Monitoramento de Reservatório com Sensor Ultrassônico (HC-SR04 + ESP32)', fontsize=12)
ax1.legend(loc='lower right', fontsize=9)
ax1.set_ylim(0, 4.3)
ax1.grid(True, alpha=0.3)

# Gráfico 2: Distância medida pelo sensor
ax2.plot(horas, distancia_sensor * 100, color='darkorange', linewidth=2)
ax2.fill_between(horas, distancia_sensor * 100, alpha=0.2, color='orange')
ax2.set_xlabel('Hora do dia', fontsize=11)
ax2.set_ylabel('Distância medida (cm)', fontsize=11)
ax2.set_title('Leitura bruta do sensor HC-SR04 (distância sensor → superfície da água)', fontsize=11)
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('monitoramento_reservatorio.png', dpi=120, bbox_inches='tight')
plt.show()

# Estatísticas
print("ESTATÍSTICAS DO MONITORAMENTO (24 horas)")
print(f"   Nível mínimo:  {nivel_agua.min():.2f} m")
print(f"   Nível máximo:  {nivel_agua.max():.2f} m")
print(f"   Leituras em alerta:  {em_alerta.sum()} de {len(horas)}")
print(f"   Leituras críticas:   {em_critico.sum()} de {len(horas)}")
print()
print("💡 Este sistema usa exatamente o mesmo princípio do sensor ultrassônico")
print("   do Otto Ninja — mas aplicado à segurança de obras hidráulicas!")

9. Expansões com ESP32#

Com o ESP32, o projeto vai muito além de um simples robô escolar:

9.1 Controle por Bluetooth (App móvel)#

// Exemplo: receber comando Bluetooth e acionar movimento
#include <BluetoothSerial.h>
BluetoothSerial SerialBT;

void setup() {
  SerialBT.begin("OttoNinja");  // Nome que aparece no celular
}
void loop() {
  if (SerialBT.available()) {
    char cmd = SerialBT.read();  // Lê comando do app
    if (cmd == 'F') andar_frente();
    if (cmd == 'B') andar_atras();
    if (cmd == 'S') parar();
  }
}

9.2 Interface Web via Wi-Fi#

O ESP32 cria um servidor HTTP na própria rede Wi-Fi. O usuário acessa pelo navegador (celular ou PC) e controla o robô através de botões numa página HTML — sem instalar nenhum aplicativo.

9.3 Possibilidades avançadas:#

Funcionalidade

Tecnologia

Aplicação Civil

Controle de voz

Google Assistant / Alexa

Acionamento de sistemas

Envio de dados

MQTT / HTTP

Monitoramento remoto

OTA (atualização remota)

Wi-Fi

Manutenção de sensores em campo

Machine Learning

TensorFlow Lite

Detecção de anomalias estruturais

Integração com banco de dados

REST API

Histórico de medições


10. Exemplos de Aplicação#

Robótica:#

  1. Novo padrão de movimento: Programe uma “dança” com pelo menos 4 movimentos diferentes encadeados.

  2. Desvio automático: Implemente lógica que faça o robô virar à esquerda quando detectar obstáculo a menos de 20 cm.

  3. Controle Bluetooth: Modifique o código para receber comandos de um app de smartphone.

  4. Suavização: Use um loop for para mover o servo gradualmente (ângulo atual → ângulo alvo em 20 passos).

Sugestões de exemplos em Engenharia Civil (integração):#

  1. Nível de água: Programe o ESP32 para enviar alerta (buzzer + Wi-Fi) quando o nível do reservatório ultrapassar 90% da capacidade.

  2. Registrador de dados: Salve as leituras do HC-SR04 em um arquivo CSV com timestamp — simule um relatório de monitoramento estrutural.

  3. Análise de temperatura: Use o sensor DHT22 junto ao HC-SR04 para corrigir a velocidade do som na medição de distância em função da temperatura ambiente.


Referências#