8 - La famiglia

Capítulo para tratar otros componentes de la familia Raspberry Pi

Microcontroladores: Pico

Introducción

¿Qué es un microcontrolador? en la Wikipedia podemos encontrar la siguiente definición:

Un microcontrolador es un circuito integrado programable, capaz de ejecutar las órdenes grabadas en su memoria. Está compuesto de varios bloques funcionales que cumplen una tarea específica. Un microcontrolador incluye en su interior las tres principales unidades funcionales de una computadora: unidad central de procesamiento, memoria y periféricos de entrada/salida.

Y si la Raspberry Pi Pico es un microntrolador, ¿qué es la raspberry Pi? Esta pregunta la tenemos ya respondida en https://libros.catedu.es/link/8787#bkmrk-una-raspberry-pi-es- 

La diferencia fundamental entre una Raspberry Pi 1/2/3/4/5 y una Raspberry Pi Pico 1/2 es que pertenecen a categorías de dispositivos completamente distintas: la primera es un ordenador completo (SBC), mientras que la segunda es un microcontrolador diseñado para tareas específicas de control electrónico:

En la página web de Raspberry Pi podemos encontrar una sección para los microcontroladores de la familia. Concretamente, en la dirección https://www.raspberrypi.com/products/raspberry-pi-pico-2/ , podemos encontrar información sobre la Raspberry Pi Pico 2.

Características principales de la Raspberry Pi Pico 2

Todas las variantes Pico 2 comparten la misma base de hardware principal, porque todas usan el RP2350. Según Raspberry Pi, las características generales son Documentación oficial :

Además, el RP2350 añade funciones de seguridad importantes, como:

El pinout de la raspberry pi pico 2 w es el siguiente:

pinout.png

Versiones

Variante Wi-Fi Bluetooth Headers presoldados
Raspberry Pi Pico 2 No No No
Raspberry Pi Pico 2 with headers No No Si
Raspberry Pi Pico 2 W Si Si No
Raspberry Pi Pico 2 W with headers Si Si Si

Algunos proyectos

Con Arduino IDE versión 2.x podemos trabajar con la placa. Si usas Linux es probable que para que te detecte la placa tengas que ejecutar el comando sudo usermod -a -G dialout $USER para añadir al usuario al grupo dialout (deberás reiniciar la sesión). Además, con independencia del sistema operativo que utilices deberás añadir a las placas disponibles la Raspberry Pi Pico. Para ello, dirígete a file > Preferences > Additional boards manager URLs y añade la url https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json Reinicia el IDE, conecta la microcontroladora y debería estar lista para funcionar.

Encender y apagar un led

La placa tiene integrado un led junto al conector USB. Para encenderlo y apagarlo alternativamente copia y pega el siguiente código:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Indicamos que el LED integrado en la placa funcione como salida
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // Enciende el LED
  delay(1000);                       // Espera 1 segundo
  digitalWrite(LED_BUILTIN, LOW);   // Apaga el LED
  delay(1000);                       // Espera 1 segundo
}

Ahora compila y envía a la microcontroladora. En cuanto el código esté en ella debería empezar a parpadear el led integrado en la placa

Activar un GPIO en concreto

Para determinados proyectos puede ser que nos interese encender y apagar un GPIO concreto. En el siguiente ejemplo vamos a encender y apagar cada 3 segundos el GPIO 0 (cero). Para ello copia y pega el siguiente código:

void setup() {
  pinMode(0, OUTPUT);      // Configura GPIO0 como salida
}

void loop() {
  digitalWrite(0, HIGH);   // Enciende GPIO0 (pone tensión en él)
  delay(3000);
  digitalWrite(0, LOW);
  delay(3000);
}

En el GPIO 0 alternarás cada 3 segundos 3,3V con 0 V de tensión. La corriente por defecto será de 4mA. En caso de querer variar la corriente debrás usar la función gpio_set_drive_strength tras haber importado la bibilioteca correspondiente:

#include "hardware/gpio.h"

void setup() {
  pinMode(0, OUTPUT);
  
  // Opciones: GPIO_DRIVE_STRENGTH_2MA, _4MA, _8MA, _12MA
  gpio_set_drive_strength(0, GPIO_DRIVE_STRENGTH_12MA);
  
  digitalWrite(0, HIGH);
}

void loop() {
  // tu código
}

Leer entrada digital GPIO

Puedes hacer uso de cualquier GPIO. El código es el siguiente:

void setup() {
  Serial.begin(115200);
  pinMode(1, INPUT);          // GPIO1 como entrada
  // Si no tienes resistencia externa, usa la pull-up interna:
  // pinMode(1, INPUT_PULLUP);
  // o pull-down:
  // pinMode(1, INPUT_PULLDOWN);
}

void loop() {
  int valor = digitalRead(1);  // Lee GPIO1: devuelve HIGH (1) o LOW (0)
  Serial.println(valor);
  delay(100);
}

Para ver la salida de Serial.println dirígete a arduinoIDE > tools > Serial Monitor

Leer entrada analógica GPIO

GPIO26, 27 y 28 son los únicos que funcionan de modo analógico. El código es el siguiente:

void setup() {
  Serial.begin(115200);
  // No hace falta pinMode para analogRead
}

void loop() {
  int valor = analogRead(26);        // 0–4095 (12 bits)
  float tension = valor * 3.3 / 4095.0;
  Serial.print("Tensión: ");
  Serial.println(tension);
  delay(100);
}

Pulsación de botón

void setup() {
  Serial.begin(115200);
  pinMode(1, INPUT_PULLUP);  // Botón entre GPIO1 y GND
}

void loop() {
  if (digitalRead(1) == LOW) {  // LOW = pulsado (con pull-up)
    Serial.println("Botón pulsado");
  }
  delay(50);
}

Sensor de movimiento

void setup() {
  pinMode(1, INPUT);   // Señal del PIR
  pinMode(0, OUTPUT);  // LED
}

void loop() {
  if (digitalRead(1) == HIGH) {  // PIR activa HIGH al detectar
    digitalWrite(0, HIGH);       // Enciende LED
  } else {
    digitalWrite(0, LOW);
  }
  delay(100);
}

Detección de agua

void setup() {
  Serial.begin(115200);
  pinMode(1, INPUT_PULLDOWN);  // Sensor de nivel
}

void loop() {
  if (digitalRead(1) == HIGH) {
    Serial.println("Nivel de agua alto");
  }
  delay(500);
}

Temperatura con termistor

Analógico. Has de usar los pines indicados anteriormente. En el ejemplo se usa GPIO26.

void loop() {
  int raw = analogRead(26);
  float tension = raw * 3.3 / 4095.0;
  // Con divisor de tensión 10kΩ + NTC 10kΩ:
  float resistencia = 10000.0 * tension / (3.3 - tension);
  // Fórmula Steinhart-Hart simplificada:
  float tempK = 1.0 / (log(resistencia / 10000.0) / 3950.0 + 1.0 / 298.15);
  float tempC = tempK - 273.15;
  Serial.print("Temperatura: ");
  Serial.print(tempC);
  Serial.println(" °C");
  delay(1000);
}

Otros

Y tu, ¿qué montajes has realizado?


AI HAT+ y AI Camera

Este proyecto nace de la intención de montar en mi centro una herramienta de IA de uso local que no dependa (y no envíe) datos a internet. Spoiler: No sale bien.

IA HAT+

Qué es

placa.png

Es una "placa" o tarjeta de expansión que se encaja encima de una Raspberry Pi (HAT significa Hardware Attached on Top). Añade potencia extra para procesar Inteligencia Artificial localmente (sin depender de internet). Permite que la computadora reconozca objetos, caras o voces de forma mucho más rápida y eficiente de lo que podría hacerlo sola. Es, básicamente, darle un "cerebro especializado" a una computadora pequeña para que pueda realizar tareas de IA sin trabarse.

Enlaces de interés

Características principales

  1. Potencia de cálculo (NPU)
    Su corazón es un acelerador Hailo-8L. Dependiendo del modelo, ofrece un rendimiento de 13 o 26 TOPS (Tera Operaciones por Segundo). Esto permite procesar redes neuronales complejas (como detección de objetos en tiempo real o segmentación de imágenes) de forma fluida.
  2. Conexión de alta velocidad
    Se conecta directamente al puerto PCIe 2.0 de la Raspberry Pi 5. Esto es clave porque permite que los datos viajen mucho más rápido entre el procesador principal y el chip de IA, evitando los "cuellos de botella" que tenían los modelos anteriores por USB.
  3. Integración total (Plug & Play)
    Al ser un accesorio oficial, el sistema operativo Raspberry Pi OS la reconoce automáticamente. No necesitas instalar controladores complicados; las librerías de cámara estándar (como rpicam-apps) ya vienen preparadas para usar este hardware.
  4. Eficiencia energética y térmica
    Está diseñada para consumir poca energía mientras trabaja a máxima potencia. Además, su formato permite que el ventilador oficial de la Raspberry Pi 5 siga funcionando debajo de ella, manteniendo todo el sistema fresco.
  5. Formato HAT+
    Sigue el nuevo estándar HAT+, lo que significa que es más delgada, permite el apilamiento de otras placas y tiene una gestión de energía más inteligente que los HAT antiguos.

Versiones

En este momento, según la documentación de la web de la Raspberry nos encontramos con las siguientes versiones hardware:

Versión Chip Rendimiento RAM
AI HAT+ 13 TOPS Hailo-8L 13 TOPS Comparte la de la Raspberry Pi.
AI HAT+ 26 TOPS Hailo-8L 26 TOPS Comparte la de la Raspberry Pi.
AI HAT+2 Hailo-10 40 TOPS Tiene 8 GB dedicados en la propia placa

AI Camera

En la documentación de este producto hacen especial hincapié en no manejarlo si tenemos riesgo de pasarle electricidad estática pues el producto es tremendamente sensible a este tipo de corrientes.

Qué es

producto.png

Es un módulo de cámara oficial que combina un sensor de imagen de alta calidad (Sony IMX500) con un procesador de IA (NPU) integrado en el mismo hardware. Sirve para dotar de visión artificial a cualquier modelo de Raspberry Pi (desde la Zero hasta la 5) sin sobrecargar el procesador principal. Como la cámara hace el trabajo sucio de la IA, el procesador de tu Raspberry Pi queda libre para otras tareas. Puede ejecutar modelos de detección de objetos a una velocidad de fotogramas muy alta y con muy baja latencia

Enlaces de interés

Características principales

  1.  Sensor de imagen inteligente (Sony IMX500): Es el primer sensor de visión con procesamiento de IA integrado. Combina un sensor de 12.3 megapíxeles con un acelerador lógico (NPU) en el mismo chip. Esto permite capturar la imagen y analizarla en microsegundos.
  2.  Procesamiento "On-board" (NPU integrada)
  3. Potencia: Ofrece un rendimiento de 2.3 TOPS (Tera Operaciones por Segundo): La Raspberry Pi no tiene que "pensar" para reconocer objetos; la cámara le envía directamente los metadatos (por ejemplo: "Hay una persona en estas coordenadas con un 95% de certeza").
  4.  Compatibilidad universal
    A diferencia de los AI HAT+ (que solo funcionan con la Raspberry Pi 5), la AI Camera se conecta mediante el puerto CSI (cámara) estándar. Esto la hace compatible con:
    Raspberry Pi 4 y 5.
    Raspberry Pi Zero / Zero 2 W.
    Modelos antiguos (3B+, etc.).
  5. Resolución: 4056 x 3040 píxeles.
  6. Posee enfoque manual ajustable, lo que permite nitidez tanto en objetos cercanos como lejanos.
  7. Campo de visión (FoV): 76 grados, ideal para vigilancia y robótica estándar.
  8. Baja latencia: Al procesar la IA en el sensor, no hay retrasos por el envío de datos pesados a través de cables.
  9. Ahorro de energía: Consume mucho menos que un HAT de IA externo, lo que la hace perfecta para proyectos que funcionan con baterías.
  10. Software "Plug & Play": Está totalmente integrada en el ecosistema oficial. Utiliza las librerías rpicam-apps, por lo que puedes ejecutar modelos de detección de objetos o segmentación con comandos muy sencillos, sin necesidad de instalar complejos entornos de programación.

diseno.png

Versiones

En este momento no existen versiones de este hardware. Hay que tener en cuenta que si existen otras cámaras compatibles con la raspberry pi pero estas no incorporan chips de IA y, por tanto, el trabajo deberá hacerlo la raspberry pi o una placa de expansión específica con lo que perderemos la ventaja de este chip.

Montaje

El montaje de la cámara en la Raspberry Pi 5 ha resultado muy sencillo. Se ha utilizado una pulsera anti estática para evitar los riesgos indicados por el fabricante. En la Raspberry Pi se dispone de 2 bahías dónde conectarla (la 0 y la 1). En mi caso la he conectado a la ranura 0. En la caja venían 2 cables para conectar la cámara. Uno mas ancho que otro. He tenido que utilizar el estrecho. En el proyecto indico como verificar que está correctamente instalada.

Proyectos

Los proyectos que a continuación se indican se han realizado con el siguiente hardware:

No nos ha sido posible encontrar en el mercado la versión AI HAT+2 (40 TOPs y memoria dedicada). Probablemente llevándose el desarrollo de la práctica principal a ese hardware  se hubiera cumplido el objetivo inicial.

Todo ensablado queda como se ve en la siguiente imagen:

(TO DO)

Creación de un LLM de uso local sin dependencia de internet

Como ya se adelantó anteriormente, la idea era montar una IA generativa en local que nos asegurase el no envío de nuestros datos de trabajo al exterior. A continuación enumero los diferentes pasos realizados. Comenzamos:

  1. Con Raspberry Pi imager cargo en la SD la imagen del sistema operativo para la raspberry pi 5
  2. Actualizamos sistema y borramos paquetes innecesarios
    1. Ejecutamos en terminal sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y && sudo apt clean
  3. Instalamos Ollama
    1. Nos va a permitir gestionar modelos de lenguaje
    2. Web de Ollama con información https://ollama.com/ 
    3. Ejecutamos en terminal curl -fsSL https://ollama.com/install.sh | sh
    4. Tras instalarlo merece la pena fijarse en 3 líneas que arroja el instalador:
      1. The Ollama API is now available at 127.0.0.1:11434 Nos indica dónde ha montado por defecto un servidor al cual lanzarle peticiones
      2. Install complete. Run "ollama" from the command line. Nos indica cual es el comando que deberamos usar para trabajar con Ollama
      3. WARNING: No NVIDIA/AMD GPU detected. Ollama will run in CPU-only mode. Aquí ya nos advierte de que el funcionamiento de Ollama no va a ser óptimo
  4. Descargamos un modelo para trabajar con él
    1. Enumero los que en este momento (abril de 2026) corren en el hw con el que contamos:
      1. llama3.2:3b (rápido y ligero)
      2. mistral:7b (más capaz, mas lento)
      3. phi3:mini (muy eficiente para su tamaño)
      4. gemma2:2b (excelente relación calidad/velocidad)
    2. Instalamos 1 de ellos. Los demás se haría de modo análogo
      1. Ejecutamos en el terminal ollama pull phi3:mini
  5. Lo probamos a través de una llamada al API REST (documentación del endpoint que vamos a usar https://docs.ollama.com/api/generate )
    1. Escribimos en el terminal:
    2. curl http://127.0.0.1:11434/api/generate -d '{ "model": "phi3:mini", "prompt": "Explica qué es una raspberry pi", "stream": false }'
    3. Y esperamos por aproximadamete 4 minutos para ver el resultado. Luego con este modelo, no es funcional
  6. Vamos a descargar otro modelo mas ligero y repetir la consulta para ese modelo:
    1. ollama pull llama3.2:3b
    2. curl http://127.0.0.1:11434/api/generate -d '{ "model": "llama3.2:3b", "prompt": "Explica qué es una raspberry pi", "stream": false }' en esta ocasión la respuesta se ha demorado 2 minutos lo cual sigue haciendo, bajo mi punto de vista, al modelo poco eficiente como sustituto de las IAs comerciales.
  7. Vamos a preparar una interfaz web para quienes no quieran usar el terminal.
    1. Uaremos docker, si no lo tienes instalado, tines que instalarlo:
      1. Consulta la documentación en web oficial para hacerlo. Yo te dejo a continuación lo que en la fecha actual he hecho yo para instalarlo
      2. sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-doc podman-docker containerd runc | cut -f1)
      3.  

        # Add Docker's official GPG key:
        sudo apt update
        sudo apt install ca-certificates curl
        sudo install -m 0755 -d /etc/apt/keyrings
        sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
        sudo chmod a+r /etc/apt/keyrings/docker.asc
        
        # Add the repository to Apt sources:
        sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
        Types: deb
        URIs: https://download.docker.com/linux/debian
        Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
        Components: stable
        Architectures: $(dpkg --print-architecture)
        Signed-By: /etc/apt/keyrings/docker.asc
        EOF
        
        sudo apt update
      4. sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
      5. sudo systemctl status docker
      6. sudo groupadd docker quizás te diga que ya existe
      7. sudo usermod -aG docker $USER
      8. sudo groupadd docker
      9. sudo systemctl enable containerd.service
      10. Reiniciamos
    2. Ahora ejecutaremos en el terminal docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -e OLLAMA_BASE_URL=http://host.docker.internal:11434 ghcr.io/open-webui/open-webui:main 
    3. Si ahora accedemos en el navegador a http://localhost:3000 tendremos acceso a una interface web para interactuar con la IA que hemos preparado y/o con openIA

En las llamadas a curl hemos utilizado 3 parámetros:

Puede resultar interesante conocer estos otros:

Aquí un ejemplo completo:

{
  "model": "llama3.2:3b",
  "prompt": "Explica qué es una Raspberry Pi",
  "stream": false,

  "system": "Eres un asistente experto en electrónica",

  "options": {
    "temperature": 0.7,
    "top_p": 0.9,
    "top_k": 40,
    "num_predict": 512,
    "num_ctx": 2048,
    "repeat_penalty": 1.1,
    "seed": 42
  },

  "format": "json",
  "keep_alive": "5m"
}

La documentación completa de la API la tenemos disponible en https://docs.ollama.com/api/introduction Además de /api/generate puede resultarte interesante probar /api/chat

Tratando de optimizar el funcionamiento

Tras buscar información en internet he encontrado que al hacer uso de ollama para correr un LLM no estamos realmente haciendo uso del HAT y que el HAT en si (esta versión del HAT) no está pensada para correr LLMs sino para ejecutar modelos relacionados con reconocimiento de imagen y audio así que descarto esa función y vamos a focalizarnos en los 2 siguientes

AI HAT+ sin cámara: procesamiento de vídeo

Vamos a tratar de detectar elementos de un vídeo que descarguemos de internet

Para resumir lo hecho en 8 pasos he realizado multitud de pruebas e interacciones con la IA para conseguir resultados

  1. Actualizamos el sistema sudo apt update && sudo apt upgrade -y
  2. Instalamos las bibliotecas del HAT sudo apt install hailo-all -y
  3. Reiniciamos sudo reboot
  4. Verificamos instalación python3 -c "from hailo_platform import VDevice; print('HailoRT OK')"
  5. Instalamos dependencias: pip3 install opencv-python numpy --break-system-packages
  6. Creamos el script nano ~/detector_trafico.py
    1. import cv2
      import numpy as np
      from hailo_platform import VDevice, HEF, HailoStreamInterface, InferVStreams, ConfigureParams, InputVStreamParams, OutputVStreamParams, FormatType
      import time
      
      HEF_PATH = "/usr/share/hailo-models/yolov8s_h8.hef"
      VIDEO_PATH = "/home/pi/trafico2.mp4"
      OUTPUT_PATH = "/home/pi/trafico2_out.mp4"
      
      COCO_LABELS = [
          "person","bicycle","car","motorcycle","airplane","bus","train","truck",
          "boat","traffic light","fire hydrant","stop sign","parking meter","bench",
          "bird","cat","dog","horse","sheep","cow","elephant","bear","zebra","giraffe",
          "backpack","umbrella","handbag","tie","suitcase","frisbee","skis","snowboard",
          "sports ball","kite","baseball bat","baseball glove","skateboard","surfboard",
          "tennis racket","bottle","wine glass","cup","fork","knife","spoon","bowl",
          "banana","apple","sandwich","orange","broccoli","carrot","hot dog","pizza",
          "donut","cake","chair","couch","potted plant","bed","dining table","toilet",
          "tv","laptop","mouse","remote","keyboard","cell phone","microwave","oven",
          "toaster","sink","refrigerator","book","clock","vase","scissors","teddy bear",
          "hair drier","toothbrush"
      ]
      
      COLORS = [(0,255,0),(0,0,255),(255,0,0),(0,255,255),(255,0,255),(255,255,0)]
      
      def letterbox(img, new_shape=(640, 640)):
          h, w = img.shape[:2]
          scale = min(new_shape[0]/h, new_shape[1]/w)
          new_w, new_h = int(w * scale), int(h * scale)
          resized = cv2.resize(img, (new_w, new_h))
          top = (new_shape[0] - new_h) // 2
          bottom = new_shape[0] - new_h - top
          left = (new_shape[1] - new_w) // 2
          right = new_shape[1] - new_w - left
          padded = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(114,114,114))
          return padded, scale, left, top
      
      def run_detection():
          cap = cv2.VideoCapture(VIDEO_PATH)
          if not cap.isOpened():
              print(f"Error: No se pudo abrir {VIDEO_PATH}")
              return
      
          fps = cap.get(cv2.CAP_PROP_FPS) or 30
          w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
          h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
          out = cv2.VideoWriter(OUTPUT_PATH, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
          print(f"Procesando vídeo: {w}x{h} @ {fps} FPS")
      
          with VDevice() as target:
              hef = HEF(HEF_PATH)
              configure_params = ConfigureParams.create_from_hef(hef, interface=HailoStreamInterface.PCIe)
              network_groups = target.configure(hef, configure_params)
              network_group = network_groups[0]
              network_group_params = network_group.create_params()
      
              input_info = hef.get_input_vstream_infos()[0]
              input_h, input_w = input_info.shape[0], input_info.shape[1]
      
              input_vstreams_params = InputVStreamParams.make(network_group, format_type=FormatType.UINT8)
              output_vstreams_params = OutputVStreamParams.make(network_group, format_type=FormatType.FLOAT32)
      
              frame_count = 0
              t_start = time.time()
      
              with InferVStreams(network_group, input_vstreams_params, output_vstreams_params) as infer_pipeline:
                  with network_group.activate(network_group_params):
                      while cap.isOpened():
                          ret, frame = cap.read()
                          if not ret:
                              break
      
                          lb, scale, pad_left, pad_top = letterbox(frame, (input_h, input_w))
                          rgb = cv2.cvtColor(lb, cv2.COLOR_BGR2RGB)
                          input_data = {input_info.name: np.expand_dims(rgb.astype(np.uint8), axis=0)}
      
                          raw_detections = infer_pipeline.infer(input_data)
      
                          for output_name, val in raw_detections.items():
                              batch0 = val[0]
                              for cls_id, class_dets in enumerate(batch0):
                                  dets = np.array(class_dets)
                                  if dets.ndim == 2 and len(dets) > 0:
                                      for d in dets:
                                          conf = float(d[4])
                                          if conf > 0.4:
                                              # Formato: [y1, x1, y2, x2] normalizado
                                              x1 = int((d[1] * input_w - pad_left) / scale)
                                              y1 = int((d[0] * input_h - pad_top) / scale)
                                              x2 = int((d[3] * input_w - pad_left) / scale)
                                              y2 = int((d[2] * input_h - pad_top) / scale)
                                              # Clamp para evitar coordenadas fuera de imagen
                                              x1, x2 = max(0, x1), min(w, x2)
                                              y1, y2 = max(0, y1), min(h, y2)
                                              label = COCO_LABELS[cls_id] if cls_id < len(COCO_LABELS) else f"ID:{cls_id}"
                                              color = COLORS[cls_id % len(COLORS)]
                                              cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
                                              cv2.putText(frame, f"{label} {conf:.2f}", (x1, y1 - 5),
                                                          cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
      
                          out.write(frame)
                          frame_count += 1
                          if frame_count % 30 == 0:
                              elapsed = time.time() - t_start
                              print(f"Frame {frame_count} | FPS: {frame_count/elapsed:.1f}")
      
          cap.release()
          out.release()
          elapsed = time.time() - t_start
          print(f"\n✅ COMPLETADO")
          print(f"Frames: {frame_count} | Tiempo: {elapsed:.1f}s | FPS: {frame_count/elapsed:.1f}")
          print(f"📹 Guardado en: {OUTPUT_PATH}")
      
      if __name__ == "__main__":
          run_detection()
  7. Ejecutamos python3 ~/detector_trafico.py
    1. Necesitarás tener un vídeo llamado trafico.mp4 en /home/pi o cambiar la ruta
    2. El resultado lo verás en trafico_out.mp4

Abro simultáneamente el vídeo original y el generado con la detección de objetos y este es el resultado:

vs.png

En la imagen se puede ver que detecta coches y la probabilidad con la que "cree" que son coches. En el vídeo también aparecen personas, motocicletas, camiones,... y todas ellas las va detectando mientras varía el porcentaje de seguridad (1: implica seguridad plena y 0: nada seguridad)

El proceso de poner este proyecto en marcha me ha llevado aproximadamente 5h y ha sido poco intuitivo y por momentos parecía orientado al fracaso.

En estas 5h en que la raspberry pi ha estado trabajando junto con el hat ninguna de las placas se ha sobrecalentado mas allá de lo razonable y la sensación de fluided del dispositivo ha sido total.

AI HAT+ y  AI cámara

Lo primero ha sido verificar que la cámara estaba correctamente instalada, para ello:

sudo apt update
sudo apt install libcamera-apps
rpicam-hello --list-cameras

Lo que en mi caso ha devuelto:

Available cameras
-----------------
0 : imx500 [4056x3040 10-bit RGGB] (/base/axi/pcie@1000120000/rp1/i2c@88000/imx500@1a)
    Modes: 'SRGGB10_CSI2P' : 2028x1520 [30.02 fps - (0, 0)/4056x3040 crop]
                             4056x3040 [10.00 fps - (0, 0)/4056x3040 crop]

Lo que significa que ha encontrado la cámara conectada, su tipo y sus características.

Si quieres ver qué se está viendo por la cámara dispones del comando rpicam-hello -t 0 mientras que si quieres hacer una foto puedes usar rpicam-still -o foto.jpg

Ahora comenzaremos con la parte de IA de la cámara:

sudo apt update
sudo apt install imx500-all

En /usr/share/rpi-camera-assets/ se habrán guardado los ficheros .json de demostración que incorpora el paquete.

Podemos probar diferentes modos de funcionamiento con rpicam-hello -t 0 --post-process-file /usr/share/rpi-camera-assets/imx500_mobilenet_ssd.json y con rpicam-hello -t 0 --post-process-file /usr/share/rpi-camera-assets/imx500_posenet.json Los comandos anteriores funcionarán respectivamente para la detección de objetos y la detección de esqueleto (brazos, piernas y tronco)