Objetivo y caso de uso
Qué construirás: un sistema “edge” de control de acceso que fusiona detección de personas en tiempo real (DeepStream) con lectura NFC para conceder/denegar entrada. Se ejecuta íntegramente en un NVIDIA Jetson Orin Nano Developer Kit con cámara CSI y lector NFC USB.
Para qué sirve
- Controlar el acceso a una sala técnica solo si hay una tarjeta NFC autorizada y se detecta una persona frente a la cámara.
- Registrar eventos con sello temporal, UID NFC y conteo de personas en CSV y consola para auditoría.
- Visualizar en pantalla cajas/clases de DeepStream junto al estado de acceso (CONCEDIDO/DENEGADO).
- Medir FPS, latencia y uso de GPU (tegrastats) para dimensionar despliegues en campo.
- Servir de pipeline base para integrar puertas electrónicas, relés o APIs de seguridad.
Resultado esperado
- FPS sostenidos ≥ 25 a 1080p con modelo primario ResNet10 (DeepStream) en FP16, batch-size=1.
- Latencia promedio NFC→OSD < 200 ms; lectura NFC.
- Conteo de personas registrado en tiempo real con precisión del 95%.
- Tiempo de respuesta de acceso (CONCEDIDO/DENEGADO) < 1 segundo.
- Registro de eventos en CSV con un tamaño máximo de 1 MB por hora.
Público objetivo: Desarrolladores y técnicos en seguridad; Nivel: Avanzado
Arquitectura/flujo: Integración de NVIDIA Jetson Orin Nano, Arducam IMX477 y ACS ACR122U en un sistema de control de acceso.
Nivel: Avanzado
Prerrequisitos (SO y toolchain)
- Sistema:
- NVIDIA Jetson Orin Nano Developer Kit con Ubuntu 22.04 L4T R36.2 (JetPack 6.0 GA).
-
Acceso shell con sudo.
-
Toolchain exacta (recomendada/probada):
- JetPack: 6.0 (L4T 36.2).
- DeepStream SDK: 6.3.
- CUDA: 12.2.
- TensorRT: 8.6.x (8.6.2 o superior dentro de JP6).
- cuDNN: 8.9.x.
- GStreamer: 1.20.x (22.04).
-
Python: 3.10.
-
Verificaciones rápidas:
- JetPack/L4T:
- cat /etc/nv_tegra_release
- sudo -E env | grep -i jetpack || true
- Kernel y paquetes NVIDIA:
- uname -a
- dpkg -l | grep -E ‘nvidia|tensorrt|deepstream|cudnn|cuda’
- DeepStream instalado y versión:
- deepstream-app –version-all
- ls -1 /opt/nvidia/deepstream/deepstream-6.3
- Modelos de muestra presentes:
-
ls -1 /opt/nvidia/deepstream/deepstream-6.3/samples/models/Primary_Detector
-
Power/performance (opcional pero recomendado para las métricas):
- sudo nvpmodel -q
- sudo nvpmodel -m 0
-
sudo jetson_clocks
-
Advertencia térmica: MAXN + jetson_clocks pueden aumentar temperatura; asegúrate de buena ventilación.
Materiales
- NVIDIA Jetson Orin Nano Developer Kit + Arducam IMX477 HQ Camera (IMX477) + ACS ACR122U NFC Reader (PN532).
- Tarjeta microSD (>= 64 GB, clase A2) o NVMe (opcional) con JetPack 6.0 flasheado.
- Cable FFC de la cámara (incluido con la Arducam IMX477 HQ).
- Cable USB para el ACR122U (USB-A).
- Monitor HDMI/DP, teclado y ratón (para visualizar nveglglessink).
- Conectividad a Internet para instalar paquetes.
Preparación y conexión
1) Conexiones físicas:
– Apaga y desconecta alimentación antes de conectar/retirar periféricos.
– Conecta la Arducam IMX477 al conector CSI MIPI “CAM0” del Jetson Orin Nano:
– Inserta el cable FFC con los contactos orientados hacia el conector según la muesca.
– Asegura la pestaña del conector.
– Conecta el ACS ACR122U a un puerto USB-A del Jetson.
2) Verificación de periféricos:
– Cámara IMX477 (Argus):
– Reinicia el demonio de Argus: sudo systemctl restart nvargus-daemon
– Prueba la cámara:
– gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! «video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1,format=NV12» ! nvvideoconvert ! fakesink -e
– Debes ver la tubería corriendo sin errores por ~5s y luego finalizar con Ctrl+C si no usaste -e.
– Lector NFC:
– lsusb | grep -i acr122
– Debe mostrar “ID 072f:2200 Advanced Card Systems, Ltd ACR122U”.
– Instala PC/SC y herramientas: sudo apt update && sudo apt install -y pcscd pcsc-tools
– Verifica:
– sudo systemctl enable –now pcscd
– pcsc_scan
– Acerca una tarjeta MIFARE; deberías ver ATR y tipo.
Tabla de asignaciones y puertos
| Componente | Interfaz/puerto Jetson Orin Nano | Comando de verificación |
|---|---|---|
| Arducam IMX477 HQ (IMX477) | CSI CAM0 (conector MIPI-CSI) | gst-launch-1.0 nvarguscamerasrc … |
| ACS ACR122U NFC Reader (PN532) | USB-A (host) | lsusb, pcsc_scan |
| Vídeo (salida para OSD) | HDMI/DisplayPort | deepstream pipeline con nveglglessink |
| Alimentación | 5V DC (suministro oficial del kit) | tegrastats (para ver consumo estimado y temperatura) |
3) Ajustes de energía/rendimiento (opcional):
– sudo nvpmodel -q
– sudo nvpmodel -m 0
– sudo jetson_clocks
4) Dependencias de software:
– DeepStream 6.3:
– sudo apt update
– sudo apt install -y deepstream-6.3
– Python y GStreamer:
– sudo apt install -y python3-gi python3-gst-1.0 gstreamer1.0-tools gstreamer1.0-plugins-{good,bad,ugly} \
python3-pip python3-dev libgstreamer1.0-dev
– DeepStream Python bindings (pyds):
– cd /opt/nvidia/deepstream/deepstream-6.3/bindings/python
– python3 -m pip install ./pyds-1.1.10-py3-none-linux_aarch64.whl
– NFC (PC/SC + pyscard para ACR122U):
– sudo apt install -y pcscd pcsc-tools python3-pyscard
– sudo systemctl enable –now pcscd
– Utilidades:
– sudo apt install -y v4l-utils jq git
– Confirmar versiones:
– deepstream-app –version-all
– python3 -c «import gi, sys; import pyds; print(‘GI OK’, gi.version, ‘pyds OK’); print(sys.version)»
Código completo
A continuación, un único programa en Python que:
– Construye la tubería DeepStream con nvarguscamerasrc → nvstreammux → nvinfer → nvdsosd → nveglglessink.
– Lanza un hilo para leer el lector NFC ACS ACR122U mediante PC/SC y pyscard, obteniendo el UID con APDU estándar.
– Fusiona ambos mundos: sobreimpone el estado de acceso (CONCEDIDO/DENEGADO) junto al conteo de personas detectadas y registra eventos en CSV.
Archivo: deepstream_epp_access_control_nfc.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import time
import json
import threading
import queue
from datetime import datetime
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib
import pyds
# NFC (PC/SC)
from smartcard.System import readers
from smartcard.Exceptions import NoReadersAvailable, CardConnectionException
# ----------------------------
# Configuración general
# ----------------------------
AUTHORIZED_UIDS_FILE = "./authorized_uids.json" # {"uids": ["04AABBCCDD"], "policy":"allowlist"}
PGIE_CONFIG_FILE = "./pgie_config_imx477.txt" # Ver bloque de configuración más abajo
CSV_LOG = "./access_log.csv"
# Estado compartido NFC→OSD
access_state = {
"last_uid": None,
"granted": False,
"last_event_ts": None,
"ttl_ms": 3000 # Mostrar estado 3 segundos
}
access_lock = threading.Lock()
# Métricas FPS
fps_lock = threading.Lock()
frame_count = 0
last_fps_ts = time.time()
# Cola de eventos para logging asíncrono
event_q = queue.Queue()
# ----------------------------
# Utilidades
# ----------------------------
def load_authorized_uids(path):
if not os.path.exists(path):
return set()
with open(path, "r") as f:
data = json.load(f)
return set([u.strip().upper() for u in data.get("uids", [])])
AUTHORIZED_UIDS = load_authorized_uids(AUTHORIZED_UIDS_FILE)
def log_event(uid, granted, persons):
ts = datetime.utcnow().isoformat()
line = f"{ts},{uid},{int(granted)},{persons}"
event_q.put(line)
print("[EVENT]", line)
def event_logger_thread(csv_path):
# Crea cabezeras si no existe
if not os.path.exists(csv_path):
with open(csv_path, "w") as f:
f.write("timestamp,uid,granted,persons\n")
while True:
line = event_q.get()
if line is None:
break
with open(csv_path, "a") as f:
f.write(line + "\n")
def nfc_reader_thread():
while True:
try:
rs = readers()
if len(rs) == 0:
print("[NFC] No hay lectores PC/SC disponibles. Reintentando en 2s...")
time.sleep(2)
continue
rdr = None
# Selecciona el ACR122U si está
for r in rs:
if "ACR122" in str(r):
rdr = r
break
if rdr is None:
rdr = rs[0]
print(f"[NFC] Usando lector: {rdr}")
conn = rdr.createConnection()
conn.connect()
print("[NFC] Conectado. Presenta una tarjeta...")
while True:
# APDU Get Data para UID en ACS ACR122U (MIFARE/ISO14443A)
GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00]
data, sw1, sw2 = conn.transmit(GET_UID)
if sw1 == 0x90 and sw2 == 0x00 and len(data) > 0:
uid = "".join(f"{b:02X}" for b in data)
granted = (uid.upper() in AUTHORIZED_UIDS)
with access_lock:
access_state["last_uid"] = uid
access_state["granted"] = granted
access_state["last_event_ts"] = time.time()
# persons lo parchearemos en la sonda OSD; aquí ponemos -1 y se actualizará
log_event(uid, granted, persons=-1)
# Evita lecturas repetidas spameando: espera retirada
time.sleep(0.5)
else:
# No hay tarjeta; espera breve
time.sleep(0.1)
except NoReadersAvailable:
print("[NFC] Sin lectores. Reintentando en 2s...")
time.sleep(2)
except CardConnectionException:
print("[NFC] Tarjeta retirada o error de conexión. Reintentando...")
time.sleep(0.5)
except Exception as e:
print(f"[NFC] Error inesperado: {e}")
time.sleep(1)
# ----------------------------
# DeepStream pipeline
# ----------------------------
def osd_sink_pad_buffer_probe(pad, info, user_data):
"""
Sonda en OSD para:
- contar personas detectadas (clase 'person' de resnet10 sample)
- pintar overlay con estado de acceso y FPS
- actualizar el último evento en CSV con el conteo real de personas
"""
global frame_count, last_fps_ts
gst_buffer = info.get_buffer()
if not gst_buffer:
return Gst.PadProbeReturn.OK
# Métricas FPS
with fps_lock:
frame_count += 1
now = time.time()
dt = now - last_fps_ts
fps = None
if dt >= 1.0:
fps = frame_count / dt
frame_count = 0
last_fps_ts = now
# Extrae metadata DS
batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))
if not batch_meta:
return Gst.PadProbeReturn.OK
l_frame = batch_meta.frame_meta_list
while l_frame is not None:
try:
frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
except StopIteration:
break
# Cuenta objetos
persons = 0
l_obj = frame_meta.obj_meta_list
while l_obj is not None:
try:
obj_meta = pyds.NvDsObjectMeta.cast(l_obj.data)
except StopIteration:
break
# En el modelo resnet10 sample, clase 0 suele ser 'person' (ver labels.txt)
if obj_meta.class_id == 0:
persons += 1
l_obj = l_obj.next
# Construye overlay
display_meta = pyds.nvds_acquire_display_meta_from_pool(batch_meta)
display_meta.num_labels = 1
txt_params = display_meta.text_params[0]
txt_params.display_text = ""
# Estado de acceso (validez por TTL)
show_state = False
with access_lock:
ts = access_state["last_event_ts"]
if ts is not None and (time.time() - ts) * 1000.0 <= access_state["ttl_ms"]:
show_state = True
granted = access_state["granted"]
uid = access_state["last_uid"]
else:
granted = False
uid = None
if show_state:
status = "ACCESO CONCEDIDO" if granted else "ACCESO DENEGADO"
color = (0.1, 0.9, 0.1, 1.0) if granted else (0.9, 0.1, 0.1, 1.0)
txt_params.display_text += f"{status} · UID={uid} "
txt_params.text_bg_clr.set(*color)
txt_params.text_bg_clr.set_alpha(0.6)
# Actualiza el último log con personas detectadas (opcional: aquí solo añadimos un nuevo log rico)
if uid:
log_event(uid, granted, persons)
# Siempre muestra conteo y FPS
if fps is not None:
txt_params.display_text += f" FPS={fps:.1f}"
txt_params.display_text += f" PERSONAS={persons}"
# Posición/estética
txt_params.x_offset = 40
txt_params.y_offset = 40
txt_params.font_params.font_name = "Serif"
txt_params.font_params.font_size = 22
txt_params.font_params.font_color.set(1.0, 1.0, 1.0, 1.0)
txt_params.set_bg_clr = 1
pyds.nvds_add_display_meta_to_frame(frame_meta, display_meta)
l_frame = l_frame.next
return Gst.PadProbeReturn.OK
def build_pipeline():
Gst.init(None)
pipeline = Gst.Pipeline()
# Fuente CSI (Argus)
source = Gst.ElementFactory.make("nvarguscamerasrc", "camera-source")
if not source:
raise RuntimeError("No se pudo crear nvarguscamerasrc")
source.set_property("sensor-id", 0)
# Conversión + caps
nvvidconv = Gst.ElementFactory.make("nvvideoconvert", "nvvideo-conv")
capsfilter = Gst.ElementFactory.make("capsfilter", "capsfilter")
caps = Gst.Caps.from_string("video/x-raw(memory:NVMM), format=NV12, width=1920, height=1080, framerate=30/1")
capsfilter.set_property("caps", caps)
# Mux
streammux = Gst.ElementFactory.make("nvstreammux", "stream-muxer")
streammux.set_property("batch-size", 1)
streammux.set_property("width", 1920)
streammux.set_property("height", 1080)
streammux.set_property("live-source", 1)
streammux.set_property("batched-push-timeout", 40000)
# Inferencia primaria (nvinfer) con config sample
pgie = Gst.ElementFactory.make("nvinfer", "primary-infer")
pgie.set_property("config-file-path", PGIE_CONFIG_FILE)
# OSD
nvosd = Gst.ElementFactory.make("nvdsosd", "on-screen-display")
# Sink
sink = Gst.ElementFactory.make("nveglglessink", "video-sink")
sink.set_property("sync", 0)
for elem in [source, nvvidconv, capsfilter, streammux, pgie, nvosd, sink]:
pipeline.add(elem)
# Enlace fuente→conv→caps
assert source.link(nvvidconv)
assert nvvidconv.link(capsfilter)
# Enlace caps→streammux (pad solicitado)
sinkpad = streammux.get_request_pad("sink_0")
if not sinkpad:
raise RuntimeError("No se pudo obtener sink_0 de streammux")
srcpad = capsfilter.get_static_pad("src")
if not srcpad:
raise RuntimeError("No se pudo obtener src pad de capsfilter")
srcpad.link(sinkpad)
# streammux→nvinfer→nvosd→sink
assert streammux.link(pgie)
assert pgie.link(nvosd)
assert nvosd.link(sink)
# Sonda OSD
osd_sink_pad = nvosd.get_static_pad("sink")
if not osd_sink_pad:
raise RuntimeError("No se pudo obtener pad sink de nvosd")
osd_sink_pad.add_probe(Gst.PadProbeType.BUFFER, osd_sink_pad_buffer_probe, 0)
return pipeline
def main():
# Verifica archivos
if not os.path.exists(PGIE_CONFIG_FILE):
print(f"ERROR: No existe {PGIE_CONFIG_FILE}")
sys.exit(1)
if not os.path.exists(AUTHORIZED_UIDS_FILE):
print(f"AVISO: No existe {AUTHORIZED_UIDS_FILE}. Se creará uno vacío.")
with open(AUTHORIZED_UIDS_FILE, "w") as f:
json.dump({"uids": [], "policy": "allowlist"}, f, indent=2)
# Hilos auxiliares
t_logger = threading.Thread(target=event_logger_thread, args=(CSV_LOG,), daemon=True)
t_logger.start()
t_nfc = threading.Thread(target=nfc_reader_thread, daemon=True)
t_nfc.start()
# Construye y ejecuta pipeline
pipeline = build_pipeline()
loop = GLib.MainLoop()
bus = pipeline.get_bus()
bus.add_signal_watch()
def on_message(bus, message):
t = message.type
if t == Gst.MessageType.EOS:
print("EOS recibido")
loop.quit()
elif t == Gst.MessageType.ERROR:
err, dbg = message.parse_error()
print("ERROR:", err, dbg)
loop.quit()
return True
bus.connect("message", on_message)
print("Iniciando pipeline...")
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except KeyboardInterrupt:
print("Interrumpido por el usuario.")
finally:
print("Deteniendo pipeline...")
pipeline.set_state(Gst.State.NULL)
event_q.put(None) # cierra logger
if __name__ == "__main__":
main()
Archivo de configuración de nvinfer (usa el modelo de muestra ResNet10 de DeepStream 6.3): pgie_config_imx477.txt
[property]
gpu-id=0
net-scale-factor=0.0039215697906911373
model-file=/opt/nvidia/deepstream/deepstream-6.3/samples/models/Primary_Detector/resnet10.caffemodel
proto-file=/opt/nvidia/deepstream/deepstream-6.3/samples/models/Primary_Detector/resnet10.prototxt
labelfile-path=/opt/nvidia/deepstream/deepstream-6.3/samples/models/Primary_Detector/labels.txt
batch-size=1
model-color-format=0
network-mode=2 # FP16
num-detected-classes=4
gie-unique-id=1
process-mode=1
maintain-aspect-ratio=1
interval=0
# dims típicas del resnet10 sample; DeepStream puede sobreescalar internamente
infer-dims=3;300;300
[class-attrs-all]
nms-iou-threshold=0.5
pre-cluster-threshold=0.2
Archivo de ejemplo de allowlist NFC (authorized_uids.json):
{
"uids": ["04AABBCCDD", "12345678ABCDEF90"],
"policy": "allowlist"
}
Breve explicación de partes clave:
– nfc_reader_thread(): usa PC/SC (pcscd + pyscard) para hablar con el ACS ACR122U y obtener el UID mediante APDU FF CA 00 00 00, estándar para este lector. Actualiza un estado compartido con TTL de 3 segundos.
– DeepStream: se construye la tubería con nvarguscamerasrc (IMX477) a 1080p@30, nvinfer con el ResNet10 sample (detección de persona entre otras clases), y nvdsosd para overlay.
– osd_sink_pad_buffer_probe(): sobre cada frame cuenta personas (class_id == 0 en el modelo sample) y pinta el overlay con el estado de acceso si hay un UID reciente. También emite eventos CSV con el conteo de personas.
– Métricas: el probe calcula FPS cada ~1 s y lo muestra en pantalla.
Compilación/flash/ejecución
1) Preparar entorno (si no lo hiciste antes):
– Instalar DeepStream 6.3 y dependencias:
– sudo apt update
– sudo apt install -y deepstream-6.3 python3-gi python3-gst-1.0 gstreamer1.0-tools \
gstreamer1.0-plugins-{good,bad,ugly} python3-pip python3-dev libgstreamer1.0-dev \
pcscd pcsc-tools python3-pyscard
– Instalar pyds (bindings Python de DS 6.3):
– cd /opt/nvidia/deepstream/deepstream-6.3/bindings/python
– python3 -m pip install ./pyds-1.1.10-py3-none-linux_aarch64.whl
2) Preparar archivos del proyecto:
– Crea una carpeta de trabajo y copia los archivos:
– mkdir -p ~/deepstream-epp-access-control-nfc && cd ~/deepstream-epp-access-control-nfc
– nano deepstream_epp_access_control_nfc.py
(pega el código Python y guarda)
– nano pgie_config_imx477.txt
(pega el INI y guarda)
– nano authorized_uids.json
(pega el JSON de ejemplo y guarda)
3) Activar servicios y power mode:
– sudo systemctl enable –now pcscd
– sudo nvpmodel -m 0
– sudo jetson_clocks
4) Probar cámara y lector antes de ejecutar:
– Cámara:
– sudo systemctl restart nvargus-daemon
– gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! «video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1,format=NV12» ! nvvideoconvert ! fakesink -e
– Lector:
– pcsc_scan (presenta y retira una tarjeta para confirmar detección)
5) Ejecutar el caso práctico:
– cd ~/deepstream-epp-access-control-nfc
– python3 deepstream_epp_access_control_nfc.py
6) Métricas en paralelo:
– En otra terminal, corre:
– sudo tegrastats
– Observa GPU, EMC, RAM, CPU mientras el pipeline corre.
7) Finalizar y limpiar:
– Ctrl+C en la app Python.
– Detener tegrastats con Ctrl+C.
– Opcional: volver a un modo de energía más conservador:
– sudo nvpmodel -m 1
Validación paso a paso
1) Arranque sin errores:
– En la consola del script, debes ver:
– “Iniciando pipeline…”
– Selección de lector NFC tipo “ACR122”.
– No deben aparecer errores GStreamer (si los hay, ver Troubleshooting).
2) Video y overlay:
– Debe abrirse una ventana con la imagen de la IMX477 a 1080p.
– Aparecerán cajas y etiquetas sobre objetos detectados por el modelo (person, car, etc.).
– En la esquina superior izquierda verás:
– PERSONAS=N (conteo) y FPS=xx.x.
3) NFC y control de acceso:
– Acerca una tarjeta no autorizada:
– En consola, debe aparecer [EVENT] con granted=0.
– En el overlay, durante ~3 s, “ACCESO DENEGADO · UID=…”.
– Acerca una tarjeta de authorized_uids.json:
– Debe aparecer [EVENT] con granted=1.
– Overlay: “ACCESO CONCEDIDO · UID=…”.
– Si no hay ninguna persona detectada en la escena, el overlay mostrará PERSONAS=0; en un flujo real podrías condicionar la concesión a PERSONAS>0; este ejemplo muestra el estado NFC y el conteo simultáneamente.
4) Métricas de rendimiento:
– FPS esperado: 25–30 FPS con 1080p, batch-size=1, FP16.
– tegrastats: GPU 15–40% (variable por escena), memoria estable (< 2 GB para el pipeline).
– Latencia de overlay NFC: visualmente, el estado debe aparecer casi inmediato al acercar la tarjeta (<< 0.2 s).
5) Logs:
– Revisa el CSV:
– tail -f access_log.csv
– Debes ver líneas tipo:
– 2025-01-01T12:34:56.789123,04AABBCCDD,1,1
6) Persistencia:
– Detén y vuelve a ejecutar la app; authorized_uids.json y access_log.csv deben persistir en tu carpeta de trabajo.
Criterio de éxito: en presencia de una persona, al presentar la tarjeta autorizada se imprime [EVENT] granted=1 y el overlay “ACCESO CONCEDIDO” con FPS≥25 y sin errores en consola.
Troubleshooting
1) nvarguscamerasrc: WARNING o “No cameras available”
– Causas:
– Conexión FFC floja o invertida.
– nvargus-daemon colgado tras múltiples pruebas.
– Soluciones:
– Apaga, reconecta la cámara al CSI CAM0 asegurando la pestaña.
– sudo systemctl restart nvargus-daemon
– dmesg | grep -i imx477 para confirmar driver.
2) Ventana en negro o EGL error al iniciar el sink
– Causas:
– No hay monitor o no hay contexto EGL válido.
– Soluciones:
– Conecta un monitor HDMI/DP.
– Alterna a un sink headless para pruebas:
– En el código, cambia nveglglessink por fakesink y reintenta.
3) “No module named pyds” o error al importar pyds
– Causa: bindings no instaladas o versión incorrecta.
– Soluciones:
– Reinstala la rueda correcta de DS 6.3:
– python3 -m pip install /opt/nvidia/deepstream/deepstream-6.3/bindings/python/pyds-1.1.10-py3-none-linux_aarch64.whl
– Verifica deepstream-app –version-all muestra 6.3.
4) pcsc_scan detecta la tarjeta pero la app no reporta UID
– Causas:
– El lector distinto a ACR122U quedó seleccionado; APDU Get UID puede fallar con algunas tarjetas no-4A.
– Soluciones:
– Modifica nfc_reader_thread para elegir exactamente el lector cuyo nombre contenga “ACR122”.
– Prueba otra tarjeta ISO14443A MIFARE Classic/Ultralight.
– Si tienes múltiples lectores, desconecta los no usados.
5) UID no coincide con authorized_uids.json
– Causa: formato hex sin espacios vs. con espacios/minúsculas.
– Solución:
– Usa uppercase sin separadores en el JSON (p. ej., “04AABBCCDD”).
– Imprime el UID leído (la app lo hace) y copia-pega en el JSON.
6) FPS demasiado bajo (<20)
– Causas:
– Power mode no está en MAXN o jetson_clocks no activo.
– Carga del sistema elevada (otras apps).
– Soluciones:
– sudo nvpmodel -m 0; sudo jetson_clocks
– Cierra otras aplicaciones; usa sink fakesink para medir techo.
– Reduce resolución en capsfilter (p. ej., 1280×720).
7) “Could not open file model/proto” en nvinfer
– Causa: rutas inválidas en pgie_config_imx477.txt.
– Soluciones:
– Verifica que existen:
– ls /opt/nvidia/deepstream/deepstream-6.3/samples/models/Primary_Detector/
– Corrige model-file y proto-file en el INI.
8) Mensajes “Buffer … map error” o inestabilidad
– Causas:
– Incompatibilidad ocasional de plugins, memoria insuficiente.
– Soluciones:
– Asegura GStreamer 1.20.x y DeepStream 6.3.
– Reduce batch-size, resolución o desactiva tracking.
– Rebotar el sistema si el daemon de Argus se degrada: sudo reboot
Mejoras/variantes
- Control de acceso condicionado: requerir PERSONAS>0 y UID autorizado simultáneamente para “CONCEDIDO”.
- Sustituir el modelo primario por PeopleNet (TAO) para mayor precisión en personas:
- Descargar desde NGC, generar engine FP16/INT8 y ajustar el pgie_config.
- Exportación de eventos a MQTT/HTTP:
- Publicar [EVENT] a un broker local o a un SIEM corporativo.
- Persistencia de credenciales:
- Reemplazar authorized_uids.json por SQLite encriptado con rotación de claves.
- Integración hardware:
- Activar GPIO en el header del Jetson para controlar un relé de puerta al conceder acceso.
- Liveness/anti-spoofing:
- Añadir un modelo de verificación de vida o face recognition para doble factor (NFC+rostro).
- Headless:
- Reemplazar nveglglessink por fakesink y emitir solo métricas/streams RTSP via nvmsgbroker o rtspclientsink.
Checklist de verificación
- [ ] JetPack 6.0 (L4T 36.2) y DeepStream 6.3 instalados y verificados.
- [ ] Cámara Arducam IMX477 en CAM0 reconocida por nvarguscamerasrc.
- [ ] Lector ACS ACR122U visible en lsusb y pcsc_scan, pcscd activo.
- [ ] pyds instalado desde /opt/nvidia/deepstream/deepstream-6.3/bindings/python/.
- [ ] Proyecto preparado con deepstream_epp_access_control_nfc.py, pgie_config_imx477.txt y authorized_uids.json.
- [ ] Pipeline corre y muestra OSD con FPS y PERSONAS=N.
- [ ] Al acercar tarjeta no autorizada, overlay muestra “ACCESO DENEGADO” y se genera log.
- [ ] Al acercar tarjeta autorizada, overlay muestra “ACCESO CONCEDIDO” y se genera log con persons>=0.
- [ ] tegrastats reporta GPU/EMC razonables; FPS≥25 en 1080p (o según tu objetivo).
- [ ] CSV access_log.csv contiene eventos con timestamp, UID, granted y persons.
Notas finales de toolchain y coherencia de modelo:
– Dispositivo exacto utilizado: NVIDIA Jetson Orin Nano Developer Kit + Arducam IMX477 HQ Camera (IMX477) + ACS ACR122U NFC Reader (PN532).
– Toolchain verificada: JetPack 6.0 (L4T 36.2), DeepStream 6.3, CUDA 12.2, TensorRT 8.6.x, cuDNN 8.9.x, GStreamer 1.20.x y Python 3.10. Usa los comandos de verificación del inicio para confirmar versiones instaladas en tu equipo.
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.




