Una impresión de doce horas que falla a la hora tres desperdicia filamento, tiempo y. si el spaghetti se enreda en el hotend. a veces el hotend completo. La solución no es quedarse mirando la impresora: es enseñarle a una cámara qué se ve cuando todo va bien, y que ella avise cuando algo se sale del molde.

Esta es la segunda parte de un proyecto que arma exactamente eso: un vigilante de impresión basado en detección de anomalías, montado sobre un Arduino UNO Q con su Media Carrier y una cámara IMX219. En la primera parte se resolvió la mecánica (el soporte impreso, el brazo articulado, la posición junto al lecho). Acá empieza la parte que hace que el hardware sirva de algo.

Al terminar este capítulo vas a tener tres cosas funcionando: la cámara reconocida por el sistema. que no es automático, y ahí está la parte interesante. , una vista en vivo accesible desde el navegador del celular para encuadrar sin adivinar, y un recolector automático que junta cientos de imágenes de entrenamiento mientras la impresora trabaja sola.

El obstáculo que nadie documentó: la cámara no existe

Conectas la cámara al puerto CAM0 (contactos hacia la placa, y siempre con la placa desconectada de la corriente), arrancas, entras por SSH y pides la lista de cámaras. No hay ninguna:

Bash
arduino@uno-q:~$ cam -l
Available cameras:
arduino@uno-q:~$ ls /dev/media*
ls: cannot access '/dev/media*': No such file or directory

El log del kernel tampoco menciona el IMX219 ni el subsistema de cámara. No es un cable mal puesto ni una cámara muerta: la causa está en el device tree.

Vale la pena entender qué es, porque explica todo lo que viene. En un PC, el firmware le entrega al sistema operativo una lista de dispositivos y Linux los descubre solo. En una plataforma ARM como el Qualcomm QRB2210 del UNO Q no existe ese mecanismo: el kernel recibe un archivo binario. el device tree blob, extensión .dtb— que describe literalmente qué periféricos hay, en qué direcciones y con qué relojes. Si el .dtb con el que arrancas no menciona el bloque de cámara del chip, ese bloque no se enciende y no hay nada que descubrir. La cámara está físicamente conectada y eléctricamente muerta.

La buena noticia: Arduino incluye el .dtb correcto en la imagen. Simplemente no lo usa por defecto.

La ruta corta: el interruptor en App Lab

En imágenes recientes del UNO Q (versión superior a la 523) hay un interruptor gráfico que hace todo esto por ti. Verificado sobre imagen 558 con App Lab 0.10:

  1. Abre App Lab y haz clic en el engranaje de Settings, abajo a la izquierda.
  2. Baja hasta la sección Carriers y activa Enable external carriers connected to your Arduino UNO Q. El Media Carrier se detecta solo.
  3. En Camera0 elige type1-2lanes. Esto importa: el IMX219 usa dos líneas de datos MIPI, y la opción de 4 lanes es para otros sensores. Elegir mal aquí deja la cámara igual de invisible.
  4. Haz clic en Apply and reboot.

Ajustes de App Lab con los carriers habilitados y Camera0 configurado en type1-2lanes

Después del reinicio, salta directamente a la verificación con cam -l más abajo.

La ruta larga: crear tu propia entrada de arranque

Esta sección es para quien corre una imagen antigua sin ese interruptor, o para quien quiere ver qué hace el interruptor por dentro. El procedimiento es copiar y pegar dos archivos de texto, y deja el arranque original intacto como red de seguridad.

En el directorio EFI de la placa conviven el device tree estándar y una variante con soporte de cámara. El nombre cambió entre versiones, así que primero averigua cuál tienes:

Bash
ls /boot/efi/dtb/qcom/

En imágenes antiguas el archivo se llama qrb2210-arduino-imola-camera-rpiv2.dtb —el "rpiv2" viene de Raspberry Pi Camera versión 2, que es justamente nuestro IMX219. . Desde la imagen 558 pasó a llamarse qrb2210-arduino-imola-carrier-media-full-2lanes.dtb.

En lugar de sobrescribir el archivo estándar (riesgoso: si algo falla te quedas sin arranque), creamos una segunda entrada de arranque que carga explícitamente ese device tree. Si algo sale mal, la entrada vieja sigue ahí:

Bash
sudo nano /boot/efi/loader/entries/camera.conf

El contenido es una copia de la entrada existente en esa misma carpeta, con una línea devicetree agregada. La versión del kernel y el UUID los copias de tu entrada original. no los inventes, no son los mismos en dos placas:

Código
title Camera (imx219)
linux /<machine-id>/<kernel>/linux
initrd /<machine-id>/<kernel>/initrd.img-<kernel>
devicetree /dtb/qcom/qrb2210-arduino-imola-camera-rpiv2.dtb
options root=UUID=<eure-uuid> clk_ignore_unused pd_ignore_unused audit=0 deferred_probe_timeout=30

Falta decirle al bootloader que use esa entrada por defecto. Eso vive en la configuración central:

Bash
sudo nano /boot/efi/loader/loader.conf

Son unas pocas líneas. Antes se ve así, donde el nombre críptico de la línea default es el machine id de tu placa (el tuyo será distinto):

Código
#timeout 3
#console-mode keep
default a3cfdcbfa9ad463e89f8a1f9bd9a5dd4-*

Modifica únicamente la línea default. Deja la anterior comentada: así el camino de vuelta queda documentado dentro del propio archivo, que es donde lo vas a buscar si algo falla.

Código
#timeout 3
#console-mode keep
# linea original, guardada como camino de vuelta:
#default a3cfdcbfa9ad463e89f8a1f9bd9a5dd4-*
default camera.conf

Guarda con Ctrl+O y Enter, sal con Ctrl+X, y reinicia con sudo reboot.

Una nota para quien se pregunte por qué no usamos bootctl set-default, que sería lo elegante: en el UNO Q las variables EFI están protegidas contra escritura bajo su firmware U-Boot, así que el comando no tiene dónde guardar el cambio. De ahí el rodeo por el archivo.

Verificación

Después del reinicio, el momento de la verdad:

Bash
arduino@uno-q:~$ cam -l
Available cameras:
1: 'imx219' (/base/soc@0/cci@5c1b000/i2c-bus@0/sensor@10)

Si sigues viendo la lista vacía, revisa en este orden: que el .dtb que pusiste en camera.conf exista realmente con ese nombre (el ls de más arriba), que la entrada se llame igual en loader.conf que el archivo en entries/, y que el cable plano esté con los contactos mirando hacia la placa. Los tres errores son igual de comunes y ninguno da un mensaje de error útil.

Dos particularidades de la plataforma Qualcomm que conviene saber antes de seguir: las capturas requieren permisos de root, porque el acceso a la memoria gráfica está bloqueado por defecto, y la resolución completa de 8 megapíxeles falla por lo justo que anda la memoria reservada para la cámara. A 640×480 funciona de forma confiable, y para lo que viene sobra: el modelo de anomalías trabaja internamente con imágenes de 96×96 píxeles.

Vista en vivo en el navegador

Para encuadrar necesitas ver lo que ve la cámara mientras mueves el brazo con la otra mano. Lo ideal es tener esa imagen en el celular.

No hace falta instalar un framework web. GStreamer saca los cuadros de la cámara y los deja como JPEG en memoria RAM, y un script de Python corto. solo biblioteca estándar, sin Flask. los sirve como stream MJPEG. Ambos archivos están en el repositorio del proyecto y se bajan directo a la placa por SSH:

Bash
cd ~
wget https://raw.githubusercontent.com/raspberry-tips/arduino-uno-q-projects/main/kamera-setup/liveview.py
wget https://raw.githubusercontent.com/raspberry-tips/arduino-uno-q-projects/main/kamera-setup/capture.sh
chmod +x capture.sh

El liveview.py es el servidor de stream de este capítulo; el capture.sh lo vas a necesitar en la sección siguiente. Antes de arrancar, instala el paquete de herramientas de GStreamer (una sola vez):

Bash
sudo apt install gstreamer1.0-tools
sudo systemd-run --unit=liveview --collect python3 /home/arduino/liveview.py
# Vista en vivo: http://<board-ip>:8080

Vista en vivo de la cámara del UNO Q en el navegador, con la impresora 3D en cuadro y controles de zoom

Hay tres detalles dentro del script que te ahorran frustración, y vale la pena saber por qué están:

El giro de 180 grados. En este soporte la cámara queda colgando de cabeza, así que la pipeline invierte la imagen con videoflip method=rotate-180. Si tu montaje es distinto, esa línea es la que tienes que cambiar.

El enfoque. El módulo IMX219 estándar y la variante NoIR son de foco fijo. A distancia de lecho de impresión la imagen suele salir suficientemente nítida sin tocar nada, así que primero mira, después desarma. Si cuelgas la cámara mucho más cerca del lecho sí vas a tener que reenfocar girando con cuidado el anillo del lente sobre su rosca; los niveles de zoom de la página ayudan a juzgar cuándo quedó. Arducam también vende una variante del IMX219 con foco motorizado controlable por software, si prefieres no depender del pulso.

El watchdog. La pipeline de cámara tiende a quedarse pegada después de un rato. El script se vigila a sí mismo y la reinicia cuando dejan de llegar cuadros frescos. Sin eso, en algún momento te quedas mirando una "vista en vivo" congelada sin darte cuenta.

Primer cuadro de prueba de la cámara: colores pálidos por el sensor NoIR sin calibración, pero la imagen llega

Un aviso sobre los colores: van a salir pálidos y con un tinte verdoso. La cámara NoIR no tiene filtro infrarrojo y la pipeline de software no trae un perfil de color para este sensor. Para detección de anomalías da exactamente lo mismo. Lo único que importa es que las imágenes se vean siempre igual.

Encuadrar y. sobre todo. asegurar la posición

Con la imagen en vivo en el celular, encuadrar toma dos minutos: en diagonal desde adelante y arriba, la zona de impresión llenando el centro del cuadro, y el cabezal cruzando solamente por el tercio superior.

Después aprieta las articulaciones. De verdad apriétalas.

Acá va la advertencia más importante de todo el capítulo, porque es la que arruina proyectos enteros:

El modelo de anomalías aprende tu escena exactamente como la ve la cámara. Posición, encuadre, enfoque e iluminación son parte del modelo, no del entorno. Fija todo antes de recolectar imágenes, y después no cambies nada. Cualquier cambio. un soporte que se corrió, el anillo del lente girado, una lámpara nueva en la pieza. invalida las imágenes recolectadas y el modelo entrenado. Toca recolectar de nuevo y entrenar de nuevo.

Existe una póliza de seguro barata contra esto, y conviene adoptarla como rutina desde el primer día: manda el cabezal y el lecho a la posición de home, y guarda una foto de referencia de esa pose. La posición de home es reproducible con exactitud cuando quieras. Si algún día sospechas que la cámara se movió, superpones la imagen en vivo semitransparente sobre esa foto vieja y ajustas hasta que los bordes calcen. Eso convierte un "se ve más o menos igual" en una comparación real, verificable, de dos minutos.

Recolectar el dataset en automático

Ahora sí, el propósito de todo el montaje: que el modelo aprenda cómo se ve una impresión normal.

El capture.sh que ya bajaste copia el cuadro actual de la cámara a una carpeta de dataset cada diez segundos. Para poder encender y apagar ambas cosas cómodamente, conviértelas en servicios de systemd. Los archivos de unidad están en el mismo repositorio:

Bash
sudo wget -P /etc/systemd/system https://raw.githubusercontent.com/raspberry-tips/arduino-uno-q-projects/main/kamera-setup/liveview.service
sudo wget -P /etc/systemd/system https://raw.githubusercontent.com/raspberry-tips/arduino-uno-q-projects/main/kamera-setup/capture.service
sudo systemctl daemon-reload
sudo systemctl enable --now liveview

Con eso la vista en vivo arranca sola junto con la placa. Si todavía tienes corriendo la prueba con systemd-run de más arriba, deténla antes con sudo systemctl stop liveview.

El recolector, en cambio, queda a propósito en modo manual: lo enciendes y lo apagas con cada impresión.

Bash
sudo systemctl start capture   # al iniciar la impresion
sudo systemctl stop capture    # cuando la impresion termina

Cuatro cuadros de la recolección automática durante una impresión: el lecho se desplaza y el cabezal entra y sale, todo normal

De la recolección salen tres reglas que deciden la calidad del material de entrenamiento más que cualquier ajuste técnico:

Recolecta desde que parte la impresión y detén al terminar. El calentamiento, el leveling y la primera capa van incluidos en el entrenamiento: es justo en esas fases donde aparecen las fallas de adherencia, y el vigilante también las va a estar mirando después. Lo que no debe entrar: el tiempo muerto, los cambios de plato y tus manos en el cuadro.

Variedad le gana a cantidad. Mil cuadros casi idénticos de la misma impresión aportan poco. Cada impresión nueva con otro objeto y otro color de filamento vale mucho más. Con cuatro impresiones quedan alrededor de 1.500 imágenes en la carpeta, más que suficiente para un primer intento.

Luz encendida significa luz encendida, siempre. La escena tiene que quedarse constante, y filamento negro sobre lecho oscuro con luz de atardecer es indistinguible incluso para una persona. La regla que funciona es sencilla: impresión corriendo = luz corriendo.

Por qué 96×96 píxeles alcanzan

Vale la pena entender qué hace el modelo, porque explica varias decisiones de arriba que parecen arbitrarias.

Un detector de anomalías tipo FOMO AD no aprende a reconocer objetos. Aprende cómo se distribuyen las características visuales de los parches de una imagen normal, y después marca los parches que se alejan demasiado de esa distribución. Nunca ve un ejemplo de "spaghetti": solo sabe que ese enredo no se parece a nada de lo que aprendió.

De ahí salen las dos consecuencias prácticas. Primero, la resolución importa poco: un enredo de filamento cambia la textura de una región completa, no un detalle fino, y eso sobrevive perfectamente a la reducción a 96×96. Segundo. y esto explica la obsesión con fijar la cámara y la luz. si mueves el encuadre o cambias la iluminación, toda la imagen se aleja de la distribución aprendida. El modelo no distingue entre "hay una falla" y "la escena cambió": ambas cosas se ven igual desde su punto de vista. Es el mismo fenómeno que en aprendizaje automático se llama desplazamiento de dominio, y es la razón por la que la disciplina de mantener la escena idéntica no es una manía, es el requisito central del método.

Variantes y mejoras

Tres extensiones concretas que este capítulo deja preparadas:

Portarlo a una Raspberry Pi 5. El montaje mecánico, el liveview.py, el capture.sh y las unidades de systemd son agnósticos a la placa: lo único específico del UNO Q es todo el capítulo del device tree. Una Raspberry Pi 5 con la misma cámara IMX219 reconoce el sensor de fábrica con rpicam-hello, sin tocar el bootloader, y además te deja entrenar y correr inferencia en la misma máquina. Es la ruta más simple si no tienes un UNO Q a mano y quieres el resultado, no el desafío.

Aviso al celular cuando aparezca la anomalía. Cuando en la parte 4 el modelo esté corriendo, la salida es un valor de anomalía por cuadro. Enviarlo a un bot de Telegram o a un tópico MQTT son unas veinte líneas de Python sobre el mismo script, y convierte el vigilante en algo que revisas desde la calle en vez de desde la pieza de al lado.

Corte automático de la impresión. Es el paso lógico siguiente y también el más delicado: si el vigilante gatilla el M112 o pausa el trabajo por la API de OctoPrint o Klipper, un falso positivo te cuesta una impresión buena. La forma sensata de hacerlo es exigir N cuadros anómalos consecutivos antes de actuar, y empezar por pausar en vez de abortar.

Iluminación propia para la escena. Una tira LED fija sobre el lecho, siempre encendida a la misma intensidad, elimina de raíz la variable que más ensucia el dataset: la luz ambiente cambiando con la hora del día. Es el accesorio que más rendimiento da por peso en este proyecto.

Personalización para Chile

En MechatronicStore encuentras la mayoría de los componentes de este montaje. El catálogo automático de productos no estuvo disponible al momento de publicar este artículo, así que revisa precios y stock actualizados directamente en la tienda:

  • Cámara IMX219 / Raspberry Pi Camera v2 NoIR. es exactamente el mismo sensor que usa el tutorial. La versión NoIR (sin filtro infrarrojo) es la del artículo; la versión estándar también funciona y da colores más fieles, algo irrelevante para la detección de anomalías.
  • Cable plano FFC de 15 pines. el largo importa más de lo que parece. Con la cámara en un brazo articulado sobre la impresora, el cable de 15 cm que viene con el módulo queda corto.
  • Raspberry Pi 5. si vas por la variante portada de la sección anterior, es la base más directa.
  • Fuente USB-C de 5 V y 3 A. no escatimes acá: una alimentación insuficiente en una placa que además mueve video se manifiesta como reinicios aleatorios en medio de la recolección.
  • Tira LED de 12 V con fuente. para la iluminación constante.

El Arduino UNO Q y su Media Carrier son placas recién salidas y probablemente tengas que importarlas. La equivalencia honesta es la Raspberry Pi 5: no es la misma plataforma ni corre App Lab, pero sí ejecuta todo lo demás de este capítulo sin el rodeo del device tree. La estructura impresa en 3D la fabricas tú mismo con la impresora que vas a vigilar, que es la parte más elegante del proyecto.

Recursos

Versión chilena inspirada en el trabajo original, con componentes en stock local en MechatronicStore.