В статье маркеры визуальной системы автоматической посадки БЛА была описана обработка видео-данных реального времени для системы оптического типа – VBLS. Это была хоть и шустрая, сделанная на C++, но модель. Теперь, как было замечено в конце этой статьи, пришло время показать систему в боевом варианте, где обработка видеопотока параллелится в ПЛИС.
В данной системе для экспериментов я выбрал весьма удобную отладочную плату Zedboard. Чип Zynq-7000 основан на SoC архитектуре ARM+FPGA, однако на этом этапе функционал ARM использовать не будем и ограничиваемся работой только с ПЛИС. В качестве камеры выступает популярный модуль OV7670 разрешением 640х480 (хвала Алиэкспрессу!). Почему такое скромное разрешение? А потому что в Zedboard ресурсы ограничены, в частности критичным для нас является размер встроенной быстродействующей памяти BRAM (не путать с DDR). Результирующее видео выводится на дисплей через разъем VGA платы.
В излагаемой конфигурации основной упор сделан на технические аспекты создания рабочей конфигурации, поскольку это занимает приличное время и опять таки: за деревьями не видно леса и требуются определенные усилия чтобы свести разрозненную информацию воедино. Да, и конечно чтобы это единое работало ) Поэтому сами алгоритмы распознавания будут дальше.
Теперь, пошли по порядку.
Инструментарий
Отладочная плата Zedboard. Конечно, это серьезный финансовый барьер для тех кто занимается разработкой в режиме хобби, но если вы собираетесь работать с ПЛИС то вам нужна эта плата. Она удобна, хорошо документирована, и к тому же на ней есть ARM, на котором вы будете дополнительно молотить то, что осталось от ПЛИС.
Micro-USB кабель. Он будет подключаться к разъему PROG платы и нужен для закачки логической матрицы.
По мере продвижения вперед ваш рабочий стол приобретет примерно такой вид.
Среда разработки Vivado 2017.4. Качайте и устанавливайте ее бесплатный вариант – WebPack. Есть версии как для Linux так и для Windows; у меня стоит Linux версия. Среда весьма требовательная к ресурсам компа. Да, и сразу предупреждаю – “компиляция” исходного кода занимает приличное время (минуты). Это дисциплинирует и заставляет более требовательно относиться к своим исходникам – попросту нужно делать меньше ошибок. Для Vivado есть и более свежии версии, но у меня они пошли плохо – начались конфликты с кириллицей (кто бы мог подумать).
Для тех кто пользует Linux: поскольку среду разработки разворачивает скрипт установки, укажите место для Vivado как /opt/Xilinx, предварительно настроив права доступа на этот каталог. Обновите правила udev для того, чтобы операционная система правильно определила кабель USB, подключенный к Zedboard. Для этого в каталоге
1 |
/opt/Xilinx/Vivado/2017.4/data/xicom/cable_drivers/lin64/install_script/install_drivers/ |
запустите соответствующие скрипты и обновите правила с помощью udevadm.
Камера OV7670. В поставке есть платы с чипом FIFO и без него. Нам он без надобности; наше описание расчитано на интерфейс камеры без этого буфера. Для подключения камеры к соединителям PMOD платы Zedboard я сделал переходную колодку. Можно обойтись и без пайки, просто соединив пины камеры с гнездами разъемов кабелями мама – папа. Только не делайте соединения слишком длинными – все таки работаем на частоте 25 МГц, длинный монтаж начнет звенеть.
Дисплей с VGA входом и VGA кабель. Да, для того чтобы увидеть плоды своих трудов нам понадобится этот раритетный девайс, ничего не поделаешь. Будем формировать сигналы классического интерфейса VGA и выдавать их на разъем платы, который подключен к PL. И еще, потихоньку привыкаем к терминологии архитектуры Zynq: PL это программируемая логика (ПЛИС), PS это процессор (ARM).
Сразу отвечаю на вопрос продвинутых пользователей: это каким образом цифровая подсистема PL формирует сугубо аналоговые сигналы VGA? Если мы взглянем на схему платы, то увидим резистивные делители, подключенные к выходу VGA. Это фактически есть не что иное, как ЦАП, сделанный дешево и сердито. На каждый из сигналов цвета выделено 4 разряда, поэтому мы ограничены 16 градациями по каждому каналу. На самом деле, в этом проекте цвет нам не понадобится, поскольку будем работать с серым изображением.
Теперь переходим к следующему этапу – связываем все это вместе.
Подключение камеры OV7670 к плате Zedboard
Дальше, по ходу изложения, я поделюсь исходниками проекта. Но уже сейчас нам понадобится один файл – zedboard.xdc, в котором описаны внешние соединения, о которых должна знать PL. Должна знать – потому что в этом файле осуществляется привязка по цепочке: контакт разъема PMOD платы – вывод PL – наименование соответствующего сигнала в коде VHDL. Функции этого файла, который в терминологии Xilinx именуется constraints файлом, горазо шире, но в нашем проекте мы используем этот необходимый минимум.
Поскольку я заговорил об исходниках, здесь будет уместно сообщить откуда я их взял ) За основу проекта использован этот VHDL код, однако имейте в виду что там есть ошибки как в самом коде, так и в распиновке PMOD разъемов платы Zedboard; кроме того я переделал этот проект с цветного на черно-белый. Можно сказать лишил его всех красок бытия ) Также я включил в состав исходников dummy модуль, в котором будут жить разные алгоритмы обработки изображения в реальном времени. Пока все что он делает – просто передает полученные байты изображения модулю VGA. А пока этот компонент живет в комфортном окружении, которое понадобится в будущем: блок памяти BRAM на входе и блок на выходе. Все в соответствии с правилами модульного программирования, выделение интерфейсов и изоляция модуля от остальных.
Итак, возвращаемся к подключению камеры. Для удобства я сделал табличку, в котором свел вместе пины камеры, коннекторов PMOD платы и данные из constraints file zedboard.xdc.
Ваша задача – соединить пины камеры из первого столбца таблицы с гнездами разъема PMOD платы Zedboard второго столбца таблицы. О том каким выводам ПЛИС Zynq-7000 соответствуют эти сигналы, знаем только мы и руководство Zedboard Hardware Guide. VHDL коду все равно – он оперирует названиями сигналов из правого столбца таблицы, а привязывает эти сигналы к выводам Zynq-7000 файл zedboard.xdc. Таким образом все сходится.
Раз мы уже занялись подключением камеры OV7670, быстро пробежимся по ее выводам. RESET и PWDN – сброс и включение камеры. Управление камерой обеспечивает последовательный интерфейс SIOC/SIOD, аналогичный I2C. В камере находится тьма регистров, которые нужно правильно установить – главная причина того что я не разработал код с нуля а взял за основу существующий. Впрочем, это меня не спасло – все равно пришлось вникать в мануал устройства. Если вам придется заняться тем же самым, имейте в виду что зарезервированные регистры и биты также нужно устанавливать определенным образом, и тайна великая сия есть.
Камеру можно синхронизировать внешним сигналом XCLK (мы так и делаем, формируя его в коде), тогда все что она выдает идет синхронно с ее выходом PCLK. А идут с нее байты видеоданных по шине D в сопровождении импульса кадровой синхронизации VSYNC, по которому мы сбрасываем в ноль счетчики и адреса, и еще строб наличия данных строки HREF, по которому мы разрешаем считывание данных.
Вот собственно и все. Для чего нужны пины 3v3 и GND вы наверное догадались сами.
Теперь самое время объявить хорошую новость для тех, у кого нет платы Zedboard, камеры и дисплея. Вы можете сразу начинать экспериментировать с VHDL, поскольку в Vivado есть режим симуляции. Единственное что вам понадобится дополнительно – включить в симуляцию testbench файл tb_top.vhdl, который имитирует данные с камеры. Вы можете написать свой testbench с тем чтобы посмотреть временные диаграммы как всего проекта, так и одного отдельного модуля.
Запуск Vivado, создание проекта, прошивка ПЛИС
Создайте новый RTL проект, добавьте VHDL файлы и constraints файл zedboard.xdc (ссылки в следующем разделе). Не забудьте указать в настройках проекта, что вы используете Zedboard: это важно. Добавьте также в симуляцию файл tb_top.vhdl. В результате иерархия компонентов должна выглядеть примерно таким образом:
Кстати, справа Vivado показывает нам сколько ресурсов мы заняли у ПЛИС (эти данные появятся после компиляции проекта). Видно, что мы хорошо поимели память BRAM: ее осталось всего 20%. Логических блоков LUT было использовано всего ничего – всего лишь 1%.
Обратите внимание на компоненты обозначенные квадратиками: это “библиотечные” IP блоки, специфичные для Zedboard, которые мы используем в проекте. Их мы находим в меню “IP Catalog” и настраиваем. Вам нужно немного поработать: создать три компонента из IP блоков, а именно Clock wizard и два блока памяти BRAM. Каким образом компоненты встраиваются в проект, видно из файла ov7670_top.vhd, который играет роль кросс – платы для остальных модулей, то есть является топовым модулем иерархии.
Даю настройки IP блоков, отличные от настроек по умолчанию (до двоеточия я указал название вкладки, в которой нужно изменить параметр):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
clk_wiz_0 Clocking Options: Primary clk_in_wiz=100.000 MHz Output Clocks: clk_100wiz=100Mhz, clk_75wiz=75MHz, clk_50wiz=50MHz, clk_25wiz=25MHz. Чекбоксы внизу диалога должны быть сброшены. blk_mem_gen_0 Basic: Interface Type=Native, Memory Type=Simple Dual Port Ram Port A Options: Port A Width=8, Port A Depth=307200, Enable Port Type=Always Enabled Port B Options: Port A Width=8, Enable Port Type=Always Enabled blk_mem_gen_1 Basic: Interface Type=Native, Memory Type=Simple Dual Port Ram Port A Options: Port A Width=4, Port A Depth=307200, Enable Port Type=Always Enabled Port B Options: Port A Width=4, Enable Port Type=Always Enabled |
Блоки BRAM конфигурации Simple Dual Ram имеют одинаковую “глубину” равную 307200 (640х480) и различаются только размером шины данных: в первом случае это 8 бит, соответствующие размерности данных с камеры, во втором – 4 бита, в котором кодируются все цветовые каналы VGA.
После того как вы вписали исходники в проект и подготовили IP блоки, нужно пройти этапы “компиляции”. Первый из этих этапов – Synthesis, на котором ваша схема будет связана вместе и для нее будут подобраны элементарные кирпичики FPGA – Slices and LUTs. Здесь вас ждут типичные ошибки синтаксиса (которые можно выловить раньше – редактор указывает на них сразу) и например ошибки несовпадения разрядности, когда к 8-пиновому разъему вы пытаетесь прикрутить 16-пиновый. На втором этапе Implementation будет предпринята попытка втиснуть плоды вашего творчества в ПЛИС. Если оно не помещается, Vivado скажет, какие именно ресурсы вы превысили. Следующий этап – Generation Bitstream, когда будет создаваться двоичный образ матрицы PL. Как ни странно, на этом этапе тоже могут возникнуть ошибки. Не расслабляйтесь!
И наконец если все прошло благополучно, открывайте Hardware Manager и если вы не напутали с подключением Zedboard по usb, получите возможность программирования платы. Для этого ее перемычки должны стоять именно так, как у меня на фото.
Файлы проекта
Пробежимся по модулям.
debounce.vhd это антидребезговая схема, которая запускается от кнопки платы и формирует сброс камеры. В принципе такой же сброс будет обеспечен в момент включения платы – но мало ли что. В процессе сброса на камеру отсылаются установки ее регистров. Поддержка последовательного интерфейса с камерой обеспечивает модуль i2_sender.vhd, хранение и логику формирования регистровых посылок – модуль ov7670_registers.vhd. В последний я внес соответствующие изменения, чтобы камера формировала последовательность YUV вместо RGB, чтобы получить градации серого Y.
Синхронную работу этих двух модулей обеспечивает кросс-плата нижнего уровня – модуль ov7670_controller.vhd.
Когда камера запустится и начнет работать, про все эти модули можно забыть – в обработке они участие не принимают.
Теперь вернемся к началу цепочки. Прием байтовой последовательности с камеры – задача модуля ov7670_capture.vhd. Синхронизация его работы с разверткой камеры выполняется с помощью сигналов VSYNC, HREF. Поскольку во входном потоке каждый второй байт кодирует цвет, эти байты отбрасываются и в первый блок памяти записываются только значения интенсивности Y. Таким образом, после каждого кадра в BRAM содержится байтовая картинка grayscale размером 640х480 байт.
Блоки памяти, сохраняя промежуточную информацию, также обеспечивают выравнивание работы модулей по скорости.
Модуль – заглушка cv_core.vhd читает первый блок BRAM и заполняет этими же данными второй блок, оставляя от исходных байтов только старшие четыре разряда – больше VGA не позволяет. Вот тут для вас самый простор заместить ленивую заглушку своим алгоритмом: фильтр подавления шумов Гаусса, выделение контуров, распознавания по шаблону и все что душа пожелает. Мы же в этой статье как договорились делаем упор на технику реализации, поэтому пойдем дальше.
Собственно, осталось всего ничего – модуль vga.vhd читает второй блок BRAM, устанавливает прочитанными 4 битами все каналы цветности и выдает результат на разъем VGA. В результате мы видим что снимает камера на дисплее, в черно – белом варианте.
Скачать все исходники разом можно здесь.
На ролике видно, как все это работает вживую. Главный персонаж – моя кружка, освещение – комнатное. Базовую конфигурацию мы создали, следующий шаг – обработка изображения.
До встречи в эфире!
Скоро все вычисления в “облако” перенесут. Какой-нибудь G8-модуль на борту БПЛА или “бездуховный” спутниковый OneWeb/Starlink, в самолетах будут распределенные вычисления навигации-полета-посадки на смартфонах пассажиров. Эк меня понесло 😉
Кстати, интересная мысль – скрестить облако с простаивающими процессорными мощностями смартфонов )
Ведь в самом деле, у подавляющего большинства домашних компьютеров и смартфонов нагрузка на CPU идет только в момент открытия документа или web-страницы. Вот сейчас набираю этот текст и вижу: загрузка CPU 1.8% в userspace, в системном режиме 0.8%. Жалко когда 90% с лишним ресурсов тупо простаивают! )
В свое время компания Sun продвигала идеологию: тупой терминал – производительный сервер. Однако по мере гонки за процессорные скорости и удешевления компонентов, терминалы стали слишком умными. Есть приложения которые позволяют отдать свои вычислительные емкости в пользу решения определенных вычислительных задач, но плюсы облака не только в том что большое место для хранения и высокие скорости, а еще и в том что в нем живет разнородная информация, из которой можно много чего вытащить.
Тут как раз пригодятся технологии Data Mining для поиска скрытых, заранее неизвестных закономерностей в потоке данных.
Были слухи, что кто-то на платежных терминалах биткоинов срубил (на пике цены), разные задачи от поиска внеземных цивилизаций до поиска лекарств решаются в распределенных системах (BOINC есть и для смартфонов). Банки хвастаются своими системами защиты от электронного воровства, но всяк умалчивают о слежке за клиентами на фоне доходов и расходов(т.е. доход большой, но что-то много платежей в мед. организации, надо понизить уровень доступа к кредиту и т.д.). А так, разный “мэшинг лернинг”, предикативный анализ – довольно таки модная тема. Хотя у нас в производстве пока надо просто попытаться собрать эту “биг дату”, масса информации/данных просто не пишется(очень настораживает тема ЭМС разных средств, хоть SDR-свистки на каждую частоту ставь), или пишется урезанно, если и пишется, то в закрытом формате производителя.
Данных будет все больше и больше, выгодоприобретатели тоже понятны: продавцы всего и вся, банки, госструктуры, можно принимать какие-то решения, только нет ответа на главный вопрос: что в будущем? Нет функции хорошего прогноза. Черный лебедь караулит за углом )