4.18. Meerdere sensoren

Een handvol OpenMV Cams koppelen twee beeldsensoren op hetzelfde bord – meestal een kleurcamera naast een FLIR® Lepton® thermische sensor, maar dezelfde vorm geldt voor de kleur-plus-event-borden en alle toekomstige dual-sensorhardware. Elke sensor heeft zijn eigen pixelarray, zijn eigen besturingsbus, en draait zijn eigen pijplijn op zijn eigen framesnelheid. De CSI-API breidt zich uit om ze te dekken door de toepassing één CSI-object per fysieke sensor te laten instantiëren.

4.18.1. Selecteren welke sensor

De CSI-constructor neemt een cid-argument dat een specifieke sensor op het bord benoemt. cid=-1 (de standaard) selecteert de primaire sensor; de benoemde cid-constanten selecteren een secundaire op chip-ID:

import csi

csi_rgb     = csi.CSI()                    # primary colour sensor
csi_thermal = csi.CSI(cid=csi.LEPTON)      # FLIR® Lepton®

Elke instantie bezit zijn eigen configuratie – pixelformaat, framesize, belichtings-/versterkingsknoppen, framebufferpool – en wordt onafhankelijk van de andere gereset, geconfigureerd en uitgelezen. De constanten voor de ondersteunde secundaire sensoren (LEPTON, GENX320 en de andere die in de CSI-referentie staan) benoemen de chip die de toepassing op de secundaire poort verwacht; de driver laat de constructie mislukken als de werkelijke chip niet overeenkomt.

4.18.2. Vastleggen vanaf beide sensoren

Elke sensor draait zijn opnamepijplijn onafhankelijk van de andere – de kleursensor levert wellicht dertig frames per seconde terwijl de Lepton® er negen levert. De eenvoudigste manier om die mismatch aan te pakken is de snellere sensor de lus te laten aandrijven en de tragere sensor niet-blokkerend uit te lezen, waarbij genomen wordt wat klaar is en de iteratie wordt overgeslagen wanneer er niets is:

import csi

csi_rgb     = csi.CSI()
csi_thermal = csi.CSI(cid=csi.LEPTON)

csi_rgb.reset()                        # powers the rail, pulses RESET
csi_rgb.pixformat(csi.RGB565)
csi_rgb.framesize(csi.QVGA)

csi_thermal.reset(hard=False)          # I2C reconfigure only
csi_thermal.pixformat(csi.GRAYSCALE)
csi_thermal.framesize(csi.QQVGA)

while True:
    rgb_img     = csi_rgb.snapshot()                  # blocks for next colour frame
    thermal_img = csi_thermal.snapshot(blocking=False)  # returns None if not ready
    if thermal_img is not None:
        # process aligned colour + thermal pair
        pass
    else:
        # process colour only on this iteration
        pass

De blokkerende snapshot() bepaalt het tempo van de lus; de niet-blokkerende retourneert het meest recente thermische frame wanneer er sinds de vorige aanroep een vers frame is binnengekomen, en anders None. De toepassing blijft draaien op de framesnelheid van de kleursensor en krijgt een thermisch frame wanneer de Lepton® er een produceert.

Het tegenovergestelde patroon – twee blokkerende snapshots achter elkaar – werkt ook, maar de lus draait dan op de tragere van de twee sensorsnelheden, waarbij de pijplijn van de snellere sensor tussen iteraties stilvalt. Kies welke snelheid de downstreamverwerking van de toepassing daadwerkelijk wil aandrijven.

4.18.3. Reset op gedeelde voedingsrails

Sommige dual-sensorborden voeden beide chips vanaf een enkele voedingsrail of delen een resetlijn. Daarop brengt de eerste reset() de rail omhoog en pulst het gedeelde signaal; latere resets op de andere CSI-instanties moeten hard=False doorgeven zodat ze alleen hun eigen chip herprogrammeren zonder de buur door een reset te slepen:

csi_rgb.reset()                        # primary -- powers the rail, pulses RESET
csi_thermal.reset(hard=False)          # secondary -- I2C reconfigure only

Een hard=True op een secundaire in deze vorm zou de primaire als neveneffect opnieuw resetten, waardoor elke configuratie die de toepassing al had doorgevoerd ongedaan wordt gemaakt. De referentiepagina voor elk dual-sensorbord vermeldt of de rails gedeeld zijn.

4.18.4. De streambron selecteren

Camera’s met twee sensoren hebben twee CSI-instanties, maar nog steeds slechts één stream-framebuffer ertussen. Een constructorargument kiest welke frames van welke sensor de preview voeden:

csi_rgb     = csi.CSI()                    # primary
csi_thermal = csi.CSI(cid=csi.LEPTON,
                      stream=True)         # preview source

stream=True maakt de benoemde instantie de bron. Zonder stream=-argument is de primaire sensor (cid=-1, de standaard) de bron; instanties die met cid= van een secundaire sensor zijn gebouwd blijven stil op de preview tenzij stream=True expliciet wordt doorgegeven. Aanroepen van snapshot() op de niet-geselecteerde sensor leggen nog steeds normaal frames vast in de framebuffers van die sensor – ze werken alleen de preview niet bij.