IoT e IA

Fusão de Sensores Explicada para Desenvolvedores IoT

O que é fusão de sensores, como os filtros complementar e de Kalman combinam sensores ruidosos, quando fazer a fusão na borda ou na nuvem e exemplos funcionais em ESP32 e Python que publicam valores fundidos via MQTT.

Diagrama de fusão de sensores combinando leituras de acelerômetro e giroscópio em um filtro complementar para obter um ângulo de inclinação estável publicado via MQTT
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Fusão de sensores é a técnica de combinar leituras de vários sensores para que o resultado seja mais preciso, mais estável ou mais completo do que qualquer sensor isolado conseguiria oferecer. Para desenvolvedores IoT, ela costuma ser a diferença entre um sinal trêmulo e com deriva e um sinal em que você pode confiar em um dashboard ou em um modelo. Este artigo explica as principais abordagens de fusão em termos simples, mostra quando fazer a fusão na borda ou na nuvem e traz código funcional para ESP32 e Python que publica valores fundidos via MQTT.

Por que combinar sensores

Todo sensor tem pontos fracos. Um acelerômetro mede bem a inclinação quando o dispositivo está parado, mas é perturbado por qualquer vibração. Um giroscópio mede a rotação de forma suave, mas o ângulo integrado deriva com o tempo. O GPS fornece posição absoluta, mas atualiza devagar e salta quando está sob árvores; a odometria das rodas é suave, mas acumula erro. Duas sondas de temperatura baratas no mesmo tanque, digamos na câmara fria de um frigorífico, discordam ligeiramente, e cada uma tem picos ocasionais.

A fusão aproveita o fato de esses pontos fracos serem diferentes. Se um sensor é ruidoso em altas frequências e outro deriva em baixas frequências, combiná-los gera um sinal bom em toda a faixa. Se dois sensores medem a mesma grandeza com ruídos independentes, uma combinação ponderada é mais precisa do que qualquer um deles sozinho. E, quando um sensor falha, uma estimativa fundida consegue detectar a inconsistência em vez de reportar silenciosamente um valor errado.

Três níveis de fusão de sensores

Nível O que é combinado Exemplo Método típico
Baixo nível (dados) Medições brutas da mesma grandeza Duas sondas de temperatura, acelerômetro mais giroscópio Média ponderada, filtro complementar, filtro de Kalman
Nível de características Características derivadas de sensores diferentes RMS de vibração mais corrente do motor mais temperatura Vetores de características para um modelo de ML
Nível de decisão Saídas de detectores separados A câmera diz "pessoa", o PIR diz "movimento" Votação, regras, combinação bayesiana

A fusão de baixo nível é o foco deste artigo, porque é nela que vivem filtros como o complementar e o de Kalman. A fusão no nível de características é a entrada cotidiana dos modelos de machine learning, como em machine learning para manutenção preditiva, onde vibração, temperatura e corrente juntas revelam uma degradação que nenhuma delas mostra claramente sozinha.

O filtro complementar

O filtro complementar é o método de fusão útil mais simples e um bom ponto de partida para sensores inerciais. Para estimar um ângulo de inclinação, ele integra a taxa do giroscópio para as mudanças de curto prazo e puxa suavemente o resultado em direção ao ângulo do acelerômetro para remover a deriva de longo prazo:

angle = alpha * (angle + gyro_rate * dt) + (1 - alpha) * accel_angle

Com alpha em torno de 0,98 e um período de amostragem de 10 ms, o giroscópio domina em frações de segundo e o acelerômetro domina em alguns segundos. O filtro não precisa de matrizes, roda em microssegundos em um microcontrolador e é fácil de ajustar: aumente alpha se a saída estiver ruidosa e diminua se ela derivar.

O filtro de Kalman

O filtro de Kalman generaliza a mesma ideia. Ele mantém uma estimativa do estado e da sua própria incerteza, prevê como o estado vai mudar e depois corrige a previsão a cada medição, ponderando a correção pelo quanto confia na medição em relação à previsão. Quando a medição é ruidosa, o filtro se apoia na previsão; quando a previsão é incerta, ele se apoia na medição.

Para uma única grandeza com dois sensores, a atualização de Kalman é curta o bastante para ser lida por inteiro:

import json
import random
import time
import uuid

import paho.mqtt.client as mqtt


class Kalman1D:
    def __init__(self, x0, p0=1.0, q=0.001):
        self.x, self.p, self.q = x0, p0, q   # estimate, its variance, process noise

    def predict(self):
        self.p += self.q

    def update(self, z, r):
        k = self.p / (self.p + r)            # Kalman gain
        self.x += k * (z - self.x)
        self.p *= (1 - k)
        return self.x


BASE = f"connectmq/demo/{uuid.uuid4().hex[:8]}/tank1"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="fusion-" + uuid.uuid4().hex[:8])
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()

kf = Kalman1D(x0=20.0)
true_temp = 20.0
R_PT100, R_NTC = 0.05 ** 2, 0.4 ** 2       # measurement variances from datasheets or tests

for _ in range(300):
    true_temp += random.gauss(0, 0.02)
    pt100 = true_temp + random.gauss(0, 0.05)
    ntc = true_temp + random.gauss(0, 0.4) + (5 if random.random() < 0.02 else 0)  # occasional spike
    kf.predict()
    if abs(ntc - kf.x) < 3 * (R_NTC + kf.p) ** 0.5:  # gate out implausible readings
        kf.update(ntc, R_NTC)
    fused = kf.update(pt100, R_PT100)
    payload = {"ts": int(time.time() * 1000), "value": round(fused, 3), "variance": round(kf.p, 6),
               "raw": {"pt100": round(pt100, 3), "ntc": round(ntc, 3)}}
    client.publish(f"{BASE}/temperature/fused", json.dumps(payload))
    time.sleep(1)

client.loop_stop()
client.disconnect()

Instale com pip install paho-mqtt e assine com mosquitto_sub -h broker.connectmq.com -p 1883 -i fusion-watch-$RANDOM -t "connectmq/demo/+/tank1/#" -v para ver o valor fundido ao lado das leituras brutas. Repare no filtro de validação: leituras que discordam da estimativa atual por mais de três desvios-padrão são descartadas, e é assim que o filtro rejeita os picos do NTC. Publicar a variância junto com o valor permite que os consumidores saibam o quanto a estimativa é confiável.

Em problemas multidimensionais, como posição e velocidade a partir de GPS e de uma IMU, a mesma estrutura usa matrizes, e sistemas não lineares usam o filtro de Kalman estendido ou o unscented. Bibliotecas como a FilterPy em Python ou os filtros de Madgwick e Mahony para orientação poupam você de implementá-los à mão.

Fusão na borda: exemplo com ESP32

A fusão inercial precisa rodar perto do sensor, porque exige amostras rápidas e regularmente espaçadas, muitas vezes a 100 Hz ou mais. Publicar cada amostra bruta via MQTT desperdiçaria banda e bateria e acrescentaria jitter. O melhor padrão é fazer a fusão no dispositivo e publicar o resultado a uma taxa moderada.

Este sketch lê um MPU6050 via I2C em um ESP32, executa um filtro complementar a 100 Hz e publica o ângulo de pitch fundido duas vezes por segundo no servidor MQTT público em broker.connectmq.com, que serve para testes e protótipos, não para dados de produção. Ele usa as bibliotecas Adafruit MPU6050 e PubSubClient.

#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* BROKER = "broker.connectmq.com";
const char* TOPIC = "connectmq/demo/imu-7f3a/arm1/pitch";

WiFiClient net;
PubSubClient mqtt(net);
Adafruit_MPU6050 mpu;

float pitch = 0.0f;
const float ALPHA = 0.98f;
unsigned long lastSample = 0, lastPublish = 0;

void connectMqtt() {
  while (!mqtt.connected()) {
    String id = "esp32-imu-" + String((uint32_t)ESP.getEfuseMac(), HEX);
    if (!mqtt.connect(id.c_str())) delay(2000);
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  mqtt.setServer(BROKER, 1883);
  if (!mpu.begin()) {
    Serial.println("MPU6050 not found");
    while (true) delay(1000);
  }
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_44_HZ);
  lastSample = micros();
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (micros() - lastSample >= 10000) {           // 100 Hz
    float dt = (micros() - lastSample) / 1e6f;
    lastSample = micros();
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    float accelPitch = atan2f(-a.acceleration.x,
                              sqrtf(a.acceleration.y * a.acceleration.y + a.acceleration.z * a.acceleration.z)) * 180.0f / PI;
    float gyroRate = g.gyro.y * 180.0f / PI;     // rad/s to deg/s
    pitch = ALPHA * (pitch + gyroRate * dt) + (1.0f - ALPHA) * accelPitch;
  }

  if (millis() - lastPublish >= 500) {            // 2 messages per second
    lastPublish = millis();
    char payload[64];
    snprintf(payload, sizeof(payload), "{\"pitch\":%.2f,\"unit\":\"deg\"}", pitch);
    mqtt.publish(TOPIC, payload);
  }
}

Troque o segmento de topic imu-7f3a por algo único. Para um dispositivo de produção, mude para WiFiClientSecure na porta 8883 com o username, a senha e o client ID do ConnectMQ; o tutorial de ESP32 com MQTT cobre a configuração de TLS em detalhes.

Fusão na borda ou na nuvem: como decidir

  1. Faça a fusão na borda quando os sensores estiverem no mesmo dispositivo, as taxas de amostragem forem altas, a latência importar (balanceamento, estabilização, segurança) ou a banda e a bateria forem limitadas.
  2. Faça a fusão na nuvem ou em um servidor quando os sensores estiverem em dispositivos diferentes, as taxas forem baixas, você precisar de contexto histórico ou quiser mudar o algoritmo sem atualizar o firmware.
  3. Publique os dois por um tempo durante o desenvolvimento: valores brutos a uma taxa reduzida e valores fundidos, para verificar o filtro contra a realidade.
  4. Sempre registre o timestamp na origem ao fundir dados de vários dispositivos, porque a ordem de chegada no broker não é a ordem das medições.

É o mesmo trade-off discutido em o que é edge AI: o processamento vai para onde estão os dados e os requisitos de latência.

Erros comuns na fusão de sensores

  • Parâmetros de ruído errados. Um filtro de Kalman é tão bom quanto o ruído de medição e de processo que ele assume. Meça o ruído a partir de uma gravação com o sensor parado, em vez de chutar.
  • Eixos e unidades incompatíveis. Giroscópios costumam reportar em rad/s; os eixos do acelerômetro podem estar montados de forma diferente da que você imagina. Confira os sinais inclinando a placa com a mão.
  • Amostragem irregular. Os filtros assumem um dt conhecido. Calcule-o a partir dos timestamps em vez de assumir uma constante.
  • Fontes não sincronizadas. Fundir dois dispositivos cujos relógios diferem em segundos gera artefatos. Sincronize com NTP e transporte os timestamps de origem.
  • Mascarar falhas de sensores. A fusão pode esconder um sensor com defeito. Publique indicadores brutos de saúde ou valores de inovação para que as falhas continuem visíveis, o que também alimenta a detecção de anomalias em IoT.

Para onde vão os dados fundidos

Valores fundidos são entradas melhores para dashboards, alertas, modelos e para um gêmeo digital do ativo. O ConnectMQ atua como o broker MQTT gerenciado que os leva dos dispositivos aos consumidores: o explorador de topics ao vivo mostra topics fundidos e brutos lado a lado, e regras de alerta por limite podem disparar sobre um valor fundido, como um ângulo de inclinação além de um limite seguro. Para entender de forma mais ampla como modelos e dispositivos conectados trabalham juntos, veja o guia de IA e IoT.

Comece a usar o ConnectMQ

Teste primeiro os exemplos no servidor MQTT público (gratuito) e depois crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, para obter credenciais privadas e TLS para os seus dispositivos.

Perguntas frequentes

O que é fusão de sensores em IoT?

A fusão de sensores combina medições de vários sensores para produzir uma estimativa mais precisa, estável ou completa do que a de qualquer sensor isolado, por exemplo um ângulo de inclinação sem deriva obtido de um acelerômetro e de um giroscópio.

Devo usar um filtro complementar ou um filtro de Kalman?

Comece com um filtro complementar para problemas simples de orientação em microcontroladores. Use um filtro de Kalman quando precisar combinar sensores com características de ruído conhecidas, estimar vários estados relacionados ou reportar a incerteza.

A fusão de sensores deve rodar no dispositivo ou na nuvem?

Rode no dispositivo quando os sensores forem locais e rápidos, porque enviar cada amostra bruta é caro e acrescenta jitter. Rode de forma centralizada quando os sensores estiverem em dispositivos diferentes ou a taxa de atualização for baixa.

Ainda consigo acessar os dados brutos se fizer a fusão na borda?

Sim. Um padrão comum é publicar os valores fundidos continuamente e os valores brutos a uma taxa menor ou sob demanda em topics separados, o que mantém o uso de banda baixo e ainda permite a verificação.

Artigos relacionados

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.