OpenMV Pure Thermal¶
La OpenMV Pure Thermal es una placa de imagen térmica de sistema completo construida en torno al STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) con 64 MB de SDRAM externa, 32 MB de memoria flash QSPI, un códec JPEG por hardware, una pantalla táctil capacitiva IPS de 4,3» y 800×480, una salida HDMI, un zócalo térmico FLIR® Lepton® y una cámara de luz visible OV5640 de 5MP. También incorpora Wi‑Fi, un zócalo microSD, un telémetro láser, un zumbador y un iluminador blanco de alta potencia.
Para consultar la hoja de datos completa, fotos y dimensiones, consulta la página del producto OpenMV Pure Thermal.
Aspectos destacados¶
STMicroelectronics STM32H743XI Cortex‑M7 a 480 MHz.
Codificador/decodificador JPEG por hardware.
64 MB de SDRAM externa (~400 MB/s) más 1 MB de SRAM interna.
2 MB de memoria flash interna + 32 MB de memoria flash QSPI externa (~50 MB/s de lectura).
Sensor de luz visible OV5640 de 5MP con obturador rodante.
Zócalo FLIR® Lepton® — acepta cualquier módulo Lepton 1/2/2.5/3/3.5, radiométrico o no radiométrico, con temperatura por píxel en grados Celsius.
Pantalla táctil capacitiva IPS de 4,3» y 800×480 (color de 24 bits @ 60 Hz) con soporte de gestos de hasta 5 puntos.
Salida HDMI a través del serializador DVI TFP410 — hasta 1280×720 @ 60 Hz.
Wi‑Fi a través del WINC1500; MJPEG sobre RTSP soportado de fábrica.
USB‑C de velocidad completa (12 Mb/s, limitado a 900 mA de corriente) — aparece como VCP + almacenamiento masivo USB ante el host, y también gestiona la carga.
Zócalo microSD — SD de hasta 2 GB, SDHC de hasta 32 GB, SDXC de hasta 2 TB.
Telémetro láser VL53L1CX (hasta ~4 m).
Zumbador con volumen / frecuencia controlados por software.
LED iluminador blanco de alta potencia además del LED de estado RGB de usuario.
Conector de batería LiPo con carga por USB a 500 mA.
10 pines de E/S, tolerantes a 5 V con salida de 3,3 V, 25 mA por pin (120 mA en total), con capacidad de interrupción. P6 no es tolerante a 5 V cuando se usa en modo ADC o DAC.
Conector SWD ARM de 10 pines para depuración con ST‑LINK / J‑Link.
Conector Qwiic para periféricos I²C.
Nota
La placa tiene una ranura en su borde inferior izquierdo para una tuerca de trípode opcional de ¼»–20. No viene instalada de fábrica — suelda una en la ranura si quieres montar la placa en un trípode de cámara estándar.
Distribución de pines¶
Referencia de pines¶
Nombre del pin |
Función |
|---|---|
P0 |
UART1 RX / SPI2 MOSI |
P1 |
UART1 TX / SPI2 MISO |
P2 |
SPI2 SCK / FDCAN2 TX |
P3 |
SPI2 NSS (CS) / FDCAN2 RX |
P4 |
I2C2 SCL / UART3 TX / TIM2 CH3 |
P5 |
I2C2 SDA / UART3 RX / TIM2 CH4 |
P6 |
ADC / DAC / TIM2 CH1 |
P7 |
I2C4 SCL / TIM4 CH1 |
P8 |
I2C4 SDA / TIM4 CH2 |
P9 |
E/S digital |
RESET |
lleva a GND para reiniciar la placa |
SYN |
pad de sincronización de fotograma — no conectado |
VIN |
pad VIN del shield — no conectado |
BOOT0 |
lleva a 3,3 V al encender para DFU / gestor de arranque (bootloader) ROM |
BUZZER |
zumbador piezoeléctrico de a bordo (controlado por TIM2/PWM) |
LED_RED |
canal rojo del LED de estado RGB (activo en bajo) |
LED_GREEN |
canal verde del LED de estado RGB (activo en bajo) |
LED_BLUE |
canal azul del LED de estado RGB (activo en bajo) |
LED_WHITE |
LED iluminador blanco de alta potencia |
Nota
Los pads SYN y VIN del shield/cabezal no tienen conexión eléctrica en la Pure Thermal — están ahí solo por compatibilidad con el cabezal. Alimenta la placa a través de USB‑C o del conector de batería LiPo de a bordo en su lugar (consulta Pines de alimentación más abajo). Ten en cuenta también que el pad VIN está serigrafiado como VBAT en la placa (un error de etiquetado) — la posición es la del pin VIN estándar del cabezal OpenMV y no está conectado de ninguna manera.
Pines de alimentación¶
3.3V — riel regulado de 3,3 V. Hasta 250 mA disponibles para shields.
GND — tierra común.
La Pure Thermal se alimenta a través de USB‑C o del conector de batería LiPo de a bordo. El puerto USB‑C está limitado a 900 mA de corriente total y también gestiona la carga del LiPo a 500 mA, por lo que se admite conectar una batería junto con el USB.
El botón de encendido de a bordo activa y desactiva los rieles del sistema y funciona tanto si la placa se alimenta por USB como por el LiPo. Mantén pulsado el botón durante un par de segundos para cambiar de estado — una pulsación rápida se ignora para evitar un apagado accidental.
La selección de fuente sigue dos reglas sencillas:
La batería solo alimenta la placa cuando su voltaje está por encima de 3 V. Por debajo de ese umbral, el PMIC de a bordo desconecta la batería para protegerla de una sobredescarga.
Cuando hay USB presente, el USB alimenta la placa y cualquier LiPo conectado se carga en segundo plano.
El conector LiPo también cuenta con protección contra polaridad inversa, por lo que conectar la batería al revés no dañará la placa.
Nota
La placa también enruta el voltaje de la batería y una señal de detección de corriente de la batería de vuelta a los canales ADC del MCU, pero todavía no se ha añadido soporte de firmware para ninguna de las dos.
Pines de recuperación y depuración¶
RESET — lleva a GND para reiniciar la placa. La Pure Thermal también tiene un botón RESET dedicado en la placa que hace lo mismo.
BOOT0 — lleva a 3,3 V mientras alimentas la placa para entrar en el gestor de arranque (bootloader) ROM del STM32 (modo DFU). OpenMV IDE usa este modo para reflashear el bootloader de a bordo. Un botón BOOT0 dedicado en la placa hace lo mismo — mantenlo pulsado mientras aplicas la alimentación.
La placa expone un cabezal de depuración SWD (RST / SWCLK / SWDIO / SWO) junto al cabezal GPIO, compatible con adaptadores ST‑LINK y SEGGER J‑Link. También se incluye un conector SWD ARM de 10 pines independiente — lleva las mismas señales SWD (sin JTAG completo) pero en el formato estándar de 10 pines a 0,05».
Nota
El pin de traza SWO se comparte con el reloj SPI del FLIR® Lepton® de a bordo. SWO no se puede usar al mismo tiempo que el Lepton — elige uno u otro.
Un tercer conector PURE Modules Debug está montado en la placa. Saca un puñado de señales orientadas a la depuración (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3,3 V, GND y dos pines GPIO) para conectar módulos complementarios. Los dos pines GPIO de este conector son controlados por un bus I²C emulado por software (bit‑banged) interno en lugar de un periférico de hardware.
Los tres conectores de depuración (el cabezal SWD en línea, el conector SWD ARM de 10 pines y el conector PURE Modules Debug) están referenciados a 3,3 V — asegúrate de que tu adaptador de depuración esté configurado para lógica de 3,3 V antes de conectar.
Periféricos de a bordo¶
LEDs¶
La Pure Thermal tiene tres LEDs en la placa:
LED RGB de usuario — controlable por software, expuesto como
LED_RED,LED_GREENyLED_BLUE:from machine import LED LED("LED_RED").on() LED("LED_GREEN").on() LED("LED_BLUE").on()
Iluminador blanco — controlado a través de
LED_WHITE.LED_WHITEestá cableado activo en alto en hardware, mientras que el firmware trata cualquier otro LED de a bordo como activo en bajo, así que usalow()/high()en lugar deon()/off()(que invertirían el sentido):from machine import LED light = LED("LED_WHITE") light.low() # turn the white LED ON light.high() # turn the white LED OFF
LED de carga — controlado directamente por el hardware de gestión de energía de a bordo, sin control por software. Funciona tanto si los rieles del sistema están encendidos como apagados (es decir, con el botón de encendido en cualquier posición).
Color
Significado
Azul
cargando — consulta la fe de erratas: puede que no se apague cuando la carga se complete
Verde
carga completa — consulta la fe de erratas: puede que no se active de forma fiable
Rojo
batería baja (≤ 3,2 V, solo cuando no se está cargando activamente)
Zumbador¶
El zumbador piezoeléctrico de a bordo está cableado a un canal de temporizador — contrólalo con machine.PWM para tonos con frecuencia (tono) y ciclo de trabajo (volumen) controlados por software:
import time
from machine import Pin, PWM
beep = PWM(Pin("BUZZER"), freq=2_000, duty_u16=32768) # ~50% duty
time.sleep_ms(500) # sound for 0.5 s
beep.deinit()
Sensor de cámara¶
El OV5640 es la CSI principal de la Pure Thermal — pasa cid=csi.OV5640 para direccionarlo explícitamente:
import csi
cam = csi.CSI(cid=csi.OV5640)
cam.reset(hard=True)
cam.pixformat(csi.RGB565)
cam.framesize(csi.WVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
El OV5640 tiene un compresor JPEG de a bordo. Configura csi.CSI.pixformat a csi.JPEG y el sensor entrega fotogramas comprimidos directamente a la cámara a través del bus de cámara, lo que hace prácticas las capturas de alta resolución: csi.HD (1280×720), csi.FHD (1920×1080) y los 5MP completos csi.WQXGA2 (2592×1944) se transmiten como JPEG. Ajusta la compresión con csi.CSI.quality (0‑100, mayor = fotogramas más grandes, más detalle):
cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)
El OV5640 tiene una lente de enfoque automático con actuador de bobina móvil. Activa una única pasada de enfoque automático mediante csi.CSI.ioctl con csi.IOCTL_TRIGGER_AUTO_FOCUS — el sensor barre el motor de enfoque una vez y se fija en lo que tenga delante:
cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)
Vuelve a emitir el ioctl cada vez que la escena cambie — el enfoque automático es de una sola toma, no continuo.
Nota
La salida STROBE del OV5640 (usada para flash sincronizado / iluminación IR) está cableada al MCU en la Pure Thermal, pero todavía no se ha añadido soporte de firmware para ella.
Sensor de cámara térmica¶
El zócalo FLIR® Lepton® aparece como una segunda CSI en la misma API csi — sensores de cámara. Pasa cid=csi.LEPTON para direccionarlo, y omite el reinicio por hardware:
import csi
lepton = csi.CSI(cid=csi.LEPTON)
lepton.reset(hard=False)
lepton.pixformat(csi.GRAYSCALE)
lepton.framesize(csi.QVGA)
while True:
img = lepton.snapshot()
Nota
La salida VSYNC del Lepton (un pulso por fotograma térmico) está cableada al MCU en la Pure Thermal, pero todavía no se ha añadido soporte de firmware para ella.
Ambas CSIs pueden funcionar en paralelo. El ejemplo siguiente extrae un fotograma de color del OV5640 y un fotograma térmico del Lepton, y luego superpone el Lepton sobre el fotograma de color usando una paleta Ironbow y una máscara alfa que se desvanece a transparente con baja intensidad:
import csi
import image
import math
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
csi0 = csi.CSI()
csi0.reset(hard=True)
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.WVGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False)
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(
img1, 0, 0,
color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR,
)
Aprendizaje automático¶
ml — Aprendizaje automático ejecuta modelos TFLite cuantizados en el Cortex‑M7 con núcleos CMSIS‑NN — lo bastante rápido para detectores compactos a unos pocos fotogramas por segundo. Los modelos en el sistema de archivos de solo lectura /rom se cargan directamente desde la memoria flash sin copiar a la RAM. Aquí tienes un detector BlazeFace de 128×128 que superpone la cara detectada y sus seis puntos de referencia en cada fotograma de la cámara de luz visible:
import csi
import time
import ml
from ml.postprocessing.mediapipe import BlazeFace
# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))
# Load built-in face detection model
model = ml.Model("/rom/blazeface_front_128.tflite", postprocess=BlazeFace(threshold=0.4))
print(model)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# faces is a list of ((x, y, w, h), score, keypoints) tuples
for r, score, keypoints in model.predict([img]):
ml.utils.draw_predictions(img, [r], ("face",), ((0, 0, 255),), format=None)
# keypoints is a ndarray of shape (6, 2)
# 0 - right eye (x, y)
# 1 - left eye (x, y)
# 2 - nose (x, y)
# 3 - mouth (x, y)
# 4 - right ear (x, y)
# 5 - left ear (x, y)
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
print(clock.fps(), "fps")
Telémetro láser¶
El telémetro de tiempo de vuelo ST VL53L1CX de a bordo está cableado al bus I²C 2. Usa el controlador congelado vl53l1x — Controlador del sensor de distancia ToF VL53L1X para obtener lecturas de distancia de hasta ~4 m:
import time
from machine import I2C
import vl53l1x
bus = I2C(2)
tof = vl53l1x.VL53L1X(bus)
while True:
print("Distance:", tof.read(), "mm")
time.sleep_ms(100)
Salida LCD¶
La LCD de a bordo de 4,3» es de 800 × 480 (WVGA) y se controla a través de la interfaz de pantalla RGB del módulo display — controlador de pantalla — pasa framesize=display.FWVGA para coincidir con su resolución nativa:
import display
lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True) # turn the LCD backlight on
lcd.write(img)
La retroiluminación está cableada a un GPIO, así que backlight() acepta True / False (o cualquier valor de 0–100, donde 0 es apagado y cualquier valor distinto de cero es encendido):
lcd.backlight(False) # turn the backlight off
lcd.backlight(True) # back on
Pantalla táctil¶
El controlador táctil capacitivo es el FT5X06; las posiciones multitáctiles y los eventos de gestos se exponen a través de ft5x06 — Controlador de pantalla táctil. Registra una función de retorno (callback) para reaccionar a los toques y leer los puntos activos dentro de ella:
import ft5x06
touch = ft5x06.FT5X06()
def on_touch(n):
for i in range(n):
x = touch.get_point_x(i)
y = touch.get_point_y(i)
print("touch", i, "at", x, y)
gesture = touch.get_gesture()
if gesture != ft5x06.GESTURE_NONE:
print("gesture:", gesture)
touch.touch_callback(on_touch)
Salida HDMI¶
El firmware también reparte el framebuffer de la LCD hacia el serializador HDMI tfp410 — Controlador DVI/HDMI de a bordo, de modo que un monitor externo refleja lo que hay en la LCD. Instancia tfp410.TFP410 para habilitar la salida HDMI:
import tfp410
hdmi = tfp410.TFP410()
Si solo quieres salida HDMI y no te importa la LCD de a bordo, apaga la retroiluminación y aumenta la resolución del framebuffer por encima de WVGA. El TFP410 admite hasta 1280×720 @ 60 Hz, así que por ejemplo:
lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False) # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()
El panel de a bordo está fijado en 800×480, por lo que cualquier valor por encima de WVGA solo tiene sentido en el monitor HDMI externo.
Para saber cuándo se ha conectado o desconectado un monitor HDMI, registra una función de retorno (callback) de conexión en caliente en el TFP410. La función de retorno se dispara con True al conectar y False al desconectar:
def on_hotplug(connected):
print("HDMI", "connected" if connected else "disconnected")
hdmi.hotplug_callback(on_hotplug)
También puedes consultar el estado de la conexión en cualquier momento con isconnected() (solo cuando no hay ninguna función de retorno (callback) registrada).
El puerto HDMI también lleva los canales DDC (datos de pantalla) y CEC (control de electrónica de consumo), expuestos a través de la clase clase DisplayData – Datos de pantalla. Úsala para leer el bloque EDID del monitor conectado (de modo que puedas adaptarte a su resolución / frecuencia de actualización nativa) o para enviar/recibir tramas CEC para controlar otros dispositivos HDMI en el mismo cable:
from display import DisplayData
dd = DisplayData(cec=True, ddc=True)
edid = dd.display_id() # EDID bytes from the monitor
print(len(edid), "byte EDID")
# Send a CEC "image view on" command (opcode 0x04) from address 1 to address 0
dd.send_frame(0, 1, b"\x04")
# ...or wait for an incoming CEC frame addressed to us (logical address 1)
src, data = dd.receive_frame(1, timeout=5_000)
print("CEC from", src, ":", data)
Wi‑Fi¶
El Wi‑Fi funciona sobre un módulo Microchip WINC1500, expuesto a través de la interfaz class WINC – controlador del escudo WiFi:
import network, time
wlan = network.WINC()
wlan.connect("ssid", "password")
while not wlan.isconnected():
time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])
Nota
Debido a la escasez de componentes, algunas unidades Pure Thermal se enviaron sin el módulo WINC1500 montado. Si network.WINC lanza un error o nunca se conecta, comprueba si a la placa le falta el módulo Wi‑Fi — el resto de la cámara funciona exactamente igual sin él.
tarjeta microSD¶
Cuando se inserta una tarjeta, se monta automáticamente en /sdcard y se puede usar a través del sistema de archivos habitual:
import os
for entry in os.listdir("/sdcard"):
print(entry)
Referencia de buses¶
GPIO¶
Usa machine.Pin para leer o controlar cualquiera de los pines serigrafiados. Las salidas son CMOS de 3,3 V, tolerantes a 5 V en el lado de entrada, y pueden absorber/suministrar hasta 25 mA por pin (120 mA en total en todo el cabezal).
from machine import Pin
out = Pin("P0", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("P1", Pin.IN, Pin.PULL_UP)
print(inp.value())
Cualquier pin de entrada también puede disparar una interrupción en las transiciones de flanco:
def handler(pin):
print("triggered:", pin)
Pin("P1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Bus |
TX |
RX |
|---|---|---|
UART1 |
P1 |
P0 |
UART3 |
P4 |
P5 |
from machine import UART
uart = UART(3, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
Bus |
SCL |
SDA |
|---|---|---|
I2C2 |
P4 |
P5 |
I2C4 |
P7 |
P8 |
from machine import I2C
i2c = I2C(2, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
El mismo hardware también se puede usar en modo objetivo (esclavo) a través de machine.I2CTarget para exponer una región de memoria a otro controlador I²C:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)
El conector Qwiic de a bordo saca uno de estos buses I²C para módulos plug‑and‑play. La línea Qwiic se eleva de nivel a 5 V mediante transistores de drenaje abierto, por lo que el bus está limitado únicamente a modo estándar (100 kHz) y modo rápido (400 kHz) — no intentes ejecutar fast‑mode‑plus o velocidades superiores a través del cabezal Qwiic.
El conector Qwiic emite 5 V para alimentar los módulos conectados; no se puede usar para alimentar la propia Pure Thermal — alimenta la placa a través de USB‑C o del conector de batería LiPo en su lugar.
SPI¶
Bus |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI2 |
P0 |
P1 |
P2 |
P3 |
from machine import SPI
from machine import Pin
spi = SPI(2, baudrate=10_000_000)
cs = Pin("P3", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
CAN (FDCAN)¶
Bus |
TX |
RX |
|---|---|---|
FDCAN2 |
P2 |
P3 |
from machine import CAN
can = CAN(2, 500_000)
can.set_filters(None)
can.send(0x123, b"\xDE\xAD\xBE\xEF")
print(can.recv())
ADC y DAC¶
P6 es el único pin analógico de usuario. Se puede usar como entrada ADC de 12 bits o como salida DAC.
ADC — escala completa a 3,3 V en el pin:
from machine import ADC import time adc = ADC("P6") while True: voltage = adc.read_u16() * 3.3 / 65535 print(voltage) time.sleep_ms(100)
DAC — a través de
pyb.DAC. El valor de 8 bits cubre 0–3,3 V:from pyb import DAC dac = DAC("P6") voltage = 1.65 dac.write(int(voltage / 3.3 * 255))
En modo ADC o DAC, P6 es tolerante solo a 3,3 V — no le apliques 5 V.
PWM¶
Pin |
Temporizador / canal |
|---|---|
P4 |
TIM2 CH3 |
P5 |
TIM2 CH4 |
P6 |
TIM2 CH1 |
P7 |
TIM4 CH1 |
P8 |
TIM4 CH2 |
Nota
TIM1 está reservado por el firmware para generar el reloj de píxel del sensor de cámara, por lo que los canales de TIM1 que están físicamente en P0/P1/P2 no se pueden usar para PWM de usuario sin romper la cámara.
TIM4 se comparte con pyb.Servo — instanciar un servo reconfigura todo el temporizador para operar a 50 Hz, así que no mezcles machine.PWM en P7/P8 con pyb.Servo en el mismo script.
Controla cualquiera de ellos a través de machine.PWM:
from machine import Pin, PWM
pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)
Buses emulados por software (bit‑banged)¶
machine.SoftI2C y machine.SoftSPI funcionan en cualquier GPIO si necesitas un bus adicional.
Sensor térmico (externo)¶
Además del FLIR Lepton de a bordo, el firmware también incluye el controlador fir — controlador de sensor térmico (fir == infrarrojo lejano) para imágenes térmicas I²C cableadas externamente:
MLX90621 — matriz IR de 16 × 4
MLX90640 — matriz IR de 32 × 24
MLX90641 — matriz IR de 16 × 12
AMG8833 — matriz IR de 8 × 8
Cablea el módulo al bus I²C de la placa y lee fotogramas con fir.init() + fir.snapshot():
import time
import image
import fir
fir.init() # auto‑detects the sensor
clock = time.clock()
while True:
clock.tick()
try:
img = fir.snapshot(x_scale=5, y_scale=5,
color_palette=image.PALETTE_IRONBOW,
hint=image.BICUBIC,
copy_to_fb=True)
except OSError:
continue
print(clock.fps())
El controlador fir solo se comunica con el sensor a través de I²C 2 — cablea el módulo a P4 (SCL) y P5 (SDA).
Temporización¶
time¶
import time
time.sleep(1)
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
elapsed = time.ticks_diff(time.ticks_ms(), start)
Temporizadores virtuales¶
from machine import Timer
one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
callback=lambda t: print("once"))
periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
callback=lambda t: print("tick"))
Los valores de período están en milisegundos. Llama a deinit() para detener y liberar la ranura.
Reloj de tiempo real¶
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())
Si hay una batería LiPo conectada, el RTC mantiene la hora incluso mientras los rieles del sistema están apagados (apagados mediante el botón de encendido de a bordo). Con solo el USB conectado, pulsar el botón de encendido también corta la alimentación al RTC — por lo que la hora del reloj no sobrevivirá a un ciclo de apagado sin una batería conectada.
Watchdog¶
from machine import WDT
wdt = WDT(timeout=5_000)
while True:
# ...do work...
wdt.feed()
Información de arranque y de ejecución¶
Ventana del gestor de arranque (bootloader) USB¶
En cada encendido, la cámara ejecuta un breve gestor de arranque (bootloader) (unos pocos segundos) que permite a OpenMV IDE actualizar el firmware sin que el usuario tenga que entrar en modo DFU. Una vez que expira la ventana, el bootloader cede el control a boot.py y luego a main.py.
Un script en ejecución puede volver a entrar en el gestor de arranque (bootloader) a demanda llamando a machine.bootloader().
Sistema de archivos y orden de arranque¶
El firmware de la Pure Thermal monta hasta tres sistemas de archivos en el arranque:
Memoria flash interna — siempre montada en
/flash. Contienemain.pyyREADME.txtpor defecto; se crea en el primer arranque.tarjeta microSD — si se inserta una tarjeta, se monta en
/sdcard.ROMFS — sistema de archivos de solo lectura mapeado en memoria en
/rom, usado para distribuir grandes recursos de datos (p. ej. modelos de IA) que se benefician del acceso sin copia. Montado automáticamente por MicroPython al inicio, antes de que se ejecute cualquier código Python de usuario.
Tras el montaje, el directorio de trabajo se establece en /sdcard cuando la tarjeta está presente, de lo contrario en /flash. El intérprete ejecuta entonces los scripts desde ese directorio:
boot.pyse ejecuta en cada reinicio suave.main.pyse ejecuta solo en el arranque en frío, inmediatamente después deboot.py.
Colocar un boot.py o main.py en la tarjeta SD anula la copia en la memoria flash sin tocarla.
Cuando está conectada por USB, el sistema de archivos de arranque (/sdcard si hay una tarjeta presente, de lo contrario /flash) también se enumera como una unidad de almacenamiento masivo USB en el host. Expulsa la unidad antes de reiniciar la cámara para que el host vacíe sus escrituras en caché.
Nota
Los archivos creados o modificados por el código que se ejecuta en la OpenMV Cam no aparecerán en el host hasta que la unidad se vuelva a montar. Usa la tarjeta SD para cualquier dato que el script escriba de vuelta, y vuelve a montar antes de leer esos archivos desde el host.
Tamaños de almacenamiento¶
La Pure Thermal viene con:
/flash— sistema de archivos FAT de 24 MB, lectura/escritura./rom— ROMFS de solo lectura mapeado en memoria de 8 MB, usado para distribuir scripts y modelos de ML que se benefician del acceso por mmap sin copia./sdcard— el tamaño completo de cualquier tarjeta microSD que se inserte (cuando está presente), lectura/escritura.
Indicador de fallo grave (hard fault)¶
Si el LED RGB de usuario está recorriendo rápidamente todos los colores — lo bastante rápido como para que tienda a parecer un LED blanco parpadeante en lugar de tonos distintos — el firmware ha sufrido un fallo grave irrecuperable. Reflashea el firmware para recuperarlo.
Fe de erratas del hardware¶
Un puñado de peculiaridades a nivel de placa están documentadas en la fe de erratas del hardware de la Pure Thermal. Aspectos clave a tener en cuenta:
Interferencia del conector de batería — hay componentes en la PCB situados justo debajo del conector de batería LiPo, y la cuña sobresaliente del enchufe del cable de la batería puede engancharse en ellos al retirar el cable, arrancando a veces piezas de la placa. Recorta la cuña del enchufe del cable con alicates de corte enrasado antes del primer uso.
El RTC se detiene mientras la placa está apagada — la capacitancia de carga del cristal de 32 kHz (Y2) es demasiado alta. Quitar C96 y C97 (el par que flanquea el cristal junto al STM32) permite que el RTC siga funcionando con la alimentación de respaldo. La mayoría de las placas se envían con estos condensadores ya retirados; si tu RTC pierde la hora al desconectarlo, comprueba esas posiciones. Consulta los issues de GitHub #1536 y #1600 para ver el hilo completo.
El LED indicador de carga se queda azul — el cargador puede terminar su ciclo de carga en cualquier punto entre 4,15 V y 4,19 V sin cambiar el indicador de azul (cargando) a verde (cargado). La batería sigue completamente cargada en este caso; confía en una medición de voltaje, no en el LED.
La serigrafía etiqueta erróneamente VIN como VBAT — el pad en la posición VIN estándar del cabezal OpenMV está serigrafiado como
VBATen la Pure Thermal. La etiqueta es incorrecta, pero no importa en la práctica porque el pad no tiene conexión eléctrica de ninguna manera.
Bibliotecas de software¶
Consulta el índice de la biblioteca para ver la lista completa de módulos — incluidos los que son exclusivos de la build de la Pure Thermal.