8.14. AsyncCSI¶
Tipik bir OpenMV Cam betiği while True: img = csi0.snapshot() ile son bulur – asyncio’ya hiç ihtiyaç duymayan, engelleyici bir anlık görüntü döngüsü. Uygulamanın yakalamaların yanı sıra başka bir şey yapması gerektiği anda – bir düğmeyi dinlemek, bir eşe veri göndermek, bir arka plan görevi çalıştırmak – engelleyici çağrı işe engel olur. snapshot bir sonraki çerçeveyi beklerken olay döngüsü çalışmaz, dolayısıyla programdaki diğer her eşyordam çerçeve gelene kadar donmuş kalır.
Bu sayfa, CSI etrafında snapshot‘ı await dostu bir eşyordama dönüştüren küçük bir sarmalayıcı oluşturur. Sonuç, bir yakalama döngüsünün bir asyncio programının geri kalanıyla bir arada var olmasını sağlayan, doğrudan kullanılabilecek bir yedektir.
8.14.1. Parçalar¶
CSI API’sinin bir parçası işin çoğunu yapar – engelleyici olmayan modunda snapshot(). snapshot(blocking=False) çağrısı ya bir sonraki çerçeveyi döndürür (hazırsa) ya da None döndürür (değilse). İlk engelleyici olmayan çağrı, daha önce çalışmıyorsa kameranın DMA yakalamasını da başlatır, böylece sarmalayıcının başlatma için özel bir şey yapması gerekmez.
Diğer parça ise asyncio.sleep_ms(). Sarmalayıcı, engelleyici olmayan anlık görüntüleri bir döngüde yoklar; bir sonraki yoklamadan önce hazır olan diğer her eşyordamın çalışma şansı bulması için kontroller arasında await asyncio.sleep_ms(0) ile olay döngüsüne denetimi devreder.
8.14.2. Sarmalayıcı¶
import asyncio
import csi
class AsyncCSI:
def __init__(self, *args, **kwargs):
self._csi = csi.CSI(*args, **kwargs)
def __getattr__(self, name):
return getattr(self._csi, name)
async def snapshot(self):
while True:
img = self._csi.snapshot(blocking=False)
if img is not None:
return img
await asyncio.sleep_ms(0)
Yapıcı bir CSI örneğini sarmalar. __getattr__, sarmalayıcının kendisi tanımlamadığı her özniteliği – reset, pixformat, framesize, tüm sensör ayarları – alttaki CSI nesnesine iletir, böylece sarmalayıcı, önemli olan tek yöntem dışında sarmalanmamış nesneyle birebir aynı görünür.
async def snapshot yeni parçadır. snapshot(blocking=False) çağrısını yapar; çağrı bir görüntü döndürürse eşyordam onu döndürür. Aksi takdirde diğer eşyordamların çalışma şansı bulması için await asyncio.sleep_ms(0) ile olay döngüsüne geri denetim verir, ardından döngüye geri döner ve yeniden dener. İlk yineleme DMA’yı başlatır; sonraki yinelemeler çerçeveleri kullanılabilir hale geldikçe alır.
8.14.3. Arkadaşlı bir anlık görüntü döngüsü¶
Sarmalayıcı yerinde olduğunda, bir anlık görüntü döngüsü daha büyük bir asyncio programına diğer her eşyordamın yaptığı gibi uyum sağlar. Aşağıdaki örnek, üç eşyordamı eşzamanlı olarak çalıştırır: yakalama döngüsü, bir LED yanıp sönücüsü ve saniyede bir kez hello yazdıran bir kalp atışı:
import asyncio
import csi
from machine import LED
async def capture_loop(cam):
while True:
img = await cam.snapshot()
# process img here
async def blinker(led, period_ms):
while True:
led.on()
await asyncio.sleep_ms(period_ms)
led.off()
await asyncio.sleep_ms(period_ms)
async def hello(period_s):
while True:
print("hello")
await asyncio.sleep(period_s)
async def main():
cam = AsyncCSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.QVGA)
asyncio.create_task(blinker(LED("LED_BLUE"), 200))
asyncio.create_task(hello(1))
await capture_loop(cam)
asyncio.run(main())
Üç eşyordamın tümü aynı olay döngüsünde ilerleme kaydeder. capture_loop engelleyici olmayan anlık görüntü yoklamaları arasında denetimi devrederken, blinker LED’i değiştirir ve hello yazdırır. blinker ve hello uyurken, capture_loop kamerayı yoklar. Yoklama aralığı kısadır – tek bir olay döngüsü tıkı – bu nedenle uygulamanın yeni bir çerçeveyi görmesine ihmal edilebilir bir gecikme ekler.
Yakalama döngüsü olay döngüsünü engellemez. Daha fazla eşzamanlı iş eklemek – örneğin bir UART istemcisi – main içinde yalnızca başka bir create_task() çağrısıdır.
Not
Bu yapıda framebuffers ayarı hâlâ önemlidir. Tek arabellek modu, snapshot(blocking=False)‘ın bir sonraki çerçeve yakalanana kadar None döndürmesine neden olur; çift veya üçlü arabelleğe alma bunu yumuşatır, böylece sarmalayıcı genellikle bir önceki çerçeve işlendikten sonraki ilk yoklamada bekleyen arabelleğe alınmış bir çerçeve bulur.