Manufatura inteligente

Monitoramento de Tempo de Ciclo com IoT: dos Sinais do CLP à Análise de Gargalos

Meça cada ciclo, em vez de amostrar com um cronômetro. Capture sinais de ciclo com um ESP32, publique-os via MQTT e calcule estatísticas móveis que revelam o verdadeiro gargalo de uma linha.

Gráfico de monitoramento de tempo de ciclo comparando os tempos de ciclo das estações com o takt time e o gargalo destacado, alimentado por dados MQTT da linha
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

O monitoramento de tempo de ciclo substitui a cronoanálise por uma medição de cada ciclo, em cada estação, o dia inteiro. Neste tutorial você vai capturar sinais de ciclo a partir de uma saída de CLP ou de um sensor com um ESP32, publicar cada ciclo via MQTT e executar um pequeno serviço de análise que calcula estatísticas móveis por estação e identifica o gargalo da linha em relação ao takt time.

Tempo de ciclo, takt time e por que a diferença importa

Três termos costumam ser confundidos:

Termo Definição Origem
Takt time Tempo disponível de produção dividido pela demanda do cliente; o ritmo que a linha precisa atingir Planejamento
Tempo de ciclo ideal (de projeto) Tempo mais rápido possível para um ciclo em condições ideais Especificação da máquina, engenharia de processos
Tempo de ciclo real Tempo medido entre conclusões consecutivas de ciclo em uma estação Medição

Quando o tempo de ciclo real de uma estação é maior que o takt, a linha não consegue atender à demanda sem horas extras. Quando ele é maior que o tempo de ciclo ideal, a diferença é uma perda de desempenho em termos de OEE. Uma cronoanálise dá um retrato de algumas dezenas de ciclos; o monitoramento contínuo mostra a distribuição completa, incluindo os ciclos lentos que acontecem no início do turno, depois de trocas de ferramenta ou com certos operadores e materiais.

Qual sinal usar

Escolha um sinal que marque o mesmo ponto de todos os ciclos:

  1. Saída de "ciclo concluído" do CLP, ou um bit que você possa mapear para uma saída livre. A opção mais precisa.
  2. Sensor de presença de peça na saída da estação, como um sensor fotoelétrico ou indutivo.
  3. Sinal de fixação ou de porta em máquinas carregadas manualmente, se uma sequência de abrir/fechar equivale a um ciclo.
  4. Assinatura de corrente de um spindle ou prensa, como último recurso quando não existe nenhum sinal discreto.

Todos os sinais de 24 V precisam chegar ao microcontrolador por meio de um optoacoplador ou de um módulo de entrada com conversão de nível adequada, nunca diretamente.

Projeto de topics

Uma mensagem por ciclo mantém os dados brutos intactos e permite que qualquer consumidor calcule suas próprias estatísticas:

connectmq/plant1/assembly/line1/st-10/cycle       {"seq":1532,"ct_ms":41250,"ts":1760600000}
connectmq/plant1/assembly/line1/st-20/cycle       ...
connectmq/plant1/assembly/line1/cycle-stats       retained summary for all stations

O número de sequência permite que os consumidores detectem mensagens perdidas, e ct_ms é calculado no dispositivo a partir do seu próprio relógio, para que a latência de rede não distorça a medição.

Capturando ciclos em um ESP32

O sketch abaixo usa uma interrupção de hardware para registrar cada borda de subida com millis(), calcula o tempo desde a borda anterior e publica uma mensagem JSON por ciclo com o PubSubClient. Instale o PubSubClient pelo Gerenciador de Bibliotecas do Arduino. Se você é novo na placa, o tutorial de MQTT com ESP32 cobre o conjunto de ferramentas.

#include <WiFi.h>
#include <PubSubClient.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* BROKER    = "broker.connectmq.com";
const char* STATION   = "st-10";
const char* TOPIC     = "connectmq/demo/ctm-3k8p/line1/st-10/cycle";

const int CYCLE_PIN = 4;                   // saída do optoacoplador, ativa em LOW
const unsigned long MIN_CYCLE_MS = 2000;   // ignora repiques e pulsos duplos

WiFiClient net;
PubSubClient mqtt(net);

volatile unsigned long lastEdge = 0;
volatile unsigned long pendingCt = 0;
volatile bool havePending = false;
unsigned long seq = 0;

void IRAM_ATTR onCycle() {
  unsigned long now = millis();
  unsigned long ct = now - lastEdge;
  if (ct < MIN_CYCLE_MS) return;
  if (lastEdge != 0) {
    pendingCt = ct;
    havePending = true;
  }
  lastEdge = now;
}

void connectMqtt() {
  while (!mqtt.connected()) {
    String id = String("ctm-3k8p-") + STATION;
    if (mqtt.connect(id.c_str())) {
      Serial.println("MQTT connected");
    } else {
      Serial.printf("MQTT failed, rc=%d\n", mqtt.state());
      delay(2000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(CYCLE_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CYCLE_PIN), onCycle, FALLING);

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  mqtt.setServer(BROKER, 1883);
}

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

  if (havePending) {
    noInterrupts();
    unsigned long ct = pendingCt;
    havePending = false;
    interrupts();

    char payload[96];
    snprintf(payload, sizeof(payload), "{\"seq\":%lu,\"ct_ms\":%lu,\"up_ms\":%lu}",
             ++seq, ct, millis());
    mqtt.publish(TOPIC, payload);
    Serial.println(payload);
  }
}

A proteção MIN_CYCLE_MS filtra repiques de contato e pulsos duplos; defina-a em aproximadamente metade do ciclo realista mais rápido. A primeira borda após a inicialização apenas dispara o relógio, então nenhum ciclo longo falso é reportado. O PubSubClient publica em QoS 0; se você precisa de entrega QoS 1 para cada ciclo, o AsyncMqttClient oferece isso, ou você pode acumular ciclos e publicá-los em lotes. Para produção, troque para WiFiClientSecure, porta 8883 e as credenciais emitidas pelo seu broker.

Analisando os dados de monitoramento de tempo de ciclo

O serviço de análise assina todas as estações, mantém os últimos 200 ciclos por estação na memória e publica um resumo retido a cada 30 segundos. Usar a mediana e o percentil 90 em vez da média evita que ciclos ocasionais muito longos (que na verdade são pequenas paradas) distorçam o quadro.

#!/usr/bin/env python3
"""Rolling cycle time statistics and bottleneck detection."""
import json
import statistics
import threading
import time
from collections import defaultdict, deque

import paho.mqtt.client as mqtt

PREFIX = "connectmq/demo/ctm-3k8p/line1"
TAKT_MS = 45_000
STOP_THRESHOLD_MS = 3 * TAKT_MS        # intervalos maiores são pequenas paradas, não ciclos

cycles = defaultdict(lambda: deque(maxlen=200))
lock = threading.Lock()


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/+/cycle", qos=1)


def on_message(client, userdata, msg):
    station = msg.topic.split("/")[-2]
    ct = json.loads(msg.payload)["ct_ms"]
    if ct <= STOP_THRESHOLD_MS:
        with lock:
            cycles[station].append(ct)


def p90(values):
    return statistics.quantiles(values, n=10)[-1] if len(values) >= 10 else max(values)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="ctm-stats-3k8p")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()

while True:
    time.sleep(30)
    with lock:
        stats = {
            st: {"n": len(v), "median_ms": int(statistics.median(v)), "p90_ms": int(p90(v))}
            for st, v in cycles.items() if v
        }
    if not stats:
        continue
    bottleneck = max(stats, key=lambda s: stats[s]["median_ms"])
    summary = {
        "ts": int(time.time()),
        "takt_ms": TAKT_MS,
        "bottleneck": bottleneck,
        "over_takt": [s for s, v in stats.items() if v["median_ms"] > TAKT_MS],
        "stations": stats,
    }
    client.publish(f"{PREFIX}/cycle-stats", json.dumps(summary), qos=1, retain=True)
    print(json.dumps(summary, indent=2))

Você pode testar sem hardware publicando ciclos sintéticos:

for i in $(seq 1 20); do
  mosquitto_pub -h broker.connectmq.com -p 1883 -i ctm-sim-$RANDOM \
    -t connectmq/demo/ctm-3k8p/line1/st-20/cycle \
    -m "{\"seq\":$i,\"ct_ms\":$((44000 + RANDOM % 6000))}"
  sleep 1
done

Observe que o servidor MQTT público permite 10 mensagens por segundo por client, muito mais do que qualquer estação real precisa. Tudo o que é publicado ali pode ser lido publicamente, então use-o apenas para testes e dados sintéticos.

Interpretando os resultados

Observação Significado provável Próximo passo
Mediana acima do takt em uma estação Gargalo real Rebalancear o conteúdo de trabalho, adicionar capacidade, reduzir setup
Mediana abaixo do takt, mas p90 muito acima Instabilidade, não capacidade Procurar causas de ciclos lentos em material, operador ou qualidade
Todas as estações perto do takt, mas a linha ainda não atinge a produção Pequenas paradas ou bloqueio/falta de alimentação Combinar com estados de máquina e níveis de buffer
Tempo de ciclo subindo ao longo de semanas Desgaste de ferramenta, degradação do equipamento Correlacionar com dados de manutenção
Grande diferença entre turnos Diferenças de método ou de quadro de pessoal Padronizar o trabalho, treinar

A estação gargalo é onde a melhoria compensa para a linha inteira; melhorar qualquer outra estação apenas acumula estoque. Fique atento ao gargalo mudando de lugar após as alterações, o que é sinal de uma linha balanceada.

Expandindo o monitoramento de tempo de ciclo para a linha inteira

Comece pela estação que todos suspeitam ser o gargalo e por uma estação de cada lado dela. Três estações bastam para ver se os ciclos lentos são causados pela própria estação ou por falta de alimentação e bloqueio vindos das vizinhas. Depois de comprovar a escolha do sinal e as configurações de debounce, copie o mesmo sketch para as estações restantes e altere apenas o nome da estação e o topic.

Algumas regras práticas facilitam a implantação:

  1. Nomeie as estações exatamente como no layout da linha. Operadores e engenheiros precisam reconhecer st-20 no dashboard sem consultar uma tabela.
  2. Combine o ponto de ciclo de cada estação. Se uma estação conta na entrada da peça e a seguinte na saída, os números não são comparáveis.
  3. Registre o takt time junto com os dados. O takt muda quando a demanda muda; armazená-lo no resumo mantém os relatórios antigos interpretáveis.
  4. Verifique os relógios dos dispositivos. ct_ms vem do temporizador do próprio dispositivo e é confiável, mas qualquer timestamp adicionado para correlação precisa de gateways sincronizados por NTP.
  5. Mostre os dados na linha. Uma tela com a mediana ao vivo por estação em relação ao takt inicia mais conversas de melhoria do que um relatório semanal.

No portal da ConnectMQ, o explorador de topics ao vivo é uma forma rápida de confirmar, durante o comissionamento, que todas as estações estão publicando, e uma regra de alerta por limite sobre o median_ms de uma estação registra cada vez que ele passa do takt.

Conectando a outras métricas

Os dados de ciclo são a perna de desempenho do OEE. Combinados com o tempo de operação do monitoramento de status de máquinas e com as contagens de peças boas da contagem de produção com IoT, você tem tudo o que precisa para calcular o OEE. Mantenha tudo em um único broker e em uma única hierarquia de topics, e cada novo KPI passa a ser um assinante, e não um novo projeto de integração. Se quiser entender o que um broker MQTT faz como o centro deste design, comece por aí; o guia de manufatura inteligente o coloca no roteiro mais amplo.

Comece com a ConnectMQ

Uma linha com dezenas de estações publicando cada ciclo precisa de um broker sempre acessível. A ConnectMQ é um broker MQTT na nuvem, um broker MQTT gerenciado com TLS, MQTT 5, retained messages, explorador de topics ao vivo e alertas por limite em campos como median_ms. Crie um broker Serverless gratuito, sem cartão de crédito, e conecte sua primeira estação.

Perguntas frequentes

Qual é a diferença entre tempo de ciclo e takt time?

O takt time é o ritmo exigido pela demanda do cliente, calculado a partir do tempo disponível e da demanda. O tempo de ciclo é quanto tempo uma estação realmente leva por unidade. Uma estação cujo tempo de ciclo excede o takt limita a produção da linha.

Devo usar a média ou a mediana do tempo de ciclo?

Use a mediana para o ciclo típico e um percentil alto, como o p90, para a variabilidade. A média é facilmente distorcida por alguns ciclos longos que, na verdade, são pequenas paradas.

Posso medir o tempo de ciclo sem acesso ao CLP?

Sim. Um sensor fotoelétrico na saída da estação, um sinal de porta ou de fixação, ou a assinatura de corrente do acionamento principal podem marcar cada ciclo. Os sinais do CLP são os mais precisos quando disponíveis.

Como trato intervalos muito longos entre ciclos?

Trate intervalos muito maiores que o takt como paradas, e não como ciclos. Exclua-os das estatísticas de ciclo e registre-os como tempo de parada usando os dados de estado das máquinas.

Artigos relacionados

OEE vs TEEP vs OOE: qual indicador você deve usar?

OEE, OOE e TEEP compartilham os mesmos fatores de desempenho e qualidade, mas medem contra bases de tempo diferentes. Esta comparação resolve um único exemplo e lista os sinais MQTT de que cada indicador precisa.

8 min de leitura

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.