Инженерный тур. 3 этап
Цель заключительного этапа — создание комплексной системы автоматизированного мониторинга объектов ТЭК с использованием квадрокоптера. Это подразумевает разработку программного обеспечения, обеспечивающего контроль состояния и функционирования объектов, позволяющего выявлять утечки и разливы нефти, проводить инспекцию нефтепроводов на предмет несанкционированных врезок и определять тепловые потери в системах теплоснабжения.
Кроме того, участникам необходимо создать программный код для визуализации результатов мониторинга на карте в режиме реального времени.
Дополнительно требуется разработка автономного комплекса, обеспечивающего безопасный взлет и посадку квадрокоптера, а также его подзарядку с использованием дронпоинта, что сопровождается подготовкой соответствующей технической документации.
Эффективное наблюдение за объектами ТЭК с использованием квадрокоптера является ключом к оптимизации эксплуатационных процессов, повышению безопасности и снижению затрат. Применение современных решений в области летающей робототехники позволяет оперативно получать данные о состоянии таких объектов, как нефтепроводы и системы теплоснабжения, а также проводить детальный визуальный анализ, что способствует принятию своевременных и обоснованных решений.
Интегрированный подход значительно повышает эффективность мониторинга объектов ТЭК и обеспечивает оперативное реагирование на возможные инциденты.
Количество участников в команде: 3–4 человека.
Компетенции, которыми должны обладать члены команды:
- Инженер-программист (Python) — написание кода для автономного полета квадрокоптера, работа с сервером, разработка алгоритма безопасного полета квадрокоптера.
- Инженер-программист (С++, Python) — алгоритмы компьютерного зрения для реализации автономных миссий квадрокоптера, машинное обучение. Работа в связке с инженером-программистом.
- Инженер-техник — моделирование и изготовление устройства, тестирование, техобслуживание и пилотирование квадрокоптера, работа с технической документацией.
- Капитан/лидер команды — работа с системами построения карты в RViz, осуществление общего руководства работой команды, распределение обязанностей и контроль соблюдения дедлайнов. Рекомендуется совмещение данной роли с другими ролями.
| Наименование | Описание |
|---|---|
| Полетный полигон (\(5 \times 8 \times 3\) м) | Полигон для запуска автономных полетных миссий |
| Персональный компьютер (Intel Core i5 7260u 2.2 GHz, 8 Gb RAM) | Разработка программного кода для запуска полетной миссии |
| Ноутбук (Ryzen 5 5500u 2.1 GHz, 20 Gb RAM) | Разработка дронопорта |
| Графическая станция (Ryzen 7 1700 3.7 GHz, 16Gb RAM, GeForce GTX 1060 3Gb) | Разработка программного кода для запуска полетной миссии |
| Конструктор программируемого квадрокоптера «Клевер 4 Code» | Запуск полетных миссий |
| 3D-принтер | Печать деталей для разработанного дронопорта и крепления тепловизора |
| Тепловизор | Автономный поиск утечек тепла |
| Лазерный станок | Резка фанеры для изготовления разработанного дронопорта |
| Полетный полигон (\(4 \times 2 \times 2\) м) | Полигон для запуска тестовых автономных полетных миссий |
|
Программное обеспечение для разработки программного кода для выполнения заданной полетной миссии |
Общая конфигурация площадки приведена на рис. 5.1.
- Зона «H» является точкой взлета и точкой посадки.
- Конфигурация застройки может изменяться.
- Положение датчиков на квадрокоптере может быть изменено при необходимости.
- Миссия мониторинга должна проходить полностью в автономном режиме.
- Доступ к сети осуществляется через роутер, выданный каждой команде; также имеется подключенный к сети роутер в полетной зоне.
- Команда несет ответственность за сохранность данных при работе в сети (нестандартный пароль на Wi-Fi, нестандартный пароль для SSH на квадрокоптере).
- Везде в задании началом координат принят левый нижний угол (по рис. 5.1 и 5.2), центр ArUco-маркера. Если в задании упоминаются координаты, то подразумевается СК aruco_map, если не сказано иное.
- На площадке для выполнения задания доступны пять тепловизоров TR256i (https://mileseeytools.com/products/thermal-imaging-camera-for-phone-mileseey-tr256i): один в полетной зоне, три доступны для работы на местах, один запасной.
- Правила использования тепловизоров: тепловизоры для работы на местах доступны на 30 мин в порядке живой очереди или в порядке расположения столов, по усмотрению организаторов (правила могут быть изменены организаторами).
Поскольку на площадке используется тепловизор, в первую очередь проверим его работу и научимся с ним работать. Задание выполняется в следующем порядке:
- Произвести подключение тепловизора перед началом сбора данных.
- Получить видеопоток с тепловизора в полном объеме.
На основании сохраненного RAW-потока тепловизора, сформировать:
- термоизображения в цветовых схемах IRONBOW или JET;
- матрицу температур в градусах Цельсия, где каждая ячейка матрицы соответствует пикселю исходного термоизображения;
- матрицу температур в градусах Цельсия, где каждая ячейка матрицы соответствует пикселю исходного термоизображения.
- Опубликовать термоизображения и матрицу температур в топик (название на усмотрение участника).
Обратите внимание, что эта задача оценивается не во время зачетных полетов. Для оценки, в любое время (за исключением перерывов), подойдите к любому эксперту на площадке и попросите оценить задание 1.1.
От координационного центра теплосетей города команде поставлена задача — провести мониторинг состояния участка теплосети. На заключительном этапе используется макет участка теплосети (прямой, см. рис. 5.1) с функцией нагрева отдельных участков.
Для успешного выполнения задания необходимо:
- Выполнить взлет: совершить автономный взлет с зоны «Н».
- Осуществить полет к началу участка теплосети (координаты: (3.95, 0.4)).
Произвести сканирование участка:
- выполнить пролет вдоль участка на любой удобной высоте;
- выполнить и сохранить видео пролета с тепловизора (в цветовой схеме IRONBOW/JET) и видео с обычной камеры;
- определить координаты участка(ов) с выявленными утечками тепла (определяется тепловизором, выше 40 °C).
- Осуществить полет к концу участка теплосети (координаты: (6.45, 3.4)).
Отобразить в системе визуализации (см. 1.4):
- каждый найденный участок, привязанный к системе координат;
- список участков, содержащий координаты начала участка, координаты конца участка, максимальную температуру на данном участке.
После осуществления мониторинга теплосетей города поставлена задача — выявление незаконных врезок в нефтепровод.
Для успешного выполнения задания необходимо:
Получить информацию об узлах нефтепровода (в т. ч. начало и конец нефтепровода), а также список легальных ответвлений c сервера. Пример полученных данных:
{"nodes": [{"x": 1.0, "y": 4.0}, {"x": 5.0, "y": 6.0}, …], "tappings": [{"x": 1.0, "y": 4.0, "legal": 1}, …]}.Допустимая погрешность в координатах возможных ответвлений — 0,1 м.
JSON-файлы на сервере: http://157.180.22.113:8080/coords_1_legal.json. Кроме того, имеется возможность получить список возможных ответвлений (и легальных, и нелегальных) c сервера JSON-файлы на сервере: http://157.180.22.113:8080/coords_1.json.
Авторизация на сервере: добавить Header:
Authorization: Bearer xxx-xxx-xxx,xxx-xxx-xxx— токен, который находится на гугл диске.- Выполнить полет к началу нефтепровода.
- Осуществить полет к возможным ответвлениям, исходя из полученных с сервера данных.
- Произвести фотофиксацию нелегального ответвления, если там на самом деле совершена врезка; выделить врезку любым образом.
- Выполнить полет к концу нефтепровода.
- Автоматически сформировать отчет, включающий в себя список точек, в которых осуществлялся мониторинг, а также результат мониторинга. Отчет должен быть сформирован в формате
.txt. Пример отчета см. ниже.Tapping 1. x=1.0, y=4.0, legal=1, illegal=1 Tapping 2. x=1.0, y=4.0, legal=0, illegal=1 ... Tapping n. x=1.0, y=4.0, legal=1, illegal=0 Отобразить в системе визуализации (см. 1.4):
- нефтепровод (принять за прямую) и ответвления с привязкой к системе координат: нефтепровод должен быть желтого цвета, масштаб относительно карты ArUco-маркеров должен соответствовать реальному;
- список координат незаконных врезок с возможностью посмотреть фото врезки.
Разработать веб-приложение с графическим интерфейсом пользователя, в котором будут реализованы:
- отображение состояния систем: статус готовности дрона к полету, уровень заряда батареи в процентах, уровень заряда батареи в вольтах;
кнопки управления миссией:
- старт — запуск автономной миссии с начала,
- стоп1 — прерывание кода, остановка в воздухе (без посадки),
killswitch2 — прерывание кода, дизарм дрона (кнопка активна в любой момент работы web-приложения),home— возврат квадрокоптера в зону взлета/посадки и выполнение посадки,land— посадка в текущей точке, в процессе осуществления автономной миссии посадка доступна после нажатия кнопки стоп/прерывания кода;
автоматически обновляемая 2D-карта:
- фон-карта ArUco-маркеров из топика
aruco_map/imageс отображением начала координат, - вывод объектов распознавания (требуемых в заданиях 1.2 и 1.3) с привязкой к системе координат
aruco-map, - список участков, содержащий координаты начала участка, координаты конца участка, максимальную температуру на данном участке (для задания 1.2),
- список координат незаконных врезок (для задания 1.3).
- фон-карта ArUco-маркеров из топика
Команда вправе сама выбирать как используемые библиотеки и фреймворки, так и то, где хостить веб-приложение (ПК или квадрокоптер) и делать выбор между собственным бэкендом или готовым адаптером к ROS.
Напоминаем, что участники должны загрузить код зачетной попытки с комментариями на GitHub за 10 мин до начала зачетных полетов.
В задании присутствуют требования визуализации некоторых частей полигона. Порядок оценки визуализации:
- Для оценивания визуализации на зачетной попытке команде необходимо представить экспертам компьютер с открытой системой визуализации.
- В визуализации должны присутствовать отображения начала системы координат
aruco_map. - По требованию экспертов участники быть готовыми (иметь настроенное для этого ПО, например, OBS) запустить запись экрана в начале зачетных полетов команды.
- По окончании полета все визуализированные элементы должны остаться на своих местах.
Конструкторское задание включает разработку двух устройств, расширяющих функционал квадрокоптера, и инфраструктуры, позволяющей ему выполнять задачи по наблюдению за объектами ТЭК.
Наименование выполняемых работ
Разработка крепления инфракрасной камеры TR256i на квадрокоптер.
Цель выполнения работ
Установить датчик, позволяющий квадрокоптеру определять тепловые потери системы теплоснабжения.
Срок выполнения работы
Документация и создание устройства: три рабочих дня, с 01.04.2025 г. по 03.04.2025 г. 19.00.
Требования к устройству:
- Устанавливаться на квадрокоптер COEX Clever 4 без доработки конструкции углепластиковой рамы. (Изменение конструкции защиты пропеллеров возможна в случае сохранения ее защитных свойств). Доработкой является нарушение целостности материала конструкции.
- Быстрая установка тепловизионной камеры (10 с установка и подключение (физическое), 10 с отключение (физическое) и съем).
- Кронштейн должен надежно крепить тепловизионную камеру исключая возможность отключения и отсоединения во время полета, транспортировки и при падениях квадрокоптера.
Требования к документации:
- 3D-модель устройства в сборке (
.stepи исходный формат программы). - В случае если кронштейн представляет собой одну деталь — чертеж детали.
В случае если кронштейн является сборной конструкцией — сборочный чертеж.
Список крепежа, необходимого для установки кронштейна на квадрокоптер, нужно указать на чертеже/сборочном чертеже.
- 3D-модель устройства в сборке (
Техническое задание
Наименование выполняемых работ
Разработка дронпорта — устройства для безопасного взлета, посадки и подзарядки квадрокоптера.
Цель выполнения работ
Создание устройства для осуществления безопасного взлета, посадки и подзарядки квадрокоптера с интеграцией всех необходимых функций и соблюдением требований безопасности.
Срок выполнения работ
- Документация и создание устройства: три рабочих дня, с 01.04.2025 г. по 03.04.2025 г. 19.00.
- Демонстрация работоспособности прототипа устройства: с 13:30 04.04.2025 г., в 12:20 разработанное устройство сдается на карантин.
- Финальное испытание устройства: выполнение зачетного полета 04.04.2025 г.
Требования к устройству:
- Взлет и посадка квадрокоптера: обеспечение безопасности взлета и посадки квадрокоптера.
- Безопасность: обеспечение безопасности операций с квадрокоптером, включая защиту от несанкционированного доступа и вмешательства. Квадрокоптер должен быть защищен от внешнего воздействия со всех сторон.
- Сигнализирование о нахождении квадрокоптера внутри устройства.
- Сигнализирование об открытии устройства для совершения взлета и посадки квадрокоптера.
- Сигнализирование о закрытии устройства после совершения взлета и посадки.
- Сигнализирование об осуществлении подзарядки квадрокоптера. Считается, что дрон заряжается в случае, если он находится внутри закрытого дронпорта более 5 с.
- Устройство должно быть единым (все датчики и механическая часть должны быть интегрированы в данное устройство).
- Максимальные габариты устройства в закрытом состоянии: \(800 \times 800 \times 800\) мм.
- Все вышеперечисленные функции должны выполняться в автономном режиме.
- Сигнализация на устройстве должна быть реализована при помощи при адресной светодиодной матрицы/светодиодной ленты.
Требования к документации:
- 3D-модель устройства в сборке (
.stepи исходный формат программы). Сборочный чертеж устройства, оформленный согласно ГОСТ 2.109-73: https://dgng.pstu.ru/sprav/10.4.htm:
- отображение всех деталей и стандартных изделий;
- количество изображений должно быть наименьшим, но достаточным для представления расположения и взаимной связи составных частей и обеспечивающим возможность осуществления сборки и контроля сборки.
Спецификация, оформленная согласно ГОСТ 2.109-73: https://dgng.pstu.ru/sprav/10.4.htm:
- наличие всех деталей;
- наличие стандартных изделий.
Инструкция по сборке устройства (все пункты относятся как к сборке механической части устройства, так и электрической):
- список всех компонентов и материалов, необходимых для сборки устройства;
- последовательное описание шагов сборки, начиная с подготовки рабочего места и инструментов;
- иллюстрации или схемы, помогающие понять процесс сборки;
- подробное описание каждого шага с указанием порядка действий и возможных трудностей;
- инструкции по проверке правильности сборки и испытания устройства;
- рекомендации по безопасности при работе с материалами и инструментами.
Инструкция по эксплуатации устройства:
- описание устройства: общие характеристики, назначение, особенности конструкции;
- инструкции по началу эксплуатации: правила подключения, настройки и первоначального запуска;
- рекомендации по использованию и безопасности: ограничения по применению, рекомендации по уходу и обслуживанию, предупреждения о потенциальных опасностях, правила безопасного использования изделия;
- программный код, необходимый для эксплуатации устройства.
- 3D-модель устройства в сборке (
| № п.п | Наименование | Формат |
|---|---|---|
| Кронштейн тепловизионной камеры | ||
| 1 | 3D-модель функционального устройства в сборке | .step и проприетарный формат |
| 2 | Чертеж/сборочный чертеж кронштейна | .pdf |
| Дронпорт | ||
| 1 | 3D-модель функционального устройства в сборке | .step и проприетарный формат |
| 2 | Сборочный чертеж устройства | .pdf |
| 3 | Спецификация | .pdf |
| 4 | Инструкция по сборке устройства | .pdf |
| 5 | Инструкция по эксплуатации устройства | .pdf |
Во время демонстрации экспертами проверяется соответствие устройства требованиям из п. 4.
Финальное испытание устройства (дронпорта)
Финальное испытание устройства проходит во время выполнения финальной зачетной миссии. Оценка результатов происходит только в тех случаях, если все составляющие итогового результата:
- предоставлены организаторам не позднее указанного срока;
- все разработанные материалы и само устройство соответствуют техническому заданию.
Оценка результатов происходит только в тех случаях, если все составляющие итогового результата:
- предоставлены организаторам не позднее указанного срока;
- все разработанные материалы и само устройство соответствуют техническому заданию.
Во время инженерного тура участники получают баллы за выполнение зачетных миссий согласно критериям оценки успешности прохождения миссии.
Максимальный балл за инженерный тур составляет 100 баллов.
Оценка инженерного задания разделена на две части:
- оценка работоспособности разработанного устройства (проверяется непосредственно во время проведения зачетной миссии);
- оценка технической документации разработанного устройства и его соответствие техническому заданию.
Определение команды-победителя в заключительном этапе проводится по результатам суммы баллов за зачетные попытки и инженерную часть. Оценка результатов зачетных испытаний происходит после окончания последней зачетной попытки. При несоблюдении правил приема результатов за каждое отдельное нарушение снимаются от 30% до 70% баллов. С команды снимаются 20 баллов (за каждое нарушение), на усмотрение организатора, в случаях:
- препятствования работе других команд, разработчиков и организаторов;
- употребления ненормативной лексики;
- агрессивного поведения (этически ненормированного);
- осуществления запуска квадрокоптера без предупреждения оператора и организаторов;
- нарушений техники безопасности при эксплуатации оборудования (квадрокоптер, 3D-принтер, лазерный станок и т. д.), в случае грубого нарушения участник может быть дисквалифицирован.
| № | Критерий | Баллы за один случай | Количество случаев* | Баллы за все случаи |
|---|---|---|---|---|
| 1. Подготовка к полету и взлет | ||||
| 1.1 | Соблюдение техники безопасности. По умолчанию полный балл — 0,1. За случай:
|
0,7 | — | 0,7 |
| 1.2 | Выполнилась функция сигнализирования** об открытии устройства перед совершением взлета квадрокоптера. Функция может осуществляться только в автономном режиме. |
0,6 | 1 | 0,6 |
| 1.3 | Крышка дронпорта открывается перед осуществлением взлета в режиме:
Нахождение участников в полетной зоне во время попыток строго запрещено. |
1 | 1 | 1 |
| 1.4 | Совершен автономный взлет из дронпорта (с дронпорта 20 %/ с зоны «Н» 10%). | 1 | 1 | 1 |
| 1.5 | Крышка дронпорта закрывается после осуществлением взлета:
Нахождение участников в полетной зоне во время попыток строго запрещено. |
1 | 1 | 1 |
| 1.6 | Выполнилась функция сигнализирования** о закрытии устройства после совершения взлета квадрокоптера. Функция может осуществляться только в автономном режиме. |
0,6 | 1 | 0,6 |
| 2. Определение тепловых потерь системы теплоснабжения | ||||
| 2.1 | Выполнен полет к началу участка теплосети. | 0,1 | 1 | 0,1 |
| 2.2 | Выполнена запись видео пролета над участком теплосети (с тепловизора). | 1,5 | 1 | 1,5 |
| 2.3 | Выполнена запись видео пролета над участком теплосети (с камеры). | 0,5 | 1 | 0,5 |
| 2.4 | Верно определены координаты начала участка теплопотерь; возможная погрешность 0,25 м по каждой оси. | 3 | — | 3 |
| 2.5 | Верно определены координаты конца участка теплопотерь; возможная погрешность 0,25 м по каждой оси. | 3 | — | 3 |
| 2.6 | Определена максимальная температура каждого участка теплопотерь. | 2 | — | 2 |
| 2.7 | Выполнен полет к концу трубы. | 0,1 | 1 | 0,1 |
| 3. Наблюдение за безопасностью нефтепровода | ||||
| 3.1 | Данные с сервера получены. | 0,5 | 1 | 0,5 |
| 3.2 | Данные с сервера получены (только список легальных ответвлений). Балл выставляется только в случае хотя бы вывода одной корректной нелегальной врезки (критерий 3.3) и отсутствия запросов к |
2 | 1 | 2 |
| 3.3 | Выполнен полет к началу нефтепровода. | 0,4 | 1 | 0,4 |
| 3.4 | Выведен список координат незаконных врезок, врезки определены корректно; возможная погрешность 0,25 м по каждой оси. В случае если выведенное количество врезок в списке превышает реальное количество, за каждую лишнюю врезку — 0,3 балла. |
3 | — | 3 |
| 3.5 | Получена фотография незаконной врезки в нефтепровод. | 0,5 | — | 0,5 |
| 3.6 | Получена фотография незаконной врезки в нефтепровод с ее выделением. | 2 | — | 2 |
| 4. Разработка веб-приложения | ||||
| 4.1 | Реализовано отображение уровня батареи в процентах. | 0,15 | 1 | 0,15 |
| 4.2 | Реализовано отображение уровня батареи в вольтах. | 0,1 | 1 | 0,1 |
| 4.3 | Реализована и функционирует кнопка запуска миссии «старт». | 0,3 | 1 | 0,3 |
| 4.4 | Реализована и функционирует кнопка остановки миссии «стоп». Проверка работоспособности осуществляется во время тестовых полетов. |
0,3 | 1 | 0,3 |
| 4.5 | Реализована и функционирует кнопка экстренного отключения Проверка работоспособности осуществляется во время тестовых полетов. |
0,3 | 1 | 0,3 |
| 4.6 | Реализована и функционирует кнопка посадки land. |
0,3 | 1 | 0,3 |
| 4.6 | Реализована и функционирует кнопка прерывания миссии и возврата в точку взлета home. |
0,3 | 1 | 0,3 |
| Уровень батареи и кнопки не проверяются и устанавливается максимальный балл, если в предыдущие дни за эту кнопку получен максимальный балл. | ||||
| 4.7 | Автоматически обновляемая 2D-карта: фон-карта ArUco-маркеров из топика aruco_map/image с отображением начала координат. |
0,2 | 1 | 0,2 |
| 4.8 | Автоматически обновляемая 2D-карта: вывод распознаваемых участков из задания 1.2 с привязкой к системе координат aruco-map. |
0,5 | — | 0,5 |
| 4.10 | Отображение списка участков, содержащего координаты начала участка, координаты конца участка, максимальную температуру на данном участке из задания 1.2. | 0,5 | — | 0,5 |
| 4.11 | Автоматически обновляемая 2D-карта: вывод нефтепровода и врезок (цвет отображен корректно) из задания 1.3 с привязкой к системе координат aruco- map. | 0,5 | — | 0,5 |
| 4.12 | Отображение списка врезок, содержащего координаты из задания 1.3. | 0,5 | — | 0,5 |
| 5. Посадка: оценивается во время полета | ||||
| 5.1 | Осуществлена посадка квадрокоптера:
|
2 | — | 2 |
| 5.2 | Выполнилась функция сигнализирования** об открытии устройства перед совершением посадки квадрокоптера. Функция может осуществляться только в автономном режиме. |
0,6 | 1 | 0,6 |
| 5.3 | Крышка дронпорта открывается перед осуществлением посадки:
Нахождение участников в полетной зоне во время попыток строго запрещено. |
1 | 1 | 1 |
| 5.4 | Выполнилась функция сигнализирования** о закрытии устройства после совершения посадки квадрокоптера. Функция может осуществляться только в автономном режиме. |
0,6 | 1 | 0,6 |
| 5.5 | Крышка дронпорта закрывается после осуществлением посадки:
Нахождение участников в полетной зоне во время попыток строго запрещено. |
1 | 1 | 1 |
| 5.6 | Выполнилась функция сигнализирования** о нахождении квадрокоптера внутри устройства. Функция может осуществляться только в автономном режиме. |
0,6 | 1 | 0,6 |
| 5.7 | Выполнилась сигнализация осуществления подзарядки квадрокоптера в дронпорте. Функция может осуществляется только в автоматическом режиме. |
0,6 | 1 | 0,6 |
| 6. Оценка результата | ||||
| 6.1 | Код зачетной попытки с комментариями выложен на Github. | 0,5 | 1 | 0,5 |
| 6.2 | В программе присутствует логика считывания данных с датчика (любого) или алгоритм компьютерного зрения. | 0,5 | 1 | 0,5 |
| 6.3 | В присутствует логика считывания температуры с тепловизора. | 1 | 1 | 1 |
| 6.4 | В форму для участников не позднее завершения финальных зачетных попыток отправлен отчет, содержащий:
|
Как при отсутствии итогового отчета от команды, так и при непредоставлении итогового отчета в положенный срок — взимается 70% баллов от суммы полученных баллов за все 3 зачетных попытки. | ||
| Итого за решение задачи | 34,85 | |||
*Примечания
**Сигнализирование дронпорта:
- функция реализована при помощи светодиодов — 50% баллов;
- функция реализована при помощи светодиодной ленты — 80% баллов;
- функция реализована при помощи светодиодной LED-матрица — 100% баллов.
Количество случаев может варьироваться. В случае изменения количества баллы за все случаи делятся на их количество. При «—» общее количество случаев неизвестно, баллы за все случаи делятся на их количество.
| № | Критерии | Баллы |
|---|---|---|
| Кронштейн тепловизионной камеры | ||
| 1. 3D-модель функционального устройства в сборке | ||
| 1.1 | Оригинальное инженерное решение. | 1,25 |
| 1.2 | Наличие 3D-модели. | 0,25 |
| 1.3 | Заданы материалы деталей. | 0,25 |
2. Сборочный чертеж устройства (если кронштейн является сборной конструкцией) 2.*Чертеж детали (если кронштейн является деталью) Проверяется только в случае соответствия ГОСТ 2.109-73. |
||
| 2.1 | Количество изображений достаточно для представления расположения и взаимной связи составных частей и обеспечивает возможность осуществления сборки и контроля сборки. Пронумерованы детали. *Присутствуют все необходимые элементы оформления чертежа. |
0,75 |
| 2.2 | Указаны все габаритные размеры и все размеры присоединений. *Указаны все необходимые размеры. |
0,5 |
| Дронпорт | ||
| 1. 3D-модель функционального устройства в сборке | ||
| 1.1 | Оригинальное инженерное решение. | 0,5 |
| 1.2 | Наличие 3D-модели. | 0,5 |
| 1.3 | Наличие всех элементов устройства в соответствии с документацией (спецификация, сборочный чертеж, инструкция по сборке). | 1 |
| 1.4 | Заданы материалы деталей. | 0,25 |
| 1.5 | Деталям задана цветовая палитра позволяющая лучше читать сборку (сопрягаемые детали имеют различную цветовую палитру). | 0,25 |
2. Сборочный чертеж устройства Проверяется только в случае соответствия ГОСТ 2.109-73. |
||
| 2.1 | Отображены все детали и их нумерация. | 0,75 |
| 2.2 | Отображены все стандартные изделия и их нумерация. | 0,75 |
| 2.3 | Количество изображений достаточно для представления расположения и взаимной связи составных частей и обеспечивает возможность осуществления сборки и контроля сборки. | 0,75 |
| 2.4 | Указаны все габаритные размеры и все размеры присоединений. | 0,5 |
3. Спецификация Проверяется только в случае соответствия ГОСТ 2.109-73. |
||
| 3.1 | Наличие всех деталей (в соответствии со сборочным чертежом). | 1 |
| 3.2 | Наличие стандартных изделий (в соответствии со сборочным чертежом). | 1 |
| 4. Инструкция по сборке устройства | ||
| 4.1 | Наличие списка всех компонентов и материалов, необходимых для сборки устройства. | 0,5 |
| 4.2 | Наличие последовательного описания шагов сборки, начиная с подготовки рабочего места и инструментов. | 0,5 |
| 4.3 | Наличие иллюстраций и/или схемы, помогающих понять процесс сборки. | 0,5 |
| 4.4 | Наличие подробного описания каждого шага с указанием порядка действий и возможных трудностей. | 0,5 |
| 4.5 | Наличие инструкций по проверке правильности сборки и испытания устройства. | 0,25 |
| 4.6 | Наличие рекомендаций по безопасности при работе с материалами и инструментами. | 0,25 |
| 5. Инструкция по эксплуатации устройства | ||
| 5.1 | Наличие описания устройства: общих характеристик, назначения, особенности конструкции. | 0,5 |
| 5.2 | Наличие инструкции по началу эксплуатации: правила подключения, настройки и первоначального запуска. | 0,5 |
| 5.3 | Наличие рекомендаций по использованию и безопасности: ограничения по применению, рекомендации по уходу и обслуживанию, предупреждения о потенциальных опасностях, правила безопасного использования изделия. | 0,75 |
| 5.4 | Наличие программного кода, необходимого для эксплуатации устройства. | 0,5 |
| Итого за решение задачи | 15 | |
| № | Критерии | Баллы |
|---|---|---|
| Кронштейн тепловизионной камеры | ||
| 1. Функциональные возможности | ||
| 1.1 | Установка кронштейна на квадрокоптер не требует существенной доработки конструкции. | 0,2 |
| 1.2 | Наличие фиксатора предохраняющего от отсоединения камеры при падениях. | 0,2 |
| 1.3 | Время установки и подключения менее 10 с. Если время более 20 с, то баллы за п. 1 не выставляются. |
0,4 |
| 1.4 | Время отключения и съема менее 10 с. Если время более 20 с, то баллы за п. 1 не выставляются. |
0,4 |
| Дронпорт | ||
| 2. Функциональные возможности | ||
| 2.1 | Квадрокоптер может осуществлять функцию взлета с устройства. | 0,25 |
| 2.2 | Квадрокоптер может осуществлять функцию посадки в/на устройство. | 0,25 |
| 2.3 | Безопасность:
|
1,75 |
| 2.4 | Устройство является цельным (все датчики и механическая часть интегрированы в устройство). | 1 |
| 2.5 | Надежность конструкции:
|
0,75 |
| 2.6 | Правильно выполнен кабель-менеджмент:
|
0,75 |
| 2.7 |
|
3 |
| 2.8 | Устройство позволяет осуществлять функцию открытия и закрытия одной из поверхностей устройства для осуществления взлета и посадки квадрокоптера внутрь устройства. Использование механической силы участников запрещено. |
2 |
| 2.9 | Наличие центрирования квадрокоптера внутри устройства. Использование механической силы участников запрещено. |
1,5 |
3. Сигнализирование статусов дронпорта Способ отображения сигнализирования:
|
||
| 3.1 | Выполняется функция сигнализирования о нахождении квадрокоптера внутри устройства. | 0,75 |
| 3.2 | Выполняется функция сигнализирования об открытии устройства перед совершением взлета квадрокоптера. | 0,75 |
| 3.3 | Выполняется функция сигнализирования о закрытии устройства после совершения взлета квадрокоптера. | 0,75 |
| 3.4 | Выполняется функция сигнализирования об открытии устройства перед совершением посадки квадрокоптера. | 0,75 |
| 3.5 | Выполняется функция сигнализирования о закрытии устройства после совершения посадки квадрокоптера. | 0,75 |
| 3.6 | Выполняется функция сигнализирования об осуществлении подзарядки квадрокоптера. В случае отображения данной сигнализации сигнализация о нахождении квадрокоптера внутри устройства не требуется. |
0,75 |
| 3.7 | Оригинальность | 1 |
| Итого за решение задачи | 17,95 | |
Работа с квадрокоптером
Первым шагом при получении квадрокоптера является его тщательная проверка и подготовка к работе, которую можно разделить на следующие этапы:
- Выполнение калибровки датчиков квадрокоптера (например, компаса и гироскопа) согласно рекомендациям производителя.
- Настройка карты ArUco-маркеров в соответствии с реальным полем на площадке.
- Подтверждение того, что все системы квадрокоптера (включая полетный контроллер, Raspberry Pi, камеру, систему навигации по ArUco-маркерам) работают исправно. Для этого можно воспользоваться инструментом
self-check, согласно инструкции на сайте https://clover.coex.tech/ru/selfcheck.html; а такжеweb video server, который позволяет выполнить визуальную проверку.
Для успешного выполнения задания по подключению и настройке тепловизора сначала необходимо изучить несколько важных моментов. Рекомендуется начать с поиска информации по следующим вопросам:
- Работа с видеопотоком тепловизора — ознакомиться с примерами получения и обработки видеопотока (обычно это RAW-данные, которые необходимо конвертировать для визуализации).
- Преобразование RAW-данных в температуру — изучить документацию на тепловизор: какие формулы необходимы для пересчета «сырых» значений пикселей в физические температуры в градусах Цельсия.
- Преобразование в цветовые схемы — найти методы визуализации термальных изображений в цветовых палитрах JET или IRONBOW (могут быть готовые функции в OpenCV, matplotlib и других библиотеках).
Для поиска этого достаточно сделать запрос в поисковую систему:
- tr256i linux;
- tr256i github;
- tr256i code.
При поиске информации по этим темам рекомендуется обратить внимание на полезные ресурсы:
- Gist на GitHub (https://gist.github.com/marcelrv/e81253c14053bcd78753554df1230dd3), содержащий ссылки на готовые решения;
- тред о похожем тепловизоре на форуме (https://www.eevblog.com/forum/thermal-imaging/infiray-and-their-p2-pro-discussion/200/), содержащий опыт reverse-инжиниринга тепловизора такого типа.
После изучения найденных источников, а также тестирования нескольких готовых решений, приходим к выводу, что код, представленный в репозитории https://github.com/leswright1977/PyThermalCamera, хорошо работает с используемым тепловизором.
При изучении кода и/или треда на форуме, извлекаем полезную информацию о формате данных, получаемых с тепловизора.
Тепловизор TR256i выдает видеоформат yuyv422, разрешение \(256 \times 384\), в котором:
- Верхняя половина кадра (256 \(\times\) 192) содержит нормализованное 8-битное градационное изображение, предобработанное камерой, обеспечивая черно-белый вид. Для перевода верхней половины кадра (8-битного черно-белого изображения, полученного с тепловизора) в цветовую схему JET достаточно воспользоваться следующей строкой на языке Python с использованием библиотеки OpenCV: Python
cv2.applyColorMap(gray_image, cv2.COLORMAP_JET)Здесь
gray_image— этоnumpy-массив, содержащий 8-битное изображение, а результатом будет изображение с наложенной цветовой картой JET, что позволяет визуально выделить диапазоны температур в привычной палитре от синего к красному. Однако для получения матрицы температур, верхней матрицы недостаточно из-за того, что она содержит уже предобработанные цветовые значения. Нижняя половина кадра (256 \(\times\) 192) содержит данные температуры напрямую в Кельвинах. Они представлены 14 битами, смещенными в старшие биты, и умноженными на коэффициент 16. Для приближенного перевода значений из нижней половины кадра в градусы Цельсия можно применить формулу: \[T(x) \approx \frac{x}{64} - 273{,}15.\]
Это необходимо сделать с каждым пикселем. Удобнее всего применить формулу ко всему массиву сразу с помощьюnumpy(см. ниже).Python# thermal_raw — numpy-массив размера (192, 256) с 14-битными температурными значениями temperature_celsius = (thermal_raw / 64) - 273.15
Для тесной интеграции с ROS рекомендуется вынести этот процесс в отдельную ROS-ноду, чтобы можно было извне получать доступ к топикам обработанных данных — см. ниже.
import rospy
from cv_bridge import CvBridge
from sensor_msgs.msg import Image
import cv2
import numpy as np
# 1. Инициализация ноды и паблишеров
rospy.init_node('thermal')
pub_raw = rospy.Publisher('/thermal/img_raw', Image, queue_size=1)
pub_jet = rospy.Publisher('/thermal/img_jet', Image, queue_size=1)
pub_celsius = rospy.Publisher('/thermal/celsius', Image, queue_size=1)
# 2. Открываем видеопоток с камеры (ID может отличаться)
cap = cv2.VideoCapture(1)
# Отключаем встроенную конвертацию в RGB — нам нужны сырые данные
cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)
bridge = CvBridge()
rate = rospy.Rate(30)
while not rospy.is_shutdown():
ok, img_raw = cap.read()
if not ok:
rospy.logwarn("Не удалось получить кадр с тепловизора")
rate.sleep()
continue
# 3. Преобразуем в одномерный массив и затем в 16-битную матрицу (384×256)
img_raw = img_raw.flatten()
img16 = img_raw.view(dtype=np.uint16).reshape((384, 256))
# 4. Делим на верхнюю (визуализация) и нижнюю (сырые температуры) половины
img_vis, img_th = np.array_split(img16, 2)
# Верхняя половина: уже нормированная 8-бит ч/б картинка
img_vis = img_vis.astype(np.uint8)
# Нижняя половина: 14-бит данные, смещённые в старшие биты и умноженные на 16
kelvins = temp_raw / 64.0
celsius = kelvins - 273.15
# Чтобы отправить в виде 8-битного изображения, нормируем и обрезаем диапазон 0–255
celsius_img = np.clip(celsius, 0, 255).astype(np.uint8)
# 5. Строим JET-карту по верхнему изображению
img_jet = cv2.applyColorMap(img_vis, cv2.COLORMAP_JET)
# 6. Публикуем результаты
pub_raw.publish(bridge.cv2_to_imgmsg(img_vis, encoding="mono8"))
pub_jet.publish(bridge.cv2_to_imgmsg(img_jet, encoding="bgr8"))
pub_celsius.publish(bridge.cv2_to_imgmsg(celsius_img, encoding="mono8"))
# 7. Логгируем средние и максимальные температуры для отладки
rospy.loginfo(f"Средняя t: {celsius.mean():.2f} °C, макс t: {celsius.max():.2f} °C")
rate.sleep()
cap.release()
В задании используется топик типа sensor_msgs/Image для публикации матрицы температур, потому что Image — это стандартный формат ROS для передачи двумерных массивов данных, и его удобно обрабатывать с помощью существующих инструментов ROS (например, визуализировать через rqt_image_view, записывать в rosbag или быстро преобразовывать в numpy-массив через cv_bridge). Это позволяет легко интегрировать матрицу температур в ROS-инфраструктуру и применить стандартные средства для дальнейшего анализа или визуализации.
Взлет и полет к точке выполняются стандартными функциями квадрокоптера Clover. После прибытия в начальную точку обследуемого участка запускается одновременная запись видео с тепловизора (в цветовой палитре JET) и с обычной камеры, чтобы зафиксировать весь маршрут пролета для последующего анализа.
Для выполнения записи рекомендуется использовать встроенный функционал OpenCV — VideoWriter.
Большинство современных контейнеров для хранения видеофайлов требуют корректного завершения записи (вызова release у VideoWriter/OpenCV, close у ffmpeg и т. п.), чтобы записать служебную информацию в шапку файла, закрыть потоки, вычислить индексы и т. д.
Для надежной работы важно корректно завершать работу с VideoWriter с помощью метода .release(), причем делать это даже в случае возникновения исключений. Для этого чаще всего используют конструкции try...finally.
Аналог структуры try...finally можно реализовать с помощью менеджеров контекста (см. ниже).
import contextlib
@contextlib.contextmanager
def safe_video_writer(*args, **kwargs):
out = cv2.VideoWriter(*args, **kwargs)
try:
yield out
finally:
out.release()
# Использование:
with safe_video_writer('result.mp4', fourcc, 30.0, (640, 480)) as out:
out.write(frame)
# и т.д.
Рекомендуется использовать контейнер AVI с кодеком MJPEG, который считается более устойчивым при записи данных в полевых условиях или нестабильных системах, что особенно актуально для задач, где важна сохранность даже частично записанной информации. В такой связке OpenCV сразу пишет кадры как набор RIFF-чанков с индексами внутри данных, а не откладывает всю таблицу оглавления до закрытия файла. Если код аварийно завершится, плееры все равно смогут воспроизвести записанную часть, а индекс легко восстановить при открытии.
Пример записи в AVI с использованием MJPG см. ниже.
fourcc = cv2.VideoWriter_fourcc(*'MJPG') # Кодек для AVI (можно попробовать 'MJPG')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (frame_width, frame_height))
Далее дрон равномерно движется вдоль макета трубы с заданной невысокой скоростью, чтобы обеспечить детальное сканирование всей поверхности. Во время пролета происходит покадровый анализ теплового изображения: из каждой тепловой карты выделяются области с температурой выше 40 °C.
Для определения координат границ участков теплопотерь может использоваться как простая система с детекцией по маске, выравнивания к нему по двухосевому (\(x\) и \(y\)) ПИД-регулятору и получение текущих координат дрона или более сложная с использованием геометрии изображения с камеры (см. https://waksoft.susu.ru/2020/02/23/geometriya-formirovaniya-izobrazhenij/), однако этот метод имеет сложности при работе с тепловизором, поскольку для него отсутствует матрица калибровки.
Примерный код выполнения полета вдоль трубы и определения точек участка теплопотерь см. ниже.
DIFF = 1.25 # отношение размеров термо к камере
camera_model = image_geometry.PinholeCameraModel()
camera_model.fromCameraInfo(rospy.wait_for_message('main_camera/camera_info', CameraInfo))
def img_xy_to_point(xy, dist):
xy_rect = camera_model.rectifyPoint(xy)
ray = camera_model.projectPixelTo3dRay(xy_rect)
return Point(x=ray[0] * dist, y=ray[1] * dist, z=dist)
# Трансформирование точки с помощью tf2 из координат камеры в координаты на aruco_map
def transform_point(x, y, z, data):
xy3d = img_xy_to_point((x, y), z)
target = PointStamped(header=data.header, point=xy3d)
return tf_buffer.transform(target, "aruco_map", timeout=rospy.Duration(0.2))
# Проекция точки на перпендикуляр к отрезку
def perpendicular_project(start, end, point):
x1, y1 = start
x2, y2 = end
px, py = point
# Вектор AB
ab_x = x2 - x1
ab_y = y2 - y1
# Вектор AP
ap_x = px - x1
ap_y = py - y1
# Скалярное произведение AP и AB
dot_product = ap_x * ab_x + ap_y * ab_y
ab_length_sq = ab_x ** 2 + ab_y ** 2
# Если отрезок вырожден (точки совпадают)
if ab_length_sq == 0:
return (x1, y1)
# Параметр t для проекции
t = dot_product / ab_length_sq
t = max(0, min(1, t)) # Ограничение t между 0 и 1
# Находим проекцию точки на отрезок
qx = x1 + t * ab_x
qy = y1 + t * ab_y
return (qx, qy)
res = navigate(x=PIPE_END[0], y=PIPE_END[1], z=1, yaw=math.pi / 2, speed=0.25, frame_id='aruco_map', auto_arm=False)
while not rospy.is_shutdown():
img, img_data = get_image()
out.write(img)
jet, _ = get_jet()
out_jet.write(jet)
cels, _ = get_celsius()
mx = int(cels.max())
max_tmp.publish(String(str(mx)))
telem = get_telemetry(frame_id='navigate_target')
if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < 0.2:
break
telem_jet = get_telemetry(frame_id='aruco_map')
cels_mask = cv2.inRange(cels, 40, 255)
pts_resp = []
P = list(np.argwhere(jet_mask != 0))[::300]
for p in P:
PX, PY = int(p[0] * DIFF), int(p[1] * DIFF)
pt = transform_point(PX, PY, telem_jet.z, img_data)
pts_resp.append(list(perpendicular_project(PIPE_START, PIPE_END, (pt.point.x, pt.point.y))))
metal_pts.publish(String(json.dumps(pts_resp)))
print(f"still going..., pushed array of {len(pts_resp)} points and {mx} max temp")
rospy.sleep(0.05)
Первым этапом решения этой подзадачи является получение данных с сервера.
pipe_data = requests.get("http://157.180.22.113:8080/coords_1.json", headers={"Authorization": "Bearer xxx-xxx-xxx"}).json()
В случае получения данных обо всех возможных врезках остается только выполнить полет по точкам возможных врезок и проверить каждую точку, не помеченную как законную, на наличие врезки.
Поскольку труба является прямой, пролет вдоль нее является тривиальной задачей.
Рассмотрим подробнее алгоритм автоматического обнаружение врезки по изображению с камеры, который может быть выполнен с помощью анализа цвета и геометрии выявленных областей:
- Изображение преобразуется в цветовое пространство HSV для более устойчивого выделения нужных цветов.
- Среди найденных на изображении контуров ищется контур характерного желтого цвета (цвет трубы).
- Вокруг предполагаемого центра врезки строится вырезанный фрагмент (предполагается, что труба всегда находится в центре кадра), к которому применяется цветовая маска, выделяющая интересующий оттенок.
- Чтобы убрать небольшие шумы, маска изображения дополнительно обрабатывается эрозией.
На полученной маске снова ищутся контуры; если таковые есть, выбирается наиболее крупный. Для этого контура вычисляется минимальный ограничивающий прямоугольник и его площадь, а также площадь найденного контура. Критерием выделения врезки служит то, что реальная площадь контура значительно меньше площади описывающего прямоугольника (отношение меньше 0,6).
В случае получения данных с сервера только о законных врезках, данный алгоритм следует применять на каждой точке во время пролета вдоль трубы.
yellow = ((20, 70, 80), (40, 255, 255))
def find_contours(img, color):
c = []
img_mask = cv2.inRange(img, color[0], color[1])
contours, _ = cv2.findContours(img_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in contours:
area = cv2.contourArea(i)
if area < 100:
continue
else:
c.append(i)
return c
def get_counter(cnts):
centers = []
contours = cnts
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 100:
moments = cv2.moments(cnt)
try:
x = int(moments['m10'] / moments['m00'])
y = int(moments['m01'] / moments['m00'])
centers.append((x, y))
except ZeroDivisionError:
return centers
return centers
def vrez(img) -> bool:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cnts = find_contours(hsv, yellow)
c = get_counter(cnts)
cropped = hsv[(c[0][1] - 30) :(c[0][1] + 30) ,(c[0][0] - 30) :(c[0][0] + 30)]
colors_mask = cv2.inRange(cropped, yellow[0], yellow[1])
colors_mask = cv2.erode(colors_mask, np.array(
[[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0]],
dtype=np.uint8)
)
cnts, _ = cv2.findContours(colors_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not cnts:
return False, None
cnt = max(cnts, key=cv2.contourArea)
(_, _), (w, h), _ = cv2.minAreaRect(cnt)
rect_area = w * h
cnt_area = cv2.contourArea(cnt)
r = (1 - cnt_area / rect_area)
if (r > 0.4):
return True, c[0]
return False, None
data = get_pipe_data()
start = data["nodes"][0]
end = data["nodes"][1]
print(f'going to start node {start}')
navigate_wait(x=start["x"], y=start["y"], z=1.0, frame_id='aruco_map')
f = open("pipe-audit.txt", "w")
for i, tap in enumerate(data["tappings"]):
print(f"going to tapping {tap}")
navigate_wait(x=tap["x"], y=tap["y"], z=1.0, frame_id='aruco_map', tolerance=0.1)
img, _ = get_image()
illegal, p = vrez.vrez(img)
if tap["legal"] == 0 and illegal:
print(f"Tapping {i+1}. x={tap['x']}, y={tap['y']}, legal=0 illegal=1 (!)", file=f)
print("^ illegal!")
cv2.circle(img, (p[0], p[1]), 5, (0, 0, 255), -1)
cv2.imwrite(f"tapping_{i}", img)
tapping_pts.publish(String(f"[{tap['x']}, {tap['y']}, 1]"))
elif tap["legal"] == 1:
print(f"Tapping {i+1}. x={tap['x']}, y={tap['y']}, legal=1 illegal=0", file=f)
tapping_pts.publish(String(f"[{tap['x']}, {tap['y']}, 0]"))
f.close()
В рамках этой задачи существует два основных подхода к разработке веб-приложения:
Написание собственного бэкэнда
В этом варианте между frontend (клиентской частью веб-приложения) и ROS-средой разрабатывается отдельный backend-сервер, например, на Python (FastAPI, Flask) или Node.js. Бэкэнд обеспечивает:
- подписку на нужные ROS-топики, обработку, агрегацию и преобразование данных,
- предоставление REST- или WebSocket API для клиентской части,
- управление миссией и трансляцию команд управления от пользователя (например, запуск/остановка скриптов миссии, команды арминга/дизарминга дрона и т. д.).
Такой подход позволяет реализовать дополнительные уровни защиты, логику доступов, хранение данных, кастомную обработку сообщений, обеспечивает лучшую независимость frontend’а от ROS-инфраструктуры и большую гибкость масштабирования.
Использование
roslib.js.Альтернативный вариант — прямое взаимодействие с ROS из браузера с помощью сторонней библиотеки
roslib.js. В этом случае ROS-ноды запускаются сrosbridge-сервером (rosbridge_suite), а браузерное приложение напрямую подписывается на ROS-топики, публикует команды и обрабатывает сообщения без отдельного backend-а. Это ускоряет разработку приложения, но делает разработанный сервис менее гибким.Остановимся подробнее на этом варианте как наиболее быстром в разработке, что является важным в условиях ограниченного времени на финале НТО.
Для отображения карты и найденных объектов с привязкой к карте наиболее простым вариантом является использование HTML-canvas. Для преобразования мировых координат в пиксельные на холсте используются предварительно заданные смещения и масштабы \((sx, sy, dx, dy)\), благодаря которым любая точка в глобальной системе \((x, y)\) проецируется на правильную позицию на картинке.
Постоянно, с интервалом 2 с, отправляется запрос на ROS-сервис get_telemetry, и полученные данные о напряжении аккумулятора конвертируются в проценты и вольты, после чего обновляют текстовые поля в интерфейсе. Похожим образом подписчики на топики /metal_pts, /tapping_pts и /max_tmp отслеживают в реальном времени координаты дефектов теплосети, координаты незаконных врезок и выводятся и список и на карту.
Кнопки Run, Killswitch, Stop, Home и Land привязаны к соответствующим ROS-сервисам set_running, set_killswitch, set_stopping, set_home и set_landing. При нажатии каждая кнопка вызывает метод callService и по получении ответа выводит простое JavaScript-окно alert, уведомляющее об успешной отправке команды (ok let’s go…, disarming… и т. д.). В это время запускается обработчик сервиса на дроне, который выполняет запрограммированные действия.
Пример регистрации сервиса и его обработчика в коде миссии см. ниже.
landing = False
def set_landing_cb(_):
global landing
landing = True
return TriggerResponse(success=True)
set_landing = rospy.Service("set_landing", Trigger, set_landing_cb)
Управление крышкой дронпорта
На встроенном контроллере дронпорта (ESP-32) требуется реализовать HTTP-сервер, который принимает команды для управления исполнительными механизмами дронпорта — в первую очередь, для открытия и закрытия крышки. Такой сервер обеспечивает взаимодействие между системой управления дроном (миссионный компьютер, внешнее веб-приложение и т. д.) и аппаратной частью дронпорта через стандартные HTTP-запросы.
После выполнения команды ESP-32 возвращает HTTP-ответ с результатом — строку «ОК» и код состояния 200, если операция успешно завершена.
Функция управления крышкой дронпорта отправляет HTTP-запросы к ESP-32. В зависимости от переданного параметра mode она формирует URL вида http://.../open или http://.../close и делает запрос. После этого программа анализирует полученный ответ, чтобы удостовериться, что команда выполнена успешно. Если ответа нет или код ответа не 200, или тело ответа отличается от ожидаемого («ОК»), то команда считается невыполненной и повторяет попытку.
mode = "open" # or " close"
while True:
try:
resp = requests.get(f"http://<esp_32_ip>/{mode}", timeout=3)
print(resp.text)
if resp.ok:
print("OK!")
break
else:
print(f"not ok? {resp.status_code}")
except Exception as e:
print(e)
print("retrying in 1 sec...")
rospy.sleep(1)
Перед началом разработки устройства необходимо ознакомиться с техническим заданием и обратить внимание на имеющиеся ограничения:
- Временные рамки на проектирование, изготовление и доработку устройства.
- Электронную компонентную базу (список доступных компонентов и материалов представляется в первый день инженерного тура).
Работу с 3D-принтером:
- для минимизации использования поддержек необходимо выбрать правильное направление и ориентацию деталей, кроме того, можно использовать геометрические формы, требующие минимальное число поддержек;
- во избежание деформации и провисания пластика во время печати необходимо обеспечить достаточную толщину стенок деталей и их правильное расположение;
- для гарантированного соединения деталей между собой необходимо расположить детали на печатном столе так, чтобы поверхности и отверстия, с помощью которых детали соединяются, имели максимальную точность;
- для минимизации времени печати и использования материала следует подобрать оптимальное расположение деталей на печатной платформе (закладывать минимальное расстояние между деталями; сторону детали, имеющую максимальный линейный размер, располагать горизонтально на поверхности стола и т. п.);
- для обеспечения правильного прижима первого слоя путем последовательной проверки зазора между соплом и столом по нескольким противолежащим точкам в углах стола перед началом работы с принтером нужно произвести калибровку печатной платформы;
- для настройки температуры перед запуском основной печати следует напечатать тестовую модель из необходимого пластика;
- использовать подходящие настройки скорости печати для конкретных деталей; чтобы определить оптимальную скорость перемещений на холостом ходу для имеющегося принтера, необходимо распечатать тестовую модель при различных скоростях движения, начиная со 100 мм/с и изменяя ее с приростом 5 мм/с; скорость печати можно увеличивать, если качество поверхности приемлемое, и уменьшать, если качество 3D-печати ухудшается (необходимо обращать внимание на такие дефекты, как несовпадение слоев).
На работу с лазерным станком с ЧПУ для резки фанеры:
- при проектировании частей устройства и необходимо учитывать количество материала;
- для минимизации использования материала необходимо подобрать оптимальное расположение деталей на каждом листе: детали размещаются на листе с зазором не менее 1 мм.
При сборке, тестировании и эксплуатации устройства необходимо соблюдать технику безопасности.
Результатом решения инженерной задачи является разработка устройства дронпорта, кронштейна крепления тепловизионной камеры и изготовление документации для данных изделий.
Крепление тепловизионной камеры
Дронопорт
Инструкция по сборке дронпорта: https://disk.yandex.ru/i/BSmEGFrCXF1j5g.
Инструкция по эксплуатации дронпорта: https://disk.yandex.ru/i/K1KBqU5uWWE7wQ.
Код микроконтроллера
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>
#include <FastLED.h>
// Конфигурация
const char *ssid = "turk";
const char *password = "torvalds";
#define SERVO_1_PIN 13
#define SERVO_2_PIN 12
#define BUTTON_PIN 27
#define LED_PIN 14
#define MATRIX_SIZE 16
#define NUM_LEDS 256
#define CLOSED_TIMEOUT 5000 // 5 секунд
#define one_frame 1000
int state = 0;
int anim = 0;
int frame = 0;
Servo servo1;
Servo servo2;
CRGB leds[NUM_LEDS];
WebServer server(80);
volatile bool isOpen = false;
bool buttonPressed = false;
unsigned long lidClosedTime = 0;
bool yellowAlert = false;
void anim0()
{
FastLED.clear();
leds[112] = CRGB::Yellow;
<...>
leds[224] = CRGB::Yellow;
leds[173] = CRGB::Blue;
<...>
leds[228] = CRGB::Blue;
FastLED.show();
}
void anim1()
{
FastLED.clear();
leds[84] = CRGB::Yellow;
// <...>
leds[224] = CRGB::Yellow;
leds[173] = CRGB::Blue;
// <...>
leds[228] = CRGB::Blue;
FastLED.show();
delay(one_frame);
FastLED.clear();
leds[11] = CRGB::Yellow;
// <...>
leds[224] = CRGB::Yellow;
leds[173] = CRGB::Blue;
// <...>
leds[228] = CRGB::Blue;
FastLED.show();
delay(one_frame);
FastLED.clear();
leds[241] = CRGB::Yellow;
// <...>
leds[255] = CRGB::Yellow;
leds[173] = CRGB::Blue;
// <...>
leds[228] = CRGB::Blue;
FastLED.show();
}
// Другие анимации <...>
void setup()
{
Serial.begin(115200);
// Инициализация сервоприводов
servo1.attach(SERVO_1_PIN);
servo2.attach(SERVO_2_PIN);
servo1.write(0);
servo2.write(0);
pinMode(BUTTON_PIN, INPUT_PULLUP);
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds,
NUM_LEDS);
FastLED.setBrightness(30);
updateLED();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
delay(500);
server.on("/", []()
{ server.send(200, "text/plain", "Status: " + String(isOpen ? "Open" : "Closed")); });
server.on("/open", handleOpen);
server.on("/close", handleClose);
server.begin();
anim0();
}
void handleOpen()
{
if (!isOpen)
{
servo1.write(180);
servo2.write(180);
isOpen = true;
yellowAlert = false;
lidClosedTime = 0;
Serial.println("Opened via web");
}
updateLED();
server.send(200, "text/plain", "OK");
}
void handleClose()
{
if (isOpen)
{
servo1.write(0);
servo2.write(0);
isOpen = false;
lidClosedTime = millis();
Serial.println("Closed via web");
}
updateLED();
server.send(200, "text/plain", "OK");
}
void updateLED()
{
// Исправлено: заменено & на &&
bool yellowCondition = !isOpen &&
(millis() - lidClosedTime) >=
CLOSED_TIMEOUT &&
buttonPressed;
if (yellowCondition)
{
animc();
}
else if (!yellowCondition)
{
int new_state = state; // Объявлено перед
использованием
// Исправлено: заменено buttonColor на
buttonPressed и &на &&if (buttonPressed && !isOpen)
{
new_state = 0;
}
else if (buttonPressed && isOpen)
{
new_state = 1;
}
else if (!buttonPressed && isOpen)
{
new_state = 2;
}
else if (!buttonPressed && !isOpen)
{
new_state = 3;
}
// Исправлено: заменено & на &&
if (state != new_state)
{
if ((state == 0 | state == -1) && new_state ==
1)
{
anim1();
}
else if (state == 1 && new_state == 2)
{
anim2();
}
else if (state == 2 && new_state == 3)
{
anim3();
}
else if (state == 3 && new_state == 2)
{
anim4();
}
else if (state == 2 && new_state == 1)
{
anim5();
}
else if (state == 1 && new_state == 0)
{
anim6();
}
state = new_state;
}
}
FastLED.show();
// Исправлен вывод в Serial
Serial.print("Anim: ");
Serial.print(anim);
Serial.print(" State: ");
Serial.println(state);
}
void loop()
{
server.handleClient();
// Обработка кнопки
static bool lastButtonState = HIGH;
static uint32_t lastDebounceTime = 0;
bool reading = digitalRead(BUTTON_PIN);
if (reading != lastButtonState)
{
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > 50)
{
if (buttonPressed != (reading == LOW))
{
buttonPressed = (reading == LOW);
lidClosedTime = millis();
updateLED();
Serial.print("Button state: ");
Serial.println(buttonPressed ? "PRESSED" : "RELEASED");
}
}
lastButtonState = reading;
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate > 100)
{
updateLED();
lastUpdate = millis();
}
}
- Статьи, видеолекции по тематике профиля на сайте документации платформы «Клевер»: https://clover.coex.tech/.
- Видеокурс по сборке, настройке и программированию квадрокоптера: https://cat.2035.university/rall/course/27662/.
- Среда симуляции платформы «Клевер»: https://clover.coex.tech/ru/simulation_vm.html.
- Работа с OpenCV при помощи Python: https://github.com/sfalexrog/coex_kb/blob/master/kb014_opencv_python.md.
- Программирование на Python: https://stepik.org/course/67/promo.
- Введение в ROS: https://stepik.org/course/3222/promo.
- Введение в Git: https://ru.hexlet.io/courses/intro_to_git.












