13.3.1.6. Справочник по API

Публичный интерфейс пакета openmv состоит из класса Camera для взаимодействия с камерой и иерархии OMVException для ошибок протокола. Оба описаны на этой странице.

13.3.1.6.1. Класс Camera

class openmv.Camera(port: str, *, baudrate: int = 921600, crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, timeout: float = 1.0, max_retry: int = 3, max_payload: int = 4096, drop_rate: float = 0.0)

Прокси на стороне хоста для камеры OpenMV, доступной через USB serial.

Параметры:
  • port – Путь к последовательному устройству. В Linux это /dev/ttyACMx для USB CDC и /dev/ttyUSBx для моста USB-to-UART. В macOS это /dev/tty.usbmodem... или /dev/cu.usbmodem.... В Windows это COMx.

  • baudrate – Скорость передачи (бод) последовательного порта. По USB значение 921600 является магическим значением, которое переключает камеру из MicroPython REPL в протокол OpenMV – любое другое значение по USB-соединению оставляет камеру в режиме REPL, поэтому необходимо использовать значение по умолчанию. По UART-соединению это фактическая скорость передачи (бод) линии, и её можно свободно задавать на обеих сторонах.

  • crc – Включить проверку CRC для каждого пакета.

  • seq – Включить порядковые номера для каждого пакета.

  • ack – Требовать подтверждение пакетов.

  • events – Включить уведомления о событиях от камеры.

  • timeout – Тайм-аут на операцию в секундах.

  • max_retry – Число повторных попыток до возбуждения исключения при сбое пакета.

  • max_payload – Максимальный согласованный размер полезной нагрузки в байтах. Камера может согласовать меньшее значение.

  • drop_rate – Вероятность сброса пакета (только для тестов) в диапазоне [0.0, 1.0]. В продакшене оставляйте 0.0.

Класс поддерживает протокол менеджера контекста; with Camera(port) as cam: вызывает connect() при входе и disconnect() при выходе.

13.3.1.6.2. Подключение

Camera.connect() None

Открыть последовательный порт и выполнить рукопожатие протокола. В качестве побочного эффекта заполняется кэшированное состояние (список каналов, информация о системе, информация о версии). Вызывается автоматически менеджером контекста.

Camera.disconnect() None

Закрыть последовательный порт и освободить транспорт. Вызывается автоматически при выходе из менеджера контекста.

Camera.is_connected() bool
Результат:

True, если последовательный порт открыт.

Camera.reset() None

Сбросить камеру. Соединение разрывается, так как камера перезагружается.

Camera.boot() None

Перевести камеру в её загрузчик. Соединение разрывается, так как камера перезагружается.

Camera.update_capabilities() None

Повторно согласовать возможности протокола (CRC, проверка последовательности, ACK, события, максимальная полезная нагрузка) с камерой. Камера сообщает максимальную полезную нагрузку, которую она может обработать; запрос хоста ограничивается этим значением, а согласованные настройки отправляются обратно. Вызывается автоматически из connect() – нет причин вызывать этот метод из пользовательского кода, кроме случаев, когда флаги конструктора нужно повторно согласовать на уже установленном соединении.

Camera.poll_events() None

Запустить путь приёма транспорта один раз, чтобы обработать любые ожидающие события от камеры без отправки команды. Полезно в долго работающих программах, которые в течение минут не выполняют другого ввода-вывода и хотят своевременно получать события регистрации каналов.

13.3.1.6.3. Выполнение скриптов

Camera.exec(script: str) None

Загрузить script (строку исходного кода Python) в буфер stdin камеры и запустить его выполнение.

Параметры:

script – Исходный код MicroPython для выполнения.

Camera.stop() None

Прервать выполняющийся скрипт. Эквивалент кнопки Stop в IDE.

Camera.read_stdout() str | None

Прочитать все байты, которые выполняющийся скрипт записал в stdout с момента последнего вызова.

Результат:

Вывод в виде декодированной строки или None, если данных нет.

13.3.1.6.4. Потоковая передача

Camera.streaming(enable: bool, raw: bool = False, resolution: tuple[int, int] | None = None) None

Включить или выключить поток кадров и выбрать формат передачи по проводу.

Параметры:
  • enableTrue включает потоковую передачу, False отключает её.

  • raw – При значении False (по умолчанию) камера сжимает каждый кадр в JPEG перед помещением его в канал потока, а read_frame() распаковывает его на хосте. При значении True камера отправляет захваченный буфер пикселей без сжатия – правильный выбор для камер без аппаратной поддержки JPEG, где программное сжатие является самым медленным шагом в цикле.

  • resolution(width, height) – целевой размер, до которого камера масштабирует каждый сырой кадр перед отправкой, поскольку несжатые кадры намного больше сжатых в JPEG. Обязательно при raw=True; в противном случае игнорируется.

Camera.read_frame() dict | None

Прочитать последний кадр из канала потока.

Результат:

None, если кадр не ожидается, или словарь с ключами width (int, пиксели), height (int, пиксели), format (int, идентификатор формата пикселей, объявленный камерой), depth (int, размер сжатого изображения в байтах для кадров JPEG / PNG; не используется для несжатых форматов), data (bytes, RGB888 длиной width * height * 3) и raw_size (int, байты, отправленные камерой по USB до декодирования).

13.3.1.6.5. Пользовательские каналы

Camera.has_channel(name: str) bool
Результат:

True, если на камере существует канал, зарегистрированный с именем name.

Camera.channel_size(name: str) int
Результат:

Число байтов, доступных в данный момент в названном канале, или 0, когда канал пуст или не существует.

Camera.channel_read(name: str, size: int | None = None) bytes | None

Прочитать из пользовательского канала.

Параметры:
  • name – Имя канала, зарегистрированное скриптом на стороне камеры.

  • size – Число байтов для чтения или None, чтобы прочитать всё доступное.

Результат:

Байты или None, если канал не существует.

Camera.channel_write(name: str, data: bytes) bool

Записать data в пользовательский канал. Записи больше полезной нагрузки автоматически разбиваются на пакеты.

Параметры:
  • name – Имя канала, зарегистрированное скриптом на стороне камеры.

  • data – Полезная нагрузка типа bytes-like для отправки.

Результат:

True, если канал существует и запись была отправлена, False в противном случае.

Camera.read_status() dict[str, bool]

Опросить каждый зарегистрированный канал.

Результат:

Словарь, сопоставляющий имя канала логическому значению «данные готовы к чтению».

Camera.update_channels() None

Обновить кэшированный список каналов из камеры. Запускается автоматически при следующем поиске канала по имени после поступления события регистрации канала; приложение, желающее немедленно узнать о только что зарегистрированном канале, может вызвать этот метод напрямую.

Camera.get_channel(name: str | None = None, channel_id: int | None = None) int | str | None

Найти канал либо по имени (возвращая его числовой ID), либо по ID (возвращая его имя). Сначала обновляет кэш каналов через update_channels(), если есть ожидающие события регистрации каналов.

Параметры:
  • name – Имя канала для разрешения в ID.

  • channel_id – ID канала для разрешения в имя.

Результат:

Соответствующий ID или имя, или None, когда канал не существует. Должен быть указан один из аргументов name или channel_id.

13.3.1.6.6. Интроспекция устройства

Camera.version() dict

Вернуть тройки версий протокола, загрузчика и прошивки камеры. Кэшируются после connect(). Каждая тройка является кортежем (major, minor, patch) из int:

  • protocol_version – версия проводного протокола OpenMV, реализуемого камерой.

  • bootloader_version – образ загрузчика, находящийся во флеш-памяти.

  • firmware_version – прошивка MicroPython, выполняющаяся в данный момент.

Camera.system_info() dict

Вернуть информацию об аппаратных возможностях и памяти камеры. Кэшируется после connect(). Ключи возвращаемого словаря делятся на четыре группы.

Идентификация

  • cpu_id – 32-битный идентификатор CPU.

  • device_id – кортеж из 3 32-битных слов, уникальный серийный номер устройства, зашитый в кремний.

  • chip_id – кортеж из 3 32-битных слов, по одной записи на каждый датчик изображения, подключённый к камере.

  • usb_vid – USB vendor ID.

  • usb_pid – USB product ID.

Размеры памяти (все в килобайтах)

  • flash_size_kb – общий объём внутренней флеш-памяти.

  • ram_size_kb – общий объём RAM.

  • framebuffer_size_kb – RAM, зарезервированная для захвата изображений.

  • stream_buffer_size_kb – RAM, зарезервированная для канала потока, который передаёт кадры на хост.

Флаги возможностей (по одному логическому значению на функцию, все названы <feature>_present)

  • gpu_present – графический процессор.

  • npu_present – нейронный процессор.

  • isp_present – процессор обработки сигнала изображения.

  • venc_present – видеокодировщик.

  • jpeg_present – аппаратный JPEG-кодировщик.

  • dram_present – внешняя DRAM.

  • crc_present – ускоритель CRC.

  • pmu_present – блок мониторинга производительности.

  • wifi_present – радиомодуль Wi-Fi.

  • bt_present – радиомодуль Bluetooth.

  • sd_present – слот для SD-карты.

  • eth_present – Ethernet PHY.

  • multicore_present – несколько ядер CPU.

Прочее

  • usb_highspeed – логическое значение, True, когда USB перечислился в высокоскоростном режиме (USB 2.0 HS, 480 Мбит/с).

  • pmu_eventcnt – число доступных счётчиков событий PMU; 0, когда PMU отсутствует.

Camera.print_system_info() None

Записать отформатированный блок системной информации в logging на уровне INFO. CLI использует это при подключении.

13.3.1.6.7. Диагностика

Camera.host_stats() dict
Результат:

Счётчики транспортного уровня, отслеживаемые на стороне хоста: sent, received, checksum, sequence.

Camera.device_stats() dict
Результат:

Счётчики транспортного уровня, отслеживаемые на стороне камеры: sent, received, checksum, sequence, retransmit, transport, sent_events, max_ack_queue_depth.

13.3.1.6.8. Профайлер

Профайлер сообщает количество вызовов каждой функции, а также минимальное / максимальное / суммарное время выполнения для инструментированных модулей прошивки – в настоящее время image, ml и ulab. Вход и выход из функций перехватываются на этапе компиляции; во время выполнения берётся отсчёт монотонного микросекундного счётчика на каждом из них, результат накапливается по функциям, и таблица предоставляется хосту через канал profile.

Профайлер встраивается в прошивку только тогда, когда make передаётся PROFILE_ENABLE=1. Стандартные образы прошивки не включают его – флаг -finstrument-functions, который сборка добавляет к отслеживаемым модулям, имеет нетривиальные накладные расходы во время выполнения, поэтому сборки с профилированием создаются из исходного кода для конкретной отладочной сессии, которой они нужны. Когда прошивка собрана без этого флага, канал profile не регистрируется, и каждый метод профайлера на этой странице молча возвращает управление, ничего не делая.

Performance Monitoring Unit (PMU) от Arm – это блок аппаратных счётчиков Cortex-M55: небольшой набор настраиваемых счётчиков, которые отслеживают количество тактов, попадания и промахи кэша, поведение ветвлений и другие определённые архитектурой события, не замедляя измеряемый код. На камерах, у которых он есть – AE3 и N6, две камеры в линейке OpenMV, построенные на M55 – профайлер снимает показания этих счётчиков вместе с данными о времени, и суммы событий отображаются в каждой записи по функции. Камеры без PMU всё равно создают записи о времени; поля событий возвращаются нулевыми, а profiler_event() не выполняет никаких действий.

Camera.profiler_mode(exclusive: bool = False) None

Переключаться между инклюзивным и эксклюзивным измерением времени. Инклюзивное измерение относит время вызываемых функций на счёт вызывающей; эксклюзивное измерение этого не делает.

Параметры:

exclusiveTrue выбирает эксклюзивное измерение времени, False выбирает инклюзивное.

Camera.profiler_reset(config: list | None = None) None

Очистить все счётчики профиля. config=None также восстанавливает назначение событий PMU по умолчанию.

Параметры:

config – Зарезервировано для будущих переопределений конфигурации по каждому счётчику. Передайте None, чтобы сохранить значения по умолчанию.

Camera.profiler_event(counter_num: int, event_id: int) None

Привязать один из слотов счётчиков PMU к конкретному аппаратному событию.

Параметры:
  • counter_num – Индекс счётчика.

  • event_id – Определённый архитектурой идентификатор события.

Camera.read_profile() list[dict] | None

Вернуть записи профиля по каждой функции, собранные с момента последнего сброса. Каждая запись является словарём с ключами address, caller, call_count, min_ticks, max_ticks, total_ticks, total_cycles и кортежем events размером, равным pmu_eventcnt камеры.

Результат:

Список словарей записей или None, если канал профиля недоступен или данные не были собраны.

13.3.1.6.9. Наследование и внутреннее устройство каналов

Описанные выше методы покрывают каждое распространённое применение пакета. Несколько шаблонов – обработка событий со стороны камеры, на которые хост хочет реагировать, блокировка канала для многошагового обмена, взаимодействие с каналами, передающими структурированные данные вместо потоков байтов, или управление специфичными для канала командами – требуют методов, которые Camera держит с префиксом подчёркивания. Эти имена являются приватными по соглашению (Python не выполняет для них name-mangling), и предполагается, что приложения, которым они нужны, либо наследуют Camera, либо вызывают эти методы напрямую.

Наследование для реакции на события. Каждое событие, которое испускает камера, поступает через Camera._handle_event(). Наследование Camera и переопределение этого метода – это способ, которым приложение реагирует на события, возбуждаемые его скриптом на стороне камеры; страница События подробно описывает полный шаблон.

Camera._handle_event(channel_id: int, event: int) None

Диспетчеризовать одно событие от камеры. Вызывается транспортным уровнем всякий раз, когда поступает пакет события. Переопределите в подклассе для добавления специфичной для приложения обработки; вызовите super()._handle_event(...), чтобы сохранить поведение по умолчанию (обновление списка каналов при CHANNEL_REGISTERED, отслеживание готовности кадра на канале stream, логирование старта / остановки канала stdin).

Параметры:
  • channel_id0 для системных событий, иначе зарегистрированный ID канала.

  • event – Идентификатор события; значения берутся из перечисления EventType для системных событий и из того, что выбрал бэкенд канала на стороне камеры для событий канала.

Подкласс, добавляющий собственные методы взаимодействия по протоколу, должен декорировать их с помощью retry_if_failed(), чтобы они наследовали то же поведение ресинхронизации и повторных попыток, которое есть у каждого поставляемого метода на этой странице.

static Camera.retry_if_failed(func)

Декоратор. Оборачивает метод экземпляра так, чтобы он повторял попытку один раз, когда транспорт возбуждает ResyncException. Любой метод, который вызывает _send_cmd_wait_resp() (напрямую или через одну из обёрток _channel_*), должен нести этот декоратор:

class MyCamera(Camera):
    @Camera.retry_if_failed
    def my_custom_command(self, payload):
        return self._send_cmd_wait_resp(Opcode.MY_CMD,
                                        0, payload)

Блокировка канала гарантирует, что состояние канала не изменится между двумя связанными операциями (например, _channel_size(), за которым следует _channel_read(), на канале, который продолжает добавлять данные). read_frame() и read_profile() используют это внутренне; приложение, управляющее пользовательским каналом с многошаговым доступом, делает то же самое.

Camera._channel_lock(channel_id: int) bool

Получить эксклюзивную блокировку на канал. Другие операции хоста на том же канале блокируются до освобождения блокировки.

Параметры:

channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

Результат:

True, когда блокировка была предоставлена.

Camera._channel_unlock(channel_id: int) bool

Освободить блокировку, ранее полученную через _channel_lock(). Всегда используется в паре с вызовом блокировки; используйте try / finally, чтобы гарантировать снятие блокировки, даже когда чтение между ними возбуждает исключение.

Параметры:

channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

Структурированные каналы передают структурированные записи, а не плоский поток байтов. Канал профайлера является поставляемым примером: его форма равна (record_count, record_size), и хост, желающий узнать, сколько записей ожидается, читает форму, а не размер в байтах.

Camera._channel_shape(channel_id: int) tuple[int, ...]

Прочитать дескриптор формы канала.

Параметры:

channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

Результат:

Кортеж беззнаковых 32-битных целых чисел, описывающий компоновку канала. Смысл зависит от конкретного канала.

Специфичные для канала команды управления – start, stop, reset, configure – передаются одним опкодом (CHANNEL_IOCTL) со специфичным для канала номером команды и необязательной полезной нагрузкой struct.pack. Поставляемые методы, такие как stop(), exec() и streaming(), являются тонкими обёртками вокруг вызовов _channel_ioctl() к каналам stdin и stream; пользовательский канал на стороне камеры, определяющий собственное меню ioctl, управляется тем же способом.

Camera._channel_ioctl(channel_id: int, cmd: int, fmt: str | None = None, *args) bytes | None

Выдать команду ioctl на канале.

Параметры:
  • channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

  • cmd – Номер команды, определённый бэкендом канала на стороне камеры.

  • fmt – Необязательная строка формата struct для кортежа аргументов. Передайте None для ioctl, не принимающих аргументов.

  • args – Значения, соответствующие fmt.

Результат:

Любая полезная нагрузка, возвращённая каналом, или None.

Варианты потока байтов по ID публичных методов канала пропускают поиск имени по ID и принимают явное байтовое смещение offset – полезно для чтения фрагмента из середины большого буфера (например, записей канала profile).

Camera._channel_size(channel_id: int) int
Параметры:

channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

Результат:

Байты, доступные в данный момент на канале.

Camera._channel_read(channel_id: int, offset: int, length: int) bytes

Прочитать length байтов, начиная со смещения offset. Многопакетные чтения собираются автоматически.

Параметры:
  • channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

  • offset – Байтовое смещение, с которого начинать чтение.

  • length – Число байтов для чтения.

Camera._channel_write(channel_id: int, data: bytes, offset: int = 0) None

Записать data по заданному смещению offset. Многопакетные записи автоматически разбиваются на пакеты.

Параметры:
  • channel_id – Числовой ID канала, обычно разрешаемый через get_channel().

  • data – Полезная нагрузка типа bytes-like для записи.

  • offset – Байтовое смещение, с которого начинать запись.

Примитивы протокола – это самый низкий уровень, который предоставляет класс: записи сырой отправки команды, получения сырого списка каналов и ручной ресинхронизации, на которых в конечном счёте построено всё вышеперечисленное. Приложение обращается к ним при отправке опкода, который класс ещё не оборачивает, или при реализации пользовательского восстановления в подклассе.

Camera._send_cmd_wait_resp(opcode: int, channel: int = 0, data: bytes = b'') bytes | None

Отправить команду протокола и дождаться ответа камеры. Примитив, на котором построен каждый другой метод в этом разделе.

Параметры:
  • opcode – Номер команды. Поставляемое перечисление Opcode перечисляет коды, с которыми поставляется прошивка, но параметр является просто целым числом – пользовательская сборка прошивки может определять и отвечать на собственные.

  • channel – ID канала или 0 для системных команд.

  • data – Специфичная для команды полезная нагрузка.

Результат:

Полезная нагрузка ответа или None для команд вроде Opcode.SYS_RESET и Opcode.SYS_BOOT, которые разрывают соединение.

Camera._channel_list() dict

Получить текущий список каналов от камеры, не затрагивая кэшированные словари channels_by_id и channels_by_name, которые заполняет update_channels(). Полезно для подкласса, желающего напрямую проверить состояние каналов камеры.

Результат:

Словарь, сопоставляющий ID канала с {'name': str, 'flags': int}.

Camera._resync() None

Повторно выполнить рукопожатие протокола с нуля. Вызывается автоматически из connect() при начальном подключении и каждым публичным методом, который перехватывает OMVException от транспорта. Приложение, реализующее собственный цикл восстановления в подклассе, может вызвать этот метод напрямую после обработки исходной ошибки.

13.3.1.6.10. Исключения

exception openmv.OMVException

Базовый класс для каждой ошибки уровня протокола. Все три подкласса ниже наследуют от него, поэтому единственный except OMVException покрывает всю поверхность ошибок.

exception openmv.TimeoutException

Камера не ответила в течение настроенного тайм-аута. Подкласс OMVException.

exception openmv.ChecksumException

CRC пакета не совпал. Возбуждается после того, как протокол исчерпал бюджет повторных попыток. Подкласс OMVException.

exception openmv.SequenceException

Пакет прибыл с неожиданным порядковым номером после повторных попыток. Подкласс OMVException.