Objetivo y caso de uso
Qué construirás: un clasificador en tiempo real “tensorrt-recyclables-classifier” que usa la cámara CSI Arducam IMX219 (imx219) en un Jetson Nano 4GB, preprocesa con OpenCV y ejecuta MobileNetV2 en TensorRT FP16 para mostrar clase (plástico, metal, vidrio, papel/cartón, no reconocido), probabilidad y FPS.
Para qué sirve
- Clasificación inicial de residuos en línea de separación (p. ej., distinguir plástico vs. metal).
- Prototipo de “smart bin” que sugiere el contenedor correcto en tiempo real.
- Monitorizar cinta y registrar conteos por material para auditorías.
- Alertar si aparece un material no esperado (p. ej., vidrio en contenedor de papel).
- Base didáctica para adaptar a dataset propio y calibración INT8.
Resultado esperado
- Latencia de inferencia FP16 (MobileNetV2, TensorRT): 10–25 ms por fotograma.
- FPS en pantalla: 25–30 FPS con IMX219 (720p@30); inferencia pura: 40–100 FPS.
- Uso de GPU: 45–70% y CPU: 20–35% en modo 10W; temperatura estable bajo carga.
- Overlay con etiqueta y probabilidad (p. ej., “plástico 0.87”) sincronizado con los FPS.
- Criterio de éxito: procesamiento estable >30 min sin caídas y latencia total captura→overlay <100 ms.
Público objetivo: makers, estudiantes e ingenieros de visión/embebidos; Nivel: intermedio.
Arquitectura/flujo: Cámara IMX219 → captura OpenCV → preprocesado (resize 224×224, normalización) → inferencia TensorRT FP16 (modelo ONNX MobileNetV2) → softmax y mapeo de clase → overlay con FPS/probabilidad → display y registro.
Prerrequisitos (SO, toolchain exacta y versiones)
- Dispositivo: NVIDIA Jetson Nano 4GB
- Cámara: Arducam IMX219 8MP (imx219) CSI-2
- Sistema operativo/SDK:
- JetPack 4.6.4 (L4T R32.7.4) basado en Ubuntu 18.04.6 LTS
- CUDA 10.2
- cuDNN 8.2.1
- TensorRT 8.2.1.8 (incluye trtexec en /usr/src/tensorrt/bin/trtexec)
- OpenCV 4.1.1 (proveído por JetPack 4.6.x)
- GStreamer 1.14.5
- Python 3.6.9
Verificar las versiones (ejecute todas las líneas):
# L4T / JetPack
cat /etc/nv_tegra_release
# Kernel
uname -a
# Paquetes NVIDIA y TensorRT
dpkg -l | grep -E 'nvidia|tensorrt'
# CUDA
nvcc --version || cat /usr/local/cuda/version.txt
# OpenCV (Python)
python3 - << 'PY'
import cv2, sys
print("Python:", sys.version.split()[0])
print("OpenCV:", cv2.__version__)
PY
# GStreamer
gst-launch-1.0 --version
Notas:
– Jetson Nano 4GB no soporta JetPack 5.x. Use JetPack 4.6.4 para coherencia.
– Si falta trtexec, revise que tenga instalado el paquete nvinfer y/o reinstale el componente TensorRT del JetPack.
Materiales
- 1× Jetson Nano 4GB Developer Kit (tarjeta + disipador)
- 1× Arducam IMX219 8MP (imx219) cámara CSI-2 para Jetson
- 1× Tarjeta microSD 64 GB (UHS-I, clase A1/A2 recomendada)
- 1× Fuente 5V/4A tipo barrel jack o 5V/3A por micro-USB (se recomienda 5V/4A para estabilidad)
- 1× Cable flexible CSI (incluido con la cámara)
- 1× Disipador/ventilador para Jetson Nano (recomendado)
- 1× Monitor HDMI/teclado/ratón (opcional si no es headless)
- Conectividad de red (Ethernet o Wi-Fi)
Importante: el modelo de cámara es exactamente Arducam IMX219 8MP (imx219), compatible con nvarguscamerasrc.
Preparación y conexión
Conexión física de la cámara CSI
- Apague y desconecte la Jetson Nano de la energía.
- Localice el puerto CSI-2 de la Jetson Nano (conector plano etiquetado “CAMERA”).
- Oriente el cable CSI con los contactos hacia el lado correcto (habitualmente hacia el conector).
- Inserte con cuidado y cierre la pestaña del conector para fijar el cable.
- Monte la cámara Arducam IMX219 (imx219) con el cable, evitando torsiones.
Tabla de referencia rápida:
| Componente | Puerto/Conector en Nano | Detalle de conexión/Orientación |
|---|---|---|
| Arducam IMX219 8MP (imx219) | CSI-2 (CAMERA) | Cable CSI con contactos hacia el conector, cierre la pestaña |
| Alimentación | Barrel jack 5V/4A o uUSB | Preferible barrel 5V/4A. Evite hubs USB alimentando el Nano |
| Monitor (opcional) | HDMI | Conectar antes de encender |
| Teclado/ratón (opcional) | USB | Cualquier puerto USB-A |
| Red | Ethernet RJ-45 | DHCP típico |
Comprobación básica de la cámara con GStreamer
Tras encender y arrancar la Nano con JetPack 4.6.4:
# Prueba rápida de la cámara (CSI IMX219) con GStreamer
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1,format=NV12' ! \
nvvidconv ! 'video/x-raw,format=I420' ! fpsdisplaysink video-sink=fakesink text-overlay=true sync=false -e
Debería ver en consola el conteo de FPS sin errores. Si hay error de nvargus-daemon, consulte la sección de troubleshooting.
Ajuste de modo de potencia y clocks (opcional pero recomendado)
Para estabilidad de rendimiento (monitoree termales):
sudo nvpmodel -q
# MAXN para Jetson Nano 4GB
sudo nvpmodel -m 0
sudo jetson_clocks
Advertencia: MAXN aumenta consumo y temperatura. Use disipador/ventilador.
Código completo (Python + TensorRT) con explicación
A continuación, un script único en Python que:
– Carga un motor TensorRT (.engine) de MobileNetV2 FP16.
– Abre la cámara CSI a través de OpenCV utilizando un pipeline GStreamer.
– Preprocesa a 224×224, normaliza (ImageNet) y ejecuta inferencia en GPU.
– Agrega las probabilidades de las clases ImageNet a categorías de reciclaje por palabras clave y muestra FPS.
Guarde como: $HOME/tensorrt-recyclables-classifier/tensorrt_recyclables.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import time
import ctypes
import numpy as np
import cv2
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit # inicializa contextos CUDA
# Configuración de rutas
BASE_DIR = os.path.expanduser("~/tensorrt-recyclables-classifier")
ENGINE_PATH = os.path.join(BASE_DIR, "mobilenetv2_fp16.engine")
LABELS_PATH = os.path.join(BASE_DIR, "imagenet_labels.txt")
# Parámetros del modelo
INPUT_W = 224
INPUT_H = 224
INPUT_NAME = "data" # para mobilenetv2-7.onnx del ONNX Model Zoo
NUM_CLASSES = 1000 # ImageNet
# Normalización ImageNet
IMAGENET_MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
IMAGENET_STD = np.array([0.229, 0.224, 0.225], dtype=np.float32)
# Mapeo simple por palabras clave a categorías de reciclaje
CATEGORY_KEYWORDS = {
"plastico": ["plastic", "bottle", "pop bottle", "water bottle", "soda bottle"],
"metal": ["can", "tin", "aluminum"],
"vidrio": ["glass", "goblet", "wine bottle", "beer bottle", "jar"],
"papel_carton": ["paper", "newspaper", "tissue", "napkin", "carton", "cardboard"],
# si no coincide en ninguna, caerá en "no_reconocido"
}
def build_gst_pipeline(width=1280, height=720, fps=30, sensor_id=0):
return (
f"nvarguscamerasrc sensor-id={sensor_id} ! "
f"video/x-raw(memory:NVMM), width={width}, height={height}, framerate={fps}/1, format=NV12 ! "
"nvvidconv ! video/x-raw, format=BGRx ! "
"videoconvert ! video/x-raw, format=BGR ! appsink drop=true sync=false"
)
def load_labels(path):
labels = []
with open(path, "r") as f:
for line in f:
line = line.strip()
if line:
# synset_words.txt suele tener "nXXXX class_name..."
parts = line.split(" ", 1)
label = parts[1] if len(parts) > 1 else parts[0]
labels.append(label)
return labels
def preprocess_bgr(frame_bgr):
# Convertir a RGB, redimensionar, normalizar y dejar en NCHW float32
img = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (INPUT_W, INPUT_H), interpolation=cv2.INTER_LINEAR)
img = img.astype(np.float32) / 255.0
img = (img - IMAGENET_MEAN) / IMAGENET_STD
img = img.transpose(2, 0, 1) # HWC -> CHW
img = np.expand_dims(img, axis=0).copy() # NCHW
return img
def softmax(x):
x = x - np.max(x, axis=1, keepdims=True)
exp_x = np.exp(x)
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
def aggregate_to_recyclables(probs, labels, topk=5):
# Toma los top-k, mapea por keywords a la categoría y suma probabilidades
topk_idx = probs.argsort()[::-1][:topk]
category_scores = {k:0.0 for k in list(CATEGORY_KEYWORDS.keys()) + ["no_reconocido"]}
matched = False
for idx in topk_idx:
label = labels[idx].lower()
p = probs[idx]
hit = False
for cat, keywords in CATEGORY_KEYWORDS.items():
if any(kw in label for kw in keywords):
category_scores[cat] += float(p)
hit = True
matched = True
if not hit:
category_scores["no_reconocido"] += float(p)
# Si ninguna keyword coincide, clasificar como no reconocido con mayor peso top-1
if not matched:
category_scores["no_reconocido"] += 0.1
# Selección de categoría con mayor score
best_cat = max(category_scores, key=category_scores.get)
best_score = category_scores[best_cat]
return best_cat, best_score, category_scores, topk_idx
class TRTInference:
def __init__(self, engine_path):
self.logger = trt.Logger(trt.Logger.INFO)
trt.init_libnvinfer_plugins(self.logger, "")
with open(engine_path, "rb") as f, trt.Runtime(self.logger) as runtime:
self.engine = runtime.deserialize_cuda_engine(f.read())
assert self.engine, "No se pudo deserializar el engine TRT"
self.context = self.engine.create_execution_context()
assert self.context, "No se pudo crear el contexto TRT"
# Ubicar índices de binding
self.input_binding_idx = self.engine.get_binding_index(INPUT_NAME)
assert self.input_binding_idx != -1, f"Binding de entrada '{INPUT_NAME}' no encontrado"
# Se asume única salida (clases)
self.output_binding_idx = 1 - self.input_binding_idx
# Reservar memoria en host y device
self.input_shape = self.engine.get_binding_shape(self.input_binding_idx)
self.output_shape = self.engine.get_binding_shape(self.output_binding_idx)
self.host_input = cuda.pagelocked_empty(trt.volume(self.input_shape), dtype=np.float32)
self.host_output = cuda.pagelocked_empty(trt.volume(self.output_shape), dtype=np.float32)
self.device_input = cuda.mem_alloc(self.host_input.nbytes)
self.device_output = cuda.mem_alloc(self.host_output.nbytes)
self.bindings = [int(self.device_input), int(self.device_output)]
# Stream CUDA
self.stream = cuda.Stream()
def infer(self, input_nchw):
# Copiar a host_input
np.copyto(self.host_input, input_nchw.ravel())
# H2D
cuda.memcpy_htod_async(self.device_input, self.host_input, self.stream)
# Ejecutar
self.context.execute_async_v2(self.bindings, self.stream.handle)
# D2H
cuda.memcpy_dtoh_async(self.host_output, self.device_output, self.stream)
# Sincronizar
self.stream.synchronize()
output = np.array(self.host_output).reshape(1, -1)
return output
def main():
if not os.path.isfile(ENGINE_PATH):
raise FileNotFoundError(f"Engine TensorRT no encontrado: {ENGINE_PATH}")
if not os.path.isfile(LABELS_PATH):
raise FileNotFoundError(f"Archivo de labels no encontrado: {LABELS_PATH}")
labels = load_labels(LABELS_PATH)
assert len(labels) >= NUM_CLASSES, "Labels ImageNet insuficientes"
trt_infer = TRTInference(ENGINE_PATH)
gst = build_gst_pipeline(width=1280, height=720, fps=30, sensor_id=0)
cap = cv2.VideoCapture(gst, cv2.CAP_GSTREAMER)
if not cap.isOpened():
raise RuntimeError("No se pudo abrir la cámara CSI con GStreamer")
print("Presiona 'q' para salir.")
t_last = time.time()
frame_count = 0
fps = 0.0
while True:
ok, frame = cap.read()
if not ok:
print("Fin de flujo o error de cámara")
break
# Preprocesado e inferencia
tensor = preprocess_bgr(frame)
logits = trt_infer.infer(tensor)
probs = softmax(logits)[0]
# Agregación por categorías
best_cat, best_score, cat_scores, topk_idx = aggregate_to_recyclables(probs, labels, topk=5)
# FPS
frame_count += 1
now = time.time()
if now - t_last >= 1.0:
fps = frame_count / (now - t_last)
t_last = now
frame_count = 0
# Overlay
overlay = f"{best_cat} ({best_score:.2f}) | {fps:.1f} FPS"
cv2.putText(frame, overlay, (12, 28), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)
# Mostrar top-3 clases ImageNet para depuración
h = 50
for rank, idx in enumerate(topk_idx[:3], start=1):
txt = f"Top{rank}: {labels[idx]} ({probs[idx]:.2f})"
cv2.putText(frame, txt, (12, 28 + h*rank), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0), 1)
cv2.imshow("tensorrt-recyclables-classifier", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Breve explicación de partes clave:
– Preprocesado: redimensiona a 224×224, normaliza por mean/std de ImageNet y convierte a NCHW float32.
– Motor TensorRT: se carga desde archivo .engine generado con trtexec (FP16). El binding de entrada debe llamarse “data” para el modelo mobilenetv2-7.onnx del ONNX Model Zoo.
– Inferencia: se gestionan los buffers H2D/D2H con pycuda y se lanza execute_async_v2 en el stream CUDA.
– Agregación: toma top-5 etiquetas de ImageNet, las compara por palabras clave para asignarlas a categorías de reciclaje y suma probabilidades. Es un demo didáctico (para despliegue real, entrenar un modelo específico de reciclaje).
– Medición: calcula FPS en ventana móvil de 1 s; permite observar rendimiento.
Compilación/ejecución paso a paso (comandos exactos)
1) Preparar carpetas y dependencias mínimas:
sudo apt-get update
sudo apt-get install -y python3-pip python3-numpy python3-opencv python3-pycuda \
git wget gstreamer1.0-tools
mkdir -p $HOME/models/tensorrt-recyclables-classifier
mkdir -p $HOME/tensorrt-recyclables-classifier
2) Descargar el modelo ONNX y etiquetas de ImageNet:
– Usaremos MobileNetV2 (opset 7) del ONNX Model Zoo (entrada: “data”, tamaño 224×224).
cd $HOME/models/tensorrt-recyclables-classifier
wget https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-7.onnx -O mobilenetv2-7.onnx
wget https://raw.githubusercontent.com/jetson-inference/jetson-inference/master/data/networks/ilsvrc12/synset_words.txt -O imagenet_labels.txt
3) Construir el motor TensorRT FP16 con trtexec:
– Herramienta: /usr/src/tensorrt/bin/trtexec (TensorRT 8.2.1.8 para JetPack 4.6.4)
/usr/src/tensorrt/bin/trtexec \
--onnx=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2-7.onnx \
--saveEngine=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine \
--explicitBatch \
--minShapes=data:1x3x224x224 \
--optShapes=data:1x3x224x224 \
--maxShapes=data:1x3x224x224 \
--fp16 \
--workspace=1024 \
--separateProfileRun \
--verbose
Salida esperada: debe reportar que se ha creado un engine con precisión FP16, tamaño de workspace y bindings “data” (entrada) y una salida de 1×1000.
4) Prueba de rendimiento rápida del engine:
/usr/src/tensorrt/bin/trtexec \
--loadEngine=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine \
--shapes=data:1x3x224x224 \
--iterations=200 \
--warmUp=50 \
--separateProfileRun
Observe el “mean latency” y “throughput” (FPS teórico del motor aislado).
5) Copiar el script de inferencia y configurar rutas:
cd $HOME/tensorrt-recyclables-classifier
# Cree el archivo con el contenido mostrado en la sección de código completo
nano tensorrt_recyclables.py
# Ajuste permisos de ejecución
chmod +x tensorrt_recyclables.py
# Enlazar/duplicar archivos del modelo hacia el directorio del proyecto:
ln -sf $HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine $HOME/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine
ln -sf $HOME/models/tensorrt-recyclables-classifier/imagenet_labels.txt $HOME/tensorrt-recyclables-classifier/imagenet_labels.txt
6) Activar MAXN y clocks (opcional pero recomendado) y lanzar inferencia:
# Potencia
sudo nvpmodel -m 0
sudo jetson_clocks
# Monitoreo (en otra terminal)
sudo tegrastats
# Ejecutar la app
cd $HOME/tensorrt-recyclables-classifier
./tensorrt_recyclables.py
Al ejecutar, se abrirá una ventana con el video y overlay de categoría + probabilidad + FPS. Presione “q” para salir.
Validación paso a paso
1) Verifique la cámara:
– Comando GStreamer anterior debe mostrar FPS sin errores. Errores comunes de nvargus indican problema de cable/driver.
2) Confirmar motor TensorRT:
– trtexec debe finalizar con “Engine built in X ms” y sin warnings críticos de precisión/shape.
– La prueba de rendimiento de trtexec debe mostrar throughput estimado > 100 FPS para MobileNetV2 FP16 (motor puro). En la app completa, el FPS será menor por captura y overlay, esperado 18–35 FPS.
3) Ejecución de la app:
– Ventana “tensorrt-recyclables-classifier” renderizando el feed CSI en 1280×720.
– Overlay superior:
– Línea 1: “plastico (0.62) | 27.4 FPS” (ejemplo)
– Líneas siguientes: Top1/Top2/Top3 de etiquetas ImageNet con probabilidades.
4) Métricas de rendimiento:
– tegrastats (en otra terminal) muestra líneas como:
– GR3D_FREQ 76%@921 (utilización GPU ~ 40–70%)
– EMC_FREQ ~ 10–40% (depende de memoria)
– Mem RAM usada: < 1.5 GB
– Si ve “throttle” o clocks reducidos, mejore la refrigeración.
5) Exactitud cualitativa (demo):
– Acerque a la cámara:
– Botella plástica transparente → categoría “plastico” con score agregado > 0.5 (si la etiqueta top-1 es “water bottle”, etc.).
– Lata de refresco → “metal”.
– Botella de vidrio o vaso → “vidrio”.
– Hoja de papel/cartón → “papel_carton”.
– En escenarios ambiguos o sin correspondencia de palabras clave, la categoría resultará “no_reconocido”.
6) Limpieza (opcional):
– Restaurar modo de potencia si lo desea:
– sudo nvpmodel -m 1 (modo más conservador) y reiniciar.
Troubleshooting (errores típicos y solución)
1) nvarguscamerasrc: “ERROR [Component ::NvArgusCameraSrc] No cameras available”
– Causa: cámara IMX219 no detectada, cable CSI mal orientado o no firme.
– Solución: apague, reconecte el cable asegurando orientación correcta, pruebe con sensor-id=0 y 1, verifique dmesg | grep imx219. Asegúrese de usar Arducam IMX219 8MP (imx219) compatible.
2) trtexec: “Network has dynamic shapes but no optimization profile provided”
– Causa: no se especificaron min/opt/max shapes.
– Solución: use los flags –minShapes/–optShapes/–maxShapes como en los comandos provistos para el binding “data:1x3x224x224”.
3) trtexec: “Could not find binding for input name ‘data’”
– Causa: el input del modelo ONNX no se llama “data”.
– Solución: confirme el nombre del input con onnx.checker o Netron. Para mobilenetv2-7 del ONNX Model Zoo suele ser “data”. Si difiere, ajuste INPUT_NAME en el script y los flags de trtexec.
4) ImportError: No module named ‘tensorrt’ o ‘pycuda’
– Causa: falta del paquete Python de TensorRT/pycuda o mismatch de Python 3.6.
– Solución: asegure JetPack 4.6.4; instale python3-pycuda vía apt; TensorRT Python viene con el SDK. Si aún falla, reinstale componentes de JetPack o configure PYTHONPATH a /usr/lib/python3.6/dist-packages.
5) Bajo rendimiento (FPS < 10) y/o throttling
– Causa: modo de potencia limitado, temperaturas altas, falta de ventilación.
– Solución: sudo nvpmodel -m 0; sudo jetson_clocks; añada ventilador/disipador; reduzca overlay pesado o resolución de captura; cierre aplicaciones en paralelo.
6) OpenCV no abre la cámara con GStreamer
– Causa: pipeline incorrecto o plugins ausentes.
– Solución: pruebe gst-launch-1.0 con nvarguscamerasrc; si funciona, revise el pipeline de appsink en el script; verifique que OpenCV tenga GStreamer habilitado (cv2.getBuildInformation()).
7) Engine incompatible tras actualizar paquetes
– Causa: el engine TRT es específico de hardware/software.
– Solución: borre y regenere el .engine con la versión actual de TensorRT (trtexec) en la Jetson Nano.
8) Artefactos de clasificación incoherentes
– Causa: el mapeo por palabras clave es didáctico; ImageNet no está optimizado para reciclables.
– Solución: entrene/fine-tune un modelo con clases de reciclaje y exporte ONNX; o amplíe keywords y normalice iluminación y encuadre.
Mejoras/variantes
- INT8 con calibración: genere un calibrador con imágenes representativas para INT8 y use trtexec –int8 –calib; ganará rendimiento con ligera pérdida de precisión.
- Modelo específico de reciclaje: fine-tune MobileNetV2/ResNet18 en dataset de “reciclables” (clases: plástico, metal, vidrio, papel/cartón). Exportar a ONNX (opset 11+) con entrada fija 224×224 para simplificar.
- DeepStream alternativa: pipeline con nvinfer, nvvidconv, nvdsosd para overlay, y source nvarguscamerasrc; útil para integrarse con RTSP y analítica multi-stream.
- Preprocesado en GPU: usar jetson-utils o cv2.cuda para conversiones y escalado; reducir latencia.
- Ahorro de energía: bajar resolución/fps, desactivar jetson_clocks cuando no se use.
- Integración con GPIO/I2C: activar un LED según categoría o enviar el resultado a un microcontrolador; registro en CSV y panel remoto (MQTT).
- Mejora de overlay: colorear por categoría, mostrar barras de probabilidad, registrar top-5.
Checklist de verificación
- [ ] Modelo exacto usado: Jetson Nano 4GB + Arducam IMX219 8MP (imx219) conectados por CSI.
- [ ] Sistema: JetPack 4.6.4 (L4T R32.7.4), Ubuntu 18.04.6; CUDA 10.2; cuDNN 8.2.1; TensorRT 8.2.1.8; OpenCV 4.1.1; GStreamer 1.14.5; Python 3.6.9.
- [ ] Cámara verificada con gst-launch-1.0 nvarguscamerasrc … sin errores.
- [ ] Modelo ONNX descargado: mobilenetv2-7.onnx y etiquetas imagenet_labels.txt en $HOME/models/tensorrt-recyclables-classifier/.
- [ ] Motor TensorRT FP16 generado con trtexec en $HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine.
- [ ] Script tensorrt_recyclables.py creado en $HOME/tensorrt-recyclables-classifier/ y ejecutable.
- [ ] Ejecución en MAXN (opcional): sudo nvpmodel -m 0; sudo jetson_clocks; tegrastats en paralelo.
- [ ] Al ejecutar, se ve video + overlay con categoría, probabilidad y FPS; respuesta coherente ante objetos plásticos/metal/vidrio/papel.
- [ ] Métricas dentro de lo esperado: 18–35 FPS en pipeline completo, GPU 40–70%, sin throttling sostenido.
- [ ] Finalización limpia y opción de revertir potencia: sudo nvpmodel -m 1 (si se desea).
Con esto, tendrás un clasificador de reciclables “tensorrt-recyclables-classifier” operativo y didáctico sobre Jetson Nano 4GB con cámara Arducam IMX219 (imx219), empleando una toolchain exacta basada en JetPack 4.6.4 y TensorRT 8.2.1.8, con código y comandos reproducibles de principio a fin.
Encuentra este producto y/o libros sobre este tema en Amazon
Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.




