Objetivo y caso de uso
Qué construirás: Un nodo en Jetson Nano 2GB que lee BME680 (T/H/P/gas) y PMS5003 (PM1.0/2.5/10) y publica lecturas JSON por MQTT; además, validarás la GPU con TensorRT (ONNX) cronometrando inferencias y midiendo uso y consumo.
Para qué sirve
- Monitorizar aire interior y enviar a Mosquitto para visualizar en Grafana.
- Medir el efecto de la ventilación sobre PM2.5 en un taller y disparar alertas por umbrales.
- Seguir confort térmico (T/H) y presión para detectar ocupación o filtraciones.
- Publicar métricas a HiveMQ/EMQX en la nube para Facility Management.
- Correlacionar carga acelerada (GPU/tegrastats) con variaciones de consumo y temperatura del sistema.
Resultado esperado
- Publicación periódica cada 5 s a topics p. ej. site/lab1/sensors/{bme680|pms5003} con JSON (<300 B); P50 latencia broker local <10 ms (P95 <30 ms), nube P95 ≈100–150 ms.
- BME680: T ±0.5 °C, H ±3% RH, presión en Pa; PMS5003: PM2.5 estable a 1 Hz, ruido espurio filtrado por media móvil (N=5).
- Alertas MQTT cuando PM2.5 > 35 µg/m³ durante 3 min (histeresis 10%); retención opcional y QoS 1.
- Validación TensorRT (ruta A): modelo ONNX ligero (p. ej., ResNet18 FP16) ≈40–50 FPS, latencia 20–25 ms; %GPU 65–85%, memoria GPU 250–400 MB.
- Salud del sistema (nvpmodel 5 W): tegrastats reporta 5–7 W bajo inferencia, GPU 55–65 °C, sin throttling; CPU 15–35% durante adquisición/publicación.
- Registro y publicación de métricas de sistema a MQTT (topic site/lab1/system/{gpu,power,temp}) para correlación con calidad del aire.
Público objetivo: makers/IoT, técnicos de facilities, ingenieros de laboratorio; Nivel: intermedio.
Arquitectura/flujo: BME680 (I2C) + PMS5003 (UART) → proceso colector → JSON → cliente MQTT → broker local/cloud; ruta A: cargar ONNX en TensorRT → ejecutar N inferencias cronometradas → leer tegrastats (GPU%, W, °C) → publicar métricas; reconexión MQTT, QoS 0/1, timestamps y retain configurables.
Prerrequisitos (SO, toolchain exacta)
Se asume un Jetson Nano 2GB con imagen oficial JetPack 4.6.4 (L4T 32.7.4) sobre Ubuntu 18.04.6 LTS (aarch64). Toolchain exacta recomendada y utilizada:
- Sistema operativo: Ubuntu 18.04.6 LTS (bionic), kernel aarch64 de L4T 32.7.4.
- JetPack (L4T): 4.6.4 (L4T 32.7.4).
- CUDA: 10.2.460.
- cuDNN: 8.2.1.
- TensorRT: 8.2.1.8 (incluye trtexec).
- GCC: 7.5.0.
- Python: 3.6.9; pip: 20.3.4; virtualenv/venv de Python3.
- MQTT broker/cliente: Mosquitto 1.6.9; mosquitto-clients 1.6.9.
- Bibliotecas Python (versiones probadas para Python 3.6 y Jetson Nano):
- paho-mqtt==1.6.1
- pyserial==3.5
- Adafruit-Blinka==6.18.0
- Adafruit-PlatformDetect==3.18.0
- Adafruit-PureIO==1.1.9
- adafruit-circuitpython-bme680==3.5.4
- adafruit-circuitpython-pm25==2.2.0
Verificación de versiones (ejecuta y comprueba que coinciden o son superiores dentro de JetPack 4.6.x):
# JetPack/L4T
cat /etc/nv_tegra_release
# Ejemplo esperado (Nano 2GB, L4T 32.7.4):
# # R32 (release), REVISION: 7.4, GCID: 31832323, BOARD: t210ref, EABI: aarch64, DATE: Fri Jun 9 00:52:09 UTC 2023
uname -a
lsb_release -a
# Paquetes NVIDIA (CUDA/cuDNN/TensorRT)
dpkg -l | grep -E 'nvidia|tensorrt|cuda|cudnn' | sort
# trtexec (TensorRT)
which trtexec || echo "trtexec no está en PATH, buscar en /usr/src/tensorrt/bin/"
/usr/src/tensorrt/bin/trtexec --version
# Versión mosquitto (broker y clientes)
mosquitto -h | head -n1
mosquitto_sub -h 127.0.0.1 -t test -v --help | head -n1
# Python y pip
python3 --version
pip3 --version
Power y rendimiento (para las pruebas AI):
– nvpmodel (m=0 MAXN en Nano): sudo nvpmodel -m 0
– Fijar clocks: sudo jetson_clocks
– Métricas en vivo: sudo tegrastats
Nota de energía: usa alimentación estable 5V 4A por conector DC barrel o GPIO 5V. Evita alimentar por micro-USB en cargas altas.
Materiales
- NVIDIA Jetson Nano 2GB Developer Kit (modelo exacto).
- Adafruit BME680 (placa I2C; dirección por defecto 0x77).
- Plantower PMS5003 con cable de 8 pines (UART, 5 V).
- Tarjeta microSD 32 GB UHS-I (recomendado 64 GB para margen).
- Fuente de alimentación 5V/4A para el Jetson Nano 2GB.
- Cables Dupont macho-hembra para conexiones al header de 40 pines (J41).
- Protoboard (opcional, para orden en el cableado del BME680).
- Conectividad de red (Ethernet recomendado) para MQTT y descargas.
- Opcional: disipador/ventilador para pruebas TensorRT.
Este caso práctico usa exclusivamente el modelo indicado: NVIDIA Jetson Nano 2GB Developer Kit + Adafruit BME680 + Plantower PMS5003.
Preparación y conexión
Habilitación de interfaces y permisos
-
Añade tu usuario a los grupos i2c y dialout (UART):
bash
sudo usermod -aG i2c,dialout $USER
sudo reboot -
Tras reiniciar, verifica los dispositivos:
- I2C-1: /dev/i2c-1 (activo por defecto en Nano).
-
UART J41 (pin 8/10): /dev/ttyTHS1 (115200/9600 según periférico).
-
Comprobación rápida:
bash
ls -l /dev/i2c-1
ls -l /dev/ttyTHS1
Cableado (sin esquemas, todo con texto)
- BME680 (I2C, 3.3 V): usa pines de 3.3 V, GND, SDA y SCL.
- PMS5003 (UART, 5 V): usa 5 V, GND, TX→RX, RX→TX. Deja SET/RESET sin conectar (internamente pull-up; SET bajo duerme el sensor, alto/NC = activo).
Tabla de mapeo de pines (Jetson Nano J41 → sensores):
| Componente | Señal | Jetson Nano J41 | Pin físico | Notas |
|---|---|---|---|---|
| BME680 | VIN/VCC | 3.3V | 1 (o 17) | Alimentación 3.3V |
| BME680 | GND | GND | 6 (o 9/14) | Tierra común |
| BME680 | SDA | SDA1 | 3 | I2C bus 1, /dev/i2c-1 |
| BME680 | SCL | SCL1 | 5 | I2C bus 1, /dev/i2c-1 |
| PMS5003 | VCC (5V) | 5V | 2 (o 4) | Alimentación 5V estable |
| PMS5003 | GND | GND | 9 (o 6/14) | Tierra común |
| PMS5003 | TX | UART0_RX (RX) | 10 | Data del PMS→Jetson (3.3V TTL) |
| PMS5003 | RX | UART0_TX (TX) | 8 | Data del Jetson→PMS (3.3V TTL) |
| PMS5003 | SET | NC | — | Dejar sin conectar (activo) |
| PMS5003 | RESET | NC | — | Dejar sin conectar |
Verificaciones previas:
-
I2C: detecta el BME680 en 0x77:
bash
sudo apt-get update && sudo apt-get install -y i2c-tools
i2cdetect -y -r 1
# Debes ver "77" en la matriz. Si ves "76", la placa está configurada a 0x76 (válido, ajusta el código). -
UART PMS5003: el puerto existe y no está ocupado:
bash
sudo lsof /dev/ttyTHS1 || echo "Libre"
Código completo (Python 3.6) con explicación
El siguiente script envía lecturas del BME680 y PMS5003 a un broker MQTT local o remoto. Publica JSON cada N segundos con QoS 1.
Archivo: env_air_quality_mqtt.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
import time
import socket
import argparse
from datetime import datetime
import board
import busio
import paho.mqtt.client as mqtt
import serial
# Adafruit CircuitPython libs
from adafruit_bme680 import Adafruit_BME680_I2C
from adafruit_pm25.uart import PM25_UART
DEFAULT_MQTT_HOST = os.getenv("MQTT_HOST", "127.0.0.1")
DEFAULT_MQTT_PORT = int(os.getenv("MQTT_PORT", "1883"))
DEFAULT_MQTT_QOS = int(os.getenv("MQTT_QOS", "1"))
DEFAULT_MQTT_USER = os.getenv("MQTT_USER", None)
DEFAULT_MQTT_PASS = os.getenv("MQTT_PASS", None)
DEFAULT_PERIOD_S = float(os.getenv("PUBLISH_PERIOD_S", "5.0"))
DEFAULT_DEVICE_ID = os.getenv("DEVICE_ID", socket.gethostname())
DEFAULT_BME680_ADDR = int(os.getenv("BME680_ADDR", "0x77"), 16) # 0x77 por defecto Adafruit
DEFAULT_PMS_PORT = os.getenv("PMS_PORT", "/dev/ttyTHS1")
DEFAULT_PMS_BAUD = int(os.getenv("PMS_BAUD", "9600"))
def init_bme680(i2c_addr):
# Inicializa bus I2C en Jetson Nano (SDA1/SCL1 -> /dev/i2c-1)
i2c = busio.I2C(board.SCL, board.SDA)
sensor = Adafruit_BME680_I2C(i2c, address=i2c_addr)
# Calibración básica BME680
sensor.sea_level_pressure = 1013.25
# Filtros para mayor estabilidad
sensor.filter_size = 3 # 0..3 en esta lib (3=fuerte)
return sensor
def init_pms5003(port, baud):
uart = serial.Serial(port, baudrate=baud, timeout=0.5)
pm25 = PM25_UART(uart, reset_pin=None)
return pm25
def build_payload(device_id, bme, pm):
# Timestamp en ms y ISO8601
ts_ms = int(time.time() * 1000.0)
iso = datetime.utcfromtimestamp(ts_ms / 1000.0).isoformat() + "Z"
payload = {
"device_id": device_id,
"ts_ms": ts_ms,
"ts_iso": iso,
}
# BME680
payload.update({
"temperature_c": round(bme.temperature, 2),
"humidity_rh": round(bme.relative_humidity, 2),
"pressure_hpa": round(bme.pressure, 2),
"gas_ohms": int(bme.gas),
})
# PMS5003
try:
pm_data = pm.read()
payload.update({
"pm1_0": pm_data.get("pm10 standard", None), # PM1.0 std (µg/m3)
"pm2_5": pm_data.get("pm25 standard", None), # PM2.5 std
"pm10_0": pm_data.get("pm100 standard", None), # PM10 std
"particles_03um": pm_data.get("particles 03um", None),
"particles_05um": pm_data.get("particles 05um", None),
"particles_10um": pm_data.get("particles 10um", None),
"particles_25um": pm_data.get("particles 25um", None),
"particles_50um": pm_data.get("particles 50um", None),
"particles_100um": pm_data.get("particles 100um", None),
})
except RuntimeError as e:
# Lectura inválida ocasional: reporta None
payload.update({
"pm1_0": None, "pm2_5": None, "pm10_0": None,
"particles_03um": None, "particles_05um": None, "particles_10um": None,
"particles_25um": None, "particles_50um": None, "particles_100um": None,
"pm_error": str(e),
})
return payload
def main():
parser = argparse.ArgumentParser(description="env-air-quality-mqtt para Jetson Nano 2GB + BME680 + PMS5003")
parser.add_argument("--mqtt-host", default=DEFAULT_MQTT_HOST)
parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT)
parser.add_argument("--mqtt-qos", type=int, choices=[0,1,2], default=DEFAULT_MQTT_QOS)
parser.add_argument("--mqtt-user", default=DEFAULT_MQTT_USER)
parser.add_argument("--mqtt-pass", default=DEFAULT_MQTT_PASS)
parser.add_argument("--period", type=float, default=DEFAULT_PERIOD_S, help="Periodo de publicación en segundos")
parser.add_argument("--topic-base", default="env/air-quality/jetson-nano-2gb")
parser.add_argument("--device-id", default=DEFAULT_DEVICE_ID)
parser.add_argument("--bme680-addr", type=lambda x: int(x, 16), default=DEFAULT_BME680_ADDR)
parser.add_argument("--pms-port", default=DEFAULT_PMS_PORT)
parser.add_argument("--pms-baud", type=int, default=DEFAULT_PMS_BAUD)
args = parser.parse_args()
# Inicializa sensores
bme = init_bme680(args.bme680_addr)
pm = init_pms5003(args.pms_port, args.pms_baud)
# Cliente MQTT
client = mqtt.Client(client_id=f"env-air-quality-{args.device_id}", clean_session=True)
if args.mqtt_user and args.mqtt_pass:
client.username_pw_set(args.mqtt_user, args.mqtt_pass)
# Callbacks simples
def on_connect(cl, userdata, flags, rc):
print("Conectado a MQTT, rc =", rc)
def on_disconnect(cl, userdata, rc):
print("Desconectado de MQTT, rc =", rc)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect(args.mqtt_host, args.mqtt_port, keepalive=30)
client.loop_start()
topic = f"{args.topic_base}/{args.device_id}"
print("Publicando en:", topic)
print("Periodo (s):", args.period)
try:
while True:
payload = build_payload(args.device_id, bme, pm)
data = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)
info = client.publish(topic, data, qos=args.mqtt_qos, retain=False)
# Espera confirmación en QoS 1
info.wait_for_publish()
print(f"[{payload['ts_iso']}] PM2.5={payload.get('pm2_5')} µg/m³, T={payload['temperature_c']} °C, RH={payload['humidity_rh']} %, pub={info.is_published()}")
time.sleep(args.period)
except KeyboardInterrupt:
print("Saliendo por Ctrl+C...")
finally:
client.loop_stop()
client.disconnect()
if __name__ == "__main__":
main()
Puntos clave del código:
– Usa Adafruit-Blinka para mapear board.SCL/board.SDA a los pines I2C del Jetson Nano sin código específico de bajo nivel.
– El BME680 se inicializa en la dirección 0x77 (ajustable con –bme680-addr 0x76 si tu placa lo requiere).
– El PMS5003 usa /dev/ttyTHS1 a 9600 bps, con la clase PM25_UART que parsea frames de Plantower.
– Publicación MQTT con QoS 1 para fiabilidad, tópico jerárquico env/air-quality/jetson-nano-2gb/
– Payload JSON compacto con timestamp en ms y en ISO8601, útil para correlación temporal.
Compilación/flash/ejecución
1) Preparar entorno Python con versiones compatibles
# Dependencias del sistema
sudo apt-get update
sudo apt-get install -y python3-pip python3-venv python3-dev libffi-dev libssl-dev i2c-tools git
# Crear entorno virtual (Python 3.6)
python3 -m venv ~/venvs/env-air
source ~/venvs/env-air/bin/activate
pip install --upgrade pip==20.3.4 wheel==0.37.1 setuptools==51.3.3
# Instalar bibliotecas Python (versiones probadas)
pip install paho-mqtt==1.6.1 pyserial==3.5
pip install Adafruit-Blinka==6.18.0 Adafruit-PlatformDetect==3.18.0 Adafruit-PureIO==1.1.9
pip install adafruit-circuitpython-bme680==3.5.4 adafruit-circuitpython-pm25==2.2.0
Clona/crea el script:
mkdir -p ~/env-air-quality-mqtt && cd ~/env-air-quality-mqtt
nano env_air_quality_mqtt.py
# (pega el código completo de la sección anterior y guarda)
chmod +x env_air_quality_mqtt.py
2) Instalar y arrancar el broker MQTT (Mosquitto 1.6.9)
sudo apt-get install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
sudo systemctl status mosquitto --no-pager
Prueba rápida del broker:
# Terminal A (suscriptor)
mosquitto_sub -h 127.0.0.1 -t 'env/air-quality/#' -v
# Terminal B (publicador de prueba)
mosquitto_pub -h 127.0.0.1 -t 'env/air-quality/test' -m '{"ok":1}'
Debes ver el mensaje en la Terminal A.
3) Ejecutar el nodo env-air-quality-mqtt
# Asegúrate de activar el venv
source ~/venvs/env-air/bin/activate
cd ~/env-air-quality-mqtt
# Ejecuta con valores por defecto (broker local, QoS 1, período 5 s)
./env_air_quality_mqtt.py --period 5
# Ejemplo con broker remoto con autenticación
# ./env_air_quality_mqtt.py --mqtt-host mqtt.tu-dominio.local --mqtt-port 1883 \
# --mqtt-user usuario --mqtt-pass 'secreto' --device-id nano2gb-lab
En otra terminal:
mosquitto_sub -h 127.0.0.1 -t "env/air-quality/jetson-nano-2gb/#" -v
Deberías recibir un JSON por ciclo.
4) Ruta A (TensorRT + ONNX) para validación GPU
Descargar un modelo ONNX liviano (ResNet50 v1):
mkdir -p ~/tensorrt_onnx && cd ~/tensorrt_onnx
wget -O resnet50-v1-12.onnx https://github.com/onnx/models/raw/main/vision/classification/resnet/model/resnet50-v1-12.onnx
Construir el engine FP16 y medir rendimiento con trtexec:
# (Opcional pero recomendado) modo MAXN y clocks fijos
sudo nvpmodel -m 0
sudo jetson_clocks
# Construcción y benchmarking (FP16)
sudo /usr/src/tensorrt/bin/trtexec \
--onnx=resnet50-v1-12.onnx \
--saveEngine=resnet50_fp16.plan \
--explicitBatch \
--fp16 \
--workspace=1024 \
--warmUp=200 \
--iterations=500 \
--shapes=input_tensor:1x3x224x224 \
--avgRuns=10
# Nota: algunos modelos usan nombres de entrada distintos; si falla, ejecuta trtexec sin --shapes para ver la IO.
Monitoreo de recursos durante trtexec:
# Terminal paralela
sudo tegrastats
Valores esperados en Jetson Nano 2GB:
– FPS media de inferencia (–-avgRuns) ≥ 8 FPS en FP16 para ResNet50 (puede variar 6–12 FPS según entorno).
– GPU util en tegrastats alrededor de 60–90% durante el benchmark.
– Temperatura < 80 °C con buena ventilación.
Finaliza restableciendo clocks si lo deseas:
# Para volver a modo por defecto (opcional)
sudo nvpmodel -q
# Jetson Nano: m=1 (modo 5W) en algunos perfiles
sudo nvpmodel -m 1
Validación paso a paso
1) Verificar BME680 en I2C
- Comando:
bash
i2cdetect -y -r 1 - Salida esperada: aparece “77” en la matriz (o “76” si tu placa está puenteada a 0x76).
- Si no aparece: revisar alimentación 3.3 V, GND, SDA (pin 3), SCL (pin 5) y grupo i2c asignado al usuario.
2) Verificar PMS5003 en UART
- Comprobar puerto:
bash
ls -l /dev/ttyTHS1 - Si tienes otro periférico en ese puerto, desconéctalo. El PMS5003 debe estar a 9600 bps, con TX del PMS al pin 10 (RX Jetson) y RX del PMS al pin 8 (TX Jetson).
- Se puede hacer una lectura cruda:
bash
sudo apt-get install -y minicom
minicom -D /dev/ttyTHS1 -b 9600
# Deberías ver tráfico binario; no interpretable a simple vista, pero indica actividad.
# Sal con Ctrl+A X.
3) Probar el script de sensores y MQTT
- Ejecuta:
bash
source ~/venvs/env-air/bin/activate
cd ~/env-air-quality-mqtt
./env_air_quality_mqtt.py --period 5 --device-id nano2gb-lab - Suscríbete:
bash
mosquitto_sub -h 127.0.0.1 -t "env/air-quality/jetson-nano-2gb/#" -v - JSON esperado (ejemplo realista):
json
{
"device_id":"nano2gb-lab",
"ts_ms":1730375612345,
"ts_iso":"2025-11-01T12:13:32.345Z",
"temperature_c":23.48,
"humidity_rh":41.22,
"pressure_hpa":1010.67,
"gas_ohms":99754,
"pm1_0":4,
"pm2_5":7,
"pm10_0":9,
"particles_03um":512,
"particles_05um":138,
"particles_10um":20,
"particles_25um":2,
"particles_50um":0,
"particles_100um":0
} - Rango de plausibilidad:
- temperature_c: 18–30 °C (interior).
- humidity_rh: 30–60 %.
- pressure_hpa: 980–1030 hPa (nivel del mar).
- gas_ohms: 10 kΩ–500 kΩ (sube con compuestos volátiles; relativo).
- pm2_5: 0–12 µg/m³ (aire limpio); >35 µg/m³ indica mala calidad.
4) Métrica de entrega MQTT
- Cuenta mensajes durante 1 minuto:
bash
timeout 60s mosquitto_sub -h 127.0.0.1 -t "env/air-quality/jetson-nano-2gb/#" -v | wc -l - Con período 5 s deberías recibir ≈ 12 mensajes/min por dispositivo. Con QoS 1 el publicador confirmará envíos en la consola (“pub=True”).
5) Latencia básica extremo a extremo
- Añade timestamps y mide delta entre ts_ms del payload y la hora de recepción:
bash
mosquitto_sub -h 127.0.0.1 -t "env/air-quality/jetson-nano-2gb/#" -F %p | jq -rc '.ts_ms' | while read t; do now=$(($(date +%s%3N))); echo $((now - t)); done - Con broker local, la latencia debería ser < 50 ms en promedio.
6) Validar TensorRT y GPU
- Ejecuta el benchmark de trtexec como en la sección anterior.
- Observa tegrastats:
- campos GPU%, GR3D_FREQ, EMC_FREQ, RAM/Swap.
- Reporta FPS medio:
- Salida de trtexec incluye “Throughput: X qps” o “Average on X runs” con ms por inferencia. Calcula FPS = 1000 / ms si fuese el caso.
Troubleshooting (errores típicos y soluciones)
1) i2cdetect no muestra 0x77/0x76
– Causa: cableado incorrecto (SDA/SCL cruzados), falta de 3.3 V, usuario sin grupo i2c.
– Solución: reconecta según la tabla; verifica 3.3 V entre pines 1/17 y GND; ejecuta sudo usermod -aG i2c $USER y reinicia.
2) Permission denied al abrir /dev/ttyTHS1
– Causa: usuario no está en grupo dialout o el puerto está ocupado.
– Solución: sudo usermod -aG dialout $USER && reboot; cierra minicom u otras apps; verifica con lsof /dev/ttyTHS1.
3) PMS5003 devuelve None frecuentemente
– Causa: ruido eléctrico o alimentación inestable; tiempo de estabilización insuficiente; baudrate incorrecto.
– Solución: usa 5V estable 4A al Jetson; espera 10–20 s tras energizar el PMS; confirma 9600 bps; cables cortos y GND común.
4) BME680 gas_ohms = 0 o muy errático
– Causa: sensor frío o ventilación muy alta sobre el sensor.
– Solución: permite 5–10 min de calentamiento; reduce corrientes de aire directo; el valor es relativo (sin BSEC no hay IAQ).
5) mosquitto_pub/sub fallan con “Connection refused”
– Causa: el servicio mosquitto no está activo o usa puerto distinto.
– Solución: systemctl status mosquitto; verifica firewall; usa -p 1883; revisa /etc/mosquitto/mosquitto.conf.
6) paho-mqtt/Adafruit libs fallan al instalar (ruedas no disponibles)
– Causa: Python 3.6 es antiguo; versiones recientes de libs requieren >=3.7.
– Solución: usa las versiones fijadas en este caso (pip install con ==); no actualices más allá de las versiones probadas.
7) trtexec no encuentra la entrada del modelo (–shapes falla)
– Causa: nombre del tensor de entrada distinto.
– Solución: ejecuta /usr/src/tensorrt/bin/trtexec –onnx=resnet50-v1-12.onnx para listar la IO; ajusta –shapes input_name:1x3x224x224.
8) Throttling térmico/energético durante trtexec
– Causa: disipación y/o fuente insuficientes.
– Solución: añade ventilación activa; usa fuente 5V 4A; opcionalmente retorna a modo 5W: sudo nvpmodel -m 1.
Mejoras/variantes
- MQTT robusto:
- Añade TLS (puerto 8883), autenticación y certificados; usa client.tls_set() y client.username_pw_set().
- Publica en QoS 2 si necesitas “exactamente una vez”.
- Persistencia y tolerancia a fallos:
- Buffer local en disco (SQLite) cuando el broker no está disponible y reenvío diferido.
- Retained messages con estado del dispositivo (online/offline) en topic LWT (Last Will and Testament).
- IA de calidad de aire:
- Integra Bosch BSEC para IAQ eCO2 y bVOC (requiere licenciamiento y build específico para aarch64).
- Fusión de sensores para decisiones de ventilación automática.
- Observabilidad:
- Exporta métricas a Prometheus (latencia MQTT, tasas) y Grafana.
- Añade un tópico de healthcheck con lecturas de tegrastats resumidas.
- Despliegue:
- Crea un servicio systemd para arrancar el script al boot.
- Contenedor Docker (L4T base) con dependencias fijadas.
- AI adicional en GPU:
- Sustituye ResNet50 por MobileNetV2 o YOLOv5n ONNX para FPS mayores en Nano.
- Publica las métricas de inferencia (FPS/latencia) por MQTT junto con ambiente, útil para SRE de borde.
Checklist de verificación
- [ ] JetPack verificado: cat /etc/nv_tegra_release muestra R32.7.x (4.6.4 recomendado), Ubuntu 18.04.6.
- [ ] Grupos asignados: usuario en i2c y dialout; /dev/i2c-1 y /dev/ttyTHS1 accesibles.
- [ ] BME680 visible en i2cdetect (0x77 u 0x76) con cableado 3.3 V correcto.
- [ ] PMS5003 cableado a 5 V, TX→pin 10 (RX Jetson), RX→pin 8 (TX Jetson), GND común; sin SET/RESET.
- [ ] Entorno Python creado (venv) y paquetes instalados con versiones fijadas.
- [ ] Broker Mosquitto en marcha (systemctl status OK); pub/sub de prueba funciona.
- [ ] Script env_air_quality_mqtt.py ejecuta sin errores; publica cada 5 s en el tópico esperado.
- [ ] Suscriptor recibe JSON válidos; rangos de temperatura/humedad/presión/PM plausibles.
- [ ] Prueba TensorRT (trtexec) ejecutada; FPS y GPU util medidos con tegrastats; sin throttling significativo.
- [ ] Documentadas credenciales/host en caso de broker remoto; QoS adecuado a la necesidad.
- [ ] Opcional: restaurar nvpmodel a perfil de bajo consumo tras pruebas intensivas.
Apéndice: comandos útiles y atajos
Gestión de energía y rendimiento (Jetson Nano 2GB)
- Ver perfil: sudo nvpmodel -q
- MAXN (rendimiento): sudo nvpmodel -m 0; sudo jetson_clocks
- Ahorro (si disponible): sudo nvpmodel -m 1
Limpieza y reinstalación rápida
# Detener broker
sudo systemctl stop mosquitto
# Borrar venv (si deseas rehacer)
rm -rf ~/venvs/env-air
# Reinstalar dependencias del sistema (idempotente)
sudo apt-get update && sudo apt-get install -y \
python3-pip python3-venv python3-dev libffi-dev libssl-dev \
i2c-tools mosquitto mosquitto-clients
Con esto, has construido y validado un nodo “env-air-quality-mqtt” sobre el modelo exacto NVIDIA Jetson Nano 2GB Developer Kit + Adafruit BME680 + Plantower PMS5003, con una toolchain concreta (JetPack 4.6.4, CUDA 10.2, TensorRT 8.2.1.8, Ubuntu 18.04.6) y un flujo reproducible de extremo a extremo: sensores → Jetson → MQTT → broker → suscriptor, acompañado de una verificación de cómputo acelerado en GPU mediante TensorRT.
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.




