v5.0.1#

v5.0.1 ist ein Wartungs-Release auf Basis von v5.0.0 — das veraltete sensor-Modul wird zu einer Python-Kompatibilitätsschicht über csi, in den Framebuffer geladene Bilder erscheinen nun wie Kamerabilder in der Vorschau, die JPEG-Encoder verlieren ihr 1-MB-Ausgabelimit und behandeln Überläufe korrekt, und es gibt eine Reihe von Korrekturen für Kamera, Protokoll, Netzwerk und ML-Bibliothek. Es bringt keine API-Brüche für Skripte mit sich, die gegen csi geschrieben wurden; die wenigen Verhaltensänderungen sind unter API-Brüche aufgeführt.

Highlights#

  • Das Modul sensor ist jetzt ein eingefrorenes Python-Modul, das auf csi aufbaut. Beim Import gibt es eine Veraltet-Warnung aus; einige Funktionen, die das csi-Modul nicht unterstützen kann, lösen nun OSError aus. Siehe die Änderungen am sensor-Modul.

  • Geladene Bilder erscheinen in der Vorschau wie Kamerabilder. Ein mit copy_to_fb=True in den Framebuffer gelegtes Bild (image.Image, image.ImageIO.read(), fir.snapshot(), tof.snapshot()) wird — mit allem, was darauf gezeichnet wurde — an die IDE ausgegeben, wenn das nächste Bild den Framebuffer überschreibt, statt sofort. Siehe die Änderungen an der Vorschau.

  • Überarbeitung der JPEG-Encoder. Die 1-MB-Obergrenze für den Ausgabepuffer ist weg (der Puffer wird anhand des freien Speichers dimensioniert), Überläufe werden sowohl auf dem Software- als auch auf dem Hardware-Pfad behandelt, statt abgeschnittene Dateien zu schreiben, und das Speichern eines komprimierten Bildes unter der jeweils anderen komprimierten Dateiendung löst eine Ausnahme aus, statt Datenmüll zu schreiben.

  • Neu: protocol.poll() sowie sechs neue CBOR-Widgets (text, lineedit, pushbutton, spinbox, radio, waveform) für protocol.CBORChannel.

  • YOLO Pro-Postprozessor, Unterstützung für FLIR Lepton 3.1R / UW, IMU-Burst-Lesevorgänge, CAN auf dem OpenMV N6 und ein netzwerkfähiges Simulator-Target.

Neue Funktionen#

  • YoloPro — ein neuer Postprozessor für Edge Impulse YOLO Pro-Objekterkennungsmodelle, plus ein yolo_pro_detector.py-Beispiel. (f3f150ebd, ea7bbb398)

  • protocol.poll() — führt bei Bedarf eine Iteration der Protokoll-Task aus, für benutzerdefinierte Transporte, die weder vom USB-Interrupt noch vom poll_ms-Timer angetrieben werden. protocol.init() kann außerdem erneut aufgerufen werden, um den Stack neu zu initialisieren. (c00c215f9, f849ffb1b)

  • Weitere CBOR-Kanal-Widgets — protocol.CBORChannel.add() erhält text (statischer String), lineedit (beschreibbarer String), pushbutton (momentane Aktion), spinbox (schrittweise Zahleneingabe), radio (Optionsgruppe) und waveform (1D-Zeitreihe mit den Argumenten sample_rate, series und typecode; weisen Sie verschachtelte Abtastwert-Bytes zu, um sie zu streamen). (8016d29ba)

  • csi.CUSTOM — csi.CSI.framesize() gibt nun nach dem Setzen einer benutzerdefinierten (w, h)-Auflösung eine verwendbare Konstante zurück statt einer anonymen Ganzzahl. (af8841654)

  • IMU-Burst-Lesevorgang — imu.__read_reg() akzeptiert einen optionalen beschreibbaren Puffer und füllt ihn in einer Transaktion aus aufeinanderfolgenden Registern. (244ca480a)

  • FLIR Lepton 3.1R und Lepton UW werden vom Lepton-Treiber erkannt, einschließlich ihrer radiometrischen Gain-Modi. (0fc356632)

  • Simulator-Netzwerk — das MPS2_AN500-QEMU-Target hat nun lwIP und eine User-Mode-NIC, mit eingefrorenem requests, mqtt und sensor sowie einem Netzwerk-Unit-Test. (23546dfb1, 61d187305, 15096c3a2)

  • Beispiel für eine OpenAI-kompatible API — openai_compatible.py nimmt ein JPEG auf und sendet es per POST an einen Chat-Completions-Endpunkt zur Szenenbeschreibung. (79033c6aa)

  • SX126x-LoRa-Beispiele — der lora-sx126x-Treiber aus micropython-lib (mit lora-sync / lora-async) ist in die OpenMV RT1062-Firmware eingefroren, mit Sender-/Empfänger-/Ping-Pong-/Bildstream-Beispielen für den Anschluss eines SX1261- oder SX1262-Moduls an den SPI-Bus. Dies ist von der Community beigesteuerte Unterstützung; OpenMV verkauft keine LoRa-Hardware. (19576e1b1)

Weitere Änderungen und Verbesserungen#

  • Neuimplementierung der Bibliothek requests — Antworten mit Chunked Transfer werden decodiert, ein timeout-Argument (Standard 5 s) wird bereitgestellt, JSON- und String-Bodys werden korrekt serialisiert/kodiert, Header werden ohne Berücksichtigung der Groß-/Kleinschreibung und die Statuszeile positionsbasiert geparst, das headers-Dict des Aufrufers wird kopiert (sodass auth nicht mehr in spätere Anfragen durchsickert), und der Body wird blockweise in ein bytearray gelesen. (889f0b096)

  • mqtt importiert ssl erst bei Bedarf, sodass das Modul und unverschlüsselte (Nicht-TLS-)Verbindungen auf Builds ohne SSL-Unterstützung funktionieren. (c2e0899e8)

  • JPEG-Ausgabepuffer nach freiem Speicher dimensioniert statt einer festen 1-MB-Obergrenze; die Encoder kürzen den Puffer vor dem Schreiben des Bildes auf die kodierte Größe, sodass Aufnahmen großer Sensoren bei hoher Qualität nicht mehr fehlschlagen. (aa1ca6776)

  • Aufräumen der ML-Nachverarbeitung — die Erzeugung von Bounding-Boxes ist über die Darknet-, Edge Impulse- und Ultralytics-Postprozessoren hinweg vereinheitlicht, und die YOLOv8-Ausgabe wird nach dem Schwellwertvergleich transponiert, sodass sie wie bei den anderen Modellen mit einer Zeile pro Erkennung gespeichert wird. (b5c7853f2, c45f99cad)

  • Sicheres Herunterfahren des PAG7936 — ein neues Sensor-Halt-Flag versetzt den PAG7936 vor dem Umschalten von RESET/PWDN in den Schlafmodus und behebt Blockaden, wenn der Sensor an einem Verlängerungskabel betrieben wird. Der Treiber wählt außerdem seinen MIPI-CSI-2- oder Parallel-Registersatz zur Laufzeit anhand der I2C-Adresse des Sensors statt zur Build-Zeit. (10026530c, f6acf14ec, 5f0251c74)

  • Die ImageIO-Wiedergabetaktung bedient nun während des Wartens auf das Intervall zwischen den Einzelbildern anstehende Ereignisse, statt in WFI zu schlafen. (a54790193)

  • Aktualisierungen des MicroPython-Submoduls — volle Netzwerkunterstützung auf dem QEMU-Port, machine.mem_backup auf STM32 über Backup-SRAM/BKP-Register, SDIO-Hardware-Flusskontrolle auf STM32F4 weiterhin deaktiviert und Wiederverwendung von MPU-Attributen für nicht cachebare Regionen. (31ada5626, ab61d27a6, 06bddf13a)

  • differential-translation.py nimmt über sein csi.CSI-Objekt statt über das veraltete sensor-Modul auf, und die Abstände bei den Imports in den Beispielen wurden vereinheitlicht. (68c866e7f, 9ceff4513)

Fehlerbehebungen#

Kamera und Sensoren:

  • Das Setzen zweier benutzerdefinierter (w, h)-Auflösungen nacheinander ließ den Sensor auf der ersten Größe, während csi.CSI.width() / height() die zweite meldeten; der „keine Änderung“-Schnellpfad schließt benutzerdefinierte Größen nun aus. (cfbb70156)

  • csi.CSI.lens_correction() parste radi und coef als Booleans, sodass die an den Treiber übergebenen Werte nicht die angegebenen waren. (ab44b3a77)

  • PAG7936: Das direkt aufeinanderfolgende Setzen von Belichtung und Gain überschrieb sich gegenseitig (beide teilen sich einen manuellen Modus, und die zurückgelesenen Register hinken ein Einzelbild hinterher); der Treiber initialisiert die manuellen Register nun nur beim Wechsel in den manuellen Modus und schreibt nur die jeweils gesetzte Steuergröße. (e7a18c0a0)

  • Die BAYER-Aufnahme mit PAG7936 und PS5520 auf dem OpenMV N6 schlug bei jeder Größe außer der vollen Auflösung mit „Failed to initialize the CSI interface“ fehl, weil der ISP des N6 rohe Bayer-Daten nicht skalieren kann. Die Sensoren laufen für BAYER nun in einem nativen Modus, der zur angeforderten Größe passt (PS5520: VGA, HD, SXGA-M, FHD, QHD, WQXGA2; QVGA hat keinen nativen Modus und wird nicht unterstützt). (fe6790055, b7622b245)

Bildkodierung und Speichern:

  • Software-JPEG-Encoder: Ein Überlauf des Ausgabepuffers war immer fatal, weil der Realloc-Pfad deaktiviert war; er vergrößert den Puffer nun (jeweils um die Hälfte seiner Größe), wenn er ihn besitzt, fällt sauber zurück, wenn der Speicher ausgeht, und kürzt das Ergebnis. jpeg_write / mjpeg_write schreiben den Puffer nach einer fehlgeschlagenen Kodierung nicht mehr heraus. (28e1110be)

  • Hardware-JPEG-Encoder (STM32): Bei einem Überlauf wurde ein teilweise kodiertes Bild mit der Allokationsgröße zurückgegeben, was abgeschnittene Dateien ohne EOI-Marker erzeugte (z. B. eine 5-MP-Aufnahme bei Qualität 100 mit leerer unterer Hälfte). Sie melden nun den Überlauf, geben den Puffer bei Fehlern frei und kürzen ihn bei Erfolg. (22ce9619c)

  • Der VC8000-Encoder erzeugte stillschweigend für jede Anforderung 4:2:0-Chroma; Subsampling außer 4:2:0 fällt nun auf den HW-Codec zurück, der es unterstützt. (71f2be7f2)

  • image.Image.save() eines PNG-Bildes als .jpg schrieb bis zu 1 MB uninitialisierten Heap, und eines JPEG-Bildes als .png schrieb eine leere Datei. Beide lösen nun eine Ausnahme aus; ein Bild, das bereits im Zielformat vorliegt, wird weiterhin unverändert kopiert. (6c1fdf822)

  • png_write prüft nun den Rückgabewert des Kompressors und komprimiert vor dem Anlegen der Datei, sodass ein Fehler keine leere Datei mehr zurücklässt. (557f52d66)

image-Modul:

  • image.Image.get_pixel() mit rgbtuple=True auf BAYER- und YUV-Bildern schrieb den konvertierten Pixel über eine lokale Stack-Variable hinaus an einen vom Aufrufer bestimmten Offset. (13f2a17b6)

  • Aus gif.Gif.add_frame() wurde ein unerreichbarer Bayer/YUV-Konvertierungszweig entfernt; es werden nur GRAYSCALE- und RGB565-Bilder akzeptiert, wie es die Python-API bereits erzwang. (f20d99d96)

Protokoll:

  • Das Registrieren eines dynamischen Kanals, wenn bereits alle Slots belegt waren, verursachte einen Schreibzugriff außerhalb der Grenzen; die Kanal-ID wird nun zuerst geprüft, und für die reservierten Kanal-IDs wird statisch sichergestellt, dass sie in die Kanaltabelle passen. (68f635d1f)

  • Dynamische Kanalobjekte überlebten einen Soft-Reset in Root-Pointern, sodass der GC weiterhin veraltete Heap-Blöcke des vorherigen Laufs durchsuchte; die Tabelle wird nun beim Initialisieren geleert. (ef0ebb03b, e23641145)

Ports:

  • i.MX RT: Die fehlende Deinitialisierung von CAN und Encoder beim Soft-Reset wurde ergänzt. (7cb9d3dc2)

Hardware- und Board-Unterstützung#

  • OpenMV N6 — CAN ist nun aktiviert (machine.CAN). (294f0febd, 91e1c9573)

  • OpenMV AE3 — der sdcard-SPI-Treiber ist für den microSD-Steckplatz auf dem AE3 Battery Shield eingefroren. (a258f4814)

  • OpenMV RT1062 — lora-sx126x / lora-sync / lora-async eingefroren (siehe Neue Funktionen).

  • FLIR Lepton 3.1R / UW — werden vom Lepton-Treiber auf allen Lepton-fähigen Boards erkannt.

  • PAG7936 — Halt für sicheres Herunterfahren, Schnittstellenauswahl zur Laufzeit, Belichtungs-/Gain-Korrektur und BAYER-Aufnahme auf dem N6.

  • PS5520 — BAYER-Aufnahme auf dem N6 in nativen Größen.

  • Simulator (MPS2_AN500) — Netzwerkunterstützung.

  • Alle Boards — das sensor-Kompatibilitätsmodul ist in das Manifest jedes Boards eingefroren.

API-Brüche#

v5.0.1 bringt keine Brüche in den APIs von csi und image. Skripte, die auf v5.0.0 liefen, laufen unverändert, mit den folgenden Verhaltensänderungen.

sensor-Modul (behavior)#

Das native sensor-Modul (modules/py_csi.c) wurde entfernt und durch ein eingefrorenes Python-Modul ersetzt, das dieselbe API auf Basis von csi implementiert. Siehe sensor.

Commit: 5e3d40631

  • import sensor gibt WARNING: The sensor module is deprecated and will be removed in a future release. Please use the csi module instead. im Terminal aus.

  • Das verborgene csi.CSI-Objekt wird beim Import erstellt, sodass eine fehlende Kamera nun bei import sensor statt bei sensor.reset() eine Ausnahme auslöst.

  • Diese Funktionen lösen nun OSError aus, weil csi keine Entsprechung hat: get_fb(), alloc_extra_fb(), dealloc_extra_fb(), set_auto_rotation(), get_auto_rotation(), disable_delays(), disable_full_flush(). (Die beiden *_extra_fb-Funktionen lösten bereits in v5.0.0 eine Ausnahme aus.) Verwenden Sie für die letzten beiden csi.CSI(delays=False) / csi.CSI(fflush=False).

  • Framesizes, die csi nicht exportiert (QQCIF, QQSIF, QQQQVGA, HQQQQVGA, HQQQVGA, HQQVGA, B64X32, B64X64, B128X64, B128X128, B160X160, B320X320, LCD, QQVGA2), sind nun (w, h)-Tupel, die als benutzerdefinierte Auflösungen durchgereicht werden. get_framesize() gibt das gesetzte Tupel zurück, solange die Kamera noch diese Größe hat, sodass Gleichheitsprüfungen gegen die Konstanten weiterhin funktionieren.

  • ioctl() reicht höchstens vier Argumente nach der Anforderung weiter.

  • sleep() / shutdown() lösen bei Fehlern wie bisher OSError aus (der RuntimeError von csi wird übersetzt).

Migrieren Sie zu csi — siehe die v5.0.0-Migrationstabelle.

Laden von Bildern in den Framebuffer (behavior)#

Funktionen, die ein Bild in den Framebuffer laden — image.Image mit copy_to_fb=True, image.Image.copy() / image.Image.scale() und die to_*-Konvertierungen mit copy_to_fb=True, image.ImageIO.read(), fir.snapshot() und tof.snapshot() mit copy_to_fb=True — schickten das neue Bild bisher sofort an die IDE-Vorschau, sodass alles, was auf das zurückgegebene Bild gezeichnet wurde, nie zu sehen war. Sie markieren den Framebuffer nun als ausstehend und geben ihn, mit allem, was darauf gezeichnet wurde, unmittelbar bevor das nächste Bild ihn überschreibt aus — dasselbe Verhalten wie csi.CSI.snapshot().

Commits: 87b6db5ee, 7b1a35c2f, f773c740d

Schleifen, die einen Strom von Bildern lesen, brauchen keine Änderung und zeigen nun ihre Zeichnungen. Ein Skript, das ein einzelnes Bild lädt und dann stoppt, muss es explizit ausgeben:

img = image.Image("example.bmp", copy_to_fb=True)
img.flush()          # new: send it to the IDE preview now
time.sleep_ms(1000)

ML-Bibliothek (behavior)#

Betrifft nur Code, der die mitgelieferten Postprozessoren ableitet oder kopiert. YoloV8 transponiert die Modellausgabe nun nach dem Schwellwertvergleich, sodass verbleibende Erkennungen mit einer Zeile pro Box gespeichert werden (bb[:, 4:]), passend zu den Darknet- und Edge Impulse-Postprozessoren, statt mit einer Spalte pro Box (bb[4:, :]). Die öffentlichen ((x, y, w, h), score)-Ergebnisse sind unverändert.

Commits: c45f99cad, b5c7853f2

protocol-Modul (minor)#

protocol.poll() ist zurück. v5.0.0 hatte es entfernt, als die Protokoll-Task auf den Timer umzog; es kehrt als expliziter Weg zurück, die Task für benutzerdefinierte Transporte anzutreiben. Sonst hat sich nichts geändert — Skripte, die es nie aufgerufen haben, sind nicht betroffen.

Commit: c00c215f9

Build / Tooling (tooling)#

Nichts davon betrifft MicroPython-Skripte. py_image.c wurde aufgeteilt, wobei die Deskriptor-Objekte (cascade, keypoints, LBP, keypoint match) nach py_image_descriptor.c und die Statistik-Objekte (similarity, statistics, percentile, threshold, histogram) nach py_image_stats.c umgezogen sind. Die imlib-Encoder-API wurde an den Rest von imlib angeglichen: jpeg_compress / png_compress geben 0 bei Erfolg und -1 bei Fehlern zurück, und jpeg_compress hat sein realloc-Argument verloren (die Größenänderung hängt vom Pufferbesitz ab). OMV_PROTOCOL_MAX_CHANNELS wurde in omv_protocol_channel.h zu OMV_PROTOCOL_CHANNEL_MAX, und Ports rufen nun py_protocol_init0() beim Initialisieren auf. Das Board-Define OMV_PAG7936_MIPI_CSI2 ist weg (die Schnittstelle wird zur Laufzeit ausgewählt). CI-Abhängigkeitsaktualisierungen und eine Korrektur für leere Release-Changelogs runden es ab. Für Fork-relevante Details siehe die Historie des Firmware-Repositorys.

Migrations-Checkliste#

  • Noch bei import sensor? Es funktioniert, mit einer Warnung. Wechseln Sie zu csi (v5.0.0-Migration); ersetzen Sie disable_delays / disable_full_flush durch die Konstruktorargumente von csi.CSI() und entfernen Sie get_fb- / Auto-Rotations-Aufrufe.

  • Sie laden ein einzelnes Bild mit copy_to_fb=True und erwarten, es zu sehen? Fügen Sie nach dem Laden img.flush() hinzu.

  • Den YOLOv8-Postprozessor kopiert? Indizieren Sie die schwellwertgefilterte Ausgabe zeilenweise (bb[:, 4:]) statt spaltenweise.

  • Sie vergleichen csi0.framesize() nach dem Setzen eines Tupels? Es gibt nun csi.CUSTOM zurück.

  • Alles andere: neu flashen und ausführen.