Русский
Русский
English
Статистика
Реклама

Raspberry pi

Перевод Проигрыватель для очень медленного воспроизведения видеофайлов

10.03.2021 20:17:40 | Автор: admin
Карантин это как раз то время, когда можно сделать особенный домашний кинотеатр, который украсит интерьер.

В декабре 2018 года Брайан Бойер опубликовал статью о создании проигрывателя для очень медленного воспроизведения видеоклипов (Creating a Very Slow Movie Player). Это прекрасный этюд о свете, о Бразилии и об архитектуре. Бойер рассказал о разработке устройства с экраном, основанным на электронной бумаге, которое показывает фильмы со скоростью 24 кадра в час, а не 24 кадра в секунду. Примерно год нужен на то, чтобы посмотреть на его проигрывателе 142-минутный фильм Космическая одиссея 2001 года.


Проигрыватель Брайана Бойера (источник)

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

Сейчас там, за $58, продаётся 7,5-дюймовый дисплей, который поставляется вместе со всем необходимым для его подключения к Raspberry Pi. Я, наконец, решился на покупку такого дисплея, а потом, за пару дней, сделал собственный замедленный кинотеатр.


Психо Альфреда Хичкока на моём проигрывателе, смонтированном в рамке из IKEA (фото автора)

Мой проигрыватель вот уже два месяца показывает Психо Альфреда Хичкока в углу нашей гостиной. Я, правда, в сравнении с проектом Бойера, немного ускорил воспроизведение. Новый кадр выводится каждые две минуты, при этом воспроизведение идёт с шагом в четыре кадра. То есть за 24 часа выводятся примерно две минуты экранного времени. На воспроизведение 110-минутного фильма понадобится немного меньше трёх месяцев.

Фильм Психо полон прекрасного, которое раскрывается перед зрителем очень медленно. Некоторые сцены, вроде поездки Джанет Ли, шли неделями, а сцена в душе длилась примерно полтора дня.


Психо Альфреда Хичкока

Если вы хотите создать собственный VSMP (Very Slow Movie Player, проигрыватель для очень медленного воспроизведения видео) вам надо будет сделать четыре дела:

  1. Настройте Raspberry Pi так, чтобы этот одноплатный компьютер мог бы работать без монитора, что позволит дистанционно загружать в него файлы и запускать на нём программы.
  2. Подключите Raspberry Pi к экрану на электронной бумаге и установите соответствующий драйвер.
  3. Напишите программу (или воспользуйтесь моей) для извлечений кадров из видеофайлов, для изменения размеров этих кадров и для их дизеринга. То, что получится, нужно будет вывести на дисплей. Программа, кроме того, должна знать о том, где именно в воспроизводимом видеофайле находится текущий кадр.
  4. Найдите какую-нибудь рамку для того чтобы оформить с её помощью готовый проигрыватель.

Экран на электронной бумаге, Raspberry Pi, microSD -карта и рамка из IKEA обошлись мне примерно в 120 (около $153).

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


VSMP в действии

Настройка Raspberry Pi


Существует множество руководств, посвящённых настройке Raspberry Pi. Я купил на сайте Pimoroni 2-гигабайтную версию Raspberry Pi 4, блок питания и карту памяти на 64 Гб с записанным на ней установщиком операционных систем NOOBS. Благодаря NOOBS в нашем распоряжении оказываются практически все необходимые библиотеки, поэтому приобретение именно такой карты, которую выбрал я, сильно упростило мне жизнь. (Если вы решите купить карту без NOOBS обратитесь к этому руководству).

Для того чтобы с платой Raspberry Pi можно было бы работать без традиционного компьютерного монитора понадобятся два основных инструмента: SSH и SFTP. С помощью SSH можно управлять устройством из командной строки (я использую терминал MacOS), а SFTP позволяет выгружать на устройство файлы (я пользуюсь FileZilla).

После того, как у вас заработает SSH (обычно всё настраивается очень просто) вы сможете управлять Raspberry Pi через домашнюю WiFi-сеть. Можно будет перемещаться по файловой системе компьютера, запускать приложения, редактировать файлы и так далее. Правда, чтобы это всё делать, надо владеть основами работы с терминалом, но я не думаю, что, в плане использованных мной команд, сильно вышел за пределы ls (вывод списка файлов), cd (смена директории) и nano (это простой текстовый редактор, к которому, правда, надо привыкнуть).

Ещё я, для решения тяжёлых задач, пользовался SFTP, передавая на Raspberry Pi большие файлы фильмов и выгружая написанный мной код, который потом доводил до ума с помощью nano.


Raspberry Pi и плата расширения для подключения дисплея приклеены к рамке из IKEA. Питание подводится к плате снизу, через разъём USB-C.

Подключение дисплея


Сам дисплей невероятно тонок, с ним идёт гибкий PCB-кабель и плата расширения, которая подключается прямо к Raspberry Pi. На экран наклеена защитная плёнка, которую можно убрать.

С физической точки зрения связать экран с Raspberry Pi очень просто: достаточно подключить к GPIO-пинам соответствующую плату расширения. Это самое большое отличие моего проекта от проекта Брайана Бойера 2018 года.

На Raspberry Pi надо включить SPI. Именно с помощью этого интерфейса плата взаимодействует с экраном. Поэтому данный шаг совершенно необходим. Но сделать это, после того, как налажена работа с платой по SSH, очень просто.

Далее, надо загрузить и установить на Raspberry Pi драйвер дисплея и мой код.

Ниже я исхожу из предположения о том, что вы, как и я, используете NOOBS. Если это не так то вам может понадобиться самостоятельно установить кое-какие вспомогательные инструменты (Git, Pip, Pil, ffmpeg).

Подключитесь к Raspberry Pi по SSH и, находясь в домашней директории, выполните следующие команды (обратите внимание на то, что во второй строке нужны кавычки):

sudo raspi-config <-- Не забудьте включить SPIgit clone https://github.com/TomWhitwell/SlowMovie/cd SlowMovie/e-paper/RaspberryPi&JetsonNano/pythonsudo python setup.py install

Теперь, если эти команды успешно отработали, у вас должна появиться возможность выполнения следующей команды, которая позволит проверить работоспособность дисплея:

python examples/epd_7in5_V2_test.py


Waveshare-версия Hello World

Если ваш экран ничего не показал проверьте две вещи. Во-первых удостоверьтесь в том, что включили SPI. Во-вторых посмотрите, пользуетесь ли таким же дисплеем, как и я (7,5 дюймов, V2).

Если у вас не включён интерфейс SPI, то вы увидите не особенно информативные сообщения об ошибках. Например такое сообщение:

IOError: [Errno 2] No such file or directory

Когда я попробовал вывести что-то на экран в первый раз, у меня ничего не заработало. Потом заработало. Потом опять не заработало. Я был уверен в том, что имею дело с аппаратной проблемой, что я как-то повредил гибкий кабель, на вид довольно хрупкий, которым дисплей подключается к плате. Но проблема была не в железе. Я просто, сначала, забыл включить SPI, а потом запустил не тот демо-пример.

На плате расширения, которая используется для подключения экрана к Raspberry Pi, есть переключатели. Мои были в таких положениях:

  • Display Config: B: Other.
  • Interface Config: 0: 4-Line SPI.


Моя версия Hello World выводит случайные кадры из двухсекундного фрагмента Психо

Hello World


Теперь, когда экран подключён к Raspberry Pi и приведён в рабочее состояние, нужно вернуться в папку SlowMovie:

cd ~/SlowMovie

Моя версия программы для замедленного воспроизведения видеофайлов написана на Python. Здесь используются 3 библиотеки:

  • ffmpeg универсальный инструмент для работы с медиафайлами.
  • ffmpeg-python ffmpeg-обёртка для Python.
  • PIL Python Image Library Python-библиотека для обработки изображений.

Если вы пользуетесь NOOB, то ffmpeg и PIL будут уже установлены. Установка ffmpeg может вызывать некоторые сложности, но этому посвящено множество руководств. Если вы, всё же, сами с этим не справились просто воспользуйтесь NOOBS.

Установить ffmpeg-python можно такой командой:

sudo pip install ffmpeg-python

После этого в нашем распоряжении должно быть всё необходимое, а значит можно запустить (находясь в папке SlowMovie) мою версию Hello World:

python helloworld.py

Эта программа случайным образом выбирает MP4-файл (в папке уже есть короткий клип test.mp4). Далее, она извлекает из этого файла случайный кадр, меняет его размеры, обрабатывает его и выводит на экран. Полный код программы можно найти здесь. А ниже я привожу самые интересные её части с комментариями:

# Использование ffmpeg для извлечения одного кадра из .mp4-файла, изменение размеров кадра, леттербоксинг, сохранение полученного изображения в локальной файловой системеdef generate_frame(in_filename, out_filename, time, width, height):(ffmpeg.input(in_filename, ss=time).filter('scale', width, height, force_original_aspect_ratio=1).filter('pad', width, height, -1, -1).output(out_filename, vframes=1).overwrite_output().run(capture_stdout=True, capture_stderr=True))# Импорт библиотеки для работы с дисплеем, его инициализация и очисткаfrom waveshare_epd import epd7in5_V2epd = epd7in5_V2.EPD()epd.init()epd.Clear()# Выяснение количества кадров в файлеframeCount = int(ffmpeg.probe(inputVid)[streams][0][nb_frames])# Выбор случайного кадраframe = random.randint(0,frameCount)# Преобразование номера кадра в тайм-код, используемый ffmpegmsTimecode = %dms%(frame*41.666666)# Открытие сохранённого кадра в PILpil_im = Image.open(grab.jpg)# Преобразование картинки в растровое изображение с глубиной цвета 1 бит (Только нули и единицы)# Использование алгоритма дизеринга Флойда-Стейнбергаpil_im = pil_im.convert(mode=1',dither=Image.FLOYDSTEINBERG)# Вывод изображенияepd.display(epd.getbuffer(pil_im))

Проигрыватель для очень медленного воспроизведения видео


После того, как у вас заработал скрипт helloworld.py, вы можете перенести на устройство свои видеофайлы, воспользовавшись SFTP. Просто разместите их в папке /Videos.

Обращайте внимание на размер вашей карты если окажется так, что при загрузке данных на почти заполненную microSD-карту часть видеофайла загрузилась, а другой части уже загружаться некуда, вы столкнётесь со странными ошибками.

А вот команда для запуска моего проигрывателя, созданного на довольно-таки любительском уровне:

python slowmovie.py

Программа запоминает место, на котором остановилось воспроизведение видео. Поэтому можно продолжить показ фильма даже после того, как плата Raspberry Pi была выключена и включена.

Мой проигрыватель поддерживает различные опции, справку по которым можно получить такой командой:

python slowmovie.py -h

Например, его можно запустить так:

python slowmovie.py -f 2001.mp4 -d 150 -i 1

Это значит, что он будет воспроизводить файл 2001.mp4, выводя на экран новый кадр каждые 150 секунд. Это даст 24 кадра в час вместо 24 кадров в секунду.

Новые кадры будут выводиться на экран до тех пор, пока работает программа, а после выхода из SSH-сессии этот процесс остановится. Для того чтобы организовать автоматический запуск скрипта slowmovie.py при включении устройства можно прибегнуть к этой инструкции. По сути же достаточно отредактировать файл /etc/profile:

sudo nano /etc/profile

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

cd SlowMoviesudo python slowmovie.py

Завершение работы над проектом


Экран настолько тонкий, что может быть размещён в обычной рамке для фотографий из IKEA. Я использовал рамку, которую купил много лет назад. Она очень похожа на рамку RIBBA. Я убрал стекло и покрасил рамку, после чего прикрепил экран к задней панели рамки. К задней части панели я, с помощью клеевого пистолета, приклеил Raspberry Pi. Конструкция получилась аккуратной и надёжной. Я собираюсь отнести всё то, что у меня получилось, в багетную мастерскую, чтобы там мою конструкцию окончательно довели бы до ума.


Образец алгоритмического искусства, созданный под влиянием Георга Нисса

Что дальше?


  • В каталоге Waveshare есть ещё много интересного. Например экран, по размеру такой же, как мой, но с гораздо более высоким разрешением, стоит там $140. Дисплей, похожий на мой, но чуть побольше, стоит $170, а модуль дисплея, который намного крупнее моего, стоит $150.
  • Похоже, что в состав PIL входит лишь алгоритм дизеринга Флойда-Стейнберга. А ведь существует очень много подобных алгоритмов.
  • Хорошо было бы, если бы моя программа могла бы читать .mp4-файлы с USB-флэшки, но мне этого добиться не удалось.
  • Есть много разных видов дисплеев, основанных на электронной бумаге. Некоторые поддерживают частичное обновление экрана. Применение такого дисплея, возможно, позволит избавиться от некрасивого процесса обновления экрана, происходящего каждый раз при смене изображения.
  • После того, как в вашем доме появится небольшой дисплей, подключённый к интернету и хорошо вписывающийся в интерьер, окажется, что использовать его можно разными способами. Мне, например, понравился бы e-paper-проект, реализующий идеи The Clock Кристиана Марклея. Или что-то вроде House of Dust Элисон Ноулз, или нечто подобное Computergrafik Георга Нисса.

Планируете сделать себе проигрыватель для замедленного воспроизведения видеофайлов?

Подробнее..

Перевод YouTube-проигрыватель сверхвысокого разрешения на Raspberry Pi

20.03.2021 12:10:38 | Автор: admin
Иногда на стандартном компьютерном экране с разрешением 1920x1080 просто не хватает пикселей для того чтобы разглядеть все детали роликов с YouTube. Эта проблема коснулась и меня. Когда это случилось я создал устройство, которое позволяет смотреть YouTube со сверхвысоким разрешением.



Обзор проекта


Бывает так, что мне надоедает смотреть ролики с YouTube на HD-мониторе или на телевизоре. Особенно меня расстраивает то, что этим роликам обычно не хватает чёткости. Эту проблему я решил с помощью особого устройства, собранного из Raspberry Pi 3 и светодиодной RGB-панели с фантастическим разрешением 64х64 пикселя.


Светодиодная RGB-панель


Raspberry Pi с платой расширения для подключения RGB-панели

Вот как выглядит просмотр видео на моём проигрывателе.


Просмотр видео на RGB-панели

В этом проекте используются следующие компоненты:

  • Светодиодная RGB-панель DFRobot с разрешением 64x64 пикселя.
  • Одноплатный компьютер Raspberry Pi 3 Model B+.
  • Плата расширения для подключения светодиодной панели к Raspberry Pi Adafruit Matrix Driver HAT.

Программный код проекта написан на Python.

Сопряжение устройств и подготовка программ


Подробности о подключении светодиодной панели к Raspberry Pi и об установке необходимого программного обеспечения можно почитать здесь. После того, как удастся наладить совместную работу устройств, установим OpenCV:

sudo apt-get updatesudo apt-get install libopencv-dev python-opencv

Далее, так как мы планируем проигрывать видео с YouTube, установим ещё пару библиотек. В частности библиотеку pafy, которая реализует именно тот функционал, который нас интересует:

sudo python -m pip install youtube_dlsudo python -m pip install pafy

Теперь, когда предварительная подготовка завершена, поговорим о коде проигрывателя.

Код


Вот полный код моей программы:

import pafyimport timeimport sysimport numpy as npfrom rgbmatrix import RGBMatrix, RGBMatrixOptions, graphicsfrom PIL import Image, ImageDrawurl = sys.argv[1]video = pafy.new(url)best = video.getbest(preftype="mp4")options = RGBMatrixOptions()options.rows = 64options.cols = 64options.chain_length = 1options.parallel = 1options.hardware_mapping = 'adafruit-hat'matrix = RGBMatrix(options=options)matrix.Clear()import cv2capture = cv2.VideoCapture()capture.open(best.url)success,image = capture.read()FRAMERATE = 120while success:image_resized = cv2.resize(image, (64,64), interpolation = cv2.INTER_AREA)image_resized = cv2.cvtColor(image_resized, cv2.COLOR_BRG2RGB)display_img = Image.fromarray(image_resized)matrix.SetImage(display_img.convert('RGB'))#cv2.imshow('frame',image_resized)#time.sleep(1/FRAMERATE)success, image = capture.read()cap.release()cv2.destroyAllWindows()

В нём реализована следующая последовательность действий:

  • Импорт библиотек.
  • Загрузка видео и преобразование его в нужный формат.
  • Настройка RGB-панели.
  • Создание объекта OpenCV для захвата видео.
  • Обход кадров видео, их преобразование к нужному виду и отправка на RGB-панель.


Видео на RGB-панели

Я написал программу так, чтобы она могла бы, в качестве аргумента командной строки, принимать URL видео, которое нужно воспроизвести. После того, как программа узнаёт адрес видео, для его загрузки и сохранения на устройстве используется библиотека pafy. В программе я указал, что используемая RGB-панель имеет разрешение 64x64 пикселя, и что в проекте применяется плата расширения adafruit-hat. Далее, чтобы помочь OpenCV в деле захвата кадров видео, я создал объект VideoCapture и передал ему видео. И наконец, после того, как изображение готово для вывода на RGB-панель, я применил библиотеку rpi-rgb-led-matrix, которая, с использованием инструментов, импортированных из PIL, выводит изображение. Для этого, в частности, объекты изображений OpenCV преобразуются в объекты изображений PIL:

display_img = Image.fromarray(image_resized)

Программа выводит на RGB-панель кадры до тех пор, пока не закончится видео, или до тех пор, пока программа не будет остановлена.

Просмотр видео


Для просмотра видео программу нужно запустить, воспользовавшись такой командой (программе надо передать адрес видео):

sudo python low_res_yt.py <youtube_video_url>

После этого останется лишь наслаждаться YouTube-роликом сверхвысокой чёткости.

Хотите собрать себе проигрыватель сверхвысокой чёткости для YouTube?

Подробнее..

Перевод Система удалённого мониторинга рабочих мест на базе 360-градусной камеры и Raspberry Pi

02.04.2021 12:23:26 | Автор: admin
Я создал прототип системы удалённого мониторинга рабочих мест. Эта система позволяет организациям, адаптирующимся к ограничениям, связанным с COVID-19, осуществлять наблюдение за сотрудниками и проводить виртуальные инспекции рабочих мест.

Система, о которой я хочу рассказать, представляет собой роботизированную панорамную камеру. Проект основан на Raspberry Pi. Здесь, ради простоты, используются панорамные фотографии, а не видеозаписи или потоковая передача сигнала. Опыт, полученный в ходе работы с сотнями компаний, использующих камеры с обзором в 360 градусов (эти компании, в целом, провели миллионы виртуальных проверок сотрудников), и анализ рынка, подсказывают мне, что сейчас, в начале 2021 года, чаще всего встречаются именно решения, основанные на панорамных фотографиях.



Я, исследуя ситуацию, пользовался материалами форума, посвящённого использованию API Ricoh Theta, и тем, что удалось узнать при личном общении с представителями бизнеса в ходе онлайн-встреч с ними.

Требования к проекту


Я остановился на следующих требованиях к проекту, касающихся его аппаратной составляющей и инфраструктуры:

  1. Гибкое позиционирование камеры с помощью робота.
  2. Использование одноплатного компьютера Raspberry Pi 4 с 4 Гб памяти для управления камерой и роботом.
  3. Ориентация системы на съёмку 360-градусных фотографий.
  4. Применение прозрачного корпуса камеры.
  5. Организация связи камеры с системой управления камерой по Wi-Fi.

Раскрою некоторые подробности, касающиеся вышеозначенных требований.

1. Гибкое позиционирование камеры


Использование робота для позиционирования камеры позволяет организовать удалённое наблюдение за рабочим местом сотрудников, что актуально во время эпидемии COVID-19. Это, кроме того, позволяет использовать камеру в составе систем, рассчитанных на работу в опасных для человека условиях, например это могут быть системы для анализа радиационной обстановки. В моём проекте используется игрушечный гусеничный робот. Благодаря этому стоимость компонентов проекта невелика, поэтому создать соответствующий прототип смогут все, кому он может понадобиться. При этом те же механизмы управления камерой, которые используются в прототипе, легко можно адаптировать к применению в подобных системах, основанных на промышленных роботах.

2. Raspberry Pi 4


На Raspberry Pi 4 можно установить, кроме прочих ОС, специализированную операционную систему Robot Operating System (ROS). Я решил использовать в проекте стандартную ОС Raspberry Pi. Благодаря этому он будет доступнее для заинтересовавшихся им разработчиков и организаций.

3. 360-градусные фотографии


Самым популярным форматом выходных данных 360-градусных камер являются именно фотоснимки. Они, в сравнении с видео, дают более высокое разрешение изображения и хранятся в файлах гораздо меньшего размера. Работать с фотографиями значительно легче, чем с видео. В результате у проекта, который создаётся в расчёте на использование фотоснимков, больше шансов на успешное завершение.

4. Прозрачный корпус камеры


Прозрачный корпус защищает камеру от дождя, от пыли и промышленных загрязнителей. Имеется растущий тренд использования камер потребительского уровня, вроде Ricoh Theta, в крупномасштабных коммерческих проектах. В результате растёт потребность в защите таких камер от физических повреждений, от загрязнений, от плохой погоды. Одна из задач моего проекта заключается в исследовании воздействия прозрачного корпуса на качество изображений.

5. Wi-Fi-соединение между камерой и контроллером


Хотя надёжнее было бы организовать управление камерой по USB, используя Picture Transfer Protocol (PTP) и применяя библиотеку libptp, я решил выбрать API Google Open Spherical Camera (OSC) и связываться с камерой по Wi-Fi. API OSC, которое в документации Ricoh называется Web API, легче реализовать, что позволяет быстрее перейти к практическим испытаниям проекта.


Снимок, сделанный камерой, смонтированной на гусеничном роботе и заключённой в прозрачный корпус, отличается минимальными искажениями

Преимущества фотоснимков перед потоковой передачей видео


Я дополнил то, что можно найти о системах наблюдения в интернете, пообщавшись с людьми, которые работают с такими системами. В частности, поговорил с инженерами из компаний fulldepth, и Unusly. Первая компания занимается глубоководными системами наблюдения, вторая специализируется на системах, предназначенных для сферы недвижимости. Меня интересовал опыт инженеров, касающийся роботизированных систем.

Компания fulldepth тестировала потоковую передачу видео с 360-градусной камеры, смонтированной на роботе, который предназначен для работы на глубине в 300 метров.


Продукция компании fulldepth

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

Изначально я хотел реализовать в описываемом тут проекте возможность потоковой передачи видео с Raspberry Pi на Windows 10-компьютер с применением RTP. Специалисты из fulldepth поделились со всеми желающими методологией потоковой передачи 360-градусного видео с Raspberry Pi. Используя их спецификации и программный код я, наверняка, смог бы реализовать нечто подобное и в своём проекте.

Но я, в итоге, остановился именно на фотоснимках. На моё решение сильнее всего повлияло то, что устройствами для получения подобных фотоматериалов очень сильно интересуются компании, занимающиеся продажей подержанных машин, фирмы, которые занимаются недвижимостью, строительные компании. Речь идёт о том, что таким организациям нужно воссоздать привычный порядок работы в условиях эпидемии COVID-19. Вот почему подобные компании отдают предпочтение фотографиям:

  • Разрешение фотоснимков больше, чем разрешение видео. Фотографии лучше выглядят с точки зрения людей, а системы искусственного интеллекта могут использовать их для определения параметров объектов.
  • При съёмке фотографий можно лучше контролировать параметры изображения такие, как выдержка (изображение можно делать светлее или темнее) и цветность.
  • Возможность создания HDR-изображений (High Dynamic Range, расширенный динамический диапазон), позволяющая корректировать неблагоприятные условия освещённости (нечто вроде слишком светлых фрагментов изображений, появление которых вызывает, например, яркий солнечный свет, проникающий в комнату через окно). При создании HDR-изображений делают несколько кадров одной и той же сцены, используя разную выдержку, после чего эти кадры объединяют, выбирая с каждого из них участки с наиболее удачной экспозицией.

Планируя проект я, кроме того, пообщался с представителем международной автомобильной компании, где потоковая передача видеоданных с 360-градусной камеры используется для контроля взаимодействия людей со встроенными в транспортное средство OLED-панелями. На картинке, которая получается при потоковой передаче видео, панели выходят слишком светлыми, а то, что на них выводится, оказывается невидимым.

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

Управление камерой


Для того чтобы упростить работу с камерой с робота, основанного на Raspberry Pi 4, я, на языке Dart, создал библиотеку и приложение, рассчитанное на работу в командной строке. Для написания библиотеки я выбрал именно Dart из-за того, что при таком подходе код библиотеки я мог бы многократно использовать во Flutter-приложениях, рассчитанных на Android и iOS. Dart-код компилируется в нативные бинарники, которые запускаются на Raspberry Pi без необходимости установки Dart SDK. Соответствующие инструменты командной строки, созданные для Raspberry Pi, можно использовать из bash-скриптов, что позволяет автоматизировать управление камерой.

Для того чтобы управлять камерой с Raspberry Pi, можно воспользоваться простым bash-скриптом. Ниже приведён пример такого скрипта, в котором выполняются следующие действия:

  1. Настройка различных параметров камеры (отключение автоматического перевода камеры в режим сна или автоматического выключения камеры).
  2. Деактивация встроенного таймера.
  3. Вывод параметров камеры в консоль для их проверки.
  4. Удаление из текущей директории, предназначенной для выгрузки изображений, всех старых изображений, снятых камерой Ricoh Theta, что приводит к тому, что в папке будут храниться только свежие изображения.
  5. Запуск процесса съёмки 500 фотографий.
  6. Передача изображений с камеры на Raspberry Pi с применением Wi-Fi-соединения.
  7. Загрузка изображений на удалённый облачный сервер. Просмотр этих изображений организован с помощью веб-сервера Apache.

#!/usr/bin/bash# отключение offDelay./theta offDelay --off# отключение sleepDelay./theta sleepDelay --off# выключение встроенного таймера./theta exposureDelay --seconds=0# уменьшение громкости звука срабатывания затвора./theta shutterVolume --low# подтверждение настроек./theta getOptionssleep 1s# ЭТА КОМАНДА УДАЛИТ ВСЕ ИЗОБРАЖЕНИЯ, ХРАНЯЩИЕСЯ В ПАПКЕ СКРИПТАrm R00*.JPGecho start timelapse photography loop testecho images will be viewable at http://45.xx.xx.xx/robot/# Пример цикла, в котором делается 500 снимков, позволяющих# наблюдать за развитием некоего процесса во времени.# Для того чтобы снять другое количество фотографий, нужно изменить# число, используемое ниже, например - так: {1..300}for counter in {1..500}do./theta takeAndDownloadecho that was picture $counter((counter++))# если снимки нужно делать с интервалом в 30 секунд# sleep 30secho 'waiting 10 seconds for the next shot'sleep 10s# если снимки нужно делать с интервалом в 5 минут# sleep 5mecho '*** Will Start Upload to Digital Ocean Hosting ***'scp -r *.JPG craig@45.xx.xx.xx:/home/craig/robot/`date +"%Y%m%d%H%M"`.JPGecho completed uploadecho deleting all RICOH THETA images from current directoryrm R001*.JPGdoneecho timelapse doneecho go to http://45.xx.xx.xx/robot/ to view images

Инструмент командной строки, используемый в этом bash-скрипте это бесплатный опенсорсный проект. Я публикую подробности о нём здесь. Например, в этом материале речь идёт о некоторых наблюдениях, сделанных в ходе использования описываемой в этой материале системы.

Проблемы проекта, выявленные в ходе полевых экспериментов


В этом разделе я хочу поделиться основными выводами, которые я сделал после того, как перенёс робота из офиса в полевые условия, оснастив автономной системой питания, и поэкспериментировал с ним.


Офисные эксперименты

Проблема электропитания автономного робота


Собственный источник питания робота слишком слаб для того чтобы эффективно обеспечивать энергией Raspberry Pi и всё сопутствующее оборудование. Подробности об энергопотреблении Raspberry Pi можно почитать в этом материале.

Обычно я тестировал систему, подключив её к настенной электрической розетке. Перевод робота на автономное питание вызвал у меня, так сказать, культурный шок. В результате я сделал вывод о том, что мне, когда робот питается от батарей, нужно внимательнее относиться к энергопотреблению дополнительного оборудования, вроде Wi-Fi-адаптера, подключённого к Raspberry Pi.


В полевых условиях на первый план выходят вопросы автономного питания устройства

Решение проблем мобильной связи


В офисе робот подключается к Wi-Fi-роутеру, а в поле к мобильному хот-споту, выводящему устройство в интернет через LTE-сеть. Наладка работы системы в таких условиях вызвала неожиданные сложности. В качестве хот-спота я использовал не специализированное устройство, а телефон Pixel 2. Для того чтобы узнать IP-адрес Raspberry Pi, мне, на Pixel 2, пришлось воспользоваться Termux и командой ip neigh. Потом я воспользовался ноутбуком для того чтобы подключиться к Raspberry Pi по SSH и настроить скрипты, ответственные за управление камерой. Если интересно вот моя статья о выполнении Linux-команд на Android-устройствах с использованием Termux.

Маршрутизация на Raspberry Pi


После загрузки Raspberry Pi с двумя Wi-Fi-интерфейсами автоматически были созданы два стандартных, конфликтующих друг с другом шлюза. Мне понадобилось вручную удалить стандартный маршрут к камере и перенаправить к камере трафик из подсети 192.168.1.0 Raspberry Pi.


Настройка двойного Wi-Fi-подключения на роботе без пользовательского интерфейса

Неожиданная польза, которую принёс этот проект моей компании


Робот, о котором я рассказываю, это экспериментальный проект, направленный на проверку различных идей. Я использую его в учебных целях. Отмечу, что не ожидал того, что работа над этим проектом хорошо отразится на оптимизации операций, которые в компании, где я работаю, выполняются вручную. Меня удивило то, что благодаря моему роботу ускорилась работа над проектами, которые даже с ним не связаны. Например, инструмент для тестирования API камеры, предназначенный для использования из командной строки на Raspberry Pi, стал широко применяться в компании для тестирования API камеры на Windows и Mac. Это стало возможным благодаря тому, что для разработки этого инструмента было решено использовать язык Dart (а так же благодаря существованию команды dart compile).

Ещё одной приятной неожиданностью стало то, что мы начали использовать при работе с этим инструментом bash-скрипты, направленные на проведение автоматизированных тестов API камеры. Это благотворно сказалось на наших мобильных разработчиках. API камеры это REST-подобное HTTP-API, в Dart-программах можно пользоваться JSON-данными. Это позволяет создавать тесты, которые подойдут тем разработчикам, которые пишут на Swift, Kotlin или Java. Я проверял робота, запуская тесты на Raspberry Pi. Однажды, отвечая на какой-то вопрос с форума, я просто показал свои результаты. В итоге оказалось, что то, что я сделал, заинтересовало разработчиков мобильного приложения. Теперь мы пользуемся WSL2 в Windows 10 для запуска bash-скриптов с соответствующих компьютеров.

Итоги


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

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

Хотите создать собственную 360-градусную камеру, смонтированную на каком-нибудь роботе?

Подробнее..

Перевод Как преобразовать текст в речь с использованием Google Tesseract и Arm NN на Raspberry Pi

17.02.2021 16:08:10 | Автор: admin

Привет, Хабр! Сегодня специально к старту нового потока курса по Maсhine Learning делимся с вами постом, автор которого создаёт устройство преобразования текста в речь. Такой механизм преобразования текста в речь (TTS) ключевой элемент систем, которые стремятся сформировать естественное взаимодействие между людьми и машинами на основе встроенных устройств. Встроенные устройства могут, например, помочь людям с нарушениями зрения читать знаки, буквы и документы. В частности, устройство может, используя оптическое распознавание символов, дать понять пользователю, что видно на изображении. Впрочем, приступим к крафту



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

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

Для точного обнаружения текста в реальном времени распознавания наборов глифов как произносимых слов можно обратиться к методам глубокого обучения ИИ. В этом случае для распознавания слов в тексте, захваченном при оптическом распознавании символов, можно было бы использовать рекуррентную нейронную сеть (РНС). А что, если бы это можно было сделать на встроенном устройстве, более лёгком и компактном, чем даже смартфон?

Такое лёгкое, мощное TTS-устройство может помочь людям с нарушениями зрения. Его можно встроить в защищённые от неумелого обращения устройства для повышения грамотности или обработки рассказов и найти ему многие другие применения.

В этой статье я покажу, как это сделать с помощью TensorFlow, OpenCV, Festival и Raspberry Pi. Для оптического распознавания текста я буду использовать платформу машинного обучения TensorFlow вместе с предварительно обученной моделью Keras-OCR. Библиотека OpenCV будет использоваться для захвата изображений с веб-камеры. Наконец, в качестве TTS-модуля будет выступать система синтеза речи Festival. Затем всё соединим, чтобы создать приложение на Python для Raspberry Pi.

Попутно я расскажу, как работают типичные OCR-модели и как дополнительно оптимизировать решение с помощью TensorFlow Lite, набора инструментов для запуска оптимизированных моделей TensorFlow в ограниченных средах, таких как встраиваемые устройства и устройства Интернета вещей. Полный исходный код, представленный здесь, доступен на моей странице GitHub.

Начало работы


Во-первых, чтобы создать устройство и приложение для этого туториала, понадобится Raspberry Pi. Для этого примера подойдут версии 2, 3 или 4. Вы также можете использовать собственный компьютер для разработки (мы тестировали код для Python 3.7).

Необходимо установить два пакета: tensorflow (2.1.0) и keras_ocr (0.7.1). Вот несколько полезных ссылок:


OCR с помощью рекуррентных нейронных сетей


Здесь для распознавания текста на изображениях я использую пакет keras_ocr. Этот пакет основан на платформе TensorFlow и свёрточной нейронной сети, которая первоначально была опубликована в качестве примера OCR на веб-сайте Keras.

Архитектуру сети можно разделить на три важных этапа. На первом берут входное изображение, а затем извлекают элементы, используя несколько свёрточных слоёв. Эти слои разделяют входное изображение по горизонтали. Для каждой части эти слои определяют набор элементов столбцов изображения. Данная последовательность элементов столбцов используется на втором этапе рекуррентными слоями.

Рекуррентные нейронные сети (РНС) обычно состоят из слоёв долгой краткосрочной памяти (LTSM). Долгая краткосрочная память произвела революцию во многих применениях ИИ, включая распознавание речи, создание субтитров к изображениям и анализ временных рядов. OCR-модели используют РНС для создания так называемой матрицы вероятностей символов. Эта матрица определяет степень уверенности в том, что заданный символ находится в конкретной части входного изображения.

Таким образом, на последнем этапе эта матрица используется для декодирования текста на изображении. Обычно люди используют алгоритм классификации по рейтингу (Connectionist Temporal Classification, CTC). CTC стремится преобразовать матрицу в осмысленное слово или последовательность таких слов. Такое преобразование не тривиальная задача, так как в соседних частях изображения могут быть найдены одинаковые символы. Кроме того, некоторые входные части могут не содержать символов.

Хотя OCR-системы на основе РНС эффективны, пытаясь внедрить их в свои проекты, можно столкнуться с множеством проблем. В идеале необходимо выполнить обучение преобразованию, чтобы настроить модель в соответствие со своими данными. Затем модель преобразуется в формат TensorFlow Lite, чтобы оптимизировать для вывода на оконечное устройство. Такой подход оказался успешным в мобильных приложениях компьютерного зрения. Например, многие предварительно обученные сети MobileNet эффективно классифицируют изображения на мобильных устройствах и устройствах Интернета вещей.

Однако TensorFlow Lite представляет собой подмножество TensorFlow, и поэтому в настоящее время поддерживается не каждая операция. Эта несовместимость становится проблемой, когда необходимо выполнить оптическое распознавание символов, подобное тому, что включено в пакет keras-ocr на устройстве Интернета вещей. Список возможных решений предоставлен на официальном сайте TensorFlow.

В этой статье я покажу, как использовать модель TensorFlow, поскольку двунаправленные слои LSTM (используемые в keras-ocr) еще не поддерживаются в TensorFlow Lite.

Предварительно обученная OCR-модель


Для начала я написал тестовый скрипт (ocr.py), который показывает, как использовать модель нейронной сети из keras-ocr:

# Importsimport keras_ocrimport helpers # Prepare OCR recognizerrecognizer = keras_ocr.recognition.Recognizer() # Load images and their labelsdataset_folder = 'Dataset'image_file_filter = '*.jpg' images_with_labels = helpers.load_images_from_folder(dataset_folder, image_file_filter) # Perform OCR recognition on the input imagespredicted_labels = []for image_with_label in images_with_labels:predicted_labels.append(recognizer.recognize(image_with_label[0])) # Display resultsrows = 4cols = 2font_size = 14helpers.plot_results(images_with_labels, predicted_labels, rows, cols, font_size)

Этот скрипт создаёт экземпляр объекта Recognizer на основе модуля keras_ocr.recognition. Затем скрипт загружает изображения и их метки из прикреплённого набора тестовых данных (папка Dataset). Этот набор данных содержит восемь случайно выбранных изображений из набора синтетических слов (Synth90k). Затем скрипт запускает оптическое распознавание символов на каждом изображении этого набора данных, а затем отображает результаты прогнозирования.



Для загрузки изображений и их меток я использую функцию load_images_from_folder, которую я реализовал в модуле helpers. Этот метод предполагает два параметра: путь к папке с изображениями и фильтр. Здесь я предполагаю, что изображения находятся в подпапке Dataset, и я читаю все изображения в формате JPEG (с расширением имени файла .jpg).

В наборе данных Synth90k каждое имя файла изображения содержит метку изображения между символами подчёркивания. Например: 199_pulpiest_61190.jpg. Таким образом, чтобы получить метку изображения, функция load_images_from_folder разделяет имя файла по символу подчёркивания, а затем берёт первый элемент полученной коллекции строк. Также обратите внимание, что функция load_images_from_folder возвращает массив кортежей. Каждый элемент такого массива содержит изображение и соответствующую метку. По этой причине я передаю обработчику OCR только первый элемент этого кортежа.

Для распознавания я использую метод распознавания объекта Recognizer. Этот метод возвращает прогнозируемую метку, которую я сохраняю в коллекции predicted_labels.

Наконец, я передаю коллекцию прогнозируемых меток, изображений и исходных меток другой вспомогательной функции, plot_results, которая отображает изображения в прямоугольной сетке размера строки x столбцы. Внешний вид сетки можно изменить, изменив соответствующие переменные.

Камера


После тестирования OCR-модели я реализовал класс camera. В этом классе используется библиотека OpenCV, которая была установлена вместе с модулем keras-ocr. OpenCV предоставляет собой удобный программный интерфейс для доступа к камере. В явном виде вы сначала инициализируете объект VideoCapture, а затем вызываете его метод чтения (read), чтобы получить изображение с камеры.

import cv2 as opencv class camera(object):def __init__(self):# Initialize the camera captureself.camera_capture = opencv.VideoCapture(0)def capture_frame(self, ignore_first_frame):# Get frame, ignore the first one if neededif(ignore_first_frame):self.camera_capture.read()(capture_status, current_camera_frame) = self.camera_capture.read() # Verify capture statusif(capture_status):return current_camera_frame else:# Print error to the consoleprint('Capture error')

В этом коде я создал объект VideoCapture в инициализаторе класса camera. Я передаю объекту VideoCapture значение 0, чтобы указать на камеру системы по умолчанию. Затем я сохраняю полученный объект в поле camera_capture класса camera.

Чтобы получать изображения с камеры, я реализовал метод capture_frame. У него есть дополнительный параметр, ignore_first_frame. Когда значение этого параметра равно True, я дважды вызываю метод caper_capture.read, но игнорирую результат первого вызова. Смысл этой операции заключается в том, что первый кадр, возвращаемый моей камерой, обычно пуст.

Второй вызов метода read дает статус захвата и кадр. Если сбор данных был успешным (capture_status = True), я возвращаю кадр камеры. В противном случае я печатаю строку Ошибка захвата.

Преобразование текста в речь


Последний элемент данного приложения TTS-модуль. Было решено использовать здесь систему Festival, потому что она может работать в автономном режиме. Другие возможные подходы к TTS хорошо описаны в статье Adafruit Speech Synthesis on the Raspberry Pi (Синтез речи на Raspberry Pi).
Чтобы установить Festival на Raspberry Pi, выполните следующую команду:

sudo apt-get install festival -y

Убедиться в том, что всё работает правильно, можно, введя следующую команду:

echo "Hello, Arm" | Festival tts

Ваш Raspberry Pi должен произнести: Hello, Arm.
Festival предоставляет API-интерфейс. Однако для простоты было решено взаимодействовать с Festival посредством командной строки. С этой целью модуль helpers был дополнен ещё одним методом:

def say_text(text):os.system('echo ' + text + ' | festival --tts')

Собираем всё вместе


Наконец, мы можем собрать всё вместе. Я сделал это в скрипте main.py:

import keras_ocrimport camera as camimport helpers if __name__ == "__main__":# Prepare recognizerrecognizer = keras_ocr.recognition.Recognizer() # Get image from the cameracamera = cam.camera() # Ignore the first frame, which is typically blank on my machineimage = camera.capture_frame(True) # Perform recognitionlabel = recognizer.recognize(image) # Perform TTS (speak label)helpers.say_text('The recognition result is: ' + label)

Сначала я создаю OCR-распознаватель. Затем я создаю объект Camera и считываю кадр с веб-камеры по умолчанию. Изображение передаётся распознавателю, а полученная в результате метка произносится вспомогательным TTS-модулем.

Заключение


Итак, мы создали надёжную систему, которая способна оптически распознавать символы с использованием глубокого обучения, а затем передавать результаты пользователям посредством механизма преобразования текста в речь. Мы использовали пакет keras-OCR с предварительным обучением.

В более сложном сценарии распознаванию текста может предшествовать обнаружение текста. Сначала на изображении обнаруживаются строки текста, а затем распознаётся каждая из них. Для этого потребуются только возможности пакета keras-ocr по обнаружению текста. Это было показано в данной версии реализации Keras CRNN и опубликованной модели обнаружения текста CRAFT Фаусто Моралесом.

Расширяя указанное выше приложение функцией обнаружения текста, можно создать систему Интернета вещей, которая поддерживает РНС и выполняет OCR, чтобы помочь людям с нарушениями зрения читать меню в ресторанах или документы в государственных учреждениях. Более того, такое приложение с поддержкой службы переводов могло бы служить автоматическим переводчиком.

Хочется завершить этот материал цитатой третьего закона Артура Кларка:

Любая достаточно развитая технология неотличима от магии.

Если следовать ему то можно спокойно сказать, что у нас в SkillFactory мы обучаем людей настоящей магии, просто она называется data science и machine learning.



image
Подробнее..

CCTV на базе Raspberry Pi. Часть первая и, возможно, последняя

16.03.2021 16:20:24 | Автор: admin

Привет, коллеги!

Время одна из главных ценностей в нашей жизни, поэтому буду краток, чтобы не тратить, ни своё, ни ваше, понапрасну. Заодно предложу такой формат статей из двух частей. В первой резюме, так сказать, вехи проекта, а во второй, если информация будет вам интересна, распишу подробнее. Или отвечу на конкретные вопросы. Воды надо поменьше, по крайне мере в этих наших интернетах.

Итак, наконец у меня дошли руки просверлить/проштробить/собрать/накодить/отладить и запустить видеонаблюдение на базе малинок.

Ничего инновационного в проекте нет, просто в удовольствие и с некоторой экономией.

Задействованы

  • две старушки малины 1B с камерами первого поколения, которые лежали уже лет семь и просились помочь им обрести хоть какой-то смысл существования

  • относительно новая малина 3B и отдельный USB HDD к ней

  • всякая сетевая и питательная инфраструктура

Что особенно интересного было в проекте

Каждая из старушек гонит по TCP с помощью raspivid два потока на свежую малинку.

  • первый поток это H.264 ES, сырой видеопоток.

  • второй поток это, о чудо, motion vectors кодека H.264, которые raspivid может отдельно отдавать.

Свежая малинка работает как сервер (NodeJS), принимающая потоки от старушек (по два с каждой).

  • всё что прилетает в видеопоток дампится в файл на накопитель (с периодическим стартом нового файла). Разумеется, для каждой камеры отдельно.

  • всё что прилетает в поток векторов, используется для детектирования движения (работает весьма неплохо!). Тут мне сильно помогла репка с питониевым кодом для визуализации (https://github.com/janblumenkamp/raspivid_motionvectors), изучив код которой, я и сделал на NodeJS "детектор" движения без всяких этих ваших нейро. Посмотрим, как будет себя вести.

Также открываем на сервере для каждой малины один исходящий TCP-порт, к которому может подключиться, например:

  • mplayer в связке с ffmpeg для отображения на десктопе

  • ffmpeg, который будет оттуда забирать поток и пихать его в rtmp-модуль nginx для веб-стриминга

Волнообразную засветку из-за ККЛ удалось устранить с помощью --flicker, но с параметром auto, а не 50hz.

Длинные шлейфы (100см) дают тёмную картинку, что исправляется с помощью --digitalgain, но удалось обойтись меньшей длиной.

В качестве основы для корпусов я брал прекрасную работу https://www.thingiverse.com/thing:2746186, но пришлось доработать:

  • удлинить корпус камеры, чтобы она всё-таки была больше похоже на камеру, во избежание, так сказать

  • переработать основание под вставку магнитов, что позволяет удобно настроить позицию камеры на металле, а потом уже прифигачить на клей

  • заменить шаровую опору на несколько колен с винтовым соединением, потому что:

    • пластик усыхает и шар начинает болтаться

    • несколько удобнее позиционировать

Подробнее..

100500-ая автоматика полива для растений. Часть 2 Сенсоры и электроника

08.04.2021 20:08:42 | Автор: admin

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

Уровень воды

Сначала был дискретный сенсор, сделанный из двух пластин нержавейки.

две пластинки нержавейки ждут касания водыдве пластинки нержавейки ждут касания воды

Через некую (давно было, не сыскать уже исходников) схему сигнал поступал на контроллер. Дискретность его заключалась в том, что он показывал лишь наличие или отсутствие погружения сенсора в воду. Планировалось также мониторить уровень линейно в зависимости от степени погружения пластин в раствор, меняется сопротивление на таком сенсоре. Но данный метод был быстро забракован ввиду накопления осадка на пластинах (даже если не брать в расчёт налёт возникающий на пластинах вследствие электрического осаждения элементов раствора, оставался налёт, возникающий из-за высыхания раствора на воздухе) и, со временем, изменяющегося оттого сопротивления. Калибровка сбивалась.

Далее были опробованы различные ультразвуковые датчики: HY-SRF05, HC-SR04, JSN-SR04T, US-025. Наиболее приемлемыми (по измеряемому диапазону) и стабильными (с точки зрения показаний и выносливости) были были выбраны HC-SR04.

HC-SR04 смотрит на воду в бакеHC-SR04 смотрит на воду в баке

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

поплавок с герконом. Такой без проблем тянет 12В, 0.4Апоплавок с герконом. Такой без проблем тянет 12В, 0.4А


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

Слышал про использование лазерного датчика уровня. В комментариях подсказывают ставится в бак трубка с поплавком и на поплавок наводим лазер. С ним я пока не имел дел. Будет датчик попробую.

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

датчик давления крови. Достаточно чувствительный прибордатчик давления крови. Достаточно чувствительный прибор


Какие проблемы возникали при использовании ультразвуковых сенсоров? Первое, самое очевидное это колебания воды, при заполнении бака. Решается такое усреднением показаний, считываемых с датчика, в прошивке контроллера. Второе иногда бывают показания вообще за пределами диапазона пустой-полный бак. Подозреваю, что такое случается вследствие помех, наведённых на провод от датчика к контроллеру. Решается использованием провода не более двух-трёх метров и опять же программным способом если значение, уже усреднённое, достаточно долго находится выше верхней границы бака (а это значение мы задаём в момент настройки, калибровкой датчика по баку), то программа долива приостанавливается, закрывая клапан забора воды. Если же значение, читаемое с датчика, выше уровня в течение времени больше некоторого таймаута (назовём его TO1), то останавливаем забор воды, поднимая флаг соответствующей ошибки.

Третья проблема датчик залип на некотором значении внутри диапазона верх-низ бака. Такое, как правило, происходит по причине попадания воды на сенсор уровня. Для подобного рода ситуаций предусмотрен ещё один таймаут TO2. Это время, подбираемое опытным путём, устанавливает пользователь во время первичной настройки. Подбирается обычно так, чтобы быть чуть больше времени, затрачиваемого системой на заполнение бака с нуля до самого верха. Если этот таймаут превышен, то отключам автоматику долива, поднимая флаг ошибки. Вернуться к работоспособности автоматики можно после сброса пользователем данной ошибки.
Кто-то может удивиться, мол, зачем такие сложности? Если у вас теплица на земле, действительно, может статься так, что часть мер излишняя. Но если под вами есть соседи, то я бы порекомендовал проверить в тестовом прогоне все варианты аварий, приводящих к потопу.

Температура

Тут можно измерять температуры воды, воздуха. Изначально опыты проводились на обычных резистивных датчиках, типа, PT100. Далее были освоены датчики DHT11/22. И ещё позже DS18B20. Резистивным датчикам необходим аналоговый вход на контроллере. По входу на каждый датчик. DHT тоже хотят по входу на каждый, но уже можно использовать цифровые входы (коих, обычно, больше). В DHT плюсом идёт измерение влажности. DS18B20 хорош тем, что на один пин контроллера можно подключить несколько датчиков разом. По-итогу, на сегодня, в самом устройстве ставится один DS18B20, измеряющий температуру воды в районе магистрали смешивания удобрений. Это становится излишним, когда в сенсор EC уже встроен резистивный термодатчик, измерения с которого снимаются AD5934, входящим в состав блока для измерения EC.

DS18B20 подключается с резистором 10к между питанием и линией данных.

EC (ака TDS, ака солемер)

Для измерения количества солей были также перепробованы несколько способов:

1. По этой ссылке была найдена следующая схема

Измеритель EC/TDS на TL074. http://www.octiva.net/projects/ppm/Измеритель EC/TDS на TL074. http://www.octiva.net/projects/ppm/

Далее была разведена плата и фоторезистивным методом собственноручно (то было во времена, когда JLCPCB был мне неизвестен, если существовал вообще) изготовлена, с применением хлорного железа и прочими шаманствами. Подозреваю, что руки мои на тот момент росли значительно ниже плеч, что попрепятствовало успеху с данной схемой. На самом деле, один модуль даже работал и весьма неплохо. А вот ещё парочка-другая, почему-то заводиться отказалась.

2. Была ещё одна схема на TL074, но сейчас, к сожалению, не вспомню откуда и какая. Учитывая только память о том, что была пробная сборка на макетке, видимо она не заработала.

3. Самой простой и очевидной оказалась схема измерения влажности на таймере 555.

измеритель влажности на таймере 555. http://www.emesystems.com/OLDSITE/OL2mhos.htmизмеритель влажности на таймере 555. http://www.emesystems.com/OLDSITE/OL2mhos.htm

Это натолкнуло меня на изучение данного таймера и в итоге я собрал нечто похожее, что даже заработало. Погрешность была, мягко говоря, так себе. Однако воспроизводимость была 100%. Достаточно долго этот вариант меня вполне устраивал, пока не появилась необходимость сделать более точный. Так появился следующий вариант с применением...

4. AD5934 который водит в состав демонстрационной платы EVAL-0349, от Analog.

демо-плата EVAL-0349 от Analogдемо-плата EVAL-0349 от Analog


Тут уже всё стало более чем серьёзно (на самом деле есть варианты ещё более точные, с более широким диапазоном измерений и более кусачей ценой, но наврядли они пригодятся в растениеводстве). Шутка ли два диапазона измерений (первый: от 25S до 2500S, второй: от 0.2mS до 200mS) с относительной погрешностью измерений 0.5% для первого диапазона и 1% (после программной коррекции. Если без неё, то 3%) для второго. Вообще, AD5934, насколько я сегодня понимаю, был придуман больше для измерения качества проводной сети (типа, проверять затухание сигнала в витой паре). Но CN0349 рассказывает удивительные вещи и про растворы солей. Рекомендую изучить сей circuit note, для общего образования.

схемы EVAL-0349 с сайта analog.comсхемы EVAL-0349 с сайта analog.com


Если вкратце, то работает эта штука следующим образом: есть микросема ADG715, которая делает выбор между одним из двух пределов измерений EC или термодатчиком. Есть сам AD5934, который измеряет сопротивление с сенсора EC или резистивного термодатчика через операционный усилитель AD8606. Всё это дело заведено через изолятор питания ADuM5000 и изолятор данных ADuM1250. Чтобы всё это собрать и запустить на своей плате, пришлось изрядно покурить даташиты по всем этим компонентам. В итоге, когда всё заработало, измерения электропроводности воды стали максимально достоверными за всю историю проекта. Сами сенсоры, после самодельных, были взяты с aliexpress, с сантехнической резьбой пол-дюйма, со встроенным резистивным термодатчиком. Константа сенсора 1.0.

EC сенсор с удлиннителем примеряется в гидросистему аппарата полива растенийEC сенсор с удлиннителем примеряется в гидросистему аппарата полива растений

Для внедрения этого, достаточно длинного сенсора, в уже имеющуюся гидросистему, пришлось сделать небольшой удлинитель.

Сенсоры давления воды

Калибровка стального датчика давленияКалибровка стального датчика давления

Были опробованы стальные из нержавейки, потом из некого иного металла, покрытого хромом и уже потом нашлись пластиковые. Первый был с метрической резьбой и найти готовый переходник на сантехническую резьбу оказалось проблемой. Второй и третий уже были с резьбой BSP на четверть дюйма. Перейти на требуемые пол-дюйма уже не составило труда (с помощью найденного в продаже полипропиленового переходника). Во времена попыток с первым сенсором из нержавейки, мне даже не пришло в голову, что можно взять метчик и нарезать метрическую резьбу нужного размера в любой подходящей заглушке на пол-дюйма, предварительно лишь засверлив её.

Все эти сенсоры расчитаны на 5В питание. Выдают, соответственно, напряжение, линейно зависящее от давления, в диапазоне от 0.5В до 4.5В. АЦП контроллера STM32 запитан от 3.3В, следовательно в схему подключения привносится самый простой делитель напряжения резистивный.

Измерение кислотности раствора

Измерение кислотности раствора происходит обычным сенсором pH, которые также продают на aliexpress.

Как уже упоминалось, первый, достаточно добротный вариант удалось собрать на операционном усилителе CA3240. Схема была взята тут.

измеритель pH. http://www.emesystems.com/OLDSITE/OL2ph.htmизмеритель pH. http://www.emesystems.com/OLDSITE/OL2ph.htm

Первая версия, собранная своими руками выглядела как-то так

как ни странно, это заработалокак ни странно, это заработалоэтот вариант стал ещё лучше, уменьшившись в размерах и получив экранэтот вариант стал ещё лучше, уменьшившись в размерах и получив экран

Следующим стал модуль на специализированном решении (LMP91200 от Texas Instruments), заточенном под измерение кислотности стандартными сенсорами pH.

Типичная схема из даташита незамысловата, её и взял.

схема типичного применения LMP91200 из даташита. ti.comсхема типичного применения LMP91200 из даташита. ti.com

там же в даташите нарисовано как надо разводить плату.

Рекомендуемый в даташите на LMP91200 дизайн платыРекомендуемый в даташите на LMP91200 дизайн платы

По схеме из даташита, как видим, выход с LMP91200 подаётся на вход АЦП контроллера, я же направил этот выход на вход отдельного АЦП ADS1110. Этот АЦП уже передаёт данные на STM32 по I2C, через гальваническую развязку в лице ADuM1250 (данные) и дешевого изолятора питания на 1 ватт B0505S-1W (питание).

Изолятор питания B0505S-1WИзолятор питания B0505S-1W


Можно, конечно, как в EVAL-0349 использовать ADuM5000, но этот товарищ имеет одно неприятное свойство достаточно сильные помехи (про это можно почитать в даташите на данный изолятор и сопутствующие аппноты про EMI considerations), требующие разводить плату соответствующим образом.

RTC

Хоть это и не сенсор, но тоже важная периферия, поскольку в системе активно используются различные таймеры. Дело в том, что многочисленные проблемы с RTC, идущим вместе с STM32 прилично утомили. Среди этих проблем были некачественные blue-pill (да, именно на них была разведена основная масса версий плат), криво припаянные кварцы, невидимые сопли на контактах кварца или пинах (PC14, PC15), самого чипа контроллера, куда подключаются кварцы. Однажды я заметил, что часы идут, пока blue-pill не вставлена в разъёмы платы контроллера. Как только вставляешь не идут. Достаёшь опять идут. Отрезал от пилюли пины (PC14, PC15), которые вонзались в разъёмы часы пошли в любом положении. Не любят эти выводы лишних емкостей. Можно было бы как следует чистить платы, разъёмы, отрезать пины, покрывать лаком... да вот один случай совсем расстроил в один из аппаратов забрался таракан и прилёг погреться на чип STM32. Что за дискотеку он там устроил не очень понятно, да вот только напачкал прилично, прям на чипе и вокруг. Встроенный RTC встал. Чистка помогла, но было принято решение дублировать часы при помощи DS3221.

Что было опробовано, но пока не вошло в обиход в силу тех или иных причин

Счётчик воды

Счётчик воды для шлангаСчётчик воды для шланга


В числе прочих тестированию подверглись две модели счётчиков воды. Однако, эти измерительные приборы для выдачи верных показаний требуют полное отсутствие пузырей в жидкости. Любые изгибы, смены диаметров водонесущих трубок и прочие мелочи вызывают появление пузырей в воде. Когда пузырь проходит по счётчику, последний норовит посчитать воздух за воду, да ещё и в бОльшем объёме.

Счётчик воды с резьбойСчётчик воды с резьбой


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

СО2

Сенсор концентрации углекислого газа MG811Сенсор концентрации углекислого газа MG811


Эксперимента ради был также испробован сенсор концентрации углекислого газа MG811. Сенсор представляет из себя устройство, типа батарейки, с электролитом внутри. Судя по даташиту, ЭДС такой батарейки связан через уравнение Нернста с концентрацией углекислого газа в измеряемой атмосфере. Генерируемые токи такого элемента в районе единиц пикоампер, поэтому часто можно в продаже встретить MG811 в составе шилда, на котором расположен операционный усилитель для поднятия столь мизерных токов. Испольуется такой сенсор не сразу, типа, включил и измеряешь, а в условиях прогретого сенсора. Для этого в MG811 встроен нагревательный элемент, который запитывается по двум (из шести всего) отдельным пинам и потребляет пару сотен миллиампер. И эти миллиамперы, зачастую, несмотря на шилды со встроенными усилителями, требуется подавать с напряжением 6В. Не сказать, чтобы большая проблема поставить дополнительный повышающий преобразователь с 3.3 или 5 вольт, но учитывать этот момент всё же приходится. Вероятно, есть в природе шилды со встроенным повышающим преобразователем напряжения, но мне попадались без него. Времени на разогрев требуется около минуты, отзывчивость тоже не такая резкая, что подышал и увидел броски показаний. За неимением газового обрудования и возможности его применять в полной мере, отложил сей сенсор пока на полку. Кстати, для полноценной работы с ним будет нелишним обзавестись смесями калибровочных газов, что иногда затруднительно и доставляет хлопот поболее, чем с теми же калибровочными жидкостями для pH сенсоров.

Из известных мне, есть ещё инфракрасные сенсоры углекислоты, так называемые NDIR. Их есть несколько моделей. Отличаются скоростью отклика, диапазонами измерений, погрешностью и, разумеется, ценой. В качестве примера, на который в своё время посматривал, могу назвать MH-Z14A. Рекомендовать или отговаривать не могу, ибо не имею в наличии и не проверял. На Хабре есть те, кто держал подобные в руках (раз и два).

Датчик освещённости

Хороший пример описан тут

Системы, способы контроля и предотвращения нештатных ситуаций. Электроника

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

Watchdog

В контроллерах STM32 имеется встроенный независимый вочдог таймер именуемый IWDG (Independent WatchDoG). Он хорошо справляется с подавляющим числом зависаний контроллера, на большинстве контроллеров позволяет даже просыпаться из глубокого сна. Однако, как показала практика (особенно на сырых версиях электроники, да простят меня олдовые), в реальных условиях, даже он не всегда справляется. Поэтому был установлен дополнительный, аппаратный сторожевой таймер. С усовершенствованием схемотехники и прошивок, толку от него становится меньше. Тем не менее, для страховки он остался по сей день. Я использовал MAX6369. Для тех кто не в курсе, поясню вкратце у аппаратного сторожевого таймера выход WDO подключается на вход RESET контроллера, а вход WDI заводится на одну из ног контроллера. Когда всё работает, прошивка периодически генерирует импульс на WDI, чтобы дать понять сторожевому таймеру, что всё впорядке. Если в течение продолжительного времени на WDI такого импульса не приходит, сторожевой таймер даёт импульс на WDO, что приводит к аппаратному (как от кнопки) перезапуску контроллера. Можно такой сторожевик собрать и на таймере 555 (чем я тоже баловался в качестве эксперимента), но он занимает прилично места, по сравнению со специализированными решениями.

Неопредённые состояния во время старта

Неопредённые состояния во время старта больше всего досаждают на исполнительных устройствах. Пока контроллер не загрузился, на выходах творится непонятное, что приводит к нежелательным срабатываниям всего, что управляется этими выводами (управление питанием измерительной техники, клапана, дозаторы...). Чтобы устранить эти явления, на контроллере можно железно подтянуть управляющие выходы к земле (или питанию. В зависимости от полярности управляющего сигнала) резистором. В данном случае так сделано, например, для полевых транзисторов, которые управляют питанием измерительных модулей и Raspberry Pi.

разные варианты драйвера нагрузок, до и после испытанийразные варианты драйвера нагрузок, до и после испытаний

Поскольку у меня исполнительными устройствами усправляет отдельный драйвер, где управляющие сигналы создаёт экспандер MCP23017, то подтянуть все 16 линий, вероятно (следует заглянуть в даташит на L6205 и/или протестировать в железе, чтобы уточнить однозначно), можно на нём. Однако, чтобы получить результат наверняка и с меньшим числом точек запайки я выбрал установку достаточно мощного полевого P-канального транзистора на питание всех L6205. В результате, этим полевиком управляет основной контроллер STM32 через оптопару. Логика прошивки сначала инициализирует все входы/выходы на выход, пишет в регистры выходов нули (всё выключено), зачитвает обратно содержимое этих регистров, сверяет с тем, что только что было записано и, если все биты совпадают, то старт считается успешным. Если старт определился как неуспешный, поднимается соответствующий флаг ошибки и работа всей силовой части блокируется (основной контроллер не станет открывать полевик до устранения проблемы). Если же старт засчитан успешным, то полевик всё ещё будет закрыт. До тех пор, пока не будет выдана команда на запуск одной из нагрузок, которая (команда) отправит на экспандер драйвера последовательность бит (где как минимум один из битов будет отличаться от нуля) и не прочитает обратно такую же последовательность. Когда все эти условия выполнятся, основной контроллер открывает MOSFET и только тогда драйвер начинает питать нагрузку. По завершении работы нагрузки/нагрузок, основной контроллер вновь отключает питание силовой части драйвера, закрывая полевик до следующих мероприятий. Если происходит физический обрыв проводов (скажем, отгрызла внезапная мышь), то линия управления полевым транзистором ложится в ноль (для P-канального, на самом деле, в 1) и нагрузки не сдвинутся с места (как минимум, до тех пор, пока не будет отгрызен подтягивающий резистор).

Кстати, о силовом драйвере. Однажды, пришёл ко мне один молодой человек и попросил дать ему попрактиковаться в сборке. Было ему выделено место, даны компоненты, паяльник, платы, схемы, тестовый аппарат. Собрал он пару таких драйверов и стал их тестировать. Не получается. Звонит мне, рассказывает невероятные вещи. Приехать на место и проверить лично в чём там дело непросто - я в другой стране. В драйвере этом, в роли экспандера, использовалась 74HC595. Он тычет в неё и говорит, мол, то ли микросема отстой, то ли прошивка твоя не важнецкая. Дело дрянь, вобщем. Я проверяю прошивку на своём девайсе, перепроверяю все подключения у себя, шлю ему видео. И у него всё-равно не работает. Ну, думаю, что с микросхемами-то может быть. Я же не DI HALT, который всё-всё видывал в силу огроменного опыта и может писать про подделки, в которых нет кристаллов или ещё что похуже. Мне чисто по теории вероятности левак достанется крайне наврядли - думал я. А вариант с прошивкой не подтверждался в моих тестах.
Микрухи, действительно, оказались леваком. Об этом я узнал, когда прибыл на место событий. Чувак к тому моменту пропал за горизонтом. Так что, если ты вдруг это читаешь, дядька, знай - ты был прав, микрухи оказались шляпой. А я ошибся.

Малина

Иногда Raspberry Pi может перестать подавать признаки жизни. Как сказано выше, основной контроллер может управлять её питанием. И в таких случаях тишины он именно это и делает. Причин тишины от малины может быть несколько. Наиболее частые из них: перегрев малины или износ карты памяти. Для нивелирования зависаний по перегреву основной контроллер выжидает заданный промежуток времени, после чего перезапускает питание Raspberry Pi. То же самое происходит и в случае с износом карты памяти, только здесь, как несложно догадаться, рестарт уже не помогает. Специальный счётчик даёт несколько попыток рестарта. Если они не помогли, то, как это уже стало традицией, поднимается соответствующий флаг ошибки и малина оставляется в покое.

Чтобы износ карт памяти происходил как можно реже, используется как минимум две карты. Одна из них монтируется в режиме только для чтения. С неё происходит загрузка системы. Логи, данные, графики пишутся на отдельную карту, смонтированную для чтения/записи. Кроме этого, в ходе испытаний были испробованы различные карты памяти и из них выбраны наиболее долговечные. Разница в жизнеспособности разных представителей карт памяти измеряется порядками. Некоторые карты перестают записываться, а некоторые даже читаться. Чтобы не просрать все полимеры логи, написана функция, запускающая телеграм-бота, который периодически шлёт пользователю графики логов.

Питание

Питание системы также отметилось в статистике отказов. Наиболее частой проблемой стали излом проводов и раскручивания клемм на блоках питания. Это нормальная ситуация на аппаратах, нагруженных вибрацией. Чтобы хоть как-то минимизировать этот эффект, было решено закручивать в клеммы не просто концы проводов, а делать на концах колечки. Это улучшает зажим. Плюс к этому, закручивать следует изо всех сил. Несмотря на силу закручивания, пользователю рекомендуется иногда приносить аппарат на профилактику, в ходе которой, среди прочего, делается протяжка клемм.

Кстати, о клеммах

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

клемма поплылаклемма поплыла

Они были использованы в первых версиях аппаратов на проводах основного насоса. Сначала ставились рядом с мотором, чтобы удобно было поставить обратный диод. Когда принесли аппарат с погоревшими клеммами, диод я стал запаивать, а клеммы вынес подальше, сантиметров на 10-15. Это не изменило ровным счётом ничего. Больше я их там не использую вообще, только запайка. А вот разём GX16 справляется и не чернеет даже (хотя, лет через 10, кто его знает).

Пара историй про химические фэйлы

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

Второй аналогичный случай произошёл на бетонном полу. Бетон тоже пришёлся органике по вкусу. Никакая перекись не смогла справится со следами после уборки. Спустя время, в этом месте, на бетоне продолжилась жизнь в лице зелёной плесени.

Ещё один случай связан с кислотой. Там была азотная кислота, около 35% концентрации, подключенная в дозатор. На КДПВ из первой части видно, как штатные светло-кремовые шланги дозаторов переходят через черные соединители в коричневые (бывают черные) ПВХ. Это был тот самый случай. Как выяснилось (да простят меня химики), так делать категорически не следует. ПВХ за считанные дни задубел, соединители превратились в сопли-порошок, система потекла (хорошо, что аварийный дренаж был в наличии). Теперь только шланги, рекомендованные производителем под эти кислоты, с регламентом снятия/замены. И кислоты разводить в воде.

светлые трубочки идущие в канистры - расходный материалсветлые трубочки идущие в канистры - расходный материал
Подробнее..

Telegram для бабушки испанец создал механическую DIY-машину для чтения и печати сообщений

27.04.2021 14:21:47 | Автор: admin

Общение в мессенджерах давно стало нормой для большинства жителей планеты. Но далеко не все пожилые люди овладели современными технологиями. Чтобы облегчить коммуникацию со своей 96-летний бабушкой, испанец Мануэль Лусио Далло создал механическую машину. Ее общение с внуками было сильно ограничено во время пандемии, что и вдохновило испанца на разработку устройства. Аппарат умеет принимать текстовые и отправлять голосовые сообщения. Технологическая схема процесса напоминает использование старого телефонного коммутатора.

Yayagram для бабушки


Источник
Испанец назвал устройство Yayagram. На кастильском диалекте yaya это вариант теплого обращения к бабушке.


Две основные функции Yayagram:

  1. Отправка голосовых сообщений.
  2. Прием сообщений с печатью на термобумаге.


Как же оно работает? Чтобы отправить сообщение, нужно подключить физический кабель рядом с именем получателя. Во время проговаривания сообщения следует нажать и удерживать кнопку встроенный микрофон запишет звук. На телефон адресату придет стандартная голосовая заметка. Когда же на устройство приходит текстовое сообщение, оно печатается с помощью встроенного термопринтера.

Создание DIY-устройства


Источник
Далло работает в компании, разрабатывающей ПО Plastic SCM. Для создания аппарата для бабушки он использовал Raspberry Pi 4 и несколько сторонних программных библиотек. Код написал на Python. Микрофон самый обычный. Встроенный принтер похож на те, что используют в кассовых аппаратах. Помимо этого, в устройстве задействованы несколько светодиодов, разъемов, кабели и кнопки. По словам Далло, синхронизировать аппарат с Telegram он решил из-за большей открытости сервиса по сравнению с другими мессенджерами. А еще он не любит Facebook.

Источник
Бабушка Далло живет в испанском городе Бургос (Burgos), вдалеке от большинства своих внуков. Во время пандемии они не могли ее навещать. Еще его бабушка плохо слышит, поэтому разговаривать с ней по телефону или с помощью видеозвонков порой проблематично. Теперь же с помощью Yayagram она может самостоятельно отправлять и получать сообщения.

Аппарат обошелся Далло в 76 евро. Патентовать устройство он не собирается. В планах у разработчика опубликовать исходный код и детали проекта, чтобы сделать его доступным для всех желающих и помочь наладить общение между поколениями.

Подробнее..

Ретроконсоль своими руками Часть1. Выбираем железо

27.04.2021 20:11:49 | Автор: admin

Нелегкая ситуация, сложившаяся на рынке видеокарт, отличный повод вспомнить о том, что компьютерные игры это вовсе не 4K, не волшебные лучи RTX и тем более не количество полигонов на кончике носа главного героя. Крепко сбитый, захватывающий игровой процесс вот то, что отличает хорошую видеоигру от плохой, а вовсе не качество графики. В наше время это сакральное знание во многом было утеряно: современные игроделы делают ставку на красивую картинку и аддиктивные механики, забывая о том, что игра прежде всего должна развлекать и приносить радость.

Впрочем, благодаря эмуляторам классических игровых систем, сегодня практически каждый может прикоснуться к удивительному миру ретроигр, создатели которых ставили во главу угла именно геймплей. Ну а самый идеологически верный способ это сделать собрать миниатюрную консоль на базе одноплатного компьютера. Справиться с подобной задачей сможет даже человек, далекий от мира DIY, благо все необходимое можно приобрести на AliExpress, а сам процесс сборки подобного девайса оказывается не намного сложнее сборки конструктора Лего.

В первой части данного материала мы поговорим о том, какие компоненты необходимы для сборки ретроконсоли, а вторую всецело посвятим выбору подходящей операционной системы и настройке программного обеспечения. Статья ориентирована на новичков, которые прежде не имели дела с подобными проектами.

Лучшая платформа для первых экспериментов

Тем, кто ранее никогда не имел дела с одноплатными компьютерами, мы настоятельно рекомендуем начинать с Raspberry Pi. Данная платформа успешно развивается с 2012года и обрела за это время массу поклонников по всему миру. Сегодня для малинки выпускается огромное количество разнообразных модулей, корпусов и периферии, а Интернет буквально переполнен пошаговыми туториалами, посвященными созданию ретроконсолей, а также решению типичных проблем, неизбежно возникающих при реализации подобных проектов. С учетом качества, дешевизны и достаточно высокой для устройств такого класса производительности, все перечисленное делает Raspberry Pi наиболее оптимальным выбором для новичка.

Но какую же модель предпочесть: наиболее актуальную Raspberry Pi 4B или же недорогую Raspberry Pi 3B? Ответ на этот вопрос зависит от того, во что именно вы собираетесь играть. Оба одноплатных компьютера прекрасно справляются с эмуляцией 8-, 16- и 32-битных консолей, демонстрируя устойчивый фреймрейт 60 кадров в секунду даже в самых технически навороченных играх для первой PlayStation. Однако, когда речь заходит о более мощных приставках, у 3B начинаются серьезные проблемы. Следующее сравнение наглядно демонстрирует разницу в производительности между третьим и четвертым поколениями малинки при эмуляции игр для Sega Dreamcast.

Разница видна невооруженным глазом. Если говорить о цифрах, то даже в наиболее тяжелых сценах фреймрейт на 4-й модели Raspberry Pi не опускается ниже 3235 кадров в секунду, чего вполне достаточно для комфортной игры, тогда как максимальный FPS достигает 5860 к/с. Третья модификация малинки, увы, не вытягивает игры для Dreamcast в принципе: FPS регулярно падает до неиграбельных 10 кадров в секунду, а в некоторых сценах можно заметить графические артефакты, причина которых кроется отнюдь не в низкой точности эмуляции, а в том, что SoC банально не успевает обрабатывать все имеющиеся в кадре объекты.

Аналогичным образом дела обстоят и с эмуляцией Nintendo 64, хотя там результаты значительно разнятся в зависимости от конкретной игры. Так, например, в Super Smash Bros. фреймрейт не опускается ниже 59 FPS, тогда как в Golden Eye средняя частота кадров колеблется у отметки 25 кадров в секунду, при этом геймплей сопровождается постоянными фризами.

А вот количество оперативной памяти (напомним, что Raspberry Pi 4B выпускается в трех версиях: с 2, 4 и 8 гигабайтами RAM на борту) закономерно не влияет на скорость эмуляции.

Сравнительные тесты наглядно показывают, что даже при работе с эмуляторами GameCube и PSP главной проблемой одноплатного компьютера оказывается именно низкая производительность CPU и видеоядра, но никак не объем оперативки.

Таким образом, если вы планируете использовать Raspberry Pi исключительно для игр, то можете дополнительно сэкономить, приобретя базовую версию с 2 гигабайтами RAM.

Корпус для ретроконсоли

Если вы являетесь счастливым обладателем 3D-принтера, то сможете самостоятельно создать для малинки подходящий корпус. В противном случае добро пожаловать на AliExpress. Здесь можно без труда найти десятки вариантов корпусов под Raspberry Pi любых модификаций, начиная от простых наборных коробочек из акрила и заканчивая продвинутыми решениями с продуманным охлаждением и контроллерами дополнительных портов. Базовый набор стоимостью около 500 рублей будет выглядеть примерно так.

В комплект, помимо самого корпуса, состоящего из нескольких акриловых пластин, уже входят радиаторы для чипов, миниатюрный кулер, крепежные винты и отвертка для сборки. В принципе, этого вполне хватит для использования Raspberry Pi в качестве игровой приставки. Жаль только, что в таком виде малинка не особо похожа на ретроконсоль и не вызывает того неуловимо-сладостного чувства, которое принято называть ностальгией. Впрочем, этот недостаток легко исправить.

На просторах маркетплейса можно отыскать и кастомные корпуса, стилизованные под игровые консоли прошлых лет. Одной из самых интересных таких моделей по соотношению цена/качество является Retroflag NESPi 4, создатели которой вдохновлялись легендарной Nintendo Entertainment System.

В набор, который обойдется вам в сумму от 3 до 3,5 тысячи рублей в зависимости от продавца, помимо самого корпуса, входят: кулер, две термопрокладки, отвертка, адаптер питания, кабель micro-HDMI для подключения ретроконсоли к монитору или телевизору, инструкция по сборке, а также картридж-переходник для 2,5-дюймового SATA SSD. Встроенный в корпус SATA-контроллер подключается к одному из разъемов USB 3.0 малинки, поэтому один из двух имеющихся на плате высокоскоростных портов будет всегда занят, что, впрочем, не является критичным для подобного проекта.

Поскольку интерфейс третьей версии обладает пропускной способностью 5 Гбит/с (то есть 640 МБ/с), твердотельный накопитель будет работать практически так же быстро, как и при прямом подключении к SATA-разъему материнской платы (для сравнения, максимальная производительность топового WD Blue 3D NAND составляет 560 МБ/с в операциях последовательного чтения и 530 МБ/с при записи файлов). А самое главное, у вас появится возможность подключать дополнительное хранилище под файлы на случай, если вы захотите собрать ультимативную коллекцию игр для PlayStation и Dreamcast или же использовать ретроконсоль в качестве видеоплеера. Подключить же такой картридж к ПК или ноутбуку можно с помощью стандартного переходника SATA-USB.

Retroflag предлагает и собственный адаптер для работы с картриджем. Стоит такое удовольствие около 1500 рублей, при этом его использование не дает каких-либо значимых преимуществ, кроме разве что светодиодного индикатора активности SSD.

Так что приобретать подобное чудо техники имеет смысл лишь в том случае, если вам важен дизайн. Ведь переходник выполнен в том же стиле, что и оригинальные чехлы для картриджей Nintendo Entertainment System, если не считать отсутствия товарного знака Nintendo, на использование которого у RetroFlag попросту нет прав.

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

Единственным недостатком этого корпуса можно назвать очень короткие провода для подключения к Raspberry Pi контроллеров внешних портов и вентилятора кулера, что несколько усложняет процедуру сборки. Впрочем, с этим недостатком вы столкнетесь лишь единожды во время установки одноплатного компьютера внутрь.

Клавиатура и мышь

Хотя для игр мы будем использовать геймпад, первичная настройка ретроконсоли потребует наличия полноценных устройств ввода. В принципе, к Raspberry Pi можно подключить любую стандартную USB-клавиатуру и мышь, благо одноплатный компьютер оснащен полноразмерными портами USB. Однако для большего удобства вы можете приобрести беспроводную мини-клавиатуру со встроенным тачпадом наподобие Rii i8.

Такое устройство не особо подходит для повседневного использования из-за своих скромных размеров, однако для периодического администрирования является практически идеальным вариантом, помогая в том числе сэкономить дополнительный USB-порт, которых у малинки и без того не очень много. Среди преимуществ данной модели также необходимо отметить наличие мультимедийных кнопок это позволяет использовать клавиатуру в качестве пульта ДУ при просмотре видео.

Геймпад в стиле ретро

Если вы привыкли к Dualshock 4 или Xbox One Controller, то сможете использовать для игр полюбившийся геймпад, благо популярные дистрибутивы операционных систем для ретроконсолей поддерживают перечисленные игровые манипуляторы из коробки. Желающие предаться ностальгии по полной программе также могут приобрести контроллеры, стилизованные под геймпады для консолей прошлых лет: на том же Aliexpress можно отыскать десятки разнообразных моделей на любой вкус и кошелек.

В качестве же своеобразной золотой середины между этими крайностями мы можем порекомендовать 8BitDo SN30 Pro+.

Компания 8BitDo хорошо зарекомендовала себя среди поклонников ретрогейминга, предлагая покупателям сравнительно недорогие, но при этом весьма качественные игровые манипуляторы. Модель SN30 Pro+ позиционируется как универсальный геймпад и совместима с операционными системами Windows, macOS, Android, корректно распознается RetroPie, Recalbox и Lakka и может использоваться даже в качестве замены Pro-контроллера для Nintendo Switch.

По дизайну SN30 Pro+ представляет собой нечто среднее между DualShock для PlayStation и геймпада SNES. Два аналоговых стика и полный набор кнопок позволяют использовать данный контроллер не только с любыми эмуляторами ретроконсолей, но и в современных играх. Среди интересных особенностей устройства необходимо отметить:

  • наличие аналоговых курков;

  • возможность написания собственных макросов с помощью фирменного ПО;

  • съемный аккумулятор, который при необходимости можно заменить на две пальчиковые батарейки;

  • расширенная поддержка (хотя релиз геймпада состоялся в 2019 году, обновления прошивки выпускаются до сих пор: последняя версия микропрограммы датируется 14 января 2021 года).

Заплатить за все это великолепие придется примерно 4 тысячи рублей. Если же вам не особо импонирует дизайн с рожками DualShock, вы можете заказать обычную версию геймпада без приставки плюс.

По размерам и форме такой геймпад приближен к контроллеру для Super Nintendo, технически ничем не отличаясь от своего старшего брата. Данная версия обойдется вам примерно на 500 рублей дешевле.

Выбираем карту памяти для ретроконсоли

С выбором карты памяти все отнюдь не так просто, как может показаться на первый взгляд. Прежде всего определимся с емкостью. Для установки и корректной работы операционной системы нам понадобится 16 ГБ дискового пространства, тогда как весь остальной доступный объем можно будет использовать для размещения самих игр. Таким образом, в минимальной конфигурации будет достаточно microSD-карты объемом 32 ГБ, но лишь в том случае, если круг ваших интересов ограничивается проектами 8/16-битной эпохи. С учетом того, что в течение жизненного цикла той же PlayStation One было выпущено около 8 тысяч проектов, средний объем каждого из которых составлял 400 МБ, полная коллекция игр для классической приставки Sony будет занимать более 3 терабайт, в то время как сборник игр для NES весит от силы 5060 МБ.

Впрочем, поскольку Raspberry Pi поддерживает стандарт SDXC, с дефицитом свободного места у вас точно не возникнет проблем: если обратиться к перечню протестированных моделей, то в нем можно найти даже SanDisk Extreme Pro на 512 ГБ.

Другое дело, что подобные карточки достаточно дороги. Так что если вы не собираетесь использовать свою ретроконсоль в качестве мультимедийного сервера, то их покупка является не особо рентабельной. В случае же приобретения упомянутого Retroflag NESPi 4, позволяющего подключать к малинке полноценные SATA SSD да еще и менять их, словно игровые картриджи, смысл в использовании карты памяти большой емкости и вовсе теряется.

Помимо объема, при выборе microSD-карты для Raspberry Pi следует обращать внимание на ее скоростные характеристики. И речь идет не только о скорости чтения/записи, но и о минимальном устойчивом количестве операций ввода-вывода в секунду (IOPS) показателе, который напрямую влияет на производительность флеш-карты при работе с приложениями. Поскольку мы с вами будем использовать микрокомпьютер в качестве ретроконсоли, нам будет вполне достаточно карты памяти уровня SanDisk Ultra.

Карты памяти данной линейки относятся к классам производительности C10, U1, A1. На практике это означает, что даже в самых неблагоприятных условиях скорость передачи данных между флеш-картой и одноплатным компьютером не будет опускаться ниже 10МБ/с (C10, U1), а минимальное устойчивое количество операций ввода-вывода составляет 1500 IOPS в операциях случайного чтения и 500 IOPS при записи файлов (A1). Поскольку эмуляторы ретроконсолей не особо требовательны к скорости системного накопителя, а сами дистрибутивы игр отличаются малым объемом, для наших нужд этого будет более чем достаточно. С учетом того, что в операциях последовательного чтения/записи производительность SanDisk Ultra достигает 100МБ/с, особых проблем с загрузкой новых игр также не возникнет, поскольку в среднем на передачу каждых 4 ГБ данных будет уходить не более 1 минуты.


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

Подробнее..

Самодельный стратостат

30.04.2021 12:16:20 | Автор: admin

result_lowres


Допустим, вы интересуетесь космосом, но космос для вас недоступен. Выше 10км не подняться, а посмотреть "что там?" очень хочется. По классификации NASA нижняя граница космоса начинается на 100км от поверхности Земли. Эта статья будет не совсем про космос, но про возможность создания своего стратосферного зонда с нуля. Я много видел примеров успешного запуска и несколько статей на Хабре, но почти все они это отчеты. Я же хочу оставить статью, которая сможет претендовать на "complete guide" для юных покорителей. Запаситесь терпением и безлимитным интернетом будет много текста, картинок и даже пару видео. Это был долгий путь для нас, но я намерен сделать его не таким изнурительным для всех желающих. Поехали?


Вступление


В этом проекте участвовало довольно много людей (навскидку ~10). Один бы я, разумеется, все это не потянул. Да и с друзьями интересней. У каждого была своя незаменимая роль в этом деле. А так как я организатор, вдохновитель и спонсор всего проекта, то мне выпала честь говорить от имени каждого участника.


Мое непосредственное участие касалось:


  • сборки электроники
  • программирования
  • финансирования
  • организационных моментов
  • подведения итогов

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


От идеи до завершения этого проекта прошел почти год. Нет, это не значит, что все так долго, сложно и т.п. Все на самом деле довольно просто, весело и интересно. Это значит: неправильное планирование и незнание особенностей работы некоторых служб. Из-за такого разрыва части этой статьи писались тоже в разное время. Так что в некоторых разделах у меня не сохранились собственные скрины и я поднатягал их из интернета.


Давайте посмотрим на распределение времени по активностям:


project_length


Ожидание Ожидание служб доставки, ожидание ответа госслужб и, наконец, ожидание весны. Так как никто не хотел искать упавший зонд в ночи. А в регионе запуска (Северо-Запад) зимой темнеет очень рано. Ожидание съело 70% времени. Всегда закладывайте побольше времени в этот сегмент. Ну что я вам рассказываю? Все тут не первый день на IT женаты ;-)


Несмотря на довольно большую задержку нам удалось довести проект до успешного (!) завершения. И сейчас я расскажу вам как.


Список оборудования и компонентов


А начнем мы со списка используемого оборудования. В этом списке ссылки даны на сайты, где это можно купить. Не рекламы ради, а референса и облегчения поиска для:


  1. Raspberry Pi 4 Model B
  2. SPOT Trace GPS Tracker
  3. Шар-зонд
  4. Фал (канат)
  5. Парашют
  6. Гелий
  7. GoPro 7 Black (+Micro SD card 128GB)
  8. Powerbank x2 (20000 mah)
  9. RPI Sense Hat
  10. LTE GPS HAT LTE / GPRS / GPS SIM7600E-H for Raspberry Waveshare 14952
  11. TEMPer Gold USB Temperature Sensor
  12. RPI Tall Case
  13. RPI Mounting Kit

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


Raspberry Pi 4 Model B


Резонный вопрос: почему не Arduino? Простой ответ потому что я не умею паять \()/


Вторая причина я предпочитаю использовать dotnet везде, где это возможно. Но это в меньшей степени повлияло на выбор.


Действительно, если дружите с паяльником ардуино может стать хорошим выбором. Тем более я видел пару схожих проектов где он успешно используется. А вот в моем случае неумение паять стало причиной выбора USB термометра с весьма скромным диапазоном измерения (и это отразилось на результатах, о них в конце).


SPOT Trace GPS Tracker


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


В чем проблема большинства трекеров, которыми завален любой радиорынок? Давайте подумаем: GPS трекер получает свои координаты с помощь GPS спутников (ну еще компенсирует погрешность по наземным станциям) это замечательно, спутники покрывают всю поверхность Земли. Также очень замечательно, что наш трекер будет знать своё местоположение. Но нас то рядом с трекером не будет! Как он должен передать свои координаты в наш ЦУП? Самое массовое решение GSM сети. Иначе говоря покупаете симку, вставляете в трекер и он шлет вам смс-ки (ммс-ки, или стикеры в телегу, не важно). Я видел примеры успешных запусков с таким подходом. Но если честно, я пару раз выезжал за пределы КАД и готов вас уверить во многих местах сотовой связи нет совсем! Если наш зонд упадет в такой зоне провал операции, начинай сначала.


А вот сабж, в отличие от, для передачи координат использует спутниковый канал связи со 100% покрытием. Не буду наседать с рекламой, т.к. удовольствие это не дешевое, да еще и требует платной подписки, равной стоимости самого трекера, но отмечу раз вы читаете эту статью, значит свою функцию он выполнил. Хотя и дал нам понервничать. Но об этом в разделе про поиск и спасение.


Так что еще раз отнеситесь к выбору поискового трекера максимально ответственно!


Шар-зонд


Максимально просто чем больше, тем выше полетит. Мы оперировали примерами успешных запусков из интернета. Там ребята часто использовали шары диаметром 2.5м. В конторе, где мы заказывали свои, нас тоже уверили, что этот долетит. Немного не долетел, но мы склонны считать, что это не вина шара. Об этом в разделе про результаты.


Фал (канат)


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


Парашют


Парашют бесстропный. Не разбираюсь в парашютах, но обратил внимание, что для таких нужд используют именно их. Его и заказали вместе с фалом.


Гелий


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


Количество стандартных баллонов по 40л которое нам понадобится мы считали так:


$B = V_s\div V_h$


Где $V_s$ объем шара в $м^3$, $V_h$ объем гелия при давлении 1атм в $м^3$


$V_s = 4\div3 * \pi * (D\div2)^3$


$V_h = V_b * P_b$


Где $D$ диаметр шара в метрах.


$V_b$ объем баллона в $м^3$. Мы взяли его равным $40\div1000$. Где 40 это известный объем баллона в литрах.


$P_b$ известное давление в баллоне в атмосферах.


В нашем случае, необходимое количество баллонов по 40л получилось равным 1.36 баллона.


Фух, надеюсь ничего не напутал пока переносил формулы из Excel.


RPI Sense Hat


Для любителей RPI это довольно известная вещь. Вкратце поясню это сенсорный мультитул для RPI. Имеет на борту следующее:


  • Датчик температуры (2 штуки)
  • Датчик давления
  • Датчик влажности
  • Гироскоп
  • Магнетометр
  • Компас
  • Акселерометр
  • LED дисплей

То что надо в одном флаконе.


LTE GPS HAT LTE / GPRS / GPS SIM7600E-H for Raspberry Waveshare 14952


Еще одна спорная штука. Нет, вне сомнения, та часть функциональности, которую мы использовали нам очень нужна и она работает отлично. Но, возможно, это overkill и можно найти вариант подешевле.


А использовали мы ее только для показаний GPS (даже без GSM). Дело в том, что трекер то у нас есть (поисковый, не подключается к RPI), но хотелось бы еще к чему-то привязать телеметрию. И, желательно, привязать ее к координатам и времени. Из-за этого и появился еще 1 трекер, но уже подключенный к RPI. Показания с него (координаты, время, курс, скорость, высота) пишутся в лог и служат точкой синхронизации с показаниями всех сенсоров.


Его достоинство он имеет выносную антенну. А это очень важно, когда на борту 2 приемника GPS и 1 передатчик (поисковый трекер). Производители Spot Trace советуют размещать их трекер на расстоянии не меньше 30см от других GPS устройств, во избежание помех. Так что тут пригодилась выносная антенна, которую мы просто кинули за борт.


Его недостаток документация в лучших китайских традициях. Ее сначала пришлось поискать, а потом еще и нехило так покурить (но, в целом, она весьма исчерпывающая и понятная). Чтобы облегчить поиск будущим начинателям этой борьбы, оставлю ссылки тут (на одном из файлов стоит гриф COMFIDENTIAL (орфография сохранена), лол): раз, два.


TEMPer Gold USB Temperature Sensor


Внешний градусник (для замера температуры внутри использовали Sense Hat).


Его достоинства: он подключается в порт USB, есть рабочий тулсет для проверки (под Win)


Его недостатки: нижний предел измерения $-40^oC$. Сразу скажу этого оказалось маловато; второй недостаток документация. Ее нет. Пришлось реанимировать проекты 5-летней давности под похожие модели и написанные на разных языках. В итоге поскрещивал ежа с ужом и немного поколдовал (тяжела и неказиста жизнь простого программиста). Но, в итоге, все работает надежно, как швейцарские часы. В разделе с кодом я поясню где был тонкий момент.


RPI Tall Case


Это крутая штука, которая доставляет мне эстетическое удовольствие.


Красивый, алюминиевый, высокий кейс для RPI 4. Разумеется, перед заказом и прикинул высоту RPI с обеими шапками (Sense + GPS) чуть-чуть не влезает при плотно закрытой крышке. Но, используя spacers (извините, не знаю русского названия), можно приподнять верхнюю крышку немного, для вентиляции.


Из проблем с ним было только одно один из разъемов GPS HAT сильно выпирал за границы платы и не влезал в кейс. Разъем пришлось нежно демонтировать кусачками.


Ну только посмотрите, как элитно стал выглядеть наш самописец:

tall_case_1
tall_case_2
tall_case_3


RPI Mounting Kit


Просто наборчик тех самых spacers и прочих мелочей. Приятное дополнение.


Конструкция


Общая конструкция


Для начала рассмотрим общую конструкцию аппарата (масштаб не соблюден!):


general_scheme


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


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


Полезная нагрузка


Конструкция короба для полезной нагрузки вызывала у меня немного больше переживаний. Требовалось соблюсти несколько очень важных условий:


  1. Предельная масса не более 2.5кг (для нашего объема шара)
  2. Защита от воды + плавучесть (облака, дождь, падение в озеро и т.п.)
  3. Хорошая терморегуляция (RPI не должна перегреться, а аккумуляторы не должны замерзнуть)

Посовещавшись с нашим конструкторским бюро, было решено делать куб со стороной 250мм из экструдированного пенополистирола (куплен в строительном магазине листами). Верхняя крышка двустворчатая из того же материала. В боковой стенке вырезано отверстие под объектив GoPro. Он легкий, имеет положительную плавучесть, достаточно прочный и не пропускает воду (швы, разумеется, проклеили):


payload_1
payload_2


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


payload_scheme


Обратите внимание, что это схема без развесовки. Сбалансируйте компоненты так, чтобы короб не перекашивало в подвешенном состоянии. Мы это делали методом проб и ошибок.

RPI располагается внизу. Забортный воздух поступает через вент. отверстия (дюбели, 8 штук) в короб и опускается к RPI. RPI выделяет тепло в процессе своей работы и нагретый воздух поднимается вверх. Тем самым подогревая аккумуляторы, расположенные над RPI. GPS трекер имеет собственное питание и довольно неприхотлив к внешним условиям (водонепроницаем, ударопрочен, низкое энергопотребление), так что за него голова не болела. До кучи, мы еще загерметизировали соединения с камерой и внешним градусником (обычным клеем залили), т.к. ожидали образование конденсата.


payload_5


Вент. отверстия также используются для крепления фала от парашюта:


payload_3
payload_4


Конфигурация Raspberry PI 4B


Сам по себе не представляет никаких проблем, все очень просто и понятно. Это мини-компьютер с портами ввода-вывода к которым мы, в дальнейшем, планируем подключать все наши датчики\сенсоры\велотренажеры.


Скачать Raspberry PI Imager, выбрать нужную OS, свою SD карту и нажать WRITE:


Raspberry PI Imager


OS было решено взять максимально облегченную. Десктоп и рюшечки нам не нужны, только консоль, только хардкор. Выбор пал на Raspberry PI OS Lite 32-bit:


Raspberry PI Imager


SD карта для Raspberry PI


Хоть в официальной документации толком и не указан максимально допустимый объем карты памяти с которой RPI сможет загрузиться (но указан минимальный 16GB и, как-то намеками указана возможность загрузки с 256GB с определенного дистрибутива), быстрый гугл показал, что лучше взять 32GB. На этом и остановились. Класс карты не сильно критичен, но разница в цене между Class 4 и Class 10 мне показалась не критичной, так что почему бы не взять ту, что побыстрее? Тем более что это, в дальнейшем, открывает возможность скидывать поток видео с GoPro на карту. Но до этой реализации мы не дошли и, честно говоря, я пока не придумал зачем это надо. Карту взяли SanDisk Extreme 32GB типа такой


Подключаем RPI к компу


После того как OS записана на карту и карта вставлена в слот на RPI, можно включить RPI просто подав на него питание. Питается это чудо через порт USB-C, так что озаботьтесь проводом заранее (я использовал 1 из павербанков).


Тут у нас первая проблема: ну включили, лампочки замигали, вроде все ОК.


И что?

Да, операционку то мы поставили без десктопной оболочки, да и мониторы с клавиатурами мы подключать не планировали, и Wi-Fi там еще не настроен.
Так что я немного присел на стул на полчаса.


(


Честно говоря, бежать в магазин за проводом\переходником mini HDMI у меня не было никакого желания. Снова запускаем гугол и видим, что ситуация не безвыходная: можно подключить RPI к компу через USB и через него же наладить SSH. И, хотя тот же гугол говорит обратное, RPI при этом будет и питаться от компа и эмулировать сетевое соединение через один и тот же USB кабель. Нуштош, вытыкаем наш кабель из павербанка и подключаем его в USB компа. Снова замигали лампочки, RPI загрузился и, судя по статусу лампочек у него все отлично.


Но по SSH все еще не подключиться. Курим вот эту страницу. Нас интересует headless mode:


Enable SSH headless mode


Ага, надо поместить пустой файл с именем ssh в корень SD карты. Извлекаем карту из RPI и вставляем ее в комп (предварительно обесточив устройство). Делаем. Пробуем снова. Hostname, User, Password указаны там же, в подразделах для каждой OS. Но, честно говоря, информация там немного устаревшая. Например для Win10 указано, что надо использовать IP вместо имени хоста. Это не так. Забегая вперед, скажу, что и hostname: raspberrypi.local тоже заработал без приключений.


Интернеты пишут, что для этого необходимо поставить доп. приблуды от Apple, чуть ли не iTunes. Либо опенсорс аналог драйвера для таких доменных имен. Но, как я уже сказал, у меня все заработало и без вот этих вот дел. На всякий случай, вот подробная статья

Итого. Что мы имеем по подключению по SSH:


Hostname: raspberrypi.local


User: pi


Password: raspberry


Пробуем не работает. К сожалению у меня не сохранились все скрины этих приключений, ну да ладно, придется поверить мне на слово не работает.


(


Переходим на нижние интернеты Оказывается, мы забыли включить режим Lan Over Usb про который я что-то не нашел упоминания в документации (в итоге на офф форумах это им припоминали). Искомая статья (может не именно она, но шаги в ней описаны верные) тут


Итак, если вкратце, нам нужно будет поменять 2 файла на SD карте: config.txt && cmdline.txt (могут быть без расширений, я уже не помню). Вынимаем карту из RPI, подключаем к компу, находим первый файл и добавляем в конце строчку dtoverlay=dwc2:


dtoverlay


Теперь ищем второй файл (cmdline.txt).


По поводу второго файла небольшое отступление мне его менять не пришлось и так все было как надо. Но мало ли \_()/

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


cmdline.txt


Всё, файлы сохранили, карту вставили обратно в RPI, подключаем USB кабель в комп и в порт питания RPI, RPI загружается. Пробуем SSH:


ssh pi@rasberrypi.local

(да, кстати, озаботьтесь наличием SSH клиента на рабочем компе, если вдруг у вас его еще нет)


На этот раз все должно пройти как по маслу (извините, этого скрина тоже не сохранилось). Мы попадем в bash консоль на нашей Raspberry PI 4B по USB и теперь можем наворотить там дел ;-) А первое дело будет обеспечить себе максимально удобные условия работы, иначе говоря Wi-Fi!


Включаем Wi-Fi на RPI


Тут совсем все просто и без неожиданностей. В RPI OS входит утилита конфигурации через которую можно сделать все (или почти все) что может понадобиться в дальнейшем. Называется она raspi-config и ее использование, в частности в контексте настройки вафли неплохо описано в официальной документации тут.


Подключаемся по кабелю в SSH сессию нашего черного ящика, запускаем из консоли:


sudo raspi-config

Всего несколько клацаний кнопками и можно отсоединять наш USB кабель от компа и подключать его к павербанку (картинки из интернета):


raspi-config wi-fi setup


raspi-config wi-fi setup


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


Для удобства также советую добавить SSH ключи. Надеюсь не надо объяснять как это делать, но если вдруг, то вот отличный тутор от DigitalOcean

Сборка .NET Core проекта под RPI


Небольшое отступление: вся возня с RPI, периферией и написание софта делалось почти год назад. Много информации с тех пор утекло из моей головы и сейчас я эту часть пытаюсь восстанавливать по памяти. К сожалению, восстановить 100% этого приключения у меня не получится, но общие моменты я обозначу.

Настало время что-нибудь напрограммировать для нашего самописца. Сейчас, прочитав этот подзаголовок, многие могут подумать:


wtf


А почему не питон??

Ну по нескольким причинам. Во-первых: хваленое комьюнити которое "уже все давно написало, просто подключай и поехали", оказывается не всё написало, а то, что написало, мягко скажем не едет (об этом в разделе про внешний градусник). А во-вторых: что-бы я не начинал писать все равно получается C#.


Так что стереотипы прочь будем ваять простенький скрипт на шарпе (зря нам что ли кроссплатформу завозили)! Я буду показывать всё на примере своего проекта для логирования всех показателей. Кто захочет может использовать свой "hello world", кто не захочет вот исходники на гитхабе


Бытует мнение, что для того, чтобы завести что-то на dotnet, надо для начала этот самый dotnet установить. На самом деле это не так. Dotnet умеет паковать свой CLR в приложение для целевой платформы. Для этого у dotnet cli есть флаг --self-contained. Так же нам потребуется указать какой конкретно рантайм мы будем использовать при помощи параметра -r linux-arm. Ну и фреймворк укажем, чего уж там. Итого полная команда для сборки самодостаточного dotnet приложения (не требующего установки dotnet runtime на целевую машину) будет выглядеть так:


dotnet publish RpiProbeLogger\RpiProbeLogger.csproj --self-contained -r linux-arm -f netcoreapp3.1 -c Release

На выходе у нас получится исполняемый файл под linux arm со всеми зависимостями. Нам останется только скопировать все содержимое директории на Raspberry по SSH, сделать файл исполняемым (не обязательно) и, собственно, запустить (подробнее в разделе про CI/CD):


chmod +x /home/pi/RpiProbeLogger/RpiProbeLogger./home/pi/RpiProbeLogger/RpiProbeLogger

Если кто-то крутит носом от self-contained приложений ничего страшного, вариант с установкой рантайма и фреймворка (ну мало ли кто-то захочет еще и билдить на распберри) на RPI тоже допустим и прекрасно работает проверено! Вот статья которую я лично использовал (в ходе экспериментов).


CI/CD для Raspberry


Немного громкое название, но смысл тот-же приложения мы писать умеем, надо теперь их собирать под целевую платформу и как-то их туда доставлять. Тут нам поможет его величество PowerShell (linux-like товарищи легко заменять его на bash, sh, etc по вкусу. Это не принципиально).


Весь скрипт находится в корне репозитория и называется buildAndDeploy.ps1. Общий алгоритм такой:


  1. Подключиться к RPI по SSH для выполнения команд
  2. Установить SFTP сессию для работы с файлами
  3. Собрать наше приложение
  4. Скопировать билд на RPI
  5. Установить и включить сервис нашего приложения (чтобы запускался автоматически при загрузке RPI)

SSH


Поехали по очереди: с SSH/SFTP нам сильно поможет модуль для Powershell Posh-SSH. На мой взгляд с этим модулем все хорошо, кроме одного почему-то документацию по нему приходится искать по всему интернету и собирать по крупинкам. Может автор посчитал, что его API и ежу понятно, но вот мне было не очень понятно. Примеры использования с описаниями нашлись тут. Нас же сейчас интересует установка SSH сессии и делается она вот так:


$sshSession = New-SSHSession -Computer raspberrypi.local -Credential $credentials -KeyFile $rsaKeyFile

Сама сессия сохраняется в переменную $sshSession. Обратите внимание на 2 переменные: $credentials и $rsaKeyFile: мы же не хотим использовать привет из 90-х пароли? Мы будем использовать RSA ключи! И как это делать в случае Posh-SSH мне пришлось поискать. Сначала объясню немного про креденшиалс в Powershell есть такой командлет Get-Credential он занимается тем, что нативными средствами запрашивает пару логин-пароль у пользователя и возвращает их в качестве объекта:


$credentials = (Get-Credential pi)

В Win10 это выглядит так:


Get-Credential


Как вы уже догадались, первым параметром можно сделать пре-ввод логина pi. Нам это подходит. Теперь тонкий момент про Posh-SSH: он имеет параметр -KeyFile куда передается путь до приватного SSH ключа. НО! Приватный ключ может иметь passphrase а такого параметра Posh-SSH не имеет. Оказывается, и это пришлось поискать, Posh-SSH будет в качестве passphrase использовать пароль из объекта $credentials и это не слишком очевидное поведение, но именно из-за этого и затевалось использование Get-Credential. Что ж, этого вполне достаточно, чтобы подключиться по SSH к RPI. Полный скрипт находится в репозитории, а мы двигаемся дальше.


SFTP


Никаких откровений тут не скрыто, тот же Posh-SSH, те же Credentials, немного другое имя команды:


$sftpSession = New-SFTPSession -Computer raspberrypi.local -Credential $credentials -KeyFile $rsaKeyFile

Сразу укажу команду для копирования файлов (да, всего в одну строчку деплоим, без хитростей):


Set-SFTPFolder -SFTPSession $sftpSession -RemotePath '/home/pi/RpiProbeLogger' -LocalFolder "RpiProbeLogger\bin\$($c)\netcoreapp3.1\linux-arm\publish" -Overwrite

Да, называется она Set-SFTPFolder, не спрашивайте почему я не знаю. Можно догадаться, что копирует она содержимое исходной директории в целевую директорию, а параметр -Overwrite указывает что содержимое целевой директории будет перезаписано в случае совпадения имен файлов. Параметры -RemotePath и -LocalFolder ясны без пояснений. Единственное, что может привлечь внимание $($c) это передача параметра командной строки, который содержит тип сборки: Release или Debug. Он также используется в следующем пункте сборке приложения.


Сборка


Итак, как уже было описано в разделе про сборку .net под arm наша команда сборки будет выглядеть следующим образом:


dotnet publish RpiProbeLogger\RpiProbeLogger.csproj --self-contained -r linux-arm -f netcoreapp3.1 -c $c

Единственная разница тут это параметр $c который мы будем подставлять из параметров командной строки (Release, Debug, etc) на самом деле можно и не параметризовывать это, а захардкодить "Release" на любителя.


Включение\запуск сервисов


Все тот же Posh-SSH имеет еще одну полезную команду: Invoke-SSHCommand. С помощью нее мы выполним установку systemctl сервиса. Unix-like ребятам тут делать нечего, для остальных немного пролью свет что это.


systemctl это системная служба для управления службами (да-да). Она запускается автоматически и запускает, останавливает, управляет пользовательскими службами, основываясь на специальных файлах .service. Такой файл присутствует и у меня в репозитории в подпапке с проектом probelogger.service и вот его содержимое:


[Unit]Description=Probe Logger Service[Service]User=rootWorkingDirectory=/home/piExecStart=/home/pi/RpiProbeLogger/RpiProbeLoggerExecReload=/bin/kill -HUP $MAINPIDKillMode=processRestart=on-failureType=execStandardOutput=syslogStandardError=syslogSyslogIdentifier=RpiProbeLogger[Install]WantedBy=multi-user.target

Я не буду врать, говоря что мне тут понятно абсолютно все, но, в основном, это читается как-то так:


  1. запускать службу от пользователя root (да, секурность не секурность, я понимаю. но рут привелегии потребовались для чтения данных с порта USB. Об этом позже)
  2. рабочая директория такая-то
  3. запускать тот-то файл
  4. для перезапуска сервиса в случае катастрофы использовать команду kill
  5. перезапускать в случае падения
  6. логи сохранять в syslog

Далее пара команд Posh-SSH. Включение сервиса (означает что он будет запускаться автоматически при запуске RPI):


Invoke-SSHCommand -Command 'sudo systemctl enable /home/pi/RpiProbeLogger/probelogger.service' -SSHSession $sshSession

Немедленный запуск сервиса (не обязательно же перезапускать RPI для нашего логгера, мы же не драйвера пишем):


Invoke-SSHCommand -Command 'sudo systemctl start probelogger.service' -SSHSession $sshSession

Переменная $sshSession нам знакома из раздела про SSH сессию это именно та самая сессия. Файл probelogger.service в репозитории.


Что ж, на этом пожалуй все, что касается билда и доставки нашего самописца на RPI. Напоминаю, весь powershell-скрипт в корне репозитория (buildAndDeploy.ps1). Не совсем автоматизировано запускать нужно ручками, но вполне себе "continuous" билди хоть после каждого коммита. Можно было бы конечно поднять pipeline на основе этого на каком-нибудь Azure DevOps или кто что любит (благо выбор сейчас из десятка платформ присутствует), но я посчитал это оверкилом для таких задач. Побилдим руками, не сломаемся.


Команда билда и деплоя выглядит вот так:


.\buildAndDeploy.ps1 -enableService -runService

По умолчанию билдится Debug версия (нам же для разработки и отладки надо). Можно добавить параметр -c=Release если необходимо собрать финальную версию.


Отладка в Visual Studio


Это та часть, где время стерло бОльшую часть информации. Но поверьте тут все просто и прозрачно, а на MSDN есть даже статья по отладке кода на RPI для VSCode и Visual Studio VS Remote Debug.


Я опишу буквально в 2-х словах для своего случая (Visual Studio):


  1. Открываем окно удаленного дебага: Debug -> Attach to Process
  2. Выбираем Connection Type: SSH
  3. Вбиваем в поле Connection Target наш pi@rasberrypi.local
  4. Ищем в списке наш процесс dotnet (иногда может потребоваться включить Show processes from all users, зависит от вашей конфигурации)
  5. Жмем Attach и мы в деле!

Breakpoints, Watches, Locals, Immediate Window, Threads все работает.


Программирование


Сразу ссылка на репозиторий с исходниками GitHub


Я очень долго откладывал этот раздел для написания, т.к. софт был написан год назад и я почти забыл все те ужасы, которые мне пришлось побороть, сражаясь с китайскими комплектующими. Но попробуем хоть что-то наковырять. Сейчас я лишь заменил project reference на nuget package, т.к. зачем-то я скачивал исходники проекта нугет пакета (надеюсь просто так, сейчас солюшен билдится).


Как и в системе "театр-вешалка", dotnet приложение начинается с конфигурации. Конфигурации DI, логгеров и вот этого всего. В нашем случае в функции Main:


static async Task Main(string[] args)        {            var host = new HostBuilder()                .ConfigureServices((hostContext, services) => {                    services.AddHostedService<RpiProbeHostedService>();                    services.AddSingleton<SerialPort>((_) => {                         var serialPort = new SerialPort("/dev/ttyS0", 115200);                        serialPort.ReadTimeout = 500;                        serialPort.WriteTimeout = 500;                        serialPort.NewLine = "\r";                        serialPort.Open();                        return serialPort;                    });                    services.AddTransient<GpsModuleStatusCommand>();                    services.AddTransient<GpsModuleCoordinatesCommand>();                    services.AddSingleton<RTIMUSettings>((_) => RTIMUSettings.CreateDefault());                    services.AddSingleton<RTIMU>((provider) => {                        var muSettings = provider.GetService<RTIMUSettings>();                        return muSettings.CreateIMU();                    });                    services.AddSingleton<RTPressure>((provider) => {                        var muSettings = provider.GetService<RTIMUSettings>();                        return muSettings.CreatePressure();                    });                    services.AddSingleton<RTHumidity>((provider) => {                        var muSettings = provider.GetService<RTIMUSettings>();                        return muSettings.CreateHumidity();                    });                    services.AddTransient<SenseService>();                    services.AddTransient<ReportService>();                    services.AddSingleton<StatusReportService>();                    services.AddSingleton<TemperService>();                })                .ConfigureLogging(logConfig =>                {                    logConfig.SetMinimumLevel(LogLevel.Information);                    logConfig.AddConsole();                })                .Build();            await host.RunAsync();        }

Как видите, мы пошли путем использования IHostedService как основной крутилки нашего логгера, настроили SerialPort для доступа к GPS HAT (зачем-то я его инжектю в hosted service, вместо того чтобы использовать там GpsMuduleCommand, очевидно проглядел тогда), добавили наши сервисы для доступа к SenseHat в контейнер DI и настроили логирование в консоль. Тут все host.RunAsync()!


Не буду приводить тут содержимое каждого файла, кому надо посмотрят на гитхабе. Тут обрисую основную идею. Вся она описана в нашем хостед сервисе RpiProbeHostedService. Содержммое метода StartAsync:


public Task StartAsync(CancellationToken cancellationToken){    var gpsStatus = _gpsModuleStatusCommand.GetStatus();    if (gpsStatus?.Enabled == false)        _gpsModuleStatusCommand.SetStatus(                new GpsModuleStatusResponse                {                    Enabled = true,                    Mode = GpsModuleModes.Standalone                });    while (true)    {        if (cancellationToken.IsCancellationRequested)            return Task.CompletedTask;        var gpsData = _gpsModuleCoordinatesCommand.GetGpsData();        if (gpsData != null || _reportService.ReportFileCreated)        {            var senseData = _senseService.GetSensorsData();            var outsideTemperatureResponse = _temperService.ReadTemperature();            try            {                _reportService.WriteReport(senseData, gpsData, outsideTemperatureResponse?.OutsideTemperature);            }            catch (Exception ex)            {                _logger.LogError(ex, "Error writing report");            }        }        Thread.Sleep(1000);    }}

Итак, для начала нам нужно узнать в каком состоянии наш GPS HAT. Т.к. тот факт, что он включен еще не означает, что включен непосредственно GPS модуль. Если GPS выключен включаем его и идем дальше.


А дальше у нас бесконечный цикл с задержкой в 1с. В первую очередь нам нужны показания GPS так как это есть точка синхронизации всех данных. Так же, дата из этих показаний используется как имя файла-репорта. Так что нам эти данные прям очень нужны.


Затем собираем данные с SenseHat и внешнего градусника и записываем это все в файл-репорт. Вот и вся нехитрая логика.


С SenseHat проблем не было вообще никаких. А сейчас, при написании статьи, оказалось что с тех пор MS даже добавила его поддержку в свою iot library. Тут подробнее MSDN.


Проблемы, как вы догадались, были с внешним градусником. Я перепробовал с десяток разных проектов на разных языках (Python в их числе). Но ни один не заработал именно с этим градусником. Пару раз было очень близко, но видимо моя модель чуть-чуть отличалась и показания отрицательных температур были неверны. Это сейчас, с остывшей головой, я понимаю если проблема в месте, где присутствует минус надо смотреть на тип данных. И таки да, замена byte на sbyte сделала свое дело. Но тогда, год назад, я был на грани отчаяния. Метод ReadTemperature:


public OutsideTemperatureResponse ReadTemperature(){    if (!_controlDeviceOpen || !_bulkDeviceOpen)        OpenDevices();    var response = new OutsideTemperatureResponse();    try    {        _bulkStream.Write(_tempCommand);        var rawResult = _bulkStream.Read();        response.OutsideTemperature = ((rawResult[4] & 0xFF) + ((sbyte)rawResult[3] << 8)) * 0.01;        _statusReportService.DisplayStatus(response);        return response;    }    catch (Exception ex)    {        _logger.LogError("Error reading outside temperature", ex);        _statusReportService.DisplayStatus(response);    }    return null;}

Метод хоть и небольшой, но содержит парочку magic numbers. Знаете где вы найдете их объяснение? Нигде. Это все наковыряно и проверено (методом проб и ошибок) из разных проектов. Так что если у вас такой градусник поздравляю, ваши страдания окончены.


Не стоит забывать, что наш самописец не подключен к монитору и нам надо бы как-то понимать все ли на нем работает штатно. Для этих целей я использовал LED матрицу на SenseHat. Она небольшая, всего 8x8, так что выводить туда картинки не получится. Но получится мигать/светить лампочками. Более чем достаточно в столь аскетичном устройстве. Код метода DisplayStatus:


public bool DisplayStatus<T>(T status) where T : IResponse{    try    {        var currentStatus = _currentStatuses.FirstOrDefault(c => c.Cell.Row == status.StatusPosition.Row                                                            && c.Cell.Column == status.StatusPosition.Column);        _currentStatuses.Remove(currentStatus);        _currentStatuses.Add(new CellColor(status.StatusPosition, statusToColorMapping[status.Status]));        Show();        return true;    }    catch (Exception ex)    {        _logger.LogError(ex, "Error displaying status on LED");        return false;    }}

Видим, что я инкапсулировал координаты лампочки, которой надо посветить, в класс ответа от конкретной функции (GPS ответ, Sense ответ, ответ от внешнего градусника и т.п.). Все эти response реализуют интерфейс IResponse:


public interface IResponse{    public bool Status { get; }    public Cell StatusPosition { get; }}

Соответственно, обязаны предоставлять статус в формате "Успех\провал" и координаты ячейки LED куда его поместить, и делают это на свое усмотрение. Не буду говорить что это идеальный дизайн, но, как минимум год назад, мне он показался подходящим. Вот, например, как реализует свой статус ответ от SenseHat:


[Ignore]public bool Status => FusionPose.HasValue &&                        FusionQPose.HasValue &&                        Gyro.HasValue &&                        Accel.HasValue &&                        Compass.HasValue &&                        Pressure.HasValue &&                        PressureTemperature.HasValue &&                        Humidity.HasValue &&                        HumidityTemperature.HasValue;[Ignore]public Cell StatusPosition => new Cell(0,2);

Итого у нас есть 5 подсистем:


  1. GPS модуль: вкл\выкл
  2. GPS модуль: координаты получены и прочитаны
  3. SenseHat
  4. Внешний градусник: показания есть\нет
  5. Лог-файл: координаты имеются\нет

Таким образом, маркером для нас, что мы готовы к запуску, будет служить 5 зеленых индикаторов на матрице.


GPS HAT тоже не вызвал особых проблем, насколько я помню. За исключением новости (для меня), что для работы с SerialPort нужны привелегии root и его ответ пришлось немного попарсить:


private string[] ParseCoordinatesResponse(string rawResponse) =>    rawResponse        .Split(Environment.NewLine)        .FirstOrDefault(s => s.StartsWith("+CGNSSINFO:"))?        .Replace("\r", "")        .Replace("+CGNSSINFO:", "")        .Trim()        .Split(',');private GpsModuleResponse FormatResponse(string[] parsedResponse) =>    new GpsModuleResponse {        Latitude = $"{parsedResponse[5]}{double.Parse(parsedResponse[4]) / 100}",        Longitude = $"{parsedResponse[7]}{double.Parse(parsedResponse[6]) / 100}",        DateTimeUtc = DateTime.ParseExact($"{parsedResponse[8]} {parsedResponse[9]}", "ddMMyy HHmmss.f", null),        Altitude = double.Parse(parsedResponse[10]),        Speed = double.Parse(parsedResponse[11]),        Course = double.Parse(parsedResponse[12])};

Положение всех компонентов ответа указано в документации.


Еще 1 момент EventBased подход я решил не использовать, но он вроде работает и методы для него (DataReceived) остались в коде. Честно говоря, не помню почему я так решил, но думаю причины были.

Перейдем к финансам.


Бухгалтерия


Быстренько пробежимся по моей нелюбимой части сколько все это чудо стоит. В этот манускрипт не попали: стоимость камеры (она у меня уже на тот момент и так была), стоимость спасения и всякая мелочевка, типа клея и винтиков. Эти позиции сильно субъективны.


costs


Внизу 2 суммы: одна за все позиции, вторая (Minimum) это только если запускать одну камеру без RPI и всего с ней связанного. Как видите, поисковый трекер вместе с подпиской занимают ~30% цены всего аппарата. Так что если найдете вариант подешевле это хороший повод сэкономить.


Также, в процессе моих экспериментов, я накупил много лишнего это красная секция в табличке. Это то, что совсем не пригодилось. Желтая секция это то, без чего можно было бы обойтись. Эдакая ни вам, ни нам середина. Запуск только лишь зеленой секции означает запуск только камеры и RPI с Sense Hat. Мы запускали зеленую + желтую.


Конечно тут есть простор для оптимизации. Например, я считаю, что вместо GPS HAT можно было бы найти что-то подешевле, за парашют мы тоже явно переплатили, карту памяти для RPI можно смело брать 16Гб (а то и меньше), ну и так далее. Но это все было в первый раз, хотелось подстраховаться отсюда и цена соответствующая.


Подготовка к запуску


Прежде всего надо понять где запускать? Если вы житель мегаполиса, у меня для вас плохие новости нигде. Ладно шучу, не все так плохо =)


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


Для этого можно воспользоваться сервисом FPLN: включаем в настройках показ всего что нам нужно и ищем глазами свободное место. Вот чисто для примера такое (в зависимости от предполагаемой траектории):


launch_options


Откуда нам взять предполагаемую траекторию? Тоже есть сервис. CUSF Landing Predictor 2.5. Вбиваем наши варианты и параметры и смотрим что будет:


route_predicted


Совмещаем картинку с FPLN и смотрим подходит/не подходит? Если нет ищем новое место, если да поздравляю.


Для прогнозирования ветра можно использовать Windy. CUSF Landing Predictor так же учитывает направление и силу ветра на выбранное время и координаты. Как вспомогательное средство, можно использовать FlightRadar чтобы помониторить в реальном времени самолеты в предполагаемом районе запуска.

Ну что. Если вы дошли до этого этапа, значит бОльшая часть пути позади. Впереди запуск!


Запуск


Со слов участников: Выбрали точку, заправили тарантас, взяли пару баллонов гелия и двинули на место. Описывать тут особо нечего. Имейте только ввиду шар такого размера с гелием имеет неплохую подъемную силу! Так что придерживайте его пока будете надувать (а лучше привяжите временно).


В этой операции использовались:


  1. Клапан Голубева
  2. Переходник под него
  3. Шланг
  4. Переходник со шланга на баллон 3/4 дюйма

Просто вставлю пару фото, чтобы дать понять масштабы:

launch_2
launch_1


Убедитесь что GPS трекер включен! Без него вся эта затея будет провалена сразу после запуска. Далее подключаем питание к RPI и GoPro. Ждем успешный статус на RPI, включаем запись видео на камере, запаковываем короб, крепим к парашютному фалу, парашют к шару и Поехали!


Поиск и спасение


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


operator


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


route_spot


Расстояние между конечными точками ~100км. Хотя расчетное было около 200км. Наш зонд немного не долетел. Но с этим разберемся в результатах.


Наивысшая точка (F) по этим показаниям 9800м. Дело в том, что у нашего поискового трекера предел измерения высоты 10км. Так что это еще не значит, что зонд выше не поднимался, нет. Просто после этой точки он пропал! Я, разумеется, ожидал этого и ждал, и ждал, и ждал. Ну сколько он может там летать над 10км? Ну час, ну максимум два. Учитывая, что расчетное время всего полета было 2ч 25мин. Но обратите внимание на дату и время в этой точке (верхняя часть):


f_point


А теперь взглянем на следующую точку G:


g_point


Где тебя носило больше суток ( )(._.`)?! Я все морги-больницы обзвонил все это время не спал и мониторил показания (да что уж там все мониторили). Но, видимо, условия для передачи сигнала были не благоприятные. Хорошо что запас автономности у этого трекера очень хороший он до сих пор передает координаты на тех же аккумах. Ок, в итоге нашелся, посмотрим где упал?


Упал он на краю лютого болота в 4-х километрах от ближайшей дороги. На фотках это не так видно, но поверьте ребята там были (дважды) болото непроходимое.


swamp_distance


Ближайшая дорога:


swamp_road


Край болота:


swamp_edge


Побродили несколько часов вокруг и, благоразумно не став геройствовать, позвонили мне со словами: ололо, нам нужен вертолет! Явно нужен был план. Соваться туда ногами (болотоходами, снегоступами и прочими средствами бывалых разведчиков) никто не захотел. Вариант забыть и простить даже не рассматривался.


Вертолет, как водится, не на каждом углу припаркован. Более реалистичный вариант вездеход! Начали шерстить интернеты, друзей и соцсети. Не скажу, что прям на каждом шагу раздают вездеходы в аренду в поисках мы провели несколько дней. Наконец вышли на одних ребят, Питерские производители вездеходов, которым нужен был, внезапно, демо-ролик их детища :3 И они согласились предоставить их вездеход с командой, если мы оплатим им сутки работы видеографа (так они его назвали). Что ж, из альтернатив был только другой вездеход, но почти вдвое дороже. Так что мы начали соглашаться. Ребята подготовили свой вездеход (все это время поисковый трекер передавал статусные сигналы раз в сутки, так что мы были вполне спокойны: его не украли медведи и он не утонул) и мы получили вот это:


awd


Согласитесь, выглядит, как то, что надо!


Не буду вставлять фотки с катанием на нем по болотам, лучше в конце прикреплю видео ;-) Итог этих покатушек, как вы понимаете, весьма успешен. Вот наш короб, открытый сразу после того, как мы его подобрали:


awd_result


Да, бутылка, с понятной жидкостью, все это время летала вместе с оборудованием. Она там была как презент нашедшему виски из стратосферы. К счастью, нашедшими оказались мы, так что и презент нам. Радовались, как дети, чесслово =)


Результаты


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


result_hires


Разумеется все кинулись проверять камеру. Это фото это один из последних кадров (я выбрал покрасивей) из заснятого видео. Вообще, по расчетам, запаса аккумулятора камеры должно было хватить еще и на приземление и на полежать немного. Но, как видите, не хватило она записала всего 25 минут видео (4k60fps), из которых 7 на земле перед запуском. Мы строили разные теории почему так произошло. В итоге, поковырявшись уже дома с оборудованием, выяснили: был сломан USB порт на павербанке для камеры. В какой момент он был сломан неизвестно. Но пока основная версия такова: подключили и включили камеру, как-то сломался порт, камера продолжала работать от внутреннего аккумулятора пока он не сел. Из-за внутреннего аккумулятора мы не смогли вовремя распознать поломку, а его запаса, по экспериментам, хватает примерно на 25-30 минут записи.


Когда все остыли, пришло время ковырять показания нашего самописца он отработал на все 100! И сейчас будет поток графиков, построенных по его показаниям. Так как RPI работал долгое время на земле (до и после запуска), я, для удобства анализа, обрезал куски данных с земли.


На шкале X всегда будет время в секундах с момента отрыва от поверхности. Поехали!


График набора высоты по показаниям GPS HAT:


alt_gps


Взглянув на него, мы видим: максимальная высота, которую он набрал на 2247-й секунде полета, составила 18993 метра над уровнем моря! Это выше чем Эверест, это выше чем летают любые пассажирские самолеты! Но прилично ниже расчетных 30км. Взглянув на то что осталось от, непосредственно, шара, мы предположили, что мы его просто перекачали и он взорвался раньше положенного. Была у меня еще версия что мы его недокачали. Но тогда бы он повисел на высоте, пока гелий не выйдет и опустился бы целым на землю. А от него ничего не осталось. Значит перекачали. Учтем на будущее.


Еще по этому графику можно прикинуть на какой высоте остановилась запись. Приблизительно на 7км. Так что кадр выше примерно с высоты всего 7км.


Раз уж у нас есть показания барометра, забавы ради (практической пользы не несет), я решил рассчитать относительную высоту по барометрической формуле и сравнить эти показания с данными GPS:


alt_compare


Как видим корреляция есть, отклонения не сказать чтобы пугающие (макс. высота получилась 16183 метра).


Теперь, что же там с давлением?


pres_over_alt


Мы видим, как падало давление с набором высоты (эффект ожидаемый). Все в той же точке 2247 было зафиксировано минимальное значение 58 миллибар. Для сравнения на поверхности было 1050 миллибар. Т.е. всего 5.7% от давления на поверхности!


Как там работал наш кустарный охладитель? Температура внутри бокса:


inside_temp


Как видно скакнула до $38,5^oC$, но это очень далеко от предельной. Так что никто не перегрелся и никто не замерз. Да и в целом разброс всего 33-35 считаю очень хорошим результатом.


Что в этот момент происходило снаружи? Снова график 2-в-1, чтобы не захламлять картинками:


outside_temp_over_alt


Помните я сетовал на градусник? Вооот. Как видите провал ниже -40. Значит там было еще холоднее! И второй вывод, который тут можно сделать: самая холодная точка не самая высокая!


Насколько наш климатизатор страдал, можно оценить по графику разницы температур Inside vs Outside:


outside_inside_temp_diff


Как видите разность температур доходила почти до 80! Не сказать что хардкор, но прилично.


Ну и последний на сегодня показатель влажность:


humidity_over_alt


Там довольно сухо, да. Влажность падала до 3%. Ну а откуда ей там взяться?


Хватит графиков. Это, конечно же не все показания, которые записал наш RPI, но статья и так уже слишком разрослась. Так что я оставлю ссылку на полную телеметрию:



Видео


Использование вездехода по назначению:



Видео полета с бортовой камеры:



Выводы


Итак, несмотря на то, что расчетная высота достигнута не была: 19км против 30км все равно считаю, что проект завершился успешно. Тем более, это был первый опыт подобного рода для всех участников проекта. Давайте обозначим технические проблемы, возникшие в процессе этого мероприятия:


  • Камера не записала весь полет.
    • Возможная причина: поломка аккумулятора на запуске.
    • Возможное решение: заменить внешний аккумулятор, удалить внутренний аккумулятор перед запуском (позволит отследить проблему с внешним на ранних этапах)
  • Не была достигнута расчетная высота.
    • Возможная причина: перекачали шар. Закачали 1.5 баллона вместо расчетных 1.36
    • Возможное решение: закачать меньше гелия (1.36 баллона)
  • Порвался парашют. Не прям в хлам, пара мелких отверстий сбоку. Купол не пострадал и на полетные характеристики это не повлияло. Решение тут только одно заменить парашют на новый во избежание дальнейшего распространения повреждений.
  • Приземление в труднодоступной местности.
    • Причина: ранний взрыв шара
    • Возможное решение: закачать правильное количество гелия. 100% гарантии это не даст, но по итогу, расчетная траектория совпала с реальной, за исключением того, что нагрузка приземлилась раньше положенного времени.

На этом все, всем чистого неба над головой и удачи!

Подробнее..

Превращаем одноплатник Cubietruck в Wi-Fi Hotspot с Captive portal, VPN-шлюзом и Ad block

25.05.2021 10:11:06 | Автор: admin
raspap

Для построения Wi-Fi сети обычно используют готовые маршрутизаторы, функционал которых всегда ограничен прошивкой. А если необходимо добавить блокировщик рекламы, VPN шлюз и красивый Captive portal, покупать новую железку? Стоимость устройства с таким функционалом будет уже весьма высока. Можно взять Linux с Hostapd и сделать точку доступа с Wi-Fi, но в отличие от готовых маршрутизаторов не будет наглядного Web-интерфейса. И для решения этой задачи был создан проект RaspAP, который на базе устройств с ОС Debian создает Wi-Fi Hotspot с Captive portal, VPN-шлюзом, Ad block. Для RaspAP в отличие от OpenWrt не требуется непосредственная поддержка устройства, достаточно поддержки последней версии Debian. RaspAP работает поверх уже установленных ОС: Raspberry Pi OS, Armbian, Debian, Ubuntu. Как сделать Wi-Fi Hotspot на RaspAP прошу под кат.

RaspAP open-source проект создания беспроводного маршрутизатора из многих популярных устройств работающих на ОС Debian, включая Raspberry Pi. Содержит удобный Web-интерфейс для настройки, блокировщик рекламы, осуществляет шлюзование сетевого трафика через OpenVPN или WireGuard.

Используя RaspAP можно быстро развернуть Hotspot с доступом в сеть Интернет, где угодно: в магазине или торговом центре, заправке, кафе и ресторане, библиотеке, больнице, аэропорте и вокзале, а также в совершенно непривычных, уединенных местах, например на вершине горы. Благодаря наличию Captive portal, посетители подключаясь к Сети, обязательно увидят информацию, которую владелец Wi-Fi желает довести до пользователей. Это может быть информация о соглашение использования публичного hotspot, и т.д.

Поддерживаемые устройства и ОС


Для устройств на ARM-архитектуре заявлена официальная поддержка, устройства на x86 процессорах в настоящее время находится в стадии Beta.

raspap

Поддерживаемые ОС и архитектуры RaspAP

Базовой платформой работы RaspAP является устройство Raspberry Pi. Но благодаря поддержки Armbian на основе Debian, список поддерживаемых устройств становится весьма широким.

Wi-Fi Hotspot на RaspAP будет развернут на одноплатном компьютере Cubietruck, процессор AllWinner A20 (ARM32), с ОС Armbian (на базе Debian). Для задач маршрутизации сетевого трафика для нескольких клиентов процессора AllWinner A20 с двумя ядрами Cortex-A7 будет недостаточно, но вы можете взять гораздо более мощное устройства из каталога поддерживаемых проектом Armbian.

RaspAP


raspap

Под капотом RaspAP использует hostapd, dnsmasq, iptables, веб-интерфейс работает на lighttpd с php-скриптами. С точки зрения использования новых функций применяется политика спонсорства. Если оформить ежемесячное спонсорство, то ваш аккаунт на GitHub будет добавлен в группу Insiders, которые первыми получают возможность протестировать новые функции. Функции доступные на данный момент только спонсорам будут помечены Insiders Edition.

raspap

Веб-интерфейс RaspAP

Возможности RaspAP:

  • Графический интерфейс для настройки и отображения графиков активности клиентских устройств;
  • Поддержка сертификатов SSL;
  • Интеграция с Captive portal;
  • Управление DHCP-сервером;
  • Поддержка адаптеров 802.11ac 5 ГГц;
  • Автоопределение внешних беспроводных адаптеров.

Пройдемся коротко по основным функциям RaspAP.

Точка доступа


По умолчанию создается точка доступа со следующими параметрами:

  • Interface: wlan0
  • SSID: raspi-webgui
  • Wireless Mode: 802.11n 2.4GHz
  • Channel: 1
  • Security Type: WPA2
  • Encryption Type: CCMP
  • Passphrase: ChangeMe

К AP можно подключаться по ключевой паре SSID + пароль или по QR-коду. В случае бездействия клиента, AP может его отключить (требуется поддержка в драйверах). В Insiders Edition доступна возможность изменять мощность в dBm. Для обеспечения гарантированной работы можно задать ограниченное количество подключаемых клиентов.

Для Raspberry Pi Zero W доступен режим виртуализации беспроводного устройства. Единственное на борту Wi-Fi устройство будет работать в режиме клиента и точки доступа. Режим виртуализации сетевых интерфейсов работает и на других адаптерах USB Wi-Fi таких как RTL8188.

Блокировщик рекламы (Ad blocking)


Блокирует ads, трекеры и узлы из черного списка. В качестве источника черного списка выступает проект notracking, список обновляется автоматически. Блокируются следующие типы узлов: tracking, поставщики рекламы, сбор аналитики, фишинговые и мошенические сайты, содержащие вредоносные программы, веб-майнеры.

Captive portal


raspap

Captive portal

Из коробки интегрирован nodogsplash. nodogsplash легкое и простое решения создания кастомизируемых порталов. Поддерживает различные политики работы клиентов.

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


Статистическую работу можно выводить на TFT-экран Adafruit Mini PiTFT контроллер ST7789. Скрипт вывода информации написан на Python, поэтому программный код можно легко адаптировать и для другого дисплея, например для ILI9341.

raspap

Вывод информации о работе AP

Поддержка различных сетевых устройств в качестве WAN-интерфейса (Insiders Edition)


В качестве доступа к сети Интернет, RaspAP поддерживает несколько различных типов сетевых устройств, такие как:

  • Ethernet interface (eth);
  • Wireless adapter (wlan);
  • Mobile data modem (ppp);
  • Mobile data adapter with built-in router;
  • USB connected smartphone (USB tethering);

Это особенно удобно когда вы путешествуете или работает в полевых условиях.

OpenVPN


raspap

Сетевой трафик можно туннелировать используя клиента OpenVPN. В Insiders Edition доступна возможность хранения нескольких профилей OpenVPN с функцией быстрого переключения между ними.

WireGuard (Insiders Edition)


raspap

WireGuard быстрый и современный VPN, в котором используется самая современная криптография. Он более производителен, чем OpenVPN, и обычно считается наиболее безопасным, простым в использовании и самым простым решением VPN для современных дистрибутивов Linux. Благодаря низкому overhead, если устройство работает от батареи, то время работы при использование WireGuard будет больше, чем при использование OpenVPN.

Доступ к Web-интересу настроек через SSL


raspap

Для защиты сетевого трафика от перехвата, доступно шифрование по SSL в пределах локальной сети. Проект mkcert позволяет в несколько простых шагов развернуть корневой центр сертификации и генерировать сертификаты, подписанные вашим собственным частным ЦС.

Постановка задачи


Установка RaspAP будет произведена из публичного репозитория, на Cubietruck установлена последняя версия Armbian (на основе Debian): Armbian 21.02.3 Buster, Linux 5.10.21-sunxi. На борту имеется встроенный адаптер wlan0, будет выступать в качестве клиентского доступа к сети Интернет (WAN-интерфейс). Для Hotspot подключим RTL8188 USB WiFi dongle wlan1.

  • IP конфигурация для wlan0: address 192.168.43.12 netmask 255.255.255.0 gateway 92.168.43.1.
  • IP конфигурация для wlan1: address 10.3.141.1 netmask 255.255.255.0 gateway 10.3.141.1.

Конфигурация DHCP-сервера:

  • Диапазон выдаваемых IP-адресов 10.3.141.50 10.3.141.254;
  • Шлюз/DNS-сервер: 10.3.141.1.

Для шлюзования сетевого трафика через OpenVPN установим на VPS сервер SoftEther VPN Server. SoftEther VPN Server мультипротокольный VPN-сервер, который может поднимать L2TP/IPsec, OpenVPN, MS-SSTP, L2TPv3, EtherIP-серверы, а также имеет свой собственный протокол SSL-VPN, который неотличим от обычного HTTPS-трафика (чего не скажешь про OpenVPN handshake, например), может работать не только через TCP/UDP, но и через ICMP (подобно pingtunnel, hanstunnel) и DNS (подобно iodine), работает быстрее (по заверению разработчиков) текущих имплементаций, строит L2 и L3 туннели, имеет встроенный DHCP-сервер, поддерживает как kernel-mode, так и user-mode NAT, IPv6, шейпинг, QoS, кластеризацию, load balancing и fault tolerance, может быть запущен под Windows, Linux, Mac OS, FreeBSD и Solaris и является Open-Source проектом под GPLv2.

Для VPS сервера выберем тариф на vdsina.ru за 330 р./месяц, в который включена квота на 32 ТБ трафика, чего более чем достаточно. SoftEther VPN Server будет развернут в Docker контейнере, поэтому выбор ОС CentOS/Debian/Ubuntu не принципиально важен.

Развертывание сервера выполняется просто и очень быстро, по результату необходимо отметить автоматическую выдачу DNS имени, можно не покупать доменное имя.

raspap

VPS сервер на vdsina.ru

Сервер был развернут в Московской локации, IP-адрес 94.103.85.152, dns-имя: v636096.hosted-by-vdsina.ru. Подключение к серверу будет по DNS имени.

raspap

Итоговая схема сети

Как будет выглядеть Web-интерфейс RaspAP и подключение к Hotspot


Подключение к AP SSID: raspi-webgui


Подключение к AP raspi-webgui

Конфигурационные файлы RaspAP


Для установки RaspAP есть Quick installer, но он выполняется без задания параметров и wlan0 настроен как Hotspot, что нам не подходит. Поэтому воспользуемся Manual installation, с некоторыми изменениями т.к. руководство содержит некоторые ошибки и сам RaspAP работает с некоторыми некритичными багами, из-за этого пришлось немного больше потратить время на установку. О багах будет в ходе установки.

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

Список конфигурационных файлов (GitHub):

  • hostapd.conf служба hostapd
  • default_hostapd служба hostapd
  • 090_raspap.conf служба dnsmasq.d
  • 090_wlan1.conf служба dnsmasq.d
  • defaults.json служба raspap
  • dhcpcd.conf служба raspap
  • config.php портал конфигурации RaspAP

hostapd.conf служба hostapd

Содержит настройки AP по умолчанию такие как: ssid, channel, password и т.д.

hostapd.conf
driver=nl80211ctrl_interface=/var/run/hostapdctrl_interface_group=0beacon_int=100auth_algs=1wpa_key_mgmt=WPA-PSKssid=raspi-webguichannel=1hw_mode=gwpa_passphrase=ChangeMeinterface=wlan1wpa=2wpa_pairwise=CCMPcountry_code=RU## Rapberry Pi 3 specific to on board WLAN/WiFi#ieee80211n=1 # 802.11n support (Raspberry Pi 3)#wmm_enabled=1 # QoS support (Raspberry Pi 3)#ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40] # (Raspberry Pi 3)## RaspAP wireless client AP mode#interface=uap0## RaspAP bridge AP mode (disabled by default)#bridge=br0



default_hostapd служба hostapd

Настройка службы hostapd, параметр DAEMON_CONF определяет путь к настройкам.

default_hostapd
# Location of hostapd configuration fileDAEMON_CONF="/etc/hostapd/hostapd.conf"



090_raspap.conf служба dnsmasq.d

Настройка службы dnsmasq, параметр conf-dir определяет путь к настройкам.

090_raspap.conf
# RaspAP default configlog-facility=/tmp/dnsmasq.logconf-dir=/etc/dnsmasq.d


090_wlan1.conf служба dnsmasq.d

Настройка dnsmasq для сетевого интерфейса wlan1. Содержит диапазон выдаваемых IP-адресов, и другие сетевые настройки. Необходимо обратить внимание на название файла по маске 090_[ИДЕНТИФИКАТОР_ИНТЕРФЕЙСА_HOTSPOT].conf. Если у вас сетевой интерфейс для hostspot будет назваться например wlan2, то следует задать название файла 090_wlan2.conf.

090_wlan1.conf
# RaspAP wlan0 configuration for wired (ethernet) AP modeinterface=wlan1domain-neededdhcp-range=10.3.141.50,10.3.141.255,255.255.255.0,12hdhcp-option=6,10.3.141.1


defaults.json служба raspap

Настройка DHCP серверов для интерфейсов wlan0 и wlan1.

defaults.json
{  "dhcp": {    "wlan1": {       "static ip_address": [ "10.3.141.1/24" ],      "static routers": [ "10.3.141.1" ],      "static domain_name_server": [ "10.3.141.1" ],      "subnetmask": [ "255.255.255.0" ]    },    "wlan0": {      "static ip_address": [ "192.168.43.12/24" ],      "static routers": [ "192.168.43.1" ],      "static domain_name_server": [ "1.1.1.1 8.8.8.8" ],      "subnetmask": [ "255.255.255.0" ]    },    "options": {      "# RaspAP default configuration": null,      "hostname": null,      "clientid": null,      "persistent": null,      "option rapid_commit": null,      "option domain_name_servers, domain_name, domain_search, host_name": null,      "option classless_static_routes": null,      "option ntp_servers": null,      "require dhcp_server_identifier": null,      "slaac private": null,      "nohook lookup-hostname": null    }  },  "dnsmasq": {    "wlan1": {      "dhcp-range": [ "10.3.141.50,10.3.141.255,255.255.255.0,12h" ]    },    "wlan0": {      "dhcp-range": [ "192.168.43.50,192.168.50.150,12h" ]    }  }}


dhcpcd.conf служба raspap

Настройка для сетевого интерфейса wlan0, который выходит в сеть Интернет.

dhcpcd.conf
# RaspAP default configurationhostnameclientidpersistentoption rapid_commitoption domain_name_servers, domain_name, domain_search, host_nameoption classless_static_routesoption ntp_serversrequire dhcp_server_identifierslaac privatenohook lookup-hostname# RaspAP wlan0 configurationinterface wlan0static ip_address=192.168.43.12/24static routers=192.168.43.1static domain_name_server=1.1.1.1 8.8.8.8


config.php портал конфигурации RaspAP

Файл настроек графического Web-интерфейса. Содержит переменные влияющие на отображение настроек. Самый главный параметр define('RASPI_WIFI_AP_INTERFACE', 'wlan1');. В качестве значения указать сетевой интерфейс hotspot wlan1.

config.php
...define('RASPI_WIFI_AP_INTERFACE', 'wlan1');...define('RASPI_ADBLOCK_ENABLED', true);define('RASPI_OPENVPN_ENABLED', false);...


Пошаговая установкаRaspAP


Руководство установки доступно в разделе Manual installation.

Шаг 1 Подключение адаптера USB WiFi RTL8188


Подключаем адаптер в любой доступный USB порт. В Armbian драйвера уже есть, поэтому проверим подключение командой lsusb:

root@bananapim64:~# lsusbBus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hubBus 003 Device 004: ID 0bda:c811 Realtek Semiconductor Corp.Bus 003 Device 002: ID 1a40:0101 Terminus Technology Inc. HubBus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hubBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubroot@bananapim64:~#

В списке присутствует Realtek Semiconductor Corp., значит адаптер успешно распознался. Если вывести название интерфейса для подключенного адаптера, то его имя будет wlxe81e0584796d, что несколько далеко от привычного именования вида wlanX. Для задания названия для адаптера wlan1, необходимо выполнить следующие действия (более подробнее почитать про именование сетевых интерфейсов по ссылке1,ссылке2):

$ sudo ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules$ sudo reboot

После перезагрузки в системе будет два беспроводных адаптера: wlan0 и wlan1.

Шаг 2 Настройка сетевых интерфейсов


Настроим сетевые интерфейсы в конфигурационном файле: /etc/network/interfaces.

# Network is managed by Network managerauto loiface lo inet loopback# WANauto wlan0allow-hotplug wlan0iface wlan0 inet dhcp# Wi-Fi APauto wlan1iface wlan1 inet static    address 10.3.141.1    netmask 255.255.255.0    gateway 10.3.141.1

Шаг 3 Установка RaspAP


Теперь приступаем к установке RaspAP.
Обновление системы:

sudo apt-get updatesudo apt-get full-upgrade

Установка зависимостей для не RPi OS:

sudo apt-get install software-properties-common sudo add-apt-repository ppa:ondrej/phpsudo apt-get install dhcpcd5

Установка пакетов:

sudo apt-get install -y lighttpd git hostapd dnsmasq iptables-persistent vnstat qrencode php7.3-cgi

PHP:

sudo lighttpd-enable-mod fastcgi-php    sudo service lighttpd force-reloadsudo systemctl restart lighttpd.service

Создание Web-портала:

sudo rm -rf /var/www/htmlsudo git clone https://github.com/RaspAP/raspap-webgui /var/www/htmlWEBROOT="/var/www/html"CONFSRC="$WEBROOT/config/50-raspap-router.conf"LTROOT=$(grep "server.document-root" /etc/lighttpd/lighttpd.conf | awk -F '=' '{print $2}' | tr -d " \"")HTROOT=${WEBROOT/$LTROOT}HTROOT=$(echo "$HTROOT" | sed -e 's/\/$//')awk "{gsub(\"/REPLACE_ME\",\"$HTROOT\")}1" $CONFSRC > /tmp/50-raspap-router.confsudo cp /tmp/50-raspap-router.conf /etc/lighttpd/conf-available/sudo ln -s /etc/lighttpd/conf-available/50-raspap-router.conf /etc/lighttpd/conf-enabled/50-raspap-router.confsudo systemctl restart lighttpd.servicecd /var/www/htmlsudo cp installers/raspap.sudoers /etc/sudoers.d/090_raspap

Создание конфигурации:

sudo mkdir /etc/raspap/sudo mkdir /etc/raspap/backupssudo mkdir /etc/raspap/networkingsudo mkdir /etc/raspap/hostapdsudo mkdir /etc/raspap/lighttpdsudo cp raspap.php /etc/raspap 

Установка разрешения:

sudo chown -R www-data:www-data /var/www/htmlsudo chown -R www-data:www-data /etc/raspap

Настройка контролирующих скриптов:

sudo mv installers/*log.sh /etc/raspap/hostapd sudo mv installers/service*.sh /etc/raspap/hostapdsudo chown -c root:www-data /etc/raspap/hostapd/*.sh sudo chmod 750 /etc/raspap/hostapd/*.sh sudo cp installers/configport.sh /etc/raspap/lighttpdsudo chown -c root:www-data /etc/raspap/lighttpd/*.shsudo mv installers/raspapd.service /lib/systemd/systemsudo systemctl daemon-reloadsudo systemctl enable raspapd.service

Установка стартовых настроек, настройки в каталоге ~/temp, при необходимости заменить на свои:

sudo apt-get install -y curl unzipmkdir -p ~/tempcurl -SL --output ~/temp/config_ct.zip https://github.com/devdotnetorg/Site/raw/master/Uploads/files/config_ct.zipunzip ~/temp/config_ct.zip -d ~/temprm ~/temp/config_ct.zipесли есть: sudo mv /etc/default/hostapd ~/default_hostapd.oldесли есть: sudo cp /etc/hostapd/hostapd.conf ~/hostapd.conf.oldsudo cp ~/temp/default_hostapd /etc/default/hostapdsudo cp ~/temp/hostapd.conf /etc/hostapd/hostapd.confsudo cp config/090_raspap.conf /etc/dnsmasq.d/090_raspap.confsudo cp ~/temp/090_wlan1.conf /etc/dnsmasq.d/090_wlan1.confsudo cp ~/temp/dhcpcd.conf /etc/dhcpcd.confsudo cp ~/temp/config.php /var/www/html/includes/sudo cp ~/temp/defaults.json /etc/raspap/networking/sudo systemctl stop systemd-networkdsudo systemctl disable systemd-networkdsudo cp config/raspap-bridge-br0.netdev /etc/systemd/network/raspap-bridge-br0.netdevsudo cp config/raspap-br0-member-eth0.network /etc/systemd/network/raspap-br0-member-eth0.network 

Оптимизация PHP:

sudo sed -i -E 's/^session\.cookie_httponly\s*=\s*(0|([O|o]ff)|([F|f]alse)|([N|n]o))\s*$/session.cookie_httponly = 1/' /etc/php/7.3/cgi/php.inisudo sed -i -E 's/^;?opcache\.enable\s*=\s*(0|([O|o]ff)|([F|f]alse)|([N|n]o))\s*$/opcache.enable = 1/' /etc/php/7.3/cgi/php.inisudo phpenmod opcache

Настройка маршрутизации:

echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/90_raspap.conf > /dev/nullsudo sysctl -p /etc/sysctl.d/90_raspap.confsudo /etc/init.d/procps restartsudo iptables -t nat -A POSTROUTING -j MASQUERADEsudo iptables -t nat -A POSTROUTING -s 192.168.43.0/24 ! -d 192.168.43.0/24 -j MASQUERADEsudo iptables-save | sudo tee /etc/iptables/rules.v4

Включение hostapd:

sudo systemctl unmask hostapd.servicesudo systemctl enable hostapd.service

OpenVPN:

sudo apt-get install openvpnsudo sed -i "s/\('RASPI_OPENVPN_ENABLED', \)false/\1true/g" /var/www/html/includes/config.phpsudo systemctl enable openvpn-client@clientsudo mkdir /etc/raspap/openvpn/sudo cp installers/configauth.sh /etc/raspap/openvpn/sudo chown -c root:www-data /etc/raspap/openvpn/*.sh sudo chmod 750 /etc/raspap/openvpn/*.sh

Ad blocking:

sudo mkdir /etc/raspap/adblockwget https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt -O /tmp/hostnames.txtwget https://raw.githubusercontent.com/notracking/hosts-blocklists/master/domains.txt -O /tmp/domains.txtsudo cp /tmp/hostnames.txt /etc/raspap/adblocksudo cp /tmp/domains.txt /etc/raspap/adblock sudo cp installers/update_blocklist.sh /etc/raspap/adblock/sudo chown -c root:www-data /etc/raspap/adblock/*.*sudo chmod 750 /etc/raspap/adblock/*.shsudo touch /etc/dnsmasq.d/090_adblock.confecho "conf-file=/etc/raspap/adblock/domains.txt" | sudo tee -a /etc/dnsmasq.d/090_adblock.conf > /dev/null echo "addn-hosts=/etc/raspap/adblock/hostnames.txt" | sudo tee -a /etc/dnsmasq.d/090_adblock.conf > /dev/nullsudo sed -i '/dhcp-option=6/d' /etc/dnsmasq.d/090_raspap.confsudo sed -i "s/\('RASPI_ADBLOCK_ENABLED', \)false/\1true/g" includes/config.php

При конфигурирование через Web-интерфейс столкнулся с багом, который при изменение настроек DHCP сервера на интерфейсе wlan1 удаляет файл конфигурации 090_wlan1.conf и не создает его заново. В результате DHCP сервер не выдает IP-конфигурацию новым клиентам. Временное решение этой проблемы заключается в блокировке файла на удаление, необходимо выполнить следующую команду (по блокировке файлов почитать по ссылке):

sudo chattr +i /etc/dnsmasq.d/090_wlan1.conf

После установки необходимо перезагрузить систему:

sudo reboot now

После перезагрузке появится Wi-Fi точка доступа с SSID raspi-webgui и паролем ChangeMe. Портал будет доступен по адресу: http://10.3.141.1.

Установка SoftEther VPN Server на VPS сервер


На сервер v636096.hosted-by-vdsina.ru установим Docker по официальному руководству Install Docker Engine on Ubuntu.

Создание сети для Docker контейнеров


Для подсети в которой будет контейнер с SoftEther VPN Server определим следующие параметры:

  • Название сети: vpnnetwork;
  • Subnet: 172.22.0.0/24;
  • Driver: bridge;
  • Range: 172.22.0.0/25;
  • gateway: 172.22.0.127;
  • HostMin: 172.22.0.1;
  • HostMax: 172.22.0.126;
  • Hosts/Net: 126.

Для создание внутренней сети Docker выполним команду:

$ docker network create --driver bridge --subnet 172.22.0.0/24 --ip-range=172.22.0.0/25 --gateway 172.22.0.127 vpnnetwork

Для проверки доступности сети выполнить команду: ping 172.22.0.127.

Создание контейнера с SoftEther VPN Server


Для создание контейнера будем использовать образ siomiz/softethervpn. До запуска основного контейнера необходимо создать конфигурацию, в которой указать пароль для управления сервером параметр SPW и пароль для управления хабом параметр HPW. Файл конфигурации будет располагаться по пути /usr/vpnserver/vpn_server.config. Выполнить следующие команды:

$ mkdir -p /usr/vpnserver$ docker run --name vpnconf -e "SPW={PASSWORD}" -e "HPW={PASSWORD}" siomiz/softethervpn echo$ docker cp vpnconf:/usr/vpnserver/vpn_server.config /usr/vpnserver/vpn_server.config$ docker rm vpnconf

Для уменьшения размера контейнера возьмем образ на основе Alpine, все журналы log в null. Выполнить следующие команды для создание контейнера:

$ docker run --name vps-server-softethervpn -d --cap-add NET_ADMIN --restart always --net vpnnetwork --ip 172.22.0.2 -p 443:443/tcp -p 992:992/tcp \-p 1194:1194/udp -p 5555:5555/tcp -v /usr/vpnserver/vpn_server.config:/usr/vpnserver/vpn_server.config \-v /dev/null:/usr/vpnserver/server_log -v /dev/null:/usr/vpnserver/packet_log -v /dev/null:/usr/vpnserver/security_log siomiz/softethervpn:alpine

Если контейнер запустился, то переходим к следующему шагу.

Настройка SoftEther VPN Server


Для настройки SoftEther VPN Server лучше использовать графическую утилиту для ОС Windows. Для загрузки необходимо перейти на страницу SoftEther Download Center. В списке Select Component, выбрать SoftEther VPN Server Manager for Windows, далее Select Platform windows. Можно выбрать пакет .zip без необходимости установки. Пакет softether-vpn_admin_tools-v4.34-9745-rtm-2020.04.05-win32.zip распаковать и запустить vpnsmgr.exe.

Создаем новый профиль кнопка New Setting, указываем следующие настройка:

  • Setting Name: VDSina_ru_main_server
  • Host Name: v636096.hosted-by-vdsina.ru
  • Port Number: 443
  • Password: пароль который был указан в переменной SPW при создание конфигурационного файла vpn_server.config

Затем подключаемся к серверу кнопка Connect.

При первом подключение появится вопрос об включение поддержки протокола IPSec. Если в дальнейшем планируете подключать мобильные устройства без использования программных клиентов, то выбрать Да. В данном случае поддержка IPSec не требуется, отвеваем Нет.

Для настройки алгоритма шифрования нажать на кнопку Encryption and Network. По умолчанию включен алгоритм DHE-RSA-AES256-SHA. Из списка выбрать другие более стойкие комбинации шифрования, но нужно помнить чем сильнее алгоритм, тем больше нагрузка на CPU сервера и на конечное маршрутизирующее устройство.

По умолчанию будет доступен хаб DEFAULT, удаляем его.

Создаем новый хаб кнопка Create a Virtual Hub. Укажем Virtual Hub Name: VPNROOT. Открываем настройки хаба кнопка Manage Virtual Hub.

Создадим пользователя подключения, кнопка Manage Users, затем кнопка New. Аутентификация будет по паре логин/пароль, укажем имя: officeuser1.

Для отделение подсети клиентов VPN сервера и подсети Docker контейнеров включим NAT, кнопка Virtual NAT and Virtual DHCP Server (SecureNAT), далее кнопка Enable SecureNAT. Изменим подсеть VPN клиентов на: 192.168.30.x, закроем окно, кнопка Exit.

На этом настройка сервера закончена.


Последовательность действий по настройке SoftEther VPN Server

Получение файлов конфигурации *.ovpn


Для подключения OpenVPN клиента необходимо получить файлы конфигурации *.ovpn, для этого переходим на главный экран настроек SoftEther VPN Server и нажимаем на кнопку OpenVPN / MS-SSTP Settings. Далее, в следующем окне генерируем файлы конфигурации, кнопка Generate a Sample Configuration File for OpenVPN Clients. Сохраняем архив OpenVPN_Sample_Config_v636096.hosted-by-vdsina.ru_20210519_150311.zip, для дальнейшего подключения потребуется файл f1167ecd086e_openvpn_remote_access_l3.ovpn.


Последовательность действий по получению файлов конфигурации *.ovpn

Настройка OpenVPN на RaspAP


Создание маршрутов
Теперь переходим в консоль Cubietruck и добавляем маршруты:

sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADEsudo iptables -A FORWARD -i tun0 -o wlan1 -m state --state RELATED,ESTABLISHED -j ACCEPTsudo iptables -A FORWARD -i wlan1 -o tun0 -j ACCEPT

Делаем копию существующих маршрутов и сохраняем новые

cp /etc/iptables/rules.v4 /etc/iptables/rules.v4.baksudo iptables-save | sudo tee /etc/iptables/rules.v4

Настройка профиля OpenVPN

Переходим на портал по адресу 192.168.43.12/openvpn_conf и указываем данные для подключения:

  • Username: officeuser1
  • Password: указанный для officeuser1 в SoftEther VPN Server
  • Для конфигурационного файла выбираем файл f1167ecd086e_openvpn_remote_access_l3.ovpn.

Сохраняем настройки и перезапускаем OpenVPN. Если подключение удалось, но в поле IPV4 ADDRESS будет публичный IP-адрес VPN сервера: 94.103.85.152 (v636096.hosted-by-vdsina.ru).

raspap
Страница настроек OpenVPN в RaspAP

Настройка Captive portal


Установка Captive portal в руководстве Captive portal setup.

Для установки выполним следующие действия:

sudo apt-get updatesudo apt-get install -y libmicrohttpd-devcd ~/git clone https://github.com/nodogsplash/nodogsplash.gitcd nodogsplashmakesudo make install

Далее необходимо внести изменения в конфигурационный файл /etc/nodogsplash/nodogsplash.conf. Указать следующие параметры:

...GatewayInterface wlan1...GatewayAddress 10.3.141.1...

Регистрация службы и запуск:

sudo cp ~/nodogsplash/debian/nodogsplash.service /lib/systemd/system/sudo systemctl enable nodogsplash.servicesudo systemctl start nodogsplash.service sudo systemctl status nodogsplash.service

Страницы html для изменение дизайна страниц располагаются по пути: /etc/nodogsplash/htdocs/. Теперь выполним подключение к AP SSID: raspi-webgui.

Устранение проблем


Первым делом необходимо проверить IP-конфигурацию сетевых интерфейсов, командами: ifconfig или ip a.

Проверить занятость портов, командами:

netstat -ntlp | grep LISTENlsof -i | grep LISTENlsof -nP -i | grep LISTEN

Если установка RaspAP выполняется на Ubuntu, то вы можете столкнуться с конфликтом использования 53 порта, который занят службой systemd-resolved. Для отключения данной службы, воспользоваться материалом How to disable systemd-resolved in Ubuntu.

Проверить статусы используемых служб, выполнить следующие команды:

sudo systemctl status hostapd.servicesudo systemctl status dnsmasq.servicesudo systemctl status lighttpd.servicesudo systemctl status openvpn-client@clientsudo systemctl status nodogsplash.servicesudo systemctl status raspapd.service


Что дальше?


Для проверки совместимости необходимо RaspAP развернуть на Banana Pi BPI-M64 (Armbian 21.02.1 на основе Ubuntu 18.04.5 LTS). Далее, развернуть на x86 с другим более новым адаптером, например USB Realtek 8811CU Wireless LAN 802.11ac. На GitHub размещен репозиторий raspap-docker, который оборачивает RaspAP в контейнер, но по факту запускает скрипт автоматической установки, что несколько неудобно и неправильно. Поэтому для более широкого распространения RaspAP необходимо его правильно обернуть в Docker контейнер для ARM и x86 архитектур.

Итог


Проект RaspAP безусловно заслуживает внимания, основные функции работают отлично. Это единственный проект связанный с Wi-Fi сетями, работающий поверх существующей ОС, у которого работает Web-интерфейс (пока есть небольшие баги). Для личного использования, теста, стоит попробовать. Но для продакшен в бизнесе пока лучше не использовать, необходимо более детально просмотреть исходный код и конфигурацию на предмет безопасности. В любом случае, проект добавил себе в закладки, надеюсь баги исправят в скором времени.



На правах рекламы


VDSina предлагает виртуальные серверы на Linux и Windows выбирайте одну из предустановленных ОС, либо устанавливайте из своего образа.

Присоединяйтесь к нашему чату в Telegram.

Подробнее..

Перевод Быстрое обнаружение Covid-19 на рентгеновских снимках с помощью Raspberry Pi

14.06.2021 18:13:31 | Автор: admin

Системы обнаружения Covid-19 на рентгеновских снимках выдают быстрые результаты, в частности информацию о том, насколько серьёзно лёгкие поражены вирусом Covid-19. Традиционные системы обнаружения Covid-19 обладают тем недостатком, что для формирования отчётов им требуется довольно длительное время, в то время как инфицированный человек нуждается в немедленной помощи. Кроме того, после каждого использования всех подобных систем обнаружения вируса часть деталей приходится утилизировать, что в некоторых случаях может приводить к их дефициту.К старту курса о машинном и глубоком обучении мы перевели статью о том, как эта проблема решается при помощи Raspberry Pi, кроме того, материал знакомит читателей с онлайн-платформой EDGE Impulse.


Наша система обнаружения Covid-19 на рентгеновских снимках требует лишь однократной установки и связки с рентгеновским аппаратом, после чего может работать сколько угодно времени. Она способна определять состояние инфицирования лёгких значительно быстрее традиционных систем. Такого результата можно достичь двумя способами: с помощью библиотеки Python или посредством создания и тренировки ML-модели. В этой статье мы расскажем, как создать и обучить модель. В скором времени мы опубликуем статьи о других методах, в которых используется предварительно обученная модель.

Что для этого нужно

Решение задачи начнём с подбора компонентов.

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

Предварительные требования

На Raspberry Pi должна быть установлена последняя версия ОС Raspbian. Также необходимо подготовить наборы данных для рентгеновских снимков лёгких, инфицированных и не инфицированных Covid-19. Такие снимки можно получить на сайте kaggle онлайн-ресурсе, где размещены рентгеновские снимки инфицированных пациентов, предоставленные сообществом экспертов и врачей. Аналогичные данные приведены на портале GitHub. Загрузим наборы данных рентгеновских снимков здоровых лёгких и лёгких, инфицированных Covid-19.

Теперь выберем платформу для создания ML-модели и обучим её обнаруживать на рентгеновских снимках инфицированные вирусом лёгкие. Здесь у нас есть разные варианты, например TensorFlow, PyTorch или онлайн-платформы: SensiML, Apache Spark, EDGE Impulse и так далее. Я выбрал EDGE Impulse.

В интерфейсе Edge Impulse переходим в меню создания проекта. Система спросит, как мы намереваемся использовать проект. Поскольку мы будем работать с проектом для создания ML-модели обработки изображений, выберем вариант, связанный с работой с изображениями.

Затем система спросит, как нужно классифицировать изображение (классификация одного или многих объектов). Здесь можно выбрать любой вариант. Я выбрал классификацию одного объекта (рис. 2). Щелчком мыши выберем только что созданный проект. Здесь система предложит указать, как его необходимо использовать. Выберем пункт Connect a development board (Подключение макетной платы). Через эту плату данные будут загружаться в проект (рис. 3).

1. Создание проекта1. Создание проекта2. Выбор типа для классификации2. Выбор типа для классификации3. Подключение макетной платы3. Подключение макетной платы

Установка на Raspberry Pi

Откроем окно терминала и с помощью приведённых ниже команд установим на Raspberry Pi зависимость для EDGE_Impulse:

curl -sL https://deb.nodesource.com/setup_12.x | sudo bash -sudo apt install -y gcc g++ make build-essential nodejs sox gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-base gstreamer1.0-plugins-base-appsnpm config set user root && sudo npm install edge-impulse-linux -g --unsafe-perm

После установки запускаем Edge_Impulse командой edge-impulse-linux. Нам будет предложено ввести адрес электронной почты и пароль для EDGE Impulse. Вводим требуемые данные и входим в систему (рис. 4).

4. Вход в систему с помощью адреса электронной почты и пароля4. Вход в систему с помощью адреса электронной почты и пароля

Система попросит выбрать проект, к которому должно быть подключено устройство. Указываем название проекта (в моём случае это COVID-19 Detector) (рис. 5).

5. Выбор проекта5. Выбор проекта

Подготовка набора данных

Система выдаст URL-адрес для загрузки набора данных. Есть два варианта загрузки наборов данных рентгеновских снимков: либо через камеру Raspberry Pi (поместив рентгеновские снимки в кадр камеры), либо загрузив файлы фотографий средствами ПК/Raspberry Pi (рис. 6). Я рекомендую второй вариант.

Чтобы вручную загрузить с ПК наборы данных, то есть изображения рентгеновских снимков, выберем эти наборы в качестве тестовых и тренировочных изображений. Выбрав наборы, загрузим их для обучения и установим метки [в оригинале level, крайне вероятна сложная опечатка label, о пороге принятия решений речь идёт далее] для классификации изображений. Здесь я устанавливаю метку Covid-19 infected (Covid-инфицированные лёгкие) и Normal Lungs (Здоровые лёгкие) (рис. 8). Далее загружаем рентгеновские снимки здоровых лёгких и лёгких, инфицированных Covid-19.

6. Получение URL-адреса для создания модели6. Получение URL-адреса для создания модели7. Загрузка набора данных с использованием камеры Raspberry Pi для модели7. Загрузка набора данных с использованием камеры Raspberry Pi для модели8. Загрузка данных из файла изображения8. Загрузка данных из файла изображения

Если вы не успели загрузить изображения в соответствующие категории, с помощью функции Edit (Редактирование) можно позже добавить и/или обозначить их как "Инфицированное лёгкое" или "Здоровое лёгкое". Размечая набор данных, пожалуйста, будьте осторожны. Если пометить рентгеновские снимки здоровых лёгких как Covid-инфицированные, модель будет обучена неправильно, и её точность будет снижена. Перед первоначальной загрузкой наборов данных (с веб-сайта) необходимо создать две отдельные папки: одну для тренировочных, другую для тестовых наборов данных. В обеих папках создадим ещё две папки с названиями Infected lung X-ray (Рентген инфицированных лёгких) и Normal lung X-ray (Рентген здоровых лёгких) соответственно. Загрузим отдельно изображения из обеих папок и после загрузки распределим их по соответствующим категориям (рис. 9).

9. Установка уровня для рентгеновского снимка наборов данных для тренировки модели9. Установка уровня для рентгеновского снимка наборов данных для тренировки модели

Повторим те же шаги, загружая рентгеновские изображения инфицированных и здоровых лёгких для тестовых наборов данных. Опция загрузки изображений для тестовых наборов данных находится рядом с опцией тренировки (рис. 10).

10. Вкладка тренировочных данных10. Вкладка тренировочных данных

Тренируем модель

После загрузки рентгеновских снимков инфицированных и неинфицированных наборов данных модель готова к тренировке. Переходим на вкладку Impulse design, выбираем пункт Create Impulse и жмём кнопку Create Impulse (см. рис. 11). Затем добавляем блок обработки и блок обучения (рис. 12, 13).

11. Создание Impulse11. Создание Impulse12. Выбор блока обработки12. Выбор блока обработки13. Блок обучения.13. Блок обучения.

После добавления блоков обработки и обучения необходимо определить параметры [в оригинале the parameter в единственном числе опечатка]. Для этого нужно получить характеристики рентгеновского снимка и сохранить их (рис. 14, 15). Затем переходим к новой опции тренировки ML-модели. Для этого в экспертном или обычном режиме Keras выбираем тренировку создаваемой ML-модели. В нашем случае выбираем обычный режим. В этом режиме можно задать количество циклов обучения. При увеличении количества циклов обучения точность работы модели увеличится, так как она пройдёт через различные циклы обучения, но при этом также увеличится время, необходимое для обучения ML-модели. Здесь можно задать такие параметры, как порог принятия решений и скорость обучения, значения которых влияют на точность и время работы модели.

15. 3D-визуализация признаков модели15. 3D-визуализация признаков модели16. Генерация параметра16. Генерация параметра17. Настройка и создание Ml-модели17. Настройка и создание Ml-модели

В оригинале надпись к рисунку 15 Feathers graph for ML model., вероятнее всего Features graph for ML model, то есть визуализация пространства признаков модели в трёхмерном пространстве.

Тестирование

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

18. Обнаружение инфекции по рентгеновскому снимку во время тестирования18. Обнаружение инфекции по рентгеновскому снимку во время тестирования19. Классификация снимка для проверки точности модели19. Классификация снимка для проверки точности модели

Развёртывание модели

Теперь наша ML-модель готова к развёртыванию. Развернуть созданную ML-модель для обнаружения инфекции вируса Covid-19 на рентгеновском снимке лёгкого можно многими способами и на разном оборудовании. Поскольку мы используем Linux, выбираем Linux. Затем открываем окно терминала и запускаем программу.

edge-impulse-runner-linux

После этого Raspberry Pi начнёт загрузку ML-модели и запустит её. Получаем URL-адрес, по которому можно наблюдать видео с камеры Raspberry Pi в реальном времени. Помещаем рентгеновский снимок лёгкого перед камерой (снимок должен быть хорошо освещён). Модель определяет инфицированное лёгкое и через несколько секунд выдает результаты Covid-теста.

Развёртывание ML-модели обнаружения Covid может быть осуществлено и другими способами. Используя SDK, можно обнаруживать Covid, развёртывая ML-модели на Python. Кроме того, можно загрузить рентгеновский снимок непосредственно в набор тестовых данных, а затем запустить ML-модель в режиме живой классификации она сработает за считанные секунды.

20. Выбор платы для развёртывания20. Выбор платы для развёртывания21. Развёртывание ML-модели в Raspberry Pi21. Развёртывание ML-модели в Raspberry Pi22. Обнаружение инфицированного лёгкого по рентгеновскому изображению22. Обнаружение инфицированного лёгкого по рентгеновскому изображению24. Вывод результатов24. Вывод результатов23. Обнаружение инфекции по рентгеновскому снимку23. Обнаружение инфекции по рентгеновскому снимку24. Здоровые лёгкие идентифицируются как здоровые24. Здоровые лёгкие идентифицируются как здоровые25. Обнаружение вирусной инфекции внутри лёгкого на рентгеновском снимке25. Обнаружение вирусной инфекции внутри лёгкого на рентгеновском снимке

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

Такое сочетание Raspberry Pi в решении проблемы коронавируса одним людям покажется очевидным, но другим неожиданным. Область ML сегодня бурно развивается, расширяет сферу влияния, так что впереди нас ждёт ещё много больших и маленьких парадоксов и неожиданностей самого разного рода. Если вы не хотите оставаться в стороне от прогресса ML, то вы можете присмотреться к нашему курсу о машинном и глубоком обучении, который может стать для вас источником новых идей и решений.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы

ПРОФЕССИИ

КУРС

Подробнее..

Сделать робота на raspberry pi, обновленный pi-tank. Часть 2. Софт

03.04.2021 18:14:06 | Автор: admin

Вторая часть полностью посвящена описанию программного обеспечения, используемого на роботе.
Так как разработанный робот (pi-tank) по большому счету рассчитан на начинающих роботостроителей, то все будет максимально упрощено, а в конце статьи будет приложен образ (image) для raspberry pi для самостоятельного дальнейшего изучения.


Небольшая оговорка. На предлагаемом образе для raspberry pi, рассчитанном на sd карту размером 8 Гб все настроено и установлено. Никаких дополнительных шагов предпринимать не требуется. Это сделано с целью упростить и облегчить часть, связанную с софтом, так как, исходя из практики, не всякий робототехник дотягивает до финиша, когда реализуется многокомпонентный проект.
Поэтому статья посвящена скорее настройке софта под себя, однако она позволит также пролить свет на то, как все собрать и настроить с нуля.

Основа.


В качестве отправной точки при разработке был взят RPi-Cam-Web-Interface. Достаточно древний, но тем не менее, не потерявший своей актуальности фреймворк.
Как его установить подробно описано на странице проекта и сложностей вызвать :
не должно
git clone https://github.com/silvanmelchior/RPi_Cam_Web_Interface.gitcd RPi_Cam_Web_Interface./install.sh


Есть нюансы для дистрибутива buster (о них написано на сайте проекта), но для Raspbian Stretch, который используется на роботе, все штатно.
После установки доступен web-сервер, который выводит по адресу raspberry-ip:8080/html/ картинку по умолчанию:


Данная картинка отличается от того, что можно наблюдать на роботе:

Как не трудно заметить, страница робота располагает стрелками для управления подвесом камеры (pan-tilt), собранном на базе серв sg-90, а также пользовательскими кнопками для управления роботом (фары, фары выкл и т.п.)
Назначение кнопок интерфейса интуитивно понятно.

Также на web-странице имеются вкладки для более детальной настройки параметров камеры, а также работы с системой:


Как попасть на raspberry.


При загрузке raspberry становится доступна через VNC c учетными данными логин pi, пароль raspberry.
wi-fi сеть, к которой по умолчанию подключается логин boss, пароль 1234554321.
Также можно попасть по ssh, пара логин-пароль те же.

Как все работает и где поменять под себя.


Вся начинка расположена в директории /var/www/html/, а сам RPi-Cam-Web-Interface стартует из /home/pi/RPi-Cam_Web_Interface.
Управление подвесом камеры осуществляется синими стрелками на web-странице. Сам фреймворк не умеет из коробки управлять сервами. Поэтому используется дополнительный пакет
И здесь есть небольшой нюанс. По умолчанию servoblaster использует gpio4 и gpio17 пины raspberry для управления подвесами (сигнальные провода серв). По счастливому стечению обстоятельств те же самые пины использует шапка raspberry pi witty pi 3 mini, отвечающая за питание, графики включения и т.п. Поэтому, чтобы железо не мешало друг другу пины для серв были перенесены для целей servoblasterа.
Делается это в /etc/rc.local командой:
sudo /home/pi/PiBits/ServoBlaster/user/servod --p1pins=13,15,0,0,0,0,0,0 & 

При этом 13,15 это физические пины, а не gpio! Остальные нули это возможность подключить еще сервы и управлять ими. То есть еще 6 серв можно подключить, обозначив пины вместо нулей.
*Какие пины задействованы servoblasterом в текущий момент можно заглянув в файл /dev/servoblaster-cfg
Также в /etc/rc.local задаются пины raspberry для управления двигателями:
код
gpio -g mode 5 out
gpio -g mode 6 out
gpio -g mode 9 out
gpio -g mode 10 out
gpio -g mode 11 out
gpio -g mode 22 out
gpio -g mode 27 out


*В данном случае gpio22 и gpio27 это и есть те пины 13,15, которые использует servoblaster.

Как с нуля настраивается pan-tilt описано на странице проекта здесь.

Как добавляются кнопки также описано на сайте в разделе User buttons. Чтобы добавить или изменить кнопки (фары и т.п.) необходимо обратиться к файлу /var/www/html/
userbuttons
фары,light.sh
фары-выкл,lightoff.sh
вперед,forward.sh
назад,reverse.sh
налево,left.sh
направо,right.sh
стоп,stop.sh
м налево,left-m.sh
м направо,right-m.sh
м вперед,forward-m.sh
м назад,reverse-m.sh

Здесь строки означают наименование кнопок, а также соответствующий им скрипт управления.
Сами скрипты управления находятся в /var/www/html/macros. И, вполне возможно, данные скрипты придется править, т.к. при подключении проводов к драйверу двигателей l298n полярность может быть иной и робот поедет не в ту сторону, согласно нажатой кнопке.
Чтобы это исправить, необходимо открыть скрипт, например /var/www/html/macros/left.sh
#!/bin/bash
gpio -g write 9 0
gpio -g write 11 1
gpio -g write 6 0
gpio -g write 5 1

И попробовать комбинации замены 1 и 0 на gpio. Но как правило, можно просто поменять left.sh на forward.sh или на right.sh и т.п. в зависимости от ситуации.

Кнопки интерфейса с приставкой м, отвечают за так называемый малый ход:

Это реализовано в скриптах left-m.sh и т.п. Ранее использовался pwm для управления. Однако стало понятно, что при задержках wi-fi и иных обстоятельствах расстояние, которое реализуется при нажатии на кнопку с pwm различается. Робот то уезжает слишком далеко до момента, когда нажата стоп, то практически не реагирует, особенно, при разряжающихся батареях.
Поэтому был реализован простой подход в скрипте подача сигнала и дальнейшее, через паузу, его гашение:
left-m.sh
#!/bin/bash
gpio -g write 9 0
gpio -g write 11 1
gpio -g write 6 0
gpio -g write 5 1
sleep 0.3
gpio -g write 9 0
gpio -g write 11 0
gpio -g write 6 0
gpio -g write 5 0



Witty pi 3 mini и управление питанием.


Продукт Witty pi 3 mini был приобретен, чтобы минимизировать потери питания при работе от powerbank и увеличить общее время функционирования робота.
Ранее при выключении робота, которое реализовано на web-странице

включить робота заново без посторонней помощи было невозможно. Были варианты с помощью внешней arduino, но все это было непросто и не эстетично.

Witty pi 3 mini не единственное решение в своем роде, и даже не первое в своей линейке. Но оно более-менее доступное и работающее из коробки.
Софт устанавливается предельно
просто

После установки может потребоваться уточняющая настройка в /home/pi/uwi/uwi.conf
текущие настройки
host='192.168.1.105';
port=8000;
web_socket_url='ws://'+host+':'+port+'/';
response_timeout=5000;
reconnect_timeout=1000;
debug=0;

wittypi3='/home/pi/wittypi';
zero2go='/home/pi/zero2go';



Далее при каждой загрузке на web странице raspberry:8000 (127.0.0.1:8000) будет доступен
web-интерфейс с настройками:


Первая вкладка это просто еще один способ управлять gpio raspberry pi

вторая вкладка это непосредственно настройки witty pi
На температурный датчик можно не обращать внимание, т.к. его точность сомнительна.

Можно настраивать прямо с web-страницы, но так же можно и с помощью скрипта:
/home/pi/wittypi/wittyPi.sh. При запуске скрипта, он выводит то же самое, что доступно на web-странице:
>>> Current temperature: 28.75C / 83.75F
>>> Your system time is: Sat 03 Apr 2021 16:20:47 MSK
>>> Your RTC time is: Sat 03 Apr 2021 16:20:48 MSK
>>> Vin=4.73V, Vout=4.68V, Iout=1.13A
Now you can:
1. Write system time to RTC
2. Write RTC time to system
3. Synchronize time
4. Schedule next shutdown
5. Schedule next startup
6. Choose schedule script
7. Set low voltage threshold
8. Set recovery voltage threshold
9. View/change other settings...
10. Reset data...
11. Exit

Здесь необходимо:
синхронизировать время на witty pi c системными часами raspberry (3. Synchronize time)
записать это время в rtc (1. Write system time to RTC)
далее поработать с пробуждением либо засыпанием, но проще сразу выбрать какой-нибудь
скрипт
6. Choose schedule script
[1] 7:00_on_7:30_off_21:00_on_21:30_off.wpi
[2] on_10m_every_2h.wpi
[3] on_1h_every_2d.wpi
[4] on_30m_everyday_but_weekend.wpi
[5] on_5m_every_20m.wpi
[6] turn_on_every_hour.wpi

Например [5], просыпаться на 5 минут каждые 20 минут.

После выбора скрипта соответствующие интервалы сна будут сразу обозначены:


обязательно заглянуть в другие настройки (9. View/change other settings...)
Здесь необходимо настроить [5] Dummy load duration [0] это паразитные импульсы для powerbankа, не дающие ему уснуть. Так как большинство powerbankов снимают питание при минимизированной нагрузке. Диапазон значений 0-255.
Все остальные настройки можно не трогать.

Witty pi предполагает также возможность контроля напряжения питания и корректное отключение при падении, а также включение при изменившихся условиях.
Доступна также более гибкая регулировка в части создания своих собственных графиков включения и выключения скриптогенератор:

Об этом подробно написано в инструкции.
Сон pi-tanka

Пока все. Если что-то забыто или непонятно пишите.

Образ для raspberry pi скачать.
Подробнее..

PXE-мультитул на базе Raspberry Pi

08.05.2021 12:05:15 | Автор: admin

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

Перед тем как приступить к достаточно тривиальной процедуре настройки BIOS и IPMI, мы должны убедиться в том, что каждый компонент сервера имеет требуемую версию прошивки. В большинстве случаев, за редким исключением, необходима актуальная версия, доступная на сайте производителя конкретных комплектующих. Сегодня мы расскажем, как мы придумали для ускорения процесса задействовать популярную нынче малинку.

В чем сложность


Казалось бы задачка весьма проста. Ну давайте возьмем какой-нибудь live-дистрибутив Linux, раскатаем его на флешку и будем с него загружаться и выполнять требуемые процедуры. Но не тут-то было.

Проблема в том, что у каждого вендора свои собственные методы и собственные утилиты для обновления прошивок. Причем, не все они способны корректно работать под Linux. Какие-то компоненты, например, BIOS у серверов SuperMicro желательно шить из-под MS-DOS. Для каких-то компонентов, например, сетевых карт Mellanox в некоторых случаях нужно использовать Windows, а некоторые поддерживают прошивку непосредственно из Linux.

Таким образом нам нужно будет либо собирать мультизагрузочный образ и записать его на несколько десятков флешек, затем долго и упорно загружаться с них, либо придумать нечто более интересное и быстрое. И вот здесь приходит на ум использование сетевых карт серверов с поддержкой загрузки по PXE (Preboot eXecution Environment, произносится как пикси).

Берем малинку, разворачиваем там DHCP- и TFTP-сервер, готовим требуемые образы для загрузки. Чтобы массово загрузить несколько десятков серверов просто временно задействуем неуправляемый гигабитный свитч на 48 портов и вуаля. По-умолчанию большинство серверов возможность загрузки с PXE предусматривают без дополнительной настройки, поэтому такой вариант идеален.

За основу я взял прекрасную статью от Romanenko_Eugene, но с поправками на особенности Raspberry Pi и решаемые задачи. Приступаем!

Малиновое варенье


Когда я первый раз проделывал такое самой продвинутой версией Raspberry Pi была третья с сетевой картой на 100 Мбит/с. Этого откровенно говоря мало для массовой раздачи тяжелых образов, так что настоятельно рекомендую использовать доступную ныне Raspberry Pi 4 с портом на 1 Гбит/с. Еще одна рекомендация по возможности использовать быструю и емкую карту памяти.

Теперь о первоначальной настройке. Графический интерфейс для такой штуки абсолютно не требуется, поэтому можно скачать самую простую Lite-версию операционной системы Raspberry Pi OS. Распаковываем образ и заливаем образ на MicroSD-карту любым удобным способом, например с помощью dd:

sudo dd if=<имя_образа> of=/dev/mmcblk0 bs=1M

В процессе настройки можно либо настраивать традиционным способом, подключив клавиатуру и монитор, либо через SSH. Чтобы при запуске SSH-сервис заработал, создаем пустой файл с именем ssh в разделе /boot.

Поскольку сетевой порт будет задействован для работы DHCP, то для доступа в интернет можно либо использовать подключение к Wi-Fi, либо подключить к малинке еще одну сетевую карту по USB. Вот такую, например:


Теперь запускаем Raspberry Pi, подключаем ее к интернету и обновляем репозитории и пакеты ПО:

sudo apt update

sudo apt upgrade

Поскольку я задействую еще одну сетевую карту, то встроенной надо задать статический IP-адрес. Открываем конфиг:

sudo nano /etc/dhcpcd.conf

Добавляем следующие строчки:

interface eth0static ip_address=192.168.50.1/24

Здесь eth0 встроенная сетевая карта Raspberry Pi. Именно с помощью нее будет осуществляться и раздача IP-адресов, и сетевая загрузка. Теперь устанавливаем tftp-сервер:

sudo apt install tftpd-hpa

После установки открываем конфигурационный файл:

sudo nano /etc/default/tftpd-hpa

Приводим строку к следующему виду:

TFTP_OPTIONS="--secure -l -v -r blksize"

В целом можно было бы и оставить все как есть, но тестировать каждый раз на отдельной машине иногда не слишком удобно. Опции -l -v -r blksize позволяют без проблем тестировать все это на виртуальной машине VirtualBox, исправляя некоторую проблему совместимости. Теперь устанавливаем DHCP-сервер для раздачи IP-адресов:

sudo apt install isc-dhcp-server

Открываем первый конфигурационный файл isc-dhcp-server:

sudo nano /etc/default/isc-dhcp-server

Явным образом указываем интерфейс, на котором предполагается работа DHCP-сервера:

INTERFACESv4="eth0"

Теперь открываем второй конфиг dhcpd.conf:

sudo nano /etc/dhcp/dhcpd.conf

Задаем необходимые параметры сервера, раздаваемую подсеть, а также передаем имя файла загрузчика:

default-lease-time 600;max-lease-time 7200;ddns-update-style none;authoritative;subnet 192.168.50.0 netmask 255.255.255.0 {        range 192.168.50.2 192.168.50.250;        option broadcast-address 192.168.50.255;        option routers 192.168.50.1;        filename "pxelinux.0";}

Сохраняем файл и теперь нам предстоит собственно скачать загрузчик, нужные модули и сформировать меню PXE. Начнем со скачивания набора загрузчиков Syslinux, в моем случае наиболее удобна версия 5.01:

wget https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-5.01.zip

Распаковываем:

unzip syslinux-5.01.zip

Теперь нам надо найти и извлечь модуль memdisk, умеющий подгружать в ОЗУ ISO-образы целиком, загрузчик pxelinux.0 и остальные модули comboot. Последовательно выполняем команды, которые отыщут и скопируют все найденное в директорию /srv/tftp:

find ./ -name "memdisk" -type f|xargs -I {} sudo cp '{}' /srv/tftp/

find ./ -name "pxelinux.0"|xargs -I {} sudo cp '{}' /srv/tftp/

find ./ -name "*.c32"|xargs -I {} sudo cp '{}' /srv/tftp/

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

cd /srv/tftp

Создаем директорию с именем pxelinux.cfg и переходим в нее:

sudo mkdir pxelinux.cfg

cd pxelinux.cfg

Создаем конфигурационный файл:

sudo nano default

В качестве примера давайте возьмем отличный live-дистрибутив GRML и загрузим его через PXE. Ниже готовый пример конфигурации:

UI vesamenu.c32                  PROMPT 0MENU TITLE Raspberry Pi PXE ServerMENU BACKGROUND bg.pngLABEL bootlocal   menu label Boot from HDD   kernel chain.c32   append hd0 0   timeout 0TEXT HELPBoot from first HDD in your systemENDTEXTLABEL grml   menu label GRML LinuxKERNEL grml/boot/grml32full/vmlinuzAPPEND root=/dev/nfs rw nfsroot=192.168.50.1:/srv/tftp/grml/ live-media-path=/live/grml32-full boot=live lang=us nomce apm=power-off noprompt noeject initrd=grml/boot/grml32full/initrd.img vga=791LABEL reboot    menu label Reboot    kernel reboot.c32TEXT HELPReboot serverENDTEXT

Здесь наверное стоит немного остановиться и разобраться что делает каждая строка:

  • UI vesamenu.c32 используем модуль vesamenu.c32 для вывода меню;
  • PROMPT 0 подсвечиваем нулевой пункт меню;
  • MENU TITLE Raspberry Pi PXE Server задаем общее название меню;
  • MENU BACKGROUND bg.png элемент оформления, используем bg.png в качестве фонового изображения.

Фоновое изображение можно изготовить заранее. По-умолчанию подойдет картинка 640x480 с глубиной цвета не более 24 бит, в формате PNG или JPG. Ее надо заранее скопировать в /srv/tftp. Теперь разберем каждую секцию. Первая секция введена для удобства. Если надо загрузится с первого жесткого диска, то прописываем:

  • LABEL bootlocal внутреннее имя секции;
  • menu label Boot from HDD то, как будет отображено меню у пользователя;
  • kernel chain.c32 используем модуль chain.c32, умеющий выполнять загрузку с различных носителей;
  • append hd0 0 явным образом указываем, что загрузка должна быть с первого раздела первого жесткого диска;
  • timeout 0 тут можно либо задать таймаут в секундах, по истечении которого будет автоматически запущена загрузка, либо указав 0 убрать таймер.
  • TEXT HELP указываем начало текста подсказки для пользователя;
  • Boot from first HDD in your system текст подсказки;
  • ENDTEXT указываем конец текста подсказки.

Приблизительно таким же образом формируем и секцию для перезагрузки. Единственным отличием будет вызов модуля reboot.c32, который собственно и отправляет машину в ребут. Ну, а перед тем как разобрать что делает третья секция, загружающая дистрибутив GRML, поговорим о том, что собственно будет загружаться и каким образом.

Everything is a file


Сам ISO-образ доступен на сайте этого live-дистрибутива. Скачиваем его и переименовываем для удобства, в примере возьмем 32-битную версию:

wget https://download.grml.org/grml32-full_2020.06.iso

mv grml32-full_2020.06.iso grml.iso

Теперь надо этот образ каким-то образом заставить загружаться. С одной стороны можно применить модуль memdisk и заставить его вначале загрузить все сырое содержимое образа непосредственно в ОЗУ и потом передать управление загрузкой. Но этот метод хорош только для очень маленьких образов, например, так удобно загружать MS-DOS. Большие же образы долго загружаются в память и не всегда работают адекватно.

Поэтому следует все-таки распотрошить образ и на загрузку передать только ядро и livefs. А вот дальнейшие файлы с диска можно предоставлять системе по запросу с помощью NFS-сервера. Такой подход работает значительно быстрее и адекватнее, но требует дополнительных телодвижений, таких как установка NFS-сервера.

Выполняется элементарно:

sudo apt install nfs-kernel-server

Чтобы не устраивать кашу из файлов создаем отдельную директорию для grml:

sudo mkdir /srv/tftp/grml

Нам потребуется примонтировать ISO-образ, поэтому позаботимся о временной точке монтирования:

sudo mkdir /tmp/iso

Монтируем образ. Система предупредит, что образ смонтирован в Read-Only режиме:

sudo mount -o loop grml.iso /tmp/iso

Рекурсивно копируем содержимое образа в нашу отдельную директорию:

sudo cp -R /tmp/iso/* /srv/tftp/grml

Чтобы не возникало проблем с правами доступа, меняем владельца и рекурсивно присваиваем этой директории права из серии Дом свободный, живите кто хотите:

sudo chown -R nobody:nogroup /srv/tftp/grml/

sudo chmod -R 777 /srv/tftp/grml/

Теперь дело за малым указать NFS-серверу, что ему следует предоставлять директорию /srv/tftp/grml любому IP-адресу из нашей подсети:

sudo nano /etc/exports

Прописываем строчку:

/srv/tftp/grml 192.168.50.0/24(rw,sync,no_subtree_check)

Обновляем список и рестартуем NFS-сервер:

sudo exportfs -a

sudo systemctl restart nfs-kernel-server

Теперь у нас наконец-то появляется возможность корректно разделить процесс загрузки на два условных этапа. Первый этап загрузка ядра и live-filesystem. Второй этап подтягивание всех остальных файлов через NFS. Пришла пора посмотреть на оставшуюся секцию:

  • LABEL grml имя секции;
  • menu label GRML Linux отображение в меню;
  • KERNEL grml/boot/grml32full/vmlinuz указываем путь до ядра, относительно корня /srv/tftp;
  • APPEND root=/dev/nfs rw nfsroot=192.168.50.1:/srv/tftp/grml/ live-media-path=/live/grml32-full boot=live lang=us nomce apm=power-off noprompt noeject initrd=grml/boot/grml32full/initrd.img vga=791 тут мы говорим, что используем NFS, прописываем пути к условному корню, задаем некоторые дополнительные параметры, рекомендуемые в документации и указываем относительный путь до initrd.

Теперь остается только последовательно запустить TFTP и DHCP-сервер и можно пробовать выполнять загрузку в PXE. Если все сделано правильно, то вы увидите созданное меню:


Выбрав пункт GRML Linux нажимаем Enter и видим, что у нас происходит успешный процесс загрузки образа:


Таким образом мы получили возможность сетевой загрузки популярного среди системных администраторов дистрибутива GRML. Но что насчет того же самого MS-DOS и как можно самостоятельно подготовить образ для перепрошивки BIOS. Об этом поговорим дальше.

In DOS We Trust


Неужели в 21 веке все еще используется операционная система из 80-х годов прошлого тысячелетия. Каким бы странным это не казалось но для некоторых специфичных задач MS-DOS по прежнему актуальна и вполне себе находит применение. Одной из таких задач является обновления прошивки BIOS на серверах.

Возьмем для примера какую-нибудь материнскую плату, например, Supemicro X11SSL-F и скачаем обновление BIOS с официального сайта. Внутри видим приблизительно подобный набор файлов:

user@linux:~/Загрузки/X11SSLF0_B26> ls -lитого 16592-rw-r--r-- 1 user users   169120 фев  1  2015 AFUDOSU.SMC-rw-r--r-- 1 user users     5219 сен 20  2003 CHOICE.SMC-rw-r--r-- 1 user users    22092 апр 27  2014 FDT.smc-rw-r--r-- 1 user users     3799 дек 15  2016 FLASH.BAT-rw-r--r-- 1 user users     3739 мая 22  2019 Readme for UP X11 AMI  BIOS.txt-rw-r--r-- 1 user users 16777216 ноя 25 23:48 X11SSLF0.B26

Видим, что у нас уже есть готовый BAT-файл, позволяющий прошить BIOS. Но для того, чтобы это сделать надо иметь уже загруженный в MS-DOS сервер. Сейчас покажем как именно это сделать.

Прежде всего нам надо подготовить небольшой raw-образ жесткого диска с операционной системой. Создаем новую виртуальную машину через Oracle VM VirtualBox с небольшим диском на 32 мегабайта. Формат выбираем QCOW, после всех манипуляций его можно будет легко сконвертировать в raw.

Наверняка вы все знаете где можно достать образы дискет с MS-DOS, так что монтируем их внутрь виртуальной машины и запускаем установку:


Дважды меняем образы дискет в виртуальном приводе и спустя буквально 20 секунд у нас есть qcow-образ со свеженькой ОС MS-DOS 6.22:


Самым простым способом теперь скопировать файлы на данный диск будет примонтировать его к любой другой виртуальной машине с Windows или Linux. После этой операции повторно монтируем диск к виртуальной машине с MS-DOS и проверяем, что файлы видны:


При желании можно даже настроить автозагрузку на выполнение BAT-файла, чтобы перепрошивка BIOS производилась автоматически. Но помните, что это потенциально опасная операция и делаете вы ее на свой страх и риск. Теперь выключаем виртуальную машину и переконвертируем ее в raw-образ с помощью qemu-img.

qemu-img convert -f qcow -O raw DOS.qcow dos.img

Полученный IMG-образ копируем в отдельную директорию нашего TFTP-сервера:

sudo mkdir /srv/tftp/dos

sudo cp dos.img /srv/tftp/dos

Теперь открываем конфигурацию /srv/tftp/pxelinux.cfg/default на редактирование и добавляем в меню еще один пункт:

LABEL DOS        kernel memdisk        initrd dos/dos.img        append raw

Сохраняем конфигурацию и теперь у нас в PXE-меню появился новый пункт меню, выбрав который мы загружаем созданный образ:


Точно так же можно создавать образы, содержащие как служебные утилиты, так и забавы ради со старыми играми под DOS.

In Windows Veritas


Давайте теперь попробуем загрузить Live-образ c WinPE (Windows Preinstallation Environment). Загружать полноценный вариант часто просто не требуется, достаточно лишь ограниченного количества функций. Реальное применение эта штука находит при перепрошивке некоторых устройств.

Та же самая Mellanox, год назад поглощенная Nvidia, выпускает утилиту Mellanox Firmware Tools для перепрошивки своих сетевых карт в вариантах для WinPE различных версий. Разумеется сейчас доступны уже различные варианты MFT, но пару раз мы сталкивались именно с необходимостью шить через WinPE-версию.

Создание своего собственного образа WinPE и интеграция нужного ПО туда задача не слишком сложная, но ее объяснение выходит за рамки данной статьи. Чтобы детально освоить этот процесс можно посетить отличный ресурс winpe.ru. Мы же для примера возьмем какую-либо готовую сборку для демонстрации процесса запуска.

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

wimboot достаточно простой загрузчик, умеющий выполнять загрузку образов в формате wim (Windows Imaging Format). Его можно использовать либо в связке с syslinux, либо с более продвинутым собратом, iPXE. Создаем отдельную директорию в /srv/tftp:

sudo mkdir wimboot

cd wimboot

Cкачиваем сам загрузчик:

wget https://github.com/ipxe/wimboot/releases/latest/download/wimboot

Теперь пришло время подмонтировать образ. Создадим временную директорию в /tmp:

sudo mkdir winpe

Переходим в каталог со скачанным ISO-образом сборки и выполняем:

sudo mount -o loop <имя_образа> /tmp/winpe

Создаем директорию в /srv/tftp, куда положим нужные нам файлы:

sudo mkdir /srv/tftp/winpe

Теперь ищем в сборке и копируем 4 файла:

sudo cp BOOTMGR /srv/tftp/winpe

sudo cp bcd /srv/tftp/winpe

sudo cp boot.sdi /srv/tftp/winpe

sudo cp boot.wim /srv/tftp/winpe

Дело за малым в конфигурационный файл /srv/tftp/pxelinux.cfg/default дописываем следующую секцию:

LABEL WinPE        menu label WinPE        com32 linux.c32 wimboot/wimboot        append initrdfile=winpe/BOOTMGR,winpe/bcd,winpe/boot.sdi,winpe/boot.wim

Фактически мы при помощи модуля linux.c32 выполняем загрузку загрузчика отличная тавтология, а ему передаем параметры уже в формате, привычном для wimboot. Таким образом вначале у нас загружается wimboot, затем последовательно распаковываются и запускаются необходимые файлы.


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


Вместо заключения


В этой статье нет какого-либо ноу-хау, но когда возникла необходимость Raspberry Pi отлично справилась. Ей не потребовалось искать дополнительную розетку питания, прекрасно подошел USB-порт ближайшего свободного сервера. Нет дополнительных заморочек с поиском места в забитой под завязку железом стойке. Работает именно так как надо, а малые габариты позволяют всегда иметь ее под рукой.

В сети на самом деле есть множество мануалов по настройке сетевой загрузки. Проблема лишь в том, что для разных образов используются разные средства и различные подходы. Выбор правильного подхода иногда требует массы времени и я очень надеюсь, что этот материал поможет многим сэкономить время при решении различных задач, связанных с необходимостью быстрого развертывания PXE на одноплатном компьютере Raspberry Pi.

Подробнее..

Шпаргалка по Linux grep, домашний термостат на Raspberry Pi, эл. книга Ansible for DevOps и PostgreSQL на Linux

25.03.2021 12:22:32 | Автор: admin

Собрали для вас много новых инсайтов, записей важных вебинаров, книжек и шпаргалок. Прокачивайте скилы, читайте, смотрите, думайте, применяйте на практике! Станьте частью DevNation!

Узнать новое:

  • 4 инструмента для Linux
    С Linux практически любая железка превращается в универсальный сервер общего доступа для файлов, аудио-, видео- и прочих ресурсов, с которыми легко и удобно работать с других платформ и устройств.

Скачать:

  • Шпаргалка по Raspberry Pi
    Как загрузить, как поставить ОС, как включить SSH и подключиться по WiFi, как установить ПО и обновить систему, а также где найти дополнительную справку и ответы на вопросы.

  • Шпаргалка по Linux grep
    Постигаем секреты поиска строк в файлах с помощью регулярных выражений.

Почитать на досуге:

Мероприятия:

  • Виртуальный Red Hat Summit 2021, 27-28 апреля
    Бесплатная онлайн-конференция Red Hat Summit это отличный способ узнать последние новости ИТ-индустрии, задать свои вопросы техническим экспертам, услышать истории успеха непосредственно от заказчиков Red Hat и увидеть, как открытый код генерирует инновации в корпоративном секторе

  • BCC и Red Hat: Освобождение от рутины. Как Ansible automation platform помогает решить задачи IT инфраструктуры любого уровня, 30 марта
    В ходе практической online-сессии проекта ВСС WEBINAR детально изучаем инструменты платформы Red Hat Ansible Automation, необходимые для реализации автоматизации предприятия. Также вас ждет 2 демо-сессии по оптимизации IT-инфраструктуры с помощью Ansible Automation Platform на примере настройки межсетевого экрана в среде Windows и в среде Linux

  • Вебинар про решения Red Hat для SAP на IBM Power Systems, 8 апреля
    Ваш бизнес зависит от среды SAP? Она поддерживает критически важные процессы и предоставляет данные? Неэффективная среда может вызвать задержки, снизить гибкость и повысить расходы в ваших ИТ-подразделениях. Более чем 20-летний опыт инноваций позволяет компаниям Red Hat и SAP разрабатывать решения, отвечающие требованиям критически важных приложений. Red Hat Enterprise Linux это не только стабильная платформа, она дает конкретные преимущества при работе с инсталляциями SAP

Смотри в записи:

  • AnsibleFest
    Два дня интереснейших докладов, демонстраций и практических занятий. Отличная возможность узнать, как разработчики, администраторы и ЛПР в сфере ИТ отвечают на вызовы перемен с помощью гибких технологий автоматизации с открытым кодом, которые позволяют перейти от того, что есть, к тому, что нужно

  • J4K Conference
    Новая виртуальная конференция по Kubernetes, Java и облаку: 17 сессий с сотрудниками Red Hat, включая доклад Марка Литтла (Mark Little), главного человека в Red Hat по связующему ПО.

Подробнее..

Перевод Запуск домашнего веб-сервера без статического IP с помощью Python

13.05.2021 08:09:48 | Автор: admin


Приветствую жителей Хабра!


Задался тут вопросом, как можно обойтись без статического IP для экспериментов в домашних условиях. Наткнулся на вот эту статью.


Если вы хотите развернуть свой вебсервер с доступом извне, а платить провайдеру за статический IP не хотите, то данное решение вполне себе выход, которое можно в дальнейшем подогнать под свои нужды.




Недавно я решил установить веб-сервер на Rasberry Pi, работающий за моим домашним маршрутизатором. У меня есть опыт настройки веб-серверов на виртуальных машинах Linux со статическими IP-адресами, поэтому в настройке сервера apache2 на Pi нет ничего особенного, и в Интернете есть сотни руководств. Проблема только в том, что при изменении внешнего IP вашего роутера сайт сломается! Один из способов решить эту проблему заплатить своему интернет-провайдеру за статический IP-адрес но тогда в чём веселье?!


Во многих своих последних проектах я использовал Google Domains для покупки доменного имени и обычно запускал сайты без собственных гугловских серверов имен на отдельном VPS/облачном сервере. Но для моего домашнего сервера я решил использовать невероятно простую в настройке функцию переадресации IP-адресов поддоменов, чтобы перенаправить базовый домен (@.example.com) на IP-адрес моего маршрутизатора (а затем настроить мой маршрутизатор на перенаправление с http портов на https порты на Pi). Тогда мне пришлось бы вручную проверять, работает ли сайт, и менять IP при необходимости. Очевидно, это не идеальный план, поэтому я решил написать скрипт для автоматизации этого процесса.


На заметку, вы можете найти полный скрипт на гитхабе или импортировать пакет Python с помощью pip install domains-api

Есть много способов проверить ваш внешний IP-адрес, и один из самых простых, которые я нашел, был через ipify API (api.ipify.org), который просто возвращает ваш общедоступный IP-адрес. При использовании Python библиотеки requests запрос выглядит следующим образом:


IP = requests.get('https://api.ipify.org').text

Вот и все, это ваш внешний IP. Легко, правда? Есть много других подобных способов получить внешний IP-адрес, но я считаю, что это самый простой.


Итак, что еще нам нужно для нашего скрипта? Нам нужно где-то хранить IP-адрес, чтобы проверять будущие запросы. Изначально я решил сохранить его в простом текстовом файле. Нам также нужен способ либо уведомить пользователя, либо обновить domain.google.com, либо и то, и другое. Первый вариант довольно легко реализовать с помощью библиотеки электронной почты для Python, поэтому я настроил её для работы с моей учетной записью Gmail следующим образом (вам нужно будет разрешить менее безопасные приложения (less secure apps) в своей учетной записи Google):


from email.message import EmailMessagedef send_notification(new_ip):    msg = EmailMessage()    msg.set_content(f'IP has changed!\nNew IP: {new_ip}')    msg['Subject'] = 'IP CHANGED!'    msg['From'] = GMAIL_USER    msg['To'] = GMAIL_USER    try:        server = smtplib.SMTP_SSL('smtp.gmail.com', 465)        server.ehlo()        server.login(GMAIL_USER, GMAIL_PASSWORD)        server.send_message(msg)        server.close()        log_msg = 'Email notification sent to %s' % GMAIL_USER)        logging.info(log_msg)    except (MessageError, ConnectionError) as e:        log_msg = 'Something went wrong: %s' % e        logging.warning(log_msg)

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


def enc_pwd():    pwd = base64.b64encode(getpass("What's your email password?: ").encode("utf-8"))    with open('cred.txt', 'wb') as f:        f.write(pwd)def read_pwd():    if os.path.isfile(f"{CWD}/cred.txt"):        with open(f'{CWD}/cred.txt', 'r') as f:            if f.read():                password = base64.b64decode(pwd).decode('utf-8')                logging.info('Password read successfully')                return password            else:                    enc_pwd()                read_pwd()    else:        enc_pwd()        read_pwd()

Теперь я мог бы заменить константу GMAIL_PASSWORD из функции уведомления на функцию read_pwd() (которая возвращает декодированный пароль), что всяко безопаснее.


Последнее, что мне нужно, чтобы программа стала эффективной, это дописать функцию, которая свяжет всё вместе и сохранит/сравнит IP-адреса:


def check_ip():    if os.path.isfile('ip.txt'):        # Снова проверим предыдущий IP        with open('ip.txt', 'r') as rf:            line = rf.readlines()            if not line:                first_run = True            elif line[0] == IP:                first_run = False                change = False            else:                first_run = False                change = True    else:        first_run = Trueif first_run or change:        # Запишем новый IP в файл        with open('ip.txt', 'w') as wf:            if first_run:                wf.write(IP)            elif change:                wf.write(IP)                # Уведомим пользователя:                send_notification(IP)    time.sleep(21600)       # в окончательной версии на моем боевом веб-сервере я удалил это 6-часовое ожидание и рекурсивный вызов в конце и просто добавил скрипт в crontab для запуска один раз в час. Мне также пришлось сделать все пути к файлам абсолютными, поскольку по умолчанию для crontab рабочий каталог - '/'.    check_ip()

Бум! Это была первая реализация моей идеи. Когда я получаю уведомление по электронной почте, я могу просто изменить правила переадресации на сайте domains.google.com


Стоп, что? Мне все еще нужно это делать самому? Конечно нет, есть способ проще!


Что ж, оказывается, есть два способа автоматизировать это один значительно менее эффективный, но бесконечно более захватывающий, а другой довольно скучный, но бесконечно более эффективный! Я начну, как и сделал, с захватывающего и сложного способа: слышали когда-нибудь о Selenium для автоматизации тестирования веб-сайтов? Я решил написать сценарий, который будет физически входить в домены Google и перемещаться по сайту, чтобы изменить правила для меня, если и когда изменится IP. Однако это приводило к следующим проблемам:


Прежде всего, Google Domains (и другие сервисы Google, такие как Gmail) довольно хорошо обнаруживают автоматизацию браузера и просто не позволяют вам войти в систему через веб-драйвер Selenium. Мне посчастливилось найти этот ответ (есть и другие решения) в Stack Overflow, который предлагал войти в сам Stack Overflow с вашей учетной записью Google, прежде чем переключаться на желаемую службу Google, что действительно работало, пока я не брал под контроль браузер и при необходимости не вводил капчу. Со скриптом, запущенным на моем ноутбуке или десктопе, это замечательно тем более, что после первоначальной проверки Captcha StackOverflow, похоже, больше не проверял тот же компьютер, поэтому после этого веб-драйвер можно было запустить в автономном режиме, но это не подходит для веб-сервера! Хотя я мог заставить веб-драйвер нормально работать с помощью PyVirtualDisplay и Geckodriver (веб-драйвер для Firefox), ему удавалось только один раз попасть на желаемую страницу Мои домены, а в других случаях вообще не мог войти в систему из-за Captcha.



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


Так уж получилось, что у Google Domains есть API именно для той цели, которая мне нужна. Я изначально отклонил APi, когда не смог заставить его работать с правилами переадресации поддоменов, которые я использовал, не понимая, что API предназначен для изменения правил динамического DNS эта документация стала намного более понятной после того, как я настроил запись динамического DNS вместо стандартного правила Переадресация поддоменов (спасибо Джереми Гейлу за его отличный урок о том, как сделать что-то подобное с помощью простого сценария bash, который помог мне победить эту проблему!)


Раздел Synthetic records на странице конфигурации DNS Google Domains должен выглядеть следующим образом:


Вот как должна выглядеть ваша запись


Выберите Dynamic DNS вместо Subdomain forward.


Затем вы получите автоматически сгенерированные учетные данные, необходимые для аутентификации с помощью API:


Просто нажмите Просмотреть учетные данные, скопируйте и вставьте их в свой запрос API.


Теперь, зная этот метод, я смог значительно уменьшить длину и нагрузку на скрипт! TTL динамического DNS также очень низок, по умолчанию: 1 мин, что сокращает возможное время простоя ещё один дополнительный бонус. Всё, что мне было нужно, это включить вызов API в мою функцию check_ip(), и он сделает все за меня! И эта единственная строка кода (2 с вызовом логирования) выглядит так:


req = requests.post(f'https://<auto_generated_username>:<auto_generated_password>@domains.google.com/nic/update?hostname=@.example.com&myip={IP}')logging.info(req.content)

Я заключил всё в блок try / except, чтобы перехватить любые исключения, и таким образом этот довольно простой, но удивительно полезный скрипт был почти готов. Теперь осталось только добавить его в crontab на моем веб-сервере и дать ему работать, и (теоретически) мне больше не придется беспокоиться о смене IP!


Стоп! Время рефакторинга:


Так, вот, о чем я позаботился! Чтобы сделать этот скрипт универсально доступным, я реорганизовал всё, чтобы использовать более объектно-ориентированный подход, основанный на классах, с классами User и IpChanger. Класс User содержит все учетные данные для входа в smtp и вызова API domains.google, а первый созданный экземпляр вместе с атрибутом previous_ip, для проверки, сохраняется в одном pickle файле (аналогично сериализации в JavaScript); в будущих экземплярах класса User() пользовательский экземпляр создается из pickle, если не указано иное. Класс User также содержит метод уведомления пользователя по электронной почте, который теперь включает условие ошибки на случай сбоя вызова API. Затем класс IpChanger вызывает класс User() каждый раз, когда он создается, а также выполняет все различные проверки и запросы, поэтому вы просто инициализируете класс IpChanger() и всё; он работает! Я также добавил несколько различных вариантов для уведомлений по электронной почте, более конкретную обработку ошибок/логирование, некоторые аргументы/параметры командной строки для управления профилем пользователя, а также смог избавиться от неуклюжей обработки файла ip.txt, сохранив всё в одном пользовательском экземпляре.


Готовый, практически уникальный (!) результат можно увидеть ниже во всей его полноте, а также его можно форкнуть/клонировать с моего GitHub (включая README.md с инструкциями по установке). Я также выпустил его как пакет Python на pypi.org, который вы можете просмотреть здесь или установить обычным способом с помощью: pip install domains-api


Любые вопросы, отзывы или предложения пишите!




Какие ещё методы стабильной работы веб-сервера без статического адреса вы знаете? И как можно доработать это решение?


Полный скрипт (без file_handlers.py):
import osimport sysimport getoptimport base64import smtplibfrom email.message import EmailMessagefrom getpass import getpassfrom itertools import cyclefrom requests import get, postfrom requests.exceptions import ConnectionError as ReqConErrorfrom domains_api.file_handlers import FileHandlersfh = FileHandlers()def get_ip_only():    """Gets current external IP from ipify.org"""    current_ip = get('https://api.ipify.org').text    return current_ipclass User:    BASE_URL = '@domains.google.com/nic/update?hostname='    def __init__(self):        """Create user instance and save it for future changes to API and for email notifications."""        self.domain, self.dns_username, self.dns_password, self.req_url = self.set_credentials()        self.notifications, self.gmail_address, self.gmail_password = self.set_email()        self.outbox = []    def set_credentials(self):        """Set/return attributes for Google Domains credentials"""        self.domain = input("What's your domain? (example.com / subdomain.example.com): ")        self.dns_username = input("What's your autogenerated dns username?: ")        self.dns_password = getpass("What's your autogenerated dns password?: ")        self.req_url = f'https://{self.dns_username}:{self.dns_password}{self.BASE_URL}{self.domain}'        return self.domain, self.dns_username, self.dns_password, self.req_url    def set_email(self):        """Set/return attributes for Gmail credentials if user enables notifications"""        self.notifications = input("Enable email notifications? [Y]all(default); [e]errors only; [n]no: ").lower()        if self.notifications != 'n':            self.gmail_address = input("What's your email address?: ")            self.gmail_password = base64.b64encode(getpass("What's your email password?: ").encode("utf-8"))            if self.notifications != 'e':                self.notifications = 'Y'            return self.notifications, self.gmail_address, self.gmail_password        else:            return 'n', None, None    def send_notification(self, ip=None, msg_type='success', error=None, outbox_msg=None):        """Notify user via email if IP change is made successfully or if API call fails."""        if self.notifications != 'n':            msg = EmailMessage()            msg['From'] = self.gmail_address            msg['To'] = self.gmail_address            if ip and msg_type == 'success' and self.notifications not in {'n', 'e'}:                msg.set_content(f'IP for {self.domain} has changed! New IP: {ip}')                msg['Subject'] = 'IP CHANGED!'            elif msg_type == 'error' and self.notifications != 'n':                msg.set_content(f"Error with {self.domain}'s IPChanger: ({error})!")                msg['Subject'] = 'IPCHANGER ERROR!'            elif outbox_msg:                msg = outbox_msg            try:                server = smtplib.SMTP_SSL('smtp.gmail.com', 465)                server.ehlo()                server.login(self.gmail_address, base64.b64decode(self.gmail_password).decode('utf-8'))                server.send_message(msg)                server.close()                return True            except Exception as e:                log_msg = 'Email notification not sent: %s' % e                fh.log(log_msg, 'warning')                self.outbox.append(msg)                fh.save_user(self)                sys.exit(1)class IPChanger:    ARG_STRING = 'cdehinu:'    ARG_LIST = ['credentials',                'delete_user',                'email',                'help',                'ip',                'notifications',                'user_load=']    def __init__(self, argv=None):        """Check for command line arguments, load/create User instance,        check previous IP address against current external IP, and change via the API if different."""        # Load old user, or create new one:        if os.path.isfile(fh.user_file):            self.user = fh.load_user(fh.user_file)            fh.log('User loaded from pickle', 'debug')        else:            self.user = User()            fh.log('New user created.\n(See `python -m domains_api --help` for help changing/removing the user)', 'info')        self.current_ip = self.get_set_ip()        # Parse command line options:        try:            opts, _args = getopt.getopt(argv, self.ARG_STRING, self.ARG_LIST)        except getopt.GetoptError:            print('''Usage:python/python3 -m domains_api --help''')            sys.exit(2)        if opts:            self.arg_parse(opts)        # Check IPs:        try:            if self.user.previous_ip == self.current_ip:                log_msg = 'Current IP: %s (no change)' % self.user.previous_ip            else:                self.user.previous_ip = self.current_ip                fh.save_user(self.user)                self.domains_api_call()                log_msg = 'Newly recorded IP: %s' % self.user.previous_ip            fh.log(log_msg, 'info')        except AttributeError:            setattr(self.user, 'previous_ip', self.current_ip)            fh.save_user(self.user)            self.domains_api_call()        finally:            if fh.op_sys == 'pos' and os.geteuid() == 0:                fh.set_permissions(fh.user_file)            # Send outbox emails:            if self.user.outbox:                for i in range(len(self.user.outbox)):                    self.user.send_notification(outbox_msg=self.user.outbox.pop(i))                    fh.log('Outbox message sent', 'info')                fh.save_user(self.user)            fh.clear_logs()    def get_set_ip(self):        """Gets current external IP from api.ipify.org and sets self.current_ip"""        try:            return get_ip_only()        except (ReqConError, ConnectionError) as e:            fh.log('Connection Error. Could not reach api.ipify.org', 'warning')            self.user.send_notification(msg_type='error', error=e)    def domains_api_call(self):        """Attempt to change the Dynamic DNS rules via the Google Domains API and handle response codes"""        try:            req = post(f'{self.user.req_url}&myip={self.current_ip}')            response = req.text            log_msg = 'Google Domains API response: %s' % response            fh.log(log_msg, 'info')            # Successful request:            _response = response.split(' ')            if 'good' in _response or 'nochg' in _response:                self.user.send_notification(self.current_ip)            # Unsuccessful requests:            elif response in {'nohost', 'notfqdn'}:                msg = "The hostname does not exist, is not a fully qualified domain" \                      " or does not have Dynamic DNS enabled. The script will not be " \                      "able to run until you fix this. See https://support.google.com/domains/answer/6147083?hl=en-CA" \                      " for API documentation"                fh.log(msg, 'warning')                if input("Recreate the API profile? (Y/n):").lower() != 'n':                    self.user.set_credentials()                    self.domains_api_call()                else:                    self.user.send_notification(self.current_ip, 'error', msg)            else:                fh.log("Could not authenticate with these credentials", 'warning')                if input("Recreate the API profile? (Y/n):").lower() != 'n':                    self.user.set_credentials()                    self.domains_api_call()                else:                    fh.delete_user()                    fh.log('API authentication failed, user profile deleted', 'warning')                    sys.exit(1)        # Local connection related errors        except (ConnectionError, ReqConError) as e:            log_msg = 'Connection Error: %s' % e            fh.log(log_msg, 'warning')            self.user.send_notification(msg_type='error', error=e)    def arg_parse(self, opts):        """Parses command line options: e.g. "python -m domains_api --help" """        for opt, arg in opts:            if opt in {'-i', '--ip'}:                print('''            [Domains API] Current external IP: %s                ''' % get_ip_only())            elif opt in {'-h', '--help'}:                print(                    """        domains-api help manual (command line options):

    You will need your autogenerated Dynamic DNS keys from    https://domains.google.com/registrar/example.com/dns    to create a user profile.    python -m domains_api                    || -run the script normally without arguments    python -m domains_api -h --help          || -show this help manual    python -m domains_api -i --ip            || -show current external IP address    python -m domains_api -c --credentials   || -change API credentials    python -m domains_api -e --email         || -email set up wizard > use to delete email credentials (choose 'n')    python -m domains_api -n --notifications || -toggle email notification settings > will not delete email address    python -m domains_api -u user.file       || (or "--user_load path/to/user.file") -load user from pickle file    python -m domains_api -d --delete_user   || -delete current user profile                                             || User files are stored in "/var/www/domains_api/domains.user""""            )        elif opt in {'-c', '--credentials'}:            self.user.set_credentials(update=True)            self.domains_api_call()            fh.save_user(self.user)            fh.log('API credentials changed', 'info')        elif opt in {'-d', '--delete'}:            fh.delete_user()            fh.log('User deleted', 'info')            print('>>>Run the script without options to create a new user, or '                  '"python3 -m domains_api -u path/to/pickle" to load one from file')        elif opt in {'-e', '--email'}:            self.user.set_email()            fh.save_user(self.user)            fh.log('Notification settings changed', 'info')        elif opt in {'-n', '--notifications'}:            n_options = {'Y': '[all changes]', 'e': '[errors only]', 'n': '[none]'}            options_iter = cycle(n_options.keys())            for option in options_iter:                if self.user.notifications == option:                    break            self.user.notifications = next(options_iter)            fh.save_user(self.user)            log_msg = 'Notification settings changed to %s' % n_options[self.user.notifications]            fh.log(log_msg, 'info')            if self.user.notifications in {'Y', 'e'} and not self.user.gmail_address:                fh.log('No email user set, running email set up wizard...', 'info')                self.user.set_email()                fh.save_user(self.user)        elif opt in {'-u', '--user_load'}:            try:                self.user = fh.load_user(arg)                fh.save_user(self.user)                fh.log('User loaded', 'info')            except FileNotFoundError as e:                fh.log(e, 'warning')                sys.exit(2)        sys.exit()

if name == "main":
IPChanger(sys.argv[1:])


<!--</spoiler>-->
Подробнее..

Пишем Hello World на WebAssembly, шпаргалка по Linux-команде sed, а также 15 самых востребованных ИТ-сертификатов года

08.04.2021 18:23:51 | Автор: admin

И вновь мы приготовили для вас много инсайтов, мероприятий, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Узнать новое:

Скачать:

  • Шпаргалка по Linux-команде sed
    SED (Stream EDitor) это потоковый текстовый редактор, который построчно обрабатывает входной поток (файл).

  • Бесплатный Developer Sandbox for OpenShift
    Это ваш личный OpenShift в облаке, всего за пару минут и без какой бы то ни было инсталляции. Среда создана специально для разработчиков и включает в себя Helm-диаграммы, builder-образы Red Hat, инструменты сборки s2i, также CodeReady Workspaces, облачную IDE с веб-интерфейсом.

Почитать на досуге:

Мероприятия:

  • Виртуальный Red Hat Summit 2021, 27-28 апреля
    Бесплатная онлайн-конференция Red Hat Summit это отличный способ узнать последние новости ИТ-индустрии, задать свои вопросы техническим экспертам, услышать истории успеха непосредственно от заказчиков Red Hat и увидеть, как открытый код генерирует инновации в корпоративном секторе

Подробнее..

Гайд по git stash, разбиваем диск под Linux с GNU Parted, шпаргалка по SQLite и полезное руководство по графикам

22.04.2021 12:11:11 | Автор: admin

Новая порция инсайтов, мероприятий, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Узнать новое:

Скачать:

Почитать на досуге:

Мероприятия:

  • Виртуальный Red Hat Summit 2021, 27-28 апреля
    Бесплатная онлайн-конференция Red Hat Summit это отличный способ узнать последние новости ИТ-индустрии, задать свои вопросы техническим экспертам, услышать истории успеха непосредственно от заказчиков Red Hat и увидеть, как открытый код генерирует инновации в корпоративном секторе.

  • Cook Your Own Cloud: OpenShift + OpenStack + немного перца! 30 апреля
    Миграция на облачную платформу тем актуальнее, чем сложнее инфраструктура и выше число изменений. Как насчет того, чтобы автоматизировать рутинные задачи и сконцентрироваться на бизнес-процессах? Мы в Red Hat знаем, как создать облачное решение для IaaS и PaaS- платформ. И мы хотим поделиться своим опытом! На вебинаре архитектор Дмитрий Алехин расскажет про связку Red Hat Openstack Platform и Red Hat Openshift Container Platform, которые позволяют осуществить стратегию открытого гибридного облака. Регистрируйтесь и приходите!

Подробнее..

Сравнение криптографической производительности популярных ARM-процессоров для DYI и Edge-устройств, плюс Xeon E-2224

13.04.2021 10:07:06 | Автор: admin

В одном из наших проектов используется Edge-модуль, работающий на широком наборе оборудования c процессором ARM, типа Raspberry Pi. Данное устройство используется для того, чтобы пересылать медиа-данные посредством зашифрованного канала на сервер.

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

На тесте были:

  • Nvidia Jetson Nano - 4 core ARM A57 @ 1.43 GHz

  • Raspberry Pi 4, Model B - Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz

  • Raspberry Pi 3, Model B+ - Broadcom BCM2837B0, Cortex-A53 (ARMv8) 64-bit SoC @ 1.4GHz

  • Orange Pi Zero LTS - AllWinner H2 Quad-coreCortex-A7

и, чтобы им не скучно было, к тестированию подключил Intel Xeon E-2224, дабы возникло понимание в сравнительных возможностях ARM vs Intel.

На Jetson Nano установлено активное охлаждение с помощью вентилятора, на других платформах просто радиатор.

Все процессоры 4х-ядерные, SMT нигде нет. Сравнение производилось в рамках однопоточного теста с помощью стандартных возможностей OpenSSL (OpenSSL 1.1.1 11 Sep 2018).

Тест алгоритмов семейства SHA

openssl speed sha

Победителем теста среди ARM оказался Nvidia Jetson Nano, причем для sha-256/16KB он обогнал даже Xeon E-2224 - я повторно провел данный бенчмарк для Xeon E-2224, результат остался тем же.

Сравнительные данные в таблицах ниже ранжированы по месту в рейтинге производительности.

Nvidia Jetson Nano

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytessha1             73350.09k   200777.04k   416181.08k   573274.72k   645373.43k   653034.35ksha256           68908.76k   188685.90k   412290.48k   568202.87k   644962.46k   651681.85ksha512           19732.45k    78505.91k   122326.65k   175421.47k   201366.51k   202794.47k

Raspberry Pi 4

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytessha1             40358.89k   103684.42k   199123.37k   258472.96k   283866.45k   285665.96ksha256           27360.34k    65673.69k   120294.66k   151455.74k   164413.44k   165281.79ksha512           10255.33k    40882.35k    60587.95k    83416.41k    94066.01k    94874.28k

Raspberry Pi 3

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytessha1             19338.74k    52534.42k   105558.02k   140777.13k   156311.55k   157537.62ksha256           12821.65k    31949.78k    59951.62k    77581.99k    84858.20k    85415.25ksha512            7444.83k    29450.71k    47035.65k    66549.76k    75893.42k    76660.74k

Orange Pi Zero

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytessha1              9313.16k    23691.09k    45304.83k    58655.40k    64249.86k    64684.03ksha256            6051.17k    14204.69k    25856.60k    32542.38k    35198.29k    35400.36ksha512            3319.25k    13320.17k    19863.55k    27670.87k    31290.71k    31582.89k

Вне конкурса: Intel Xeon E-2224

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytessha1            171568.52k   420538.79k   843694.68k  1124105.90k  1259615.57k  1257401.00ksha256          101953.18k   231621.03k   427492.44k   534554.28k   575944.02k   582303.74ksha512           69861.21k   279030.78k   493514.41k   732609.88k   855792.76k   864578.22k

Тест алгоритмов семейства AES

openssl speed aes

Победителем теста среди ARM оказался Raspberry Pi 4, отставание от Xeon E-2224 более чем в 2 раза, следом расположился Nvidia Jetson Nano.

Raspberry Pi 4

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytesaes-128 cbc      74232.10k    80724.61k    84387.02k    85057.54k    85314.22k    85196.80kaes-192 cbc      66069.32k    70589.59k    72967.00k    73584.64k    73766.23k    73667.93kaes-256 cbc      58926.68k    62458.30k    64351.40k    64619.16k    64976.21k    64913.41k

Nvidia Jetson Nano

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytesaes-128 cbc      64590.62k    68711.06k    71231.36k    71509.33k    71963.57k    71401.47kaes-192 cbc      55971.60k    59210.12k    60951.72k    61140.65k    61300.74k    61289.31kaes-256 cbc      49413.88k    51999.08k    53115.39k    53581.57k    53518.34k    53513.76k

Raspberry Pi 3

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytesaes-128 cbc      37401.48k    45102.98k    47455.83k    48064.51k    48130.73k    48119.81kaes-192 cbc      33444.87k    38794.88k    40544.51k    40930.30k    41047.38k    41036.46kaes-256 cbc      30299.70k    34635.65k    36142.58k    36331.52k    36424.36k    36427.09k

Orange Pi Zero

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytesaes-128 cbc      22108.15k    24956.95k    25791.06k    26007.89k    26069.67k    26072.41kaes-192 cbc      19264.22k    21327.66k    21971.29k    22138.88k    22186.67k    22189.40kaes-256 cbc      17211.09k    18887.40k    19399.34k    19532.12k    19570.69k    19573.42k

Вне конкурса: Intel Xeon E-2224

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytesaes-128 cbc     173352.23k   196197.33k   201970.86k   203862.70k   204595.20k   203975.34kaes-192 cbc     149237.38k   164843.65k   167562.58k   168944.98k   169667.24k   169056.58kaes-256 cbc     130430.20k   141325.91k   143808.17k   144901.46k   145601.88k   145424.38k

Выводы

Делать выводы о том, насколько хорошо, согласно результатам бенчмарка OpenSSL, будет работать тот или иной CPU на реальной невычислительной задаче, конечно, нельзя. Однако, с точки зрения производительности в рамках задач, завязанных на TLS, можно сказать, что чипы, использованные в Raspberry Pi 4 и Jetson Nano, обладая низкой стоимостью, позволяют обеспечить достойную производительность: в расчете на 1 рубль, вероятно, непринужденно побеждают Xeon E-2224.

Надеюсь, что было полезно.

Подробнее..

Перевод Делаем своими руками KVM Over IP при помощи Raspberry Pi

09.03.2021 00:06:18 | Автор: admin

На Хабре вряд ли стоит рассказывать о программах удаленного доступа к ПК, вроде TeamViewer. Но все это работает лишь в среде операционной системы. А вот доступа к BIOS, возможности установки, переустановки и прочих операций с операционной системой нет. Для всего этого есть иные решения. Одно из самых доступных KVM Over IP.

Конечно, если покупать брендовую систему, то получится дорого. Но есть иное решение создание собственной системы на основе малинки. Это решение предложил разработчик Максим Деваев (Maxim Devaev). Он собирается начать продавать эту систему по $130. Но собрать все это можно и самостоятельно главное запастись собственными компонентами. Под катом описание того, как это сделать.


Прототип Pi-KVM без корпуса

Необходимые компоненты


  • Raspberry Pi 4 или Raspberry Pi Zero
  • Карточка памяти microSD с объемом памяти 16 ГБ.
  • Переходник HDMI-to-CSI.
  • Сплиттер USB female to dual male Type-A.
  • Кабель
  • USB C to Type-A
  • Источник питания 5В, 3А с портом USB Type-A.

Настройка SD-карты для Raspberry Pi KVM Over IP


Все, что нужно для настройки можно загрузить из сети в виде образа диска и записать потом этот образ на карточку. Сделать это можно при помощи Raspberry Pi или balenaEtcher (есть и другие варианты).

  1. Загрузить образ диска Pi-KVM. Вот ссылка. На исходном ресурсе есть несколько версий образов для разных версий Pi. Кроме того, выбирать нужно исходя из того, что вы используете HDMI-to-CSI или HDMI-to-USB.

  2. Распаковываем образ.
  3. Запускаем Raspberry Pi Imager.
  4. Теперь нужно выбрать опцию Choose OS Use Custom и, соответственно, использовать образ. Еще требуется определить SD карту при помощи не самой сложной опции Choose SD Card.
  5. Write прошиваем.


Собираем и настраиваем Raspberry Pi for KVM Over IP


Теперь можно приступить к сборке железа. Здесь тоже все просто.


  1. Соединяем CSI шлейф нашего HDMI-to-CSI-2 бриджа с портом камеры малинки. Чтобы убедиться, что все правильно подключено, лучше посмотреть на фото. Если вы используете HDMI-to-USB, то просто подключите коннектор к разъему USB. Ну или в случае Pi Zero подключаем microUSB к USB Type-A.
  2. Нужно заизолировать 5В пин на коннекторе USB Type-A сплиттера. Проще всего сделать это при помощи тонкого изолирующего материала. Можно просто убрать и контакты, которые ведут к этим пинам, но все же безопаснее и проще просто заизолировать коннектор. Если этого не сделать, то USB порт компьютера может быть поврежден.
  3. Подключаем кабель USB C-to-A к Type-A

  4. Подключаем кабель USB-C к порту USB-C малинки.
  5. Подключаем коннектор Type-A к питанию.

  6. Подключаем USB Type-A коннектор и HDMI ПК, которым нужно управлять.

  7. Наконец, вставляем карту памяти и включаем малинку.

Настройка ПО Pi-KVM


Теперь мы можем начать работу с Pi-KVM. Первая загрузка будет довольно продолжительной, так что придется подождать. Но в итоге все запустится, после чего можно начать настройку.
1. Определяем IP малинки. Собственно, вряд ли на Хабре нужно рассказывать, как это сделать, но на всякий случай сделать это можно при помощи роутера, в панели которого отображаются IP всех подключенных девайсов.

Кроме того, можно запустить командную строку Windows и выполнить команду arp -a. После этого вы увидите все адреса устройств, подключенных к локальной сети. Любой девайс, адрес которого начинается с b8:27:eb: или dc:a6:32: и является Raspberry Pi.


2. Вводим IP в браузере клиентского ПК, после чего открывается страничка входа.

3. Дефолтные значения входа admin и admin.


4. Кликаем по иконке KVM.


Теперь должен загрузится экран, как показано на скриншоте ниже. Он предоставляет доступ к удаленному ПК при помощи меню. Можно получить и больше меню, чем указано на картинке, вот ссылка, где рассказывается, как это сделать.


Чем больше объем вашей SD-карты, тем больше образов ISO можно загрузить и использовать в дальнейшем, расширяя функциональность системы.


Если все правильно подключено и настроено, инструменты управления уже должны быть доступны.


Для расширения функциональности системы, например, использования дополнительных дисплеев, можно использовать подключение HDMI 4.


А вот прототип нашей системы без корпуса и 4-х портовый KVM switch.

Обновление Pi-KVM до последней версии


Pi-KVM часто получает обновления, поэтому постарайтесь держать актуальную версию. Для обновления нужно:

  1. Выбираем иконку консоли в главном меню Pi-KVM, после чего запускается консоль.
  2. Вводим su и получаем суперпользователя. Пароль root
  3. Вводим rw и открываем систему для записи.

  4. Обновляемся при последовательном вводе команд pacman -Syu и Y.



Удаленное управление


Лучше всего использовать такой инструмент, как Tailscale. Он удобен, бесплатен для обычных пользователей, плюс с его помощью можно без труда развернуть небольшую VPN-сеть.

  1. Заводим учетку в Tailscale, выбирая бесплатный тариф Solo Plan для частного использования.
  2. Нажимаем на иконку консоли в главном меню Pi-KVM

  3. Становимся супер-пользователем при помощи su и пароля root
  4. Открываем систему для записи.

  5. Вводим команду pacman -S tailscale-pikvm для запуска VPN-сервиса на нашей системе.
  6. Вводим reboot для перезагрузки.
  7. После этого нужно снова получить доступ к системе, повторяем шаги 1-4.
  8. Вводим systemctl enable --now tailscaled для активации сервиса.
  9. Инициализируем начало работы, вводя tailscale up.

  10. Авторизуем все.

  11. Если все прошло хорошо, то вы увидите сообщение Success в консоли.
  12. Заходим вот по этой ссылке для того, чтобы увидеть IP, назначенный нашему VPN.

Сторона клиента


Теперь настроим tailscale на клиенте. Tailscale поддерживает большинство операционных систем, включая windows, mac и linux.

  1. Загружаем версию для своей ОС по этой ссылке.
  2. Переходим по этой ссылке для отображения IP VPN.

  3. Вводим IP в строку браузера, что позволяет подключиться к PI-KVM.


В целом, это и все. Благодаря этой инструкции получаем недорогой, быстрый и простой в использовании KVM over IP сервис. Если нужны дополнительные подробности, то они доступны по этой ссылке.

Подробнее..

Настройка Plex, Samba, Transmission на Raspberry pi 4 с помощью Ansible

24.03.2021 10:15:26 | Автор: admin

Предисловие

Не так давно я начал пользоваться Plex media server для просмотра видео на ТВ через Amazon fire stick. Plex server был настроен на десктопе, а файлы с видео были подключены через внешний USB диск и такая связка меня впринципе устраивала. Однако при выключенном ПК доступа к контенту нет и каждый раз включать ПК только для того что бы посмотреть фильм или послушать музыку уже стало напрягать. Поэтому решил настроить plex на raspberry и подключить к нему внешний USB с уже имеющимся контентом. А уже в процессе понял, что еще бы не плохо иметь доступ к файлам и качалку для торентов и заодно упростить процесс настройки с помощью автоматизации на Ansible. Playbook выложил на GitHub.

Что портебуется (железо / софт)

  • Window и Ubuntu Desktop. В принципе можно только что то одно, но мне привычнее какие то вещи делать на Window, а какие то на Ubuntu. (Ubuntu установлена через VirtualBox на Windows). Все тоже самое думаю удастся без проблем и на Mac.

  • Raspberry Pi Imager под Windows. Можно скачать с официального сайта.

  • Образ Raspberry Pi OS Lite. Тоже с официального сайта. Быстрее скачать через торрент, чем по прямой ссылке.

  • Raspberry pi 3/4. Изначально проводил опыты на третьей версии, но потом закупил четвертую.

  • SD карта 8Gb или больше. (USB кардридер)

  • Ansible под Ubuntu описание и установка здесь.

  • USB диск. Желательно с USB 3.0 если собираете на pi 4.

  • Блок питания на 3A что бы хватало мощности для подключенного USB диска.

  • Возможно потребуется подключение дисплея и клавиатуры. (настройка статического IP в первый раз)

  • Playbook для Ansible с GitHub.

  • Ansible. Установка описана здесь.

  • Git.

Подготовка raspberry pi

Для начала зальем скаченный образ с ОС на SD карту с помощью Pi Imager. В пункте Choose image выбираем Use custom и выбираем тот образ что скачали. Можно выбрать тот же образ в самой программе, но тогда он будет скачивать его из интернета, у меня процесс закачки занимал очень длительное время, поэтому снача попробовал скачать по прямой ссылке с сайта, но это тоже оказалось медленно и в итоге скачал через торрент. Указываем нашу SD карту и жмем write.

Дальше отформатируем внешний USB накопитель в NTFS и присвоим ему понятный лейбел (например usb_750g), который будем использовать в дальнейшем для монтирования диска на raspberry. У меня внеший USB накопитель был уже с данными и отформатирован в NTFS поэтому просто списал название лейбла. Можно так же отформатировать в диск в exFAT, но в таком случае на raspberry придется ставить дополнительный пакет, поэтому в данной статье рассмотрю только случай с NTFS. Возможно в дальнейшем добавлю и для других.

На данном этапе работа с Windows заканчивается и дальнейшие действия будут производиться на Ubuntu.

Подключаем нашу SD карту к компьютеру с Ubuntu или переподключаем устройство на гостевую систему в VirtualBox. Должны появиться два подматированных диска boot и rootfs. Через терминал зайдем сначала в boot cd /media/ваш_пользователь/boot/. и положим туда файл ssh который при первом запуске даст понять raspberry что нужно включить ssh соединения.

Для подключения к raspberry я буду пользоваться ssh ключем, он так же понадобится для плейбука на Ansible, поэтому создадим его командой cd ~/.ssh && ssh-gen в папке для ключей (если ее нет то создайте ее). Дайте понятное имя ключу напимер raspberry, на вопросе о секретной фразе жмем enter. На выходе получим два ключа raspberry и raspberry.pub приватный и публичный. С помощью приватного будем подключаться, а публичный положим скопируем на сам raspberry. Для этого зайдем в папку rootfs cd /media/ваш_пользователь/rootfs/ и создадим папку для ключа авторизации mkdir home/pi/.ssh и скопируме сам ключ cp ~/.ssh/raspberry.pub home/pi/.ssh/authorized_keys.

Вставляем SD карту в raspberry, подключем сетевой кабель, USB диск и питание. У меня в домашней сети IP адреса раздает роутер, если у вас такая же конфигурация и в интерфейсе роутера можно посмотреть какой IP адресс выдан устройству и его MAC адрес, то установть выдачу постоянного IP вашему raspberry по MAC адресу. MAC адресс можно посмотреть и на самом raspberry. Подключаем монитор с клавиатурой и запускаем команду cat /sys/class/net/eth0/address . Либо же выставить статический IP на самом raspberry воспользовавшись этой статьей с официального сайта.

Установка и настройка

Если на Ubuntu еще не установлен Ansible, то сделать это можно по ссылке выше. Клонируем репозиторий git clone https://github.com/notfoundsam/raspberry-plex-ansible.git и заходим в папку с плейбуками cd raspberry-plex-ansible.

Для начала установим статический IP адресс нашего raspberry в файле hosts.ini к которому будет обращаться Ansible для настройки. Можно указать и группу адресов если необходимо настроить сразу несколько устройств.

В файле group_vars/all.yml если вы не изменяли имя пользователя на raspberry, то ansible_user оставляем без изменений. Укажем путь к ssh ключу в переменной ansible_ssh_private_key_file. Если все делали по шагам как описано выше, то оставляем без изменений. Установим имя хоста в переменной host_name. В переменную usb_volume_label запишем имя лейбла подключенного USB диска. Монтирование диска будет производиться как раз по этому лейблу. Если предполагается использовать transmission для закачки торентов то установите в переменные transmission_username, transmission_password, transmission_white_list свои значения. Для transmission_white_list обязвтельно оставьте адрес 127.0.0.1.

Установка Plex и монтирование диска. Запустите плейбук plex.yml командой ansible-playbook plex.yml который установит необходимые пакеты, сам Plex изменит имя хоста и сделает перезагрузку. После завершения работы скрипта запустите другой плейбук ansible-playbook usb-volume.yml который подмонтирует наш USB диск и добавит автоматическое монтирование при старте. Зайдем на веб интерфейс плекса raspberry_ip:32400/web и пройдем шаги которые plex предлагает. На некоторых шагах бывало что plex выдавал ошибку что нет доступа, но после обновления страницы все отображалось или повторного перехода на raspberry_ip:32400/web все корректно отображалось. Я думаю это связано с тем, что при первом запуске plex сервер не успевает ответить клиенту из за большой нагрузки. Дальше в интерфейсе plex уже можно выбрать наш USB диск.

Установка Samba сервера. Заливать файлы на raspberry удобнее по сети, поэтому добавил плейбук который установит Samba сервер и расшарит USB диск в локальной сети. Для установки запускаем ansible-playbook samba.yml. Замечание, если ваш Windows хост принадлежит группе отличной от workgroup, то поправте на свою в файле /etc/samba/smb.conf на raspberry. Теперь можно зайти по IP и проверить доступ \\raspberry_ip в проводнике Windows.

Установка Transmission. Запустите плейбук который установит transmission демон и утилиту для работы с iptables, добавит папку downloads на USB диск для загрузок и сделает ее папкой по умолчанию для загружаемых торентов. Папка для временных файлов таже самая, но transmission будет добавлять .part к еще незавершенным файлам. Так же откроет порт 51413 для входящих подключений. Проверим доступ зайдя на raspberry_ip:9091/transmission, логин и пароль для входа те что прописаны в файле group_vars/all.yml. В настройках клиента на вкладке Network проверим что порт 51413 открыт, если написано closed, то нужно настроить перенаправление этого порта на вашем роутере.

Сравнение raspberry 3 с raspberry 4

Проводил проверку работы на raspberry pi 3B / 3B+/ 4B. У pi 3 сетевой интерфейс поддерживает только 100Mbs поэтому скопировать туда 100-200GB данных займет много времени. С 3B+ ситуация уже по лучше, потому что установлен сетевой интерфейс на 1Gbs. Plex сервер достаточно хорошо себя показал на нем, особенно если видео файлы в формате H.264, но на некоторых avi файлах сжатых MPEG4(XVID) кодеком, процессор еле-еле тянул, открывал видео долго, и порой не успевал отдавать видео и картинка останавливалась. Впринципе такие файлы можно заранее оптимизировать в плексе под TV и тогда эта проблема уйдет, но потребуется больше менста для перекодированных файлов.

После некоторого времени использования pi 3B+, все таки стал замечать что обновление библиотеки с несколькой сотней файлов занимае приличное время и редкие залипания, например ни как не может открыть фильм, решил заказать себе pi 4B. У pi 4B процессор уже по мощнее и это решило проблему с MPEG4 уже можно было смотреть файлы без сильных задержек и при перемотке не ждать по 10-15 секунд. USB 3.0 добавил быстроты работы с диском при обновлении библиотеки.

После прочтения этой статьи решил преобрести себе Samsung Evo+ вместо ScanDisk Ultra. И по ощущениям загрузка ОС стала быстрее.

Стоимость / Комплектущие

  • Raspberry pi 4B 4GB RAM ~ $62

  • SD карта Samsung Evo+ ~ $8

  • Металлический корпус с пассивным охлаждением ~ $17

  • USB 3.0 жесткий диск 750GB (покупал 4 года назад) ~ $50

  • Питание Anker PowerPort 6 (покупал 3 года назад) ~ $30

Если какие то комплектующие уже есть в наличии, то и список можно сократить. В моем случае получилось $87.

Выводы

За небольшую сумму удалось собрать медиа центр, который на данный момент удовлетворяет все мои потребности. При выходе из строя внешнего накопителя я согласен с полной или частичной потерей данных. Для снижения нагрузки на внешний диск медиа-сервера, собрал еще один комплект USB диск + Samba + Transmission на raspberry pi 3B, но передача данных по сети со скоростью 100Mbs начинает напрягать, планирую перенести на pi 3B+. Благодаря созданному скрипту на Ansible процесс настройки стал занимать гораздо меньше времени.
Плейбуки написаны по отдельности, что бы можно было использовать в различных комбинациях, например только для настройки Samba с подключением внешнего диска, для организации простого сетевого хранилища.

Надеюсь что данный материал поможет быстрее справиться с аналогичной задачей. Если есть предложения по улучшению, критика или ошибки пишите в коментариях.

Дальнейшие планы

Объем данных постоянно растет, поэтому планирую докупить стойку с USB хабом и несколькими отсеками для HDD дисков. В планах приобрести что то из этого Yottamaster Hard Drive с 4мя отсеками. Есть уже со встроенным RAID контроллером, но наверное возьму без него, если потребуется RAID, то настрою его на raspberry и только для двух дисков остальные оставлю как single. А старый 750GB диск переключу на закачку торрентов.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru