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

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

13.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.1.6.10. Исключения#

exception openmv.OMVException#

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

exception openmv.TimeoutException#

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

exception openmv.ChecksumException#

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

exception openmv.SequenceException#

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