OpenMV Pure Thermal

L’OpenMV Pure Thermal est une carte d’imagerie thermique complète bâtie autour du STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) avec 64 Mo de SDRAM externe, 32 Mo de mémoire flash QSPI, un codec JPEG matériel, un écran tactile capacitif IPS de 4,3 » 800×480, une sortie HDMI, un connecteur thermique FLIR® Lepton® et une caméra à lumière visible OV5640 de 5 MP. Elle embarque également le Wi‑Fi, un emplacement microSD, un télémètre laser, un avertisseur sonore et un illuminateur blanc haute puissance.

OpenMV Pure Thermal

Pour la fiche technique complète, les photos et les dimensions, consultez la page produit OpenMV Pure Thermal.

Points forts

  • STMicroelectronics STM32H743XI Cortex‑M7 à 480 MHz.

  • Encodeur/décodeur JPEG matériel.

  • 64 Mo de SDRAM externe (~400 Mo/s) plus 1 Mo de SRAM interne.

  • 2 Mo de mémoire flash interne + 32 Mo de mémoire flash QSPI externe (~50 Mo/s en lecture).

  • Capteur à lumière visible OV5640 5 MP à obturateur déroulant (rolling‑shutter).

  • Connecteur FLIR® Lepton® — accepte tout module Lepton 1/2/2.5/3/3.5, radiométrique ou non, avec température par pixel en degrés Celsius.

  • Écran tactile capacitif IPS de 4,3 » 800×480 (couleur 24 bits @ 60 Hz) avec prise en charge des gestes jusqu’à 5 points.

  • Sortie HDMI via le sérialiseur DVI TFP410 — jusqu’à 1280×720 @ 60 Hz.

  • Wi‑Fi via WINC1500 ; MJPEG over RTSP pris en charge nativement.

  • USB‑C full‑speed (12 Mb/s, courant limité à 900 mA) — apparaît comme VCP + stockage de masse USB pour l’hôte, et gère également la charge.

  • Emplacement microSD — SD jusqu’à 2 Go, SDHC jusqu’à 32 Go, SDXC jusqu’à 2 To.

  • Télémètre laser VL53L1CX (jusqu’à ~4 m).

  • Avertisseur sonore (buzzer) avec volume / fréquence contrôlés par logiciel.

  • Illuminateur à LED blanche haute puissance en plus de la LED RGB d’état utilisateur.

  • Connecteur de batterie LiPo avec charge USB à 500 mA.

  • 10 broches d’E/S, tolérantes 5 V avec sortie 3,3 V, 25 mA par broche (120 mA au total), capables de gérer les interruptions. P6 n’est pas tolérante 5 V lorsqu’elle est utilisée en mode ADC ou DAC.

  • Connecteur SWD ARM 10 broches pour le débogage ST‑LINK / J‑Link.

  • Connecteur Qwiic pour les périphériques I²C.

Note

La carte dispose d’un emplacement sur son bord inférieur gauche pour un écrou de trépied ¼ »–20 optionnel. Il n’est pas monté en usine — soudez‑en un dans l’emplacement si vous souhaitez fixer la carte sur un trépied de caméra standard.

Brochage

Brochage de l'OpenMV Pure Thermal

Référence des broches

Nom de broche

Fonction

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 numérique

RESET

tirer vers GND pour réinitialiser la carte

SYN

pad de synchronisation de trame (frame‑sync) — non connecté

VIN

pad VIN du shield — non connecté

BOOT0

tirer vers 3,3 V à la mise sous tension pour le DFU / programme d’amorçage ROM

BUZZER

avertisseur sonore piézo embarqué (piloté par TIM2/PWM)

LED_RED

canal rouge de la LED RGB d’état (actif à l’état bas)

LED_GREEN

canal vert de la LED RGB d’état (actif à l’état bas)

LED_BLUE

canal bleu de la LED RGB d’état (actif à l’état bas)

LED_WHITE

LED de l’illuminateur blanc haute puissance

Note

Les pads SYN et VIN du shield/header n’ont aucune connexion électrique sur la Pure Thermal — ils ne sont présents que pour la compatibilité du header. Alimentez plutôt la carte via l’USB‑C ou le connecteur de batterie LiPo embarqué (voir Broches d’alimentation ci‑dessous). Notez également que le pad VIN porte la sérigraphie VBAT sur la carte (une erreur d’étiquetage) — la position correspond à la broche VIN standard du header OpenMV et n’est de toute façon pas connectée.

Broches d’alimentation

  • 3.3V — rail 3,3 V régulé. Jusqu’à 250 mA disponibles pour les shields.

  • GND — masse commune.

La Pure Thermal est alimentée via l”USB‑C ou le connecteur de batterie LiPo embarqué. Le port USB‑C est limité à 900 mA au total et gère également la charge de la LiPo à 500 mA, de sorte que brancher une batterie en parallèle de l’USB est pris en charge.

Le bouton d’alimentation embarqué active et désactive les rails du système et fonctionne que la carte soit alimentée par USB ou par la LiPo. Maintenez le bouton enfoncé pendant quelques secondes pour changer d’état — une simple pression rapide est ignorée afin d’éviter un arrêt accidentel.

La sélection de la source suit deux règles simples :

  • La batterie n’alimente la carte que lorsque sa tension est supérieure à 3 V. En dessous de ce seuil, le PMIC embarqué déconnecte la batterie pour la protéger d’une décharge excessive.

  • Lorsque l’USB est présent, l’USB alimente la carte et toute LiPo connectée se charge en arrière‑plan.

Le connecteur LiPo dispose également d’une protection contre l’inversion de tension, de sorte que brancher la batterie à l’envers n’endommagera pas la carte.

Note

La carte achemine également la tension de la batterie et un signal de mesure du courant de la batterie vers des canaux ADC du MCU, mais la prise en charge logicielle de l’un ou l’autre n’a pas encore été ajoutée.

Broches de récupération et de débogage

  • RESET — tirer vers GND pour réinitialiser la carte. La Pure Thermal dispose également d’un bouton RESET dédié sur la carte qui fait la même chose.

  • BOOT0 — tirer vers 3,3 V pendant l’alimentation de la carte pour entrer dans le programme d’amorçage ROM du STM32 (mode DFU). OpenMV IDE utilise ce mode pour reflasher le programme d’amorçage embarqué. Un bouton BOOT0 dédié sur la carte fait la même chose — maintenez‑le enfoncé pendant la mise sous tension.

La carte expose un header de débogage SWD (RST / SWCLK / SWDIO / SWO) à côté du header GPIO, compatible avec les adaptateurs ST‑LINK et SEGGER J‑Link. Un connecteur SWD ARM 10 broches distinct est également monté — il achemine les mêmes signaux SWD (pas de JTAG complet) mais au format standard 10 broches au pas de 0,05 ».

Note

La broche de trace SWO est partagée avec l’horloge SPI du FLIR® Lepton® embarqué. SWO ne peut pas être utilisé en même temps que le Lepton — choisissez l’un ou l’autre.

Un troisième connecteur PURE Modules Debug est monté sur la carte. Il dérive une poignée de signaux orientés débogage (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3,3 V, GND et deux broches GPIO) pour connecter des modules compagnons. Les deux broches GPIO de ce connecteur sont pilotées par un bus I²C bit‑banged interne plutôt que par un périphérique matériel.

Les trois connecteurs de débogage (le header SWD en ligne, le connecteur SWD ARM 10 broches et le connecteur PURE Modules Debug) sont référencés à 3,3 V — assurez‑vous que votre adaptateur de débogage est configuré pour une logique 3,3 V avant de le connecter.

Périphériques embarqués

LED

La Pure Thermal possède trois LED sur la carte :

  • LED RGB utilisateur — contrôlable par logiciel, exposée sous LED_RED, LED_GREEN et LED_BLUE:

    from machine import LED
    
    LED("LED_RED").on()
    LED("LED_GREEN").on()
    LED("LED_BLUE").on()
    
  • Illuminateur blanc — piloté via LED_WHITE. LED_WHITE est câblée en actif à l’état haut au niveau matériel alors que le micrologiciel traite toutes les autres LED embarquées comme actives à l’état bas ; utilisez donc low() / high() plutôt que on() / off() (qui inverseraient le sens):

    from machine import LED
    
    light = LED("LED_WHITE")
    light.low()    # turn the white LED ON
    light.high()   # turn the white LED OFF
    
  • LED de charge — pilotée directement par le matériel de gestion de l’alimentation embarqué, sans contrôle logiciel. Elle fonctionne que les rails du système soient activés ou non (c’est‑à‑dire avec le bouton d’alimentation dans l’une ou l’autre position).

    Couleur

    Signification

    Bleu

    en charge — voir errata : peut ne pas s’éteindre une fois la charge terminée

    Vert

    charge terminée — voir errata : peut ne pas se déclencher de façon fiable

    Rouge

    batterie faible (≤ 3,2 V, uniquement lorsqu’elle n’est pas en charge active)

Avertisseur sonore

L’avertisseur sonore piézo embarqué est câblé à un canal de minuteur — pilotez‑le avec machine.PWM pour des tonalités avec fréquence (hauteur) et rapport cyclique (volume) contrôlés par logiciel:

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()

Capteur de caméra

L’OV5640 est le CSI principal de la Pure Thermal — passez cid=csi.OV5640 pour l’adresser explicitement:

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()

L’OV5640 dispose d’un compresseur JPEG embarqué. Réglez csi.CSI.pixformat sur csi.JPEG et le capteur délivre des trames compressées directement à la caméra via le bus de la caméra, ce qui rend les captures haute résolution pratiques : csi.HD (1280×720), csi.FHD (1920×1080) et le 5 MP complet csi.WQXGA2 (2592×1944) sont tous diffusés en JPEG. Ajustez la compression avec csi.CSI.quality (0‑100, plus élevé = trames plus volumineuses, plus de détails):

cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)

L’OV5640 dispose d’un objectif à autofocus actionné par moteur à bobine acoustique (voice‑coil). Déclenchez une seule passe d’autofocus via csi.CSI.ioctl avec csi.IOCTL_TRIGGER_AUTO_FOCUS — le capteur balaie le moteur de mise au point une fois et verrouille sur ce qui se trouve devant lui:

cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)

Réémettez l’ioctl chaque fois que la scène change — l’autofocus est à coup unique (one‑shot), pas continu.

Note

La sortie STROBE de l’OV5640 (utilisée pour le flash / l’illumination IR synchronisés) est câblée au MCU sur la Pure Thermal, mais la prise en charge logicielle de celle‑ci n’a pas encore été ajoutée.

Capteur de caméra thermique

Le connecteur FLIR® Lepton® apparaît comme un second CSI sur la même API csi — capteurs de caméra. Passez cid=csi.LEPTON pour l’adresser, et ignorez la réinitialisation matérielle:

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()

Note

La sortie VSYNC du Lepton (une impulsion par trame thermique) est câblée au MCU sur la Pure Thermal, mais la prise en charge logicielle de celle‑ci n’a pas encore été ajoutée.

Les deux CSI peuvent fonctionner côte à côte. L’exemple ci‑dessous récupère une trame en couleur de l’OV5640 et une trame thermique du Lepton, puis superpose le Lepton sur la trame couleur à l’aide d’une palette Ironbow et d’un masque alpha qui se fond vers la transparence à faible intensité:

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,
    )

Apprentissage automatique

ml — Apprentissage automatique exécute des modèles TFLite quantifiés sur le Cortex‑M7 avec les noyaux CMSIS‑NN — assez rapides pour des détecteurs compacts à quelques trames par seconde. Les modèles présents sur le système de fichiers en lecture seule /rom se chargent directement depuis la mémoire flash sans copie en RAM. Voici un détecteur BlazeFace 128×128 qui superpose le visage détecté et ses six points de repère sur chaque trame issue de la caméra à lumière 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")

Télémètre laser

Le télémètre à temps de vol ST VL53L1CX embarqué est câblé sur le bus I²C 2. Utilisez le pilote figé vl53l1x — Pilote du capteur de distance ToF VL53L1X pour obtenir des mesures de distance jusqu’à ~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)

Sortie LCD

Le LCD embarqué de 4,3 » est en 800 × 480 (WVGA) et est piloté via l’interface d’affichage RGB du module display — pilote d’affichage — passez framesize=display.FWVGA pour correspondre à sa résolution native:

import display

lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True)           # turn the LCD backlight on
lcd.write(img)

Le rétroéclairage est câblé à un GPIO, donc backlight() accepte True / False (ou toute valeur de 0 à 100, où 0 signifie éteint et toute valeur non nulle allumé):

lcd.backlight(False)           # turn the backlight off
lcd.backlight(True)            # back on

Écran tactile

Le contrôleur tactile capacitif est le FT5X06 ; les positions multi‑touch et les événements de geste sont exposés via ft5x06 — Pilote d’écran tactile. Enregistrez une fonction de rappel pour réagir aux contacts et lire les points actifs en son sein:

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)

Sortie HDMI

Le micrologiciel diffuse également le tampon d’image du LCD vers le sérialiseur HDMI tfp410 — Contrôleur DVI/HDMI embarqué, de sorte qu’un moniteur externe reflète ce qui est affiché sur le LCD. Instanciez tfp410.TFP410 pour activer la sortie HDMI:

import tfp410

hdmi = tfp410.TFP410()

Si vous ne voulez que la sortie HDMI et que le LCD embarqué vous importe peu, éteignez le rétroéclairage et augmentez la résolution du tampon d’image au‑dessus de WVGA. Le TFP410 prend en charge jusqu’à 1280×720 @ 60 Hz, donc par exemple:

lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False)         # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()

Le panneau embarqué est figé à 800×480, donc tout ce qui dépasse WVGA n’a de sens que sur le moniteur HDMI externe.

Pour savoir quand un moniteur HDMI a été branché ou débranché, enregistrez une fonction de rappel de branchement à chaud (hot‑plug) sur le TFP410. La fonction de rappel se déclenche avec True lors du branchement et False lors du débranchement:

def on_hotplug(connected):
    print("HDMI", "connected" if connected else "disconnected")

hdmi.hotplug_callback(on_hotplug)

Vous pouvez également interroger l’état de la connexion à tout moment avec isconnected() (uniquement lorsqu’aucune fonction de rappel n’est enregistrée).

Le port HDMI achemine également les canaux DDC (données d’affichage) et CEC (contrôle de l’électronique grand public), exposés via la classe classe DisplayData – Données d’affichage. Utilisez‑la pour lire le bloc EDID du moniteur connecté (afin de vous adapter à sa résolution / fréquence de rafraîchissement natives) ou pour envoyer/recevoir des trames CEC afin de contrôler d’autres appareils HDMI sur le même câble:

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

Le Wi‑Fi fonctionne via un module Microchip WINC1500, exposé via l’interface class WINC – pilote du shield 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])

Note

En raison de pénuries de composants, certaines unités Pure Thermal ont été livrées sans le module WINC1500 monté. Si network.WINC lève une erreur ou ne se connecte jamais, vérifiez si la carte est dépourvue d’un module Wi‑Fi — le reste de la caméra fonctionne exactement de la même manière sans lui.

Carte microSD

Lorsqu’une carte est insérée, elle est montée automatiquement sous /sdcard et est utilisable via le système de fichiers habituel:

import os

for entry in os.listdir("/sdcard"):
    print(entry)

Référence des bus

GPIO

Utilisez machine.Pin pour lire ou piloter n’importe laquelle des broches sérigraphiées. Les sorties sont en CMOS 3,3 V, tolérantes 5 V côté entrée, et peuvent absorber/débiter jusqu’à 25 mA par broche (120 mA au total sur l’ensemble du header).

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())

Toute broche d’entrée peut également déclencher une interruption sur les transitions de front:

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")

Le même matériel peut également être utilisé en mode cible (esclave) via machine.I2CTarget pour exposer une région de mémoire à un autre contrôleur I²C:

from machine import I2CTarget

buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)

Le connecteur Qwiic embarqué dérive l’un de ces bus I²C pour les modules plug‑and‑play. La ligne Qwiic est décalée en niveau à 5 V via des transistors à drain ouvert, de sorte que le bus est limité au mode standard (100 kHz) et au mode rapide (400 kHz) uniquement — n’essayez pas de faire fonctionner le mode fast‑mode‑plus ou des débits plus élevés via le header Qwiic.

Le connecteur Qwiic fournit en sortie 5 V pour alimenter les modules connectés ; il ne peut pas être utilisé pour alimenter la Pure Thermal elle‑même — alimentez plutôt la carte via l’USB‑C ou le connecteur de batterie LiPo.

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 et DAC

P6 est la seule broche analogique utilisateur. Elle peut être utilisée soit comme entrée ADC 12 bits, soit comme sortie DAC.

  • ADC — pleine échelle à 3,3 V sur la broche:

    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 — via pyb.DAC. La valeur 8 bits couvre 0 à 3,3 V:

    from pyb import DAC
    
    dac = DAC("P6")
    voltage = 1.65
    dac.write(int(voltage / 3.3 * 255))
    

En mode ADC ou DAC, P6 est tolérante 3,3 V uniquement — ne lui appliquez pas 5 V.

PWM

Broche

Minuteur / canal

P4

TIM2 CH3

P5

TIM2 CH4

P6

TIM2 CH1

P7

TIM4 CH1

P8

TIM4 CH2

Note

TIM1 est réservé par le micrologiciel pour générer l’horloge pixel du capteur de la caméra, de sorte que les canaux TIM1 physiquement présents sur P0/P1/P2 ne peuvent pas être utilisés pour du PWM utilisateur sans casser la caméra.

TIM4 est partagé avec pyb.Servo — l’instanciation d’un servo reconfigure l’ensemble du minuteur pour un fonctionnement à 50 Hz, donc ne mélangez pas machine.PWM sur P7/P8 avec pyb.Servo dans le même script.

Pilotez‑en n’importe lequel via machine.PWM:

from machine import Pin, PWM

pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)

Bus logiciels bit‑banged

machine.SoftI2C et machine.SoftSPI fonctionnent sur n’importe quel GPIO si vous avez besoin d’un bus supplémentaire.

Capteur thermique (externe)

En plus du FLIR Lepton embarqué, le micrologiciel inclut également le pilote fir — pilote de capteur thermique (fir == infrarouge lointain) pour les imageurs thermiques I²C câblés en externe :

  • MLX90621 — matrice IR 16 × 4

  • MLX90640 — matrice IR 32 × 24

  • MLX90641 — matrice IR 16 × 12

  • AMG8833 — matrice IR 8 × 8

Câblez le module sur le bus I²C de la carte et lisez les trames avec 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())

Le pilote fir ne communique avec le capteur que via I²C 2 — câblez le module sur P4 (SCL) et P5 (SDA).

Synchronisation

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)

Minuteurs virtuels

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"))

Les valeurs de période sont en millisecondes. Appelez deinit() pour arrêter et libérer l’emplacement.

Horloge temps réel

from machine import RTC

rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())

Si une batterie LiPo est connectée, le RTC conserve l’heure même lorsque les rails du système sont éteints (mis hors tension via le bouton d’alimentation embarqué). Avec uniquement l’USB branché, appuyer sur le bouton d’alimentation coupe également l’alimentation du RTC — l’heure murale ne survivra donc pas à un cycle d’alimentation sans batterie connectée.

Chien de garde (watchdog)

from machine import WDT

wdt = WDT(timeout=5_000)
while True:
    # ...do work...
    wdt.feed()

Informations de démarrage et d’exécution

Fenêtre du programme d’amorçage USB

À chaque mise sous tension, la caméra exécute un court programme d’amorçage (quelques secondes) qui permet à OpenMV IDE de mettre à jour le micrologiciel sans que l’utilisateur ait à entrer en mode DFU. Une fois la fenêtre expirée, le programme d’amorçage passe la main à boot.py puis à main.py.

Un script en cours d’exécution peut réentrer dans le programme d’amorçage à la demande en appelant machine.bootloader().

Système de fichiers et ordre de démarrage

Le micrologiciel de la Pure Thermal monte jusqu’à trois systèmes de fichiers au démarrage :

  • Mémoire flash interne — toujours montée sous /flash. Contient main.py et README.txt par défaut ; créée au tout premier démarrage.

  • Carte microSD — si une carte est insérée, elle est montée sous /sdcard.

  • ROMFS — système de fichiers en lecture seule, mappé en mémoire, sous /rom, utilisé pour livrer de gros actifs de données (par ex. des modèles d’IA) qui bénéficient d’un accès sans copie (zero‑copy). Monté automatiquement par MicroPython au démarrage, avant l’exécution de tout code Python utilisateur.

Après le montage, le répertoire de travail est défini sur /sdcard lorsque la carte est présente, sinon /flash. L’interpréteur exécute ensuite les scripts depuis ce répertoire :

  • boot.py est exécuté à chaque réinitialisation logicielle.

  • main.py est exécuté uniquement au démarrage à froid, immédiatement après boot.py.

Déposer un boot.py ou un main.py sur la carte SD remplace la copie présente en mémoire flash sans y toucher.

Lorsqu’elle est connectée en USB, le système de fichiers de démarrage (/sdcard si une carte est présente, sinon /flash) s’énumère également comme un lecteur de stockage de masse USB sur l’hôte. Éjectez le lecteur avant de réinitialiser la caméra afin que l’hôte vide ses écritures mises en cache.

Note

Les fichiers créés ou modifiés par le code s’exécutant sur l’OpenMV Cam n’apparaîtront pas sur l’hôte tant que le lecteur n’aura pas été remonté. Utilisez la carte SD pour toutes les données que le script réécrit, et remontez avant de lire ces fichiers depuis l’hôte.

Tailles de stockage

La Pure Thermal est livrée avec :

  • /flash — système de fichiers FAT de 24 Mo, lecture/écriture.

  • /rom — ROMFS de 8 Mo en lecture seule mappé en mémoire, utilisé pour livrer des scripts et des modèles ML qui bénéficient d’un accès mmap sans copie (zero‑copy).

  • /sdcard — taille complète de la carte microSD insérée (lorsqu’elle est présente), lecture/écriture.

Indicateur de défaillance matérielle (hard‑fault)

Si la LED RGB utilisateur parcourt rapidement toutes les couleurs — assez vite pour ressembler à une LED blanche scintillante plutôt qu’à des teintes distinctes — le micrologiciel a rencontré une défaillance matérielle irrécupérable (hard fault). Reflashez le micrologiciel pour récupérer.

Errata matériel

Une poignée de particularités au niveau de la carte sont documentées dans l”errata matériel de la Pure Thermal. Points clés à connaître :

  • Interférence du connecteur de batterie — des composants sur le PCB se trouvent directement sous le connecteur de batterie LiPo, et l’ergot saillant sur la prise du câble de batterie peut s’accrocher dessus lors du retrait du câble, arrachant parfois des pièces de la carte. Coupez l’ergot de la prise du câble avec une pince coupante à ras avant la première utilisation.

  • Le RTC s’arrête lorsque la carte est hors tension — la capacité de charge du quartz 32 kHz (Y2) est trop élevée. Retirer C96 et C97 (la paire flanquant le quartz à côté du STM32) permet au RTC de continuer à fonctionner sur l’alimentation de secours. La plupart des cartes sont livrées avec ces condensateurs déjà retirés ; si votre RTC perd l’heure une fois débranché, vérifiez ces positions. Consultez les tickets GitHub #1536 et #1600 pour le fil de discussion complet.

  • La LED indicatrice de charge reste bleue — le chargeur peut terminer son cycle de charge n’importe où entre 4,15 V et 4,19 V sans faire passer l’indicateur du bleu (en charge) au vert (chargé). La batterie est néanmoins entièrement chargée dans ce cas ; fiez‑vous à une mesure de tension, pas à la LED.

  • La sérigraphie étiquette par erreur VIN comme VBAT — le pad situé à la position VIN standard du header OpenMV porte la sérigraphie VBAT sur la Pure Thermal. L’étiquette est erronée, mais cela n’a pas d’importance en pratique car le pad n’a aucune connexion électrique de toute façon.

Bibliothèques logicielles

Consultez l”index des bibliothèques pour la liste complète des modules — y compris ceux qui sont propres à la build de la Pure Thermal.