Fabricación inteligente

Conteo de producción IoT: sensores, contadores en el edge y totales por turno con MQTT

Cuenta automáticamente piezas buenas y rechazadas con sensores fotoeléctricos y una Raspberry Pi, conserva los conteos tras los reinicios y publica totales por turno retenidos por MQTT para que todas las pantallas muestren la cifra correcta.

Montaje de conteo de producción IoT con un sensor fotoeléctrico en una cinta transportadora, un contador de edge Raspberry Pi y una pantalla de total por turno actualizada por MQTT
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

El conteo de producción con sensores IoT sustituye las hojas de conteo manual y las estimaciones de fin de turno por conteos de piezas exactos y en vivo. En este tutorial contarás piezas buenas y rechazadas con sensores fotoeléctricos y una Raspberry Pi, harás que el contador sobreviva a reinicios y cortes de red, y publicarás totales por turno retenidos por MQTT para que todos los tableros, tablets e informes muestren la misma cifra.

Por qué importa el conteo automático

Los conteos escritos a mano llegan tarde, redondeados y a veces con optimismo. Aparecen después del turno, cuando ya no se puede hacer nada ante un déficit. Un contador automático muestra la brecha frente al objetivo mientras todavía hay tiempo de reaccionar, y aporta las entradas de calidad y rendimiento que necesita el OEE. Además, es uno de los proyectos IoT más sencillos de la planta: un sensor, un dispositivo de edge, un topic.

Elegir el punto de conteo

Punto de conteo Ventajas Inconvenientes
Contador de piezas del PLC o bit de "pieza terminada" Exacto, ya filtrado contra rebotes Requiere acceso y cambios en el PLC
Sensor fotoeléctrico a la salida de la estación Retrofit sin tocar el PLC; funciona con la mayoría de piezas Debe manejar huecos, piezas juntas y superficies reflectantes
Sensor inductivo Robusto con piezas metálicas, ignora la suciedad Corto alcance, solo metal
Sensor en la rampa de rechazo o en el contenedor de scrap Da el conteo de scrap para la tasa de calidad Necesita un segundo sensor
Estación de embalaje (cajas, luego multiplicar) Cuenta lo que realmente se envía Con retraso, oculta el scrap entre la estación y el embalaje

Cuenta lo más cerca posible del punto donde la pieza pasa a ser "buena". Si la línea tiene una estación de inspección, cuenta las piezas aprobadas después de ella y las rechazadas en la vía de rechazo. El conteo de buenas y el de scrap juntos dan la producción total.

En sensores fotoeléctricos, los de barrera son los más fiables en cintas transportadoras, porque las piezas juntas o brillantes pueden confundir a los sensores difusos. Monta el sensor de forma que cada pieza interrumpa el haz exactamente una vez, con un hueco entre piezas.

Cableado

Los sensores industriales funcionan a 24 V y conmutan salidas PNP o NPN. Llévalos a la Raspberry Pi a través de una placa de entradas con optoacopladores; los pines GPIO de la Pi solo toleran 3,3 V. Asignación de ejemplo:

Entrada GPIO (BCM) Señal
Sensor de pieza buena 17 Salida del receptor de barrera
Sensor de rechazo 27 Sensor de la rampa de rechazo
Reinicio de turno (opcional) 22 Interruptor de llave o botón del supervisor

Diseño de topics para conteos y totales por turno

connectmq/plant1/packaging/line2/counter/count      every N seconds, not retained
connectmq/plant1/packaging/line2/counter/shift      retained shift totals
connectmq/plant1/packaging/line2/counter/status     retained online / offline

El mensaje shift es retenido, así que un dashboard que se abra a mitad de turno muestra de inmediato los totales actuales. Su payload contiene totales absolutos, no incrementos:

{
  "shift": "2026-10-16-A",
  "start": 1760594400,
  "good": 1843,
  "reject": 27,
  "target": 2400,
  "ts": 1760600000
}

Publicar totales absolutos es la decisión de diseño clave. Si un mensaje se pierde o se entrega dos veces, el siguiente sigue conteniendo el total correcto; los incrementos acabarían desviándose.

El script de edge para conteo de producción IoT

El script cuenta flancos en ambas entradas, guarda los totales en un pequeño archivo cada pocos segundos para que un reinicio no los pierda, detecta los cambios de turno a partir de un horario y publica los totales retenidos. Instala las dependencias en un entorno virtual con pip install gpiozero lgpio paho-mqtt.

#!/usr/bin/env python3
"""Production counting IoT edge: sensors -> persistent counts -> retained MQTT totals."""
import json
import os
import threading
import time
from datetime import datetime, timedelta

import paho.mqtt.client as mqtt
from gpiozero import DigitalInputDevice

BROKER = "broker.connectmq.com"
BASE = "connectmq/demo/pc-9d1x/line2/counter"
STATE_FILE = "/var/lib/pc-counter/state.json"
PUBLISH_EVERY = 5                      # segundos
SHIFTS = [("A", 6), ("B", 14), ("C", 22)]
TARGET_PER_SHIFT = 2400

lock = threading.Lock()


def current_shift(now=None):
    now = now or datetime.now()
    starts = []
    for name, hour in SHIFTS:
        start = now.replace(hour=hour, minute=0, second=0, microsecond=0)
        if start > now:
            start -= timedelta(days=1)
        starts.append((start, name))
    start, name = max(starts)
    return f"{start:%Y-%m-%d}-{name}", int(start.timestamp())


def load_state():
    shift_id, start = current_shift()
    try:
        with open(STATE_FILE) as f:
            state = json.load(f)
        if state.get("shift") == shift_id:
            return state
    except (FileNotFoundError, ValueError):
        pass
    return {"shift": shift_id, "start": start, "good": 0, "reject": 0}


def save_state(state):
    tmp = STATE_FILE + ".tmp"
    with open(tmp, "w") as f:
        json.dump(state, f)
    os.replace(tmp, STATE_FILE)        # atómico en el mismo sistema de archivos


state = load_state()


def count(field):
    def handler():
        with lock:
            state[field] += 1
    return handler


good_in = DigitalInputDevice(17, pull_up=True, bounce_time=0.01)
reject_in = DigitalInputDevice(27, pull_up=True, bounce_time=0.01)
good_in.when_activated = count("good")
reject_in.when_activated = count("reject")


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.publish(f"{BASE}/status", "online", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="pc-9d1x-line2")
client.will_set(f"{BASE}/status", "offline", qos=1, retain=True)
client.on_connect = on_connect
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()

os.makedirs(os.path.dirname(STATE_FILE), exist_ok=True)

while True:
    time.sleep(PUBLISH_EVERY)
    shift_id, start = current_shift()
    with lock:
        if shift_id != state["shift"]:
            final = dict(state, ts=int(time.time()), final=True)
            client.publish(f"{BASE}/shift-closed", json.dumps(final), qos=1)
            state.update(shift=shift_id, start=start, good=0, reject=0)
        snapshot = dict(state, target=TARGET_PER_SHIFT, ts=int(time.time()))
        save_state(state)
    client.publish(f"{BASE}/shift", json.dumps(snapshot), qos=1, retain=True)
    client.publish(f"{BASE}/count", json.dumps(snapshot), qos=0)

Puntos que conviene destacar:

  • Guardado atómico: escribir en un archivo temporal y renombrarlo significa que un corte de luz durante la escritura no puede corromper el archivo de estado.
  • Cambio de turno en el edge: el propio dispositivo cierra el turno y publica un registro final en shift-closed, de modo que el total es correcto aunque ningún servidor esté escuchando en ese momento. Un historiador suscrito con sesión persistente lo recibe más tarde.
  • Antirrebote: bounce_time filtra el ruido eléctrico; las piezas que pasen más rápido que la ventana antirrebote se contarían de menos, así que ajústalo según tu ritmo máximo de piezas.

Crea /var/lib/pc-counter con permisos para el usuario del servicio y ejecuta el script con systemd.

Observar los conteos

mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-view-$RANDOM \
  -t "connectmq/demo/pc-9d1x/line2/counter/#" -v

Primero llegan el total del turno retenido y el estado, y después las actualizaciones cada cinco segundos. En el servidor MQTT público gratuito cualquiera puede leer estos topics, lo cual está bien para una prueba de banco pasando la mano por una barrera de luz, pero no para una línea real. En producción, añade client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD") y client.tls_set(), usa tu client ID asignado y conéctate al puerto 8883.

Validar el contador

Antes de que nadie confíe en las cifras, verifícalas:

  1. Pasa un lote conocido (por ejemplo, 200 piezas contadas a mano) y compara.
  2. Prueba con piezas que se tocan entre sí y con la velocidad de línea realista más alta.
  3. Comprueba el comportamiento tras un reinicio en mitad de una corrida: el conteo debe continuar, no volver a cero.
  4. Desconecta la red unos minutos: el conteo sigue en local y el siguiente total publicado incluye las piezas fabricadas sin conexión.
  5. Compara un turno completo con el conteo de embalaje o del ERP; las diferencias deben poder explicarse (scrap, retrabajo, WIP).

Problemas habituales

Problema Causa Solución
Conteos dobles Bordes u orificios de la pieza interrumpen el haz dos veces Aumentar el antirrebote, reubicar el sensor, usar barrera
Conteos perdidos Piezas juntas, antirrebote demasiado largo Separar piezas en la cinta, acortar el antirrebote, usar la señal del PLC
El conteo se reinicia tras un corte de luz Estado no persistido Persistir en archivo como se muestra, o usar el contador del PLC
Los dashboards muestran el turno de ayer Mensaje retenido de un dispositivo detenido Monitorear status; mostrar "offline" de forma destacada
Los totales difieren entre pantallas Las pantallas calculan a partir de incrementos Mostrar siempre el total absoluto retenido

Mostrar los conteos en la línea

La pantalla más eficaz es la sencilla: piezas buenas hasta ahora, objetivo hasta ahora (prorrateado según el tiempo transcurrido del turno) y la diferencia, con dígitos grandes visibles desde el puesto de trabajo. Un navegador en una pantalla de pared puede suscribirse por WebSocket seguro al topic retenido shift y calcular el objetivo prorrateado a partir de start y target, sin necesidad de un servidor adicional. Colorea la diferencia en verde cuando se va por delante y en rojo cuando se va por detrás, y muestra el conteo de rechazos al lado para que nunca se celebre la velocidad a costa de la calidad.

Durante la puesta en marcha, el explorador de topics en vivo del portal de ConnectMQ muestra el total retenido y el estado de cada contador, lo que facilita comprobar que todas las líneas publican antes de instalar las pantallas.

Aprovechar los conteos

Los conteos en vivo frente al objetivo son la visualización motivadora más simple de una línea. Combinados con el tiempo de marcha del monitoreo del estado de las máquinas y los datos de ciclo del monitoreo del tiempo de ciclo, alimentan directamente el monitoreo de OEE en tiempo real: el conteo de buenas sobre el conteo total es la tasa de calidad, y el conteo total frente al tiempo de ciclo ideal da el rendimiento. Los equipos de energía usan el mismo conteo de piezas buenas para calcular la energía por pieza. Y si quieres ver esas cifras sobre la propia planta, pueden alimentar un gemelo digital 3D.

El broker es la fuente única de verdad para todos estos consumidores, por eso conviene entender qué hace un broker MQTT antes de escalar a muchas líneas. La guía de manufactura inteligente muestra dónde encaja el conteo en una hoja de ruta más amplia.

Escala tus contadores con ConnectMQ

ConnectMQ es un broker MQTT gestionado con TLS, MQTT 5, mensajes retenidos, una vista de dispositivos ISA-95 y alertas por umbral, por ejemplo cuando un conteo good se queda por detrás del plan. Crea un broker Serverless gratuito sin tarjeta de crédito y conecta tu primer contador en minutos.

Preguntas frecuentes

¿Un contador de producción debe publicar incrementos o totales?

Totales. Un total absoluto del turno en un mensaje retenido es correcto aunque se pierdan o dupliquen mensajes, y los nuevos suscriptores ven el valor actual de inmediato.

¿Qué pasa con los conteos si se cae la red?

El dispositivo de edge sigue contando en local y persiste los totales. Cuando vuelve la conexión, el siguiente mensaje publicado contiene el total completo, incluidas las piezas fabricadas durante el corte.

¿Qué sensor es mejor para proyectos de conteo de producción IoT?

Los sensores fotoeléctricos de barrera son la opción general más fiable en cintas transportadoras. Los sensores inductivos son adecuados para piezas metálicas, y la señal de pieza terminada del PLC es la mejor cuando está disponible.

¿Cómo cuento el scrap por separado?

Añade un segundo sensor en la vía de rechazo o usa la señal de rechazo de la estación de inspección, y publica los conteos de buenas y rechazadas en el mismo mensaje para que la tasa de calidad sea siempre coherente.

Artículos relacionados

OEE vs TEEP vs OOE: ¿qué indicador deberías usar?

OEE, OOE y TEEP comparten los mismos factores de rendimiento y calidad, pero se miden frente a bases de tiempo distintas. Esta comparativa resuelve un único ejemplo y enumera las señales MQTT que necesita cada indicador.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.