protocol — Canais do Protocolo OpenMV¶
O módulo protocol expõe o protocolo de host da OpenMV ao Python. Ele permite inicializar e configurar a pilha de protocolo do lado do firmware e possibilita que o código do usuário registre canais lógicos personalizados respaldados por um objeto Python que implementa a interface do canal (read, write, size, poll, etc.). É com isso que as ferramentas complementares de desktop se comunicam quando transmitem dados de imagem ou expõem widgets interativos a uma câmera conectada.
Exemplos¶
Transmite uma imagem RGB565 para uma ferramenta de host usando um backend personalizado que implementa a interface de canal bruto (backend.size(), backend.shape(), backend.poll(), backend.read()):
import csi
import protocol
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.HD)
img = csi0.snapshot()
img_mv = memoryview(img.bytearray())
frame_ready = True
class FrameChannel:
def size(self):
return len(img_mv)
def shape(self):
return (img.height(), img.width(), len(img_mv))
def poll(self):
return frame_ready
def read(self, offset, size):
global frame_ready
end = offset + size
chunk = img_mv[offset:end]
if end >= len(img_mv):
frame_ready = False
return chunk
protocol.register(name="frame", backend=FrameChannel())
while True:
if not frame_ready:
img = csi0.snapshot()
img_mv = memoryview(img.bytearray())
frame_ready = True
O script correspondente do lado do host, usando o pacote Python openmv (pip install openmv) para conectar, enviar o script da câmera e receber cada quadro:
import cv2
import numpy as np
from openmv.camera import Camera
# The on-cam script above, stored as a string (or read from a file).
SCRIPT = open("frame_streamer_on_cam.py").read()
with Camera("/dev/ttyACM0", baudrate=921600) as cam:
cam.stop()
cam.exec(SCRIPT)
while True:
status = cam.read_status()
if not cam.has_channel("frame") or not status.get("frame"):
continue
h, w, size = cam._channel_shape(cam.get_channel(name="frame"))
if cam.channel_size("frame") < size:
continue
data = cam.channel_read("frame", size)
rgb565 = np.frombuffer(data, dtype="<u2").reshape(h, w)
# Unpack RGB565 to an HxWx3 uint8 RGB image.
r = ((rgb565 >> 11) & 0x1F) << 3
g = ((rgb565 >> 5) & 0x3F) << 2
b = ( rgb565 & 0x1F) << 3
frame = np.dstack([r, g, b]).astype(np.uint8)
# Display with OpenCV (cv2 expects BGR, not RGB).
cv2.imshow("OpenMV", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
if cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
Substitua /dev/ttyACM0 pela porta serial da câmera (por exemplo, COM3 no Windows). O construtor openmv.camera.Camera aceita os mesmos parâmetros de protocolo que init (crc / seq / ack / events / max_payload / max_retry / timeout) quando a pilha do lado da câmera foi reconfigurada para corresponder.
Funções¶
- protocol.init(crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, max_payload: int = ..., rtx_retries: int = 3, rtx_timeout_ms: int = 500, lock_interval_ms: int = 10, poll_ms: int = 0) None¶
Inicializa (ou reconfigura) a pilha de protocolo e registra os canais lógicos de dados padrão (
stdin,stdout,streame, se compilado,profile). LevantaRuntimeErrorse a inicialização falhar. O firmware inicializa com uma pilha de protocolo USB padrão já em execução, portanto chamar isto só é necessário para alterar o transporte ou sobrescrever os parâmetros de framing padrão.crchabilita a validação CRC nos quadros do protocolo.seqhabilita o rastreamento de número de sequência.ackhabilita confirmações por quadro.eventshabilita notificações de eventos de canal.max_payloadé o tamanho máximo do payload em bytes. Se omitido, é usado o padrão por câmera abaixo; ele é derivado do tamanho do buffer de protocolo de cada placa comobuffer - 10 (header) - 4 (CRC).Câmera
Tamanho do buffer
Payload máximo
OpenMV Cam M4 (
OPENMV2)512
498
OpenMV Cam M7 (
OPENMV3)512
498
OpenMV Cam H7 (
OPENMV4)512
498
OpenMV Cam H7 Plus (
OPENMV4P)4096
4082
OpenMV Pure Thermal (
OPENMVPT)4096
4082
OpenMV Cam RT1062 (
OPENMV_RT1060)4096
4082
OpenMV Cam N6 (
OPENMV_N6)8192
8178
OpenMV AE3 (
OPENMV_AE3)8192
8178
Arduino Portenta H7 (
ARDUINO_PORTENTA_H7)4096
4082
Arduino Giga (
ARDUINO_GIGA)4096
4082
Arduino Nicla Vision (
ARDUINO_NICLA_VISION)4096
4082
rtx_retriesé o número de tentativas de retransmissão. Padrão3.rtx_timeout_msé o tempo limite de retransmissão em milissegundos (dobrado após cada tempo limite). Padrão500.lock_interval_msé o intervalo mínimo de bloqueio em milissegundos. Padrão10.poll_msé o intervalo de polling em milissegundos.0(o padrão) desabilita o polling por timer.
- protocol.is_active() bool¶
Retorna
Truese um host estiver atualmente conectado e a pilha de protocolo estiver ativa, caso contrárioFalse.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
Registra um objeto Python
backendcomo um novo canal lógico e retorna um manipuladorProtocolChannel. Os métodos disponíveis do objetobackend(consulte Interface do Backend abaixo) determinam as capacidades do canal;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEeprotocol.CHANNEL_FLAG_LOCKsão adicionados aflagsautomaticamente quando os métodos correspondentes são implementados.nameé o nome do canal como uma string. Truncado para o tamanho do buffer de nome de canal do firmware. Obrigatório.backendé o objeto Python que implementa a interface do backend. Obrigatório. Normalmente passado por palavra-chave (backend=...).flagssão bits adicionais de flag de canal (consulte as constantesCHANNEL_FLAG_*). Opcional; o padrão é0.Levanta
RuntimeErrorse o canal não puder ser registrado (por exemplo, se não houver slots de canal livres).
Classes¶
- class protocol.ProtocolChannel¶
Manipulador retornado por
protocol.register. As instâncias não são construídas diretamente.
Interface do Backend¶
Um objeto backend passado a protocol.register pode implementar qualquer subconjunto dos métodos a seguir. Apenas os métodos presentes no objeto são conectados à camada de protocolo em C; métodos ausentes deixam a capacidade correspondente desabilitada.
- class protocol.backend¶
Objeto backend de canal passado a
protocol.register. Os métodos abaixo descrevem a interface opcional que um backend Python pode implementar.- init() object¶
Chamado uma vez quando o canal é inicializado. Retorne qualquer valor diferente de
Noneem caso de sucesso; uma exceção ou a ausência de retorno é tratada como um erro.
- shape() tuple¶
Retorna uma tupla de até quatro inteiros descrevendo o formato dos dados (por exemplo, as dimensões da imagem). Até quatro elementos são consumidos pela camada de protocolo.
- flush() object¶
Descarrega quaisquer dados pendentes. Retorne qualquer valor diferente de
Noneem caso de sucesso.
- read(offset: int, size: int) bytes¶
Retorna até
sizebytes a partir deoffsetcomo um objeto do tipobytesque suporta o protocolo de buffer.
- readp(offset: int, size: int) bytes¶
Variante zero-copy de
read. Retorna um buffer cuja memória subjacente é lida diretamente pela camada de protocolo; o buffer deve permanecer válido durante toda a transferência.
- write(offset: int, data: bytearray) int¶
Escreve
dataemoffset.dataé umbytearrayque referencia diretamente o buffer em C. Retorne o número de bytes escritos, ou0para o sucesso padrão.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
Um backend Python de nível mais alto (fornecido pelo pacote
protocolcongelado) que serializa campos nomeados em CBOR usando chaves inteiras compatíveis com SenML. Suporta widgets de exibição (label,depth) e controles interativos (toggle,slider,select) com callbackson_read/on_write.on_readé um callable opcionalon_read(channel)invocado antes de o canal ser serializado para o host. Use-o para atualizar os valores dos campos.on_writeé um callable opcionalon_write(channel, name, value)invocado quando o host escreve um novo valor para um campo nomeado.- add(name: str, type: str, value: Any = None, unit: str | None = None, min: int | float | None = None, max: int | float | None = None, step: int | float | None = None, options: list | None = None, width: int | None = None, height: int | None = None) None¶
Adiciona um campo nomeado ao canal.
nameé o nome de exibição; deve ser único dentro deste canal.typeé o tipo de widget:"label","toggle","slider","select"ou"depth".valueé o valor inicial. O padrão depende detype.unité a string de unidade paralabel/slider(por exemplo,"Cel","%RH").miné o valor mínimo (intervalo do slider ou intervalo de profundidade).maxé o valor máximo (intervalo do slider ou intervalo de profundidade).stepé o tamanho do passo (slider).optionsé a lista de strings de opção (select).widthé a largura em pixels (depth).heighté a altura em pixels (depth).
- __getitem__(name: str) object¶
Retorna o valor atual do campo nomeado. Para campos
depth, o buffer de dados binários é retornado; caso contrário, o valor escalar.
- __setitem__(name: str, value: Any) None¶
Define o valor do campo nomeado. Para campos
slider, uma tupla(min, max, value)atualiza o intervalo e o valor atual simultaneamente. Para camposdepth,valueé o buffer de dados binários.
- poll() bool¶
Método da interface do backend. Retorna
Truequando há dados serializados disponíveis para o host.
- size() int¶
Método da interface do backend. Invoca
on_read(se definido) e retorna o tamanho do buffer serializado.
Constantes¶
Bits de flag de canal (combinados bit a bit; passados a protocol.register via flags ou definidos automaticamente com base nos métodos do backend).
- protocol.CHANNEL_FLAG_PHYSICAL: int¶
O canal representa um transporte físico (em oposição a um canal lógico de dados).
Identificadores de canal embutidos.