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

Реальное время

Linux в режиме реального времени

23.11.2020 14:22:47 | Автор: admin


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

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

Возможности ядра в реальном времени существует уже более десяти лет в экосистеме программ с открытым исходным кодом. Столько же времени доступна поддержка Red Hat Enterprise Linux (RHEL) для ядра реального времени. Тем не менее многие системные администраторы неверно истолковывают его основные концепции и фактическое рабочее поведение. В этой статье я опишу некоторые из его основных функций, отличия от стандартного ядра и шаги по установке.

Планировщик ЦП в реальном времени


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

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

  • Задержка прерывания относится к периоду времени от поступления прерывания в CPU до запуска процедуры обработки. Когда происходит событие, ОС должна сначала завершить выполняемую инструкцию и определить тип возникшего прерывания. Затем он должен сохранить состояние текущего процесса до обработки прерывания с помощью специальной процедуры, interrupt service routine (ISR).


    Рис. 1 Задержка прерывания.
  • Время, необходимое диспетчеру планирования для остановки одного процесса и запуска другого, называется задержкой диспетчеризации. Предоставление задач реального времени с немедленным доступом к процессору требует, чтобы ОС реального времени минимизировали также и эту задержку. Наиболее эффективным методом поддержания низкой задержки отправки является предоставление ядер с приоритетным прерыванием.


    Рис. 2 Задержка диспетчеризации.


Планировщик с учетом приоритетности процессов


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


Рис. 3 Классификация планировщиков.

Существует несколько алгоритмов для планировщика в реальном времени.

  • Rate-Monotonic Scheduling алгоритм со статическим приоритетом класса планирования. Статические приоритеты назначаются в соответствии с продолжительностью цикла задачи, вследствие чего более короткие циклы имеют более высокий приоритет исполнения. В худшем случае КПД загрузки центрального процессора ограничен следующей величиной.


    При числе процессов n, стремящемся к бесконечности ряд будет сходиться к ln2 0.693147.
  • Earliest-deadline-first (EDF) Scheduling динамически назначает приоритеты в соответствии с крайним сроком. Чем раньше крайний срок, тем выше приоритет и чем позже крайний срок, тем ниже приоритет. В отличие от RMS, планировщик EDF не требует, чтобы процессы были периодическими и постоянно запрашивали одно и то же количество процессорного времени на пакет. Единственное требование состоит в том, чтобы процесс объявлял свой крайний срок планировщику, когда он готов к запуску.


    Рис. 4 Планировщик EDF.

    На рисунке видим общий принцип работы планировщика. На точке 4 был замещён T1 и его место занял T2 так как его крайний срок наступал раньше, чем у T2. После отработки T3 планировщик вернулся к T1, который завершился на отметке 21.
  • POSIX real-time-scheduling. Стандарт POSIX.4 определяет три политики планирования. Каждый процесс имеет атрибут планирования, который может быть выставлен в одну из трех вариантов политики.

    • SCHED_FIFO политика упреждающего планирования с постоянным приоритетом, при которой процессы с одинаковым приоритетом обрабатываются в порядке первым пришел первым обслужен (FIFO). Данная политика иметь не менее 32 уровней приоритета.
    • SCHED_RR политика аналогична SCHED_FIFO, но использует метод временного среза (циклический перебор) для планирования процессов с одинаковыми приоритетами. Он также имеет 32 уровня приоритета.
    • SCHED_OTHER политика не определена и зависит от системы; может вести себя по-разному в разных реализация.


Установка и использование RHEL Real Time


Для начала следует подключить репозиторий Red Hat Enterprise Linux для Real Time, и установить группу пакетов RT.

[root@server ~]# subscription-manager repos --enable rhel-8-for-x86_64-rt-rpms[root@server ~]# yum groupinstall RT

В составе RT идут эти компоненты:

  • kernel-rt ядро с функционалом реального времени;
  • rt-setup установка окружения Red Hat Enterprise Linux Real Time;
  • rt-tests утилиты тестирования функций RT;
  • rt-eval для оценки возможности применять RT на данной системе;

После установки RT и перезагрузки нужно убедиться, что загружено ядро kernel-rt.

[root@server ~]# uname -aLinux rt-server.example.com 4.18.0-80.rt9.138.el8.x86_64 

Посмотрим на некоторые отличия kernel-rt от стандартного ядра.

  • При высокой нагрузке происходит проверка приоритета задачи (1-99).
  • Высокоприоритетным (99) задачам отдается предпочтение при доступе к ресурсам центрального процессора.
  • Не задействует политику Completely Fair Scheduling (CFS).
  • Использует политику SCHED_FIFO, либо же SCHED_RR.


Рис. 5 Сравнение kernet_rt со стандартным ядром.


На графике показан замер времени отклика из миллиона повторений для систем, использующих ядра RHEL Linux 7 и RHEL Real Time соответственно. Синие точки на этом графике представляют время отклика (в микросекундах) систем со стандартным ядром RHEL 7, а зеленые RHEL 7 Real Time. Из графика видно, что особенность kernel-rt в гораздо меньшей дисперсии и, соответственно, в большей предсказуемости времени отклика системы.

Настройка и тестирование


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

Утилита hwlatdetect из пакета rt-tests покажет задержки, вызванные аппаратным и микропрограммным обеспечением, путем опроса источника тактовых импульсов и поиска непонятных пропусков.

[root@server ~]#  hwlatdetect --duration=60shwlatdetect:  test duration 60 secondsdetector: tracerparameters:Latency threshold: 10usSample window:     1000000usSample width:      500000usNon-sampling period:  500000usOutput File:       NoneStarting testtest finishedMax Latency: Below thresholdSamples recorded: 0Samples exceeding threshold: 0

В данном примере parameters указывает на задержку и способ обнаружения. Порог задержки по умолчанию был выставлен на 10 микросекунд (10 s).

RT имеет также утилиту rteval для тестирования производительности системы в реальном времени под нагрузкой. Программа создаёт большую нагрузку на систему, используя планировщик SCHED_OTHER, а затем измеряет отклик в реальном времени на каждом из активных CPU. Цель в том, чтобы постоянно выполнялись различные задачи, такие как выделение / освобождение памяти, дисковый I/O, вычисления, копирование памяти и другие.

Каждый поток измерений берет временную метку, бездействует в течение некоторого интервала, а затем принимает другую временную метку после пробуждения. Задержка по результатам измерения равна t1 - (t0 + i), где

  • t1 фактическое время измерения;
  • t0 теоретическое время пробуждения первой временной метки;
  • i интервал ожидания.

Отчет утилиты rteval выглядит так.

System:Statistics:Samples:           1440463955Mean:              4.40624790712usMedian:            0.0usMode:              4usRange:             54usMin:               2usMax:               56usMean Absolute Dev: 1.0776661507usStd.dev:           1.81821060672usCPU core 0       Priority: 95Statistics:Samples:           36011847Mean:              5.46434910711usMedian:            4usMode:              4usRange:             38usMin:               2usMax:               40usMean Absolute Dev: 2.13785341159usStd.dev:           3.50155558554us

Использованные материалы





Подробнее..

Из песочницы OBS Studio Lua Скриптинг

25.09.2020 18:15:34 | Автор: admin

Всем привет, в этом руководстве рассмотрим создание скриптов для OBS на языке Lua.


Скриптинг в OBS доступен начиная с версии 21, на данный момент новейшая 26.0.0-rc3 версия доступна для тестирования.Обновление включает в себя виртуальную веб камеру (пока что только на Windows), улучшенный UI, возможность скриншота любого источника( КДПВ была сделана с помощью этой функции).


image


Описание глобальных функций, API, настроек


Добавить скрипт можно через меню -> Инструменты -> Скрипты -> значок "плюс".
Скрипты могут быть добавлены, перезагружены, удалены в режиме реального времени.


Сходства и различия c С-API


Сходства: почти полный доступ к API, СБОЙ или УТЕЧКА ПАМЯТИ с неправильно написанным скриптом.


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


У каждого скрипта своё пространство имён, убедиться в этом можно открыв текущую коллекцию сцен "~/obs-studio/basic/scenes".


Настройки settings представляют собой JSON строку, они могут быть созданы/загружены/сохранены с помощью JSON строк или файлов.


Описание функций:


  • obslua модуль для доступа к функциям OBS
  • script_description() описание скрипта, поддерживает примитивный HTML
  • script_properties() пользовательский интерфейс
  • script_defaults(settings) устанавливает настройки по умолчанию
  • script_update(settings) вызывается каждый раз когда пользователь изменил настройки через пользовательский интерфейс
  • script_load(settings) загружает настройки при первом запуске
  • script_unload() вызывается при закрытии скрипта
  • script_save(settings) используется в основном для сохранения горячих клавиш, настройки c пользовательского интерфейса сохраняются автоматически
  • script_tick(seconds) вызывается каждый кадр, аргумент seconds получает значение потраченных секунд с предыдущего кадра
  • script_path() возвращает абсолютный путь к папке скрипта
  • timer_add(callback,milliseconds) вызов функции периодично
  • timer_remove(callback) удаление функции с таймера, также есть вариант использовать remove_current_callback() внутри функции которая вызывается периодично

Пример скрипта


Скрипт: Движение по линии с использованием кнопок и таймера.


local obs = obslualocal selected_sourcepos = obs.vec2()switch = falsecounter = 0

Короткая запись модуля, local var инициализация значения как nil, pos структура предоставляемая OBS для перемещения источников на сцене.


function script_properties()  local props = obs.obs_properties_create()  obs.obs_properties_add_button(props, "button1", "Вкл/Выкл",on_off)  obs.obs_properties_add_button(props, "button2", "Добавить источник",add_source)  obs.obs_properties_add_button(props, "button3", "Подвинуть источник на +10,0",move_button)  local p = obs.obs_properties_add_list(props, "selected_source", "Выберите источник", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)  local sources = obs.obs_enum_sources()  if sources ~= nil then    for _, source in ipairs(sources) do      source_id = obs.obs_source_get_unversioned_id(source)      if source_id == "color_source" then        local name = obs.obs_source_get_name(source)        obs.obs_property_list_add_string(p, name, name)      end    end  end  obs.source_list_release(sources)  return propsend

Добавляем пользовательский интерфейс. obs.obs_properties_add_button(props, "имя", "Описание",функция), local p = obs.obs_properties_add_list выпадающие меню с выбором источника, source_id = obs.obs_source_get_unversioned_id(source) получение имени источника при этом игнорируя его версию, obs.source_list_release(sources) освобождение памяти


function script_update(settings)  selected_source = obs.obs_data_get_string(settings,"selected_source")end

Обновление selected_source каждый раз когда настройки (выпадающее меню в этом случае) изменены.


function add_source()  current_scene = obs.obs_frontend_get_current_scene()  scene = obs.obs_scene_from_source(current_scene)  settings = obs.obs_data_create()  counter = counter + 1  green = 0xff00ff00  hotkey_data = nil  obs.obs_data_set_int(settings, "width",200)  obs.obs_data_set_int(settings, "height",200)  obs.obs_data_set_int(settings, "color",green)  source = obs.obs_source_create("color_source", "ист#" .. counter, settings, hotkey_data)  obs.obs_scene_add(scene, source)  obs.obs_scene_release(scene)  obs.obs_data_release(settings)  obs.obs_source_release(source)end

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


function move_source_on_scene()  current_scene = obs.obs_frontend_get_current_scene()  scene = obs.obs_scene_from_source(current_scene)  scene_item = obs.obs_scene_find_source(scene, selected_source)  if scene_item then    dx, dy = 10, 0    obs.obs_sceneitem_get_pos( scene_item, pos) -- обновить позицию если источник был перемещён мышкой    pos.x = pos.x + dx    pos.y = pos.y + dy    obs.obs_sceneitem_set_pos(scene_item, pos)   end  obs.obs_scene_release(scene)end

Функция перемещения источника в рамках сцены.


function move_button(props,p)  move_source_on_scene()end

Кнопка перемещения источника и 2 необходимых аргумента.


function on_off()  if switch then     obs.timer_add(move_source_on_scene,50)  else    obs.timer_remove(move_source_on_scene)  end  switch = not switchend

Кнопка переключатель и таймер периодического запуска функции в миллисекундах.
Гифка


Исходный код
local obs = obslualocal selected_sourcepos = obs.vec2()switch = falsecounter = 0function on_off()  if switch then     obs.timer_add(move_source_on_scene,50)  else    obs.timer_remove(move_source_on_scene)  end  switch = not switchendfunction add_source()  current_scene = obs.obs_frontend_get_current_scene()  scene = obs.obs_scene_from_source(current_scene)  settings = obs.obs_data_create()  counter = counter + 1  green = 0xff00ff00  hotkey_data = nil  obs.obs_data_set_int(settings, "width",200)  obs.obs_data_set_int(settings, "height",200)  obs.obs_data_set_int(settings, "color",green)  source = obs.obs_source_create("color_source", "ист#" .. counter, settings, hotkey_data)  obs.obs_scene_add(scene, source)  obs.obs_scene_release(scene)  obs.obs_data_release(settings)  obs.obs_source_release(source)endfunction move_button(props,p)  move_source_on_scene()endfunction move_source_on_scene()  current_scene = obs.obs_frontend_get_current_scene()  scene = obs.obs_scene_from_source(current_scene)  scene_item = obs.obs_scene_find_source(scene, selected_source)  if scene_item then    dx, dy = 10, 0    obs.obs_sceneitem_get_pos( scene_item, pos) -- обновить позицию если источник был перемещён мышкой    pos.x = pos.x + dx    pos.y = pos.y + dy    obs.obs_sceneitem_set_pos(scene_item, pos)   end  obs.obs_scene_release(scene)endfunction script_properties()  local props = obs.obs_properties_create()  obs.obs_properties_add_button(props, "button1", "Вкл/Выкл",on_off)  obs.obs_properties_add_button(props, "button2", "Добавить источник",add_source)  obs.obs_properties_add_button(props, "button3", "Cдвинуть источник на +10,0",move_button)  local p = obs.obs_properties_add_list(props, "selected_source", "Выберите источник", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)  local sources = obs.obs_enum_sources()  if sources ~= nil then    for _, source in ipairs(sources) do      source_id = obs.obs_source_get_unversioned_id(source)      if source_id == "color_source" then        local name = obs.obs_source_get_name(source)        obs.obs_property_list_add_string(p, name, name)      end    end  end  obs.source_list_release(sources)  return propsendfunction script_update(settings)  selected_source = obs.obs_data_get_string(settings,"selected_source")end

Пример горячих клавиш


Скрипт: Создание постоянных и изменяющихся горячих клавиш.


Создание изменяющихся горячих клавиш, в том смысле что их можно поменять в настройках OBS.


hotkeys = {  htk_stop = "Стоп",  htk_start = "Старт",}hk = {}function hotkey_mapping(hotkey)  if hotkey == "htk_stop" then    print('Стоп')  elseif hotkey == "htk_start" then    print('Старт')  endend

Словарь с клавишами и функция типа "switch"


function script_load(settings)  for k, v in pairs(hotkeys) do     hk[k] = obs.obs_hotkey_register_frontend(k, v, function(pressed)      if pressed then         hotkey_mapping(k)      end     end)    a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(hk[k], a)    obs.obs_data_array_release(a)  end  ...function script_save(settings)  for k, v in pairs(hotkeys) do    a = obs.obs_hotkey_save(hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endend

Сохранение/загрузка изменяющихся горячих клавиш.


function htk_1_cb(pressed)   if pressed then    print('1')  endendfunction htk_2_cb(pressed)   if pressed then    print('2 активно')  else    print('2 не активно')  endendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ],'key_2 = '"htk_2": [ { "key": "OBS_KEY_2" } ]}'json_s = key_1 .. key_2default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},  {id='htk_2',des='Кнопка 2 ',callback=htk_2_cb},}

Создание постоянных клавиш, их можно поменять в настройках, но при перезапуске OBS они примут значения по умолчанию. В данном случае кнопку 1 и 2.


function script_load(settings)  ...  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)end

Гифка


Исходный код
local obs = obsluahotkeys = {  htk_stop = "Стоп",  htk_start = "Старт",}hk = {}function hotkey_mapping(hotkey)  if hotkey == "htk_stop" then    print('Стоп')  elseif hotkey == "htk_start" then    print('Старт')  endendfunction htk_1_cb(pressed)   if pressed then    print('1')  endendfunction htk_2_cb(pressed)   if pressed then    print('2 активно')  else    print('2 не активно')  endendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ],'key_2 = '"htk_2": [ { "key": "OBS_KEY_2" } ]}'json_s = key_1 .. key_2default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},  {id='htk_2',des='Кнопка 2 ',callback=htk_2_cb},}function script_load(settings)  for k, v in pairs(hotkeys) do     hk[k] = obs.obs_hotkey_register_frontend(k, v, function(pressed)      if pressed then         hotkey_mapping(k)      end     end)    a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(hk[k], a)    obs.obs_data_array_release(a)  end  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)endfunction script_save(settings)  for k, v in pairs(hotkeys) do    a = obs.obs_hotkey_save(hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endend

Задачи


Задача на движение по кругу:
На основе скрипта движение по линии, создайте скрипт с движением вокруг часовой/против.


Гифка


Задача на использование кнопок клавиатуры:
На основе скрипта с горячими клавишами, создайте скрипт с переключателем вкл/выкл,
доп кнопкой через JSON, доп кнопкой с комбинацией клавиш через JSON.


Гифка


Ссылки


Подробнее..

OBS Studio Lua Скриптинг. Часть 2

06.10.2020 16:11:14 | Автор: admin

Всем привет, в этой части руководства рассмотрим:
фильтры, сцены, предметы сцен, Frontend API, создание функциональных фильтров и прочее
С первой частью можно ознакомиться по этой ссылке.


КДПВ сделана в OBS 26.0.0


Краткая справка для этой части


  • Источник Источники используются для рендера аудио/видео, например: захват камеры, игры, звука. С помощью источников можно создавать фильтры, переходы


  • Фильтр Источник который дополняет другие источники


  • Сцены Коллекция источников, сцена является источником ( сцену можно добавить как источник в другой сцене)


  • Предмет сцены конкретный источник в сцене, его можно: перемещать, увеличивать/уменьшать, переворачивать, менять состояние выкл/вкл и.т.д


  • Frontend API Набор функций который предоставляет OBS Studio, например:


    • подписка на событие о переключении сцен
    • запрос статуса о том, идёт ли стрим/запись
    • вкл/выкл стрим/запись
    • переключение сцен


Фильтры


Типы фильтров так же как и источников, можно узнать через функцию obs_source_get_unversioned_id


Название Внутреннее представление типа
Компрессор compressor_filter
Экспандер expander_filter
Усиление gain_filter
Инвертировать полярность invert_polarity_filter
Лимитер limiter_filter
Пропускной уровень шума noise_gate_filter
Шумоподавление noise_suppress_filter
VST 2.x плагин vst_filter
Задержка видео (асинхронность) async_delay_filter
Хромакей chroma_key_filter
Коррекция цвета color_filter
Цветовой ключ color_key_filter
Кадрирование crop_filter
Маска изображения/Смешивание mask_filter
Яркостный ключ luma_key_filter
Задержка отображения gpu_delay
Масштабирование/Соотношение сторон scale_filter
Прокрутка scroll_filter
Увеличить резкость sharpness_filter

В английском варианте: ссылка


Скрипт: изменение параметра прозрачности у фильтра на случайную величину от 1 до 100.


Чтобы узнать название параметра "прозрачность" необходимо добавить фильтр с прозрачностью на какой-нибудь источник, изменить этот параметр. Далее открыть файл коллекции сцен, путь к директории можно узнать через меню OBS:
Справка > Файлы журнала > Показать файлы журнала
далее с этой директории поднимаемся выше, и получаем путь ~/basic>scenes>название_сцены.json
В этом файле ищем color_filter или color_key_filter (оба фильтра могут изменить прозрачность источника).
В строке settings видим что прозрачность записана как opacity.
Ещё один способ узнать название параметра, прочитать исходный код фильтра ссылка


Находим источник по имени


function add_filter_to_source(random_n)  source = obs.obs_get_source_by_name(source_name)

Создаём настройки с изменением параметра opacity на случайное число


settings = obs.obs_data_create()obs.obs_data_set_int(settings, "opacity",random_n)

Проверяем существует ли уже фильтр на источнике, если нет добавляем


_color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")if _color_filter == nil then -- if not exists  _color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)  obs.obs_source_filter_add(source, _color_filter)end

Обновляем и освобождаем память


  obs.obs_source_update(_color_filter,settings)  obs.obs_source_release(source)  obs.obs_data_release(settings)  obs.obs_source_release(_color_filter)end

Привязка к горячей клавише


function htk_1_cb(pressed)   if pressed then    n = math.random(1,100)    add_filter_to_source(n)  endend

Гифка


Исходный код
local obs = obsluasource_name = ''function htk_1_cb(pressed)   if pressed then    n = math.random(1,100)    add_filter_to_source(n)  endendfunction add_filter_to_source(random_n)  source = obs.obs_get_source_by_name(source_name)  settings = obs.obs_data_create()  obs.obs_data_set_int(settings, "opacity",random_n)  _color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")  if _color_filter == nil then -- if not exists    _color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)    obs.obs_source_filter_add(source, _color_filter)  end  obs.obs_source_update(_color_filter,settings)  obs.obs_source_release(source)  obs.obs_data_release(settings)  obs.obs_source_release(_color_filter)endfunction script_properties()  -- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua  local props = obs.obs_properties_create()  local source = obs.obs_properties_add_list(    props,    'source',    'Source:',    obs.OBS_COMBO_TYPE_EDITABLE,    obs.OBS_COMBO_FORMAT_STRING)  for _, name in ipairs(get_source_names()) do    obs.obs_property_list_add_string(source, name, name)  end  return propsendfunction script_update(settings)  source_name = obs.obs_data_get_string(settings, 'source')end--- get a list of source names, sorted alphabeticallyfunction get_source_names()  local sources = obs.obs_enum_sources()  local source_names = {}  if sources then    for _, source in ipairs(sources) do      -- exclude Desktop Audio and Mic/Aux by their capabilities      local capability_flags = obs.obs_source_get_output_flags(source)      if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and        capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then        table.insert(source_names, obs.obs_source_get_name(source))      end    end  end  obs.source_list_release(sources)  table.sort(source_names, function(a, b)    return string.lower(a) < string.lower(b)  end)  return source_namesendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'json_s = key_1default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},}function script_load(settings)  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)end

Стоит упомянуть также о функции obs_source_enum_filters с её помощью можно получить
список всех фильтров у конкретного источника, кстати эта функция не работает в obspython,
но об этом чуть позже.


function check()  source = obs.obs_get_source_by_name(source_name)  result = obs.obs_source_enum_filters(source)  for k,v in pairs(result) do     name = obs.obs_source_get_name(v)    print('name'.. name)  end  obs.source_list_release(result)  obs.obs_source_release(source)end

Эвенты и состояние


Скрипт: звуковое оповещение о том что сцена изменена, с использованием .mp3 файла.
На основе этого скрипта


Создадим функцию для проигрывания звука при смене сцен.


function on_event(event)   if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED    then obs_play_sound_release_source()  end end

Добавим источник медиа, установим настройки: файл alert.mp3 относителен директории нахождения
скрипта, obs_source_set_monitoring_type выставляет прослушивание аудио.


function play_sound()  mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)  local s = obs.obs_data_create()  obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")  obs.obs_source_update(mediaSource,s)  obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)  obs.obs_data_release(s)  obs.obs_set_output_source(outputIndex, mediaSource)  return mediaSourceendfunction obs_play_sound_release_source()  r = play_sound()  obs.obs_source_release(r)end

Исходный код
local obs = obsluamediaSource = nil -- Null pointeroutputIndex = 63 -- Last indexfunction play_sound()  mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)  local s = obs.obs_data_create()  obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")  obs.obs_source_update(mediaSource,s)  obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)  obs.obs_data_release(s)  obs.obs_set_output_source(outputIndex, mediaSource)  return mediaSourceendfunction obs_play_sound_release_source()  r = play_sound()  obs.obs_source_release(r)endfunction on_event(event)   if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED    then obs_play_sound_release_source()  end endfunction script_load(settings)  obs.obs_frontend_add_event_callback(on_event)endfunction script_unload()  obs.obs_set_output_source(outputIndex, nil)end

Время и файлы


Запись в файл, "a" создаст(если нет) файл и добавит "content", а "w" перезапишет .


io.output(io.open(script_path() .. "out.txt","a"))io.write("content")io.close()

print(os.date("%c"))-- День недели Месяц Время Год


Сцены и предметы сцен


  • obs_sceneitem_get_source предметы сцен в источник
  • obs_scene_from_source преобразование сцены в источник
  • obs_scene_find_source преобразование источника в предмет сцены
  • obs_frontend_get_scenes получение всех сцен, освобождать с source_list_release
  • obs_frontend_get_current_scene получение текущей сцены
  • obs_scene_enum_items список всех предметов в сцене, освобождать с sceneitem_list_release

Скрипт: включение и выключение предмета сцены(источника на сцене).


Получение всех сцен и предметов в них


function toggle_source()  scenes = obs.obs_frontend_get_scenes()  for _,scene in pairs(scenes) do    scene_source = obs.obs_scene_from_source(scene)    items = obs.obs_scene_enum_items(scene_source)...

Поиск конкретного источника и его включение или выключение, source_name и boolean определены глобально.


...for _,scene_item in pairs(items) do  _source = obs.obs_sceneitem_get_source(scene_item)  _name = obs.obs_source_get_name(_source)  if _name == source_name then    boolean = not boolean     obs.obs_sceneitem_set_visible(scene_item, boolean)  endend...

Гифка


Исходный код
local obs = obsluasource_name = ''boolean = truefunction htk_1_cb(pressed)   if pressed then    toggle_source()  endendfunction toggle_source()  scenes = obs.obs_frontend_get_scenes()  for _,scene in pairs(scenes) do    scene_source = obs.obs_scene_from_source(scene)    items = obs.obs_scene_enum_items(scene_source)    for _,scene_item in pairs(items) do      _source = obs.obs_sceneitem_get_source(scene_item)      _name = obs.obs_source_get_name(_source)      if _name == source_name then        boolean = not boolean         obs.obs_sceneitem_set_visible(scene_item, boolean)      end    end    obs.sceneitem_list_release(items)  end  obs.source_list_release(scenes)endfunction script_properties()  -- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua  local props = obs.obs_properties_create()  local source = obs.obs_properties_add_list(    props,    'source',    'Source:',    obs.OBS_COMBO_TYPE_EDITABLE,    obs.OBS_COMBO_FORMAT_STRING)  for _, name in ipairs(get_source_names()) do    obs.obs_property_list_add_string(source, name, name)  end  obs.obs_property_set_long_description(source,"?" )  return propsendfunction script_update(settings)  source_name = obs.obs_data_get_string(settings, 'source')end--- get a list of source names, sorted alphabeticallyfunction get_source_names()  local sources = obs.obs_enum_sources()  local source_names = {}  if sources then    for _, source in ipairs(sources) do      -- exclude Desktop Audio and Mic/Aux by their capabilities      local capability_flags = obs.obs_source_get_output_flags(source)      if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and        capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then        table.insert(source_names, obs.obs_source_get_name(source))      end    end  end  obs.source_list_release(sources)  table.sort(source_names, function(a, b)    return string.lower(a) < string.lower(b)  end)  return source_namesendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'json_s = key_1default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},}function script_load(settings)  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)end

Регистрация фильтров


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


Скрипт: закрепление горячих клавиш на фильтре, и полный доступ к источнику.


Импорт библиотеки, и определение типа как источник-фильтр.


local obs = obslualocal bit = require("bit")local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.htmlinfo.id = "uniq_filter_id"info.type = obs.OBS_SOURCE_TYPE_FILTERinfo.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)info.get_name = function() return 'default filter name' end

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


info.create = function(settings,source)   local filter = {}  filter.context = source

Начальная регистрация горячих клавиш, принадлежащих конкретному фильтру.


filter.hotkeys = {  htk_stop = "[stop] ",  htk_restart = "[start] ",}filter.hotkey_mapping = function(hotkey,data)  if hotkey == "htk_stop" then    print('stop '.. data.srsn .. " : " .. data.filn)  elseif hotkey == "htk_restart" then    print('restart ' .. data.srsn .. " : " .. data.filn)  endendfilter.hk = {}for k,v in pairs(filter.hotkeys) do   filter.hk[k] = obs.OBS_INVALID_HOTKEY_IDend

Создание функции которая запустится не сразу ( это необходимо т.к фильтр ещё не создан)
Он будет создан после return


filter._reg_htk = function()    info.reg_htk(filter,settings)  end  obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only

Завершающая регистрация горячих клавиш,obs_filter_get_parent источник который фильтруется
к которому прикреплён фильтр этого типа. Удаление таймера.


info.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created  local target = obs.obs_filter_get_parent(filter.context)  local srsn = obs.obs_source_get_name(target)   local filn =  obs.obs_source_get_name(filter.context)  local data = {srsn = srsn, filn = filn}   for k, v in pairs(filter.hotkeys) do     filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)    if pressed then filter.hotkey_mapping(k,data) end end)    local a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(filter.hk[k], a)    obs.obs_data_array_release(a)  end  obs.remove_current_callback()end

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


info.video_render = function(filter, effect)   -- called every frame  local target = obs.obs_filter_get_parent(filter.context)  if target ~= nil then    filter.width = obs.obs_source_get_base_width(target)    filter.height = obs.obs_source_get_base_height(target)  end  obs.obs_source_skip_video_filter(filter.context) endinfo.get_width = function(filter)  return filter.widthendinfo.get_height = function(filter)  return filter.heightend

Функция .save вызывается при сохранении настроек, т.е можно переназначить горячие клавиши.
obs.obs_register_source(info) регистрация фильтра, теперь его видно при нажатии ПКМ


info.save = function(filter,settings)  for k, v in pairs(filter.hotkeys) do    local a = obs.obs_hotkey_save(filter.hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endendobs.obs_register_source(info)

info.load также как и script_load, вызывается при запуске программы, но в данном
случае дублирует функциональность и требует перезапуска. .update, .get_properties
функции аналогичные script_update, script_properties.


Гифка


Исходный код
local obs = obslualocal bit = require("bit")local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.htmlinfo.id = "uniq_filter_id"info.type = obs.OBS_SOURCE_TYPE_FILTERinfo.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)info.get_name = function() return 'default filter name' endinfo.create = function(settings,source)   local filter = {}  filter.context = source  filter.hotkeys = {    htk_stop = "[stop] ",    htk_restart = "[start] ",  }  filter.hotkey_mapping = function(hotkey,data)    if hotkey == "htk_stop" then      print('stop '.. data.srsn .. " : " .. data.filn)    elseif hotkey == "htk_restart" then      print('restart ' .. data.srsn .. " : " .. data.filn)    end  end  filter.hk = {}  for k,v in pairs(filter.hotkeys) do     filter.hk[k] = obs.OBS_INVALID_HOTKEY_ID  end  filter._reg_htk = function()    info.reg_htk(filter,settings)  end  obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only  return filterendinfo.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created  local target = obs.obs_filter_get_parent(filter.context)  local srsn = obs.obs_source_get_name(target)   local filn =  obs.obs_source_get_name(filter.context)  local data = {srsn = srsn, filn = filn}   for k, v in pairs(filter.hotkeys) do     filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)    if pressed then filter.hotkey_mapping(k,data) end end)    local a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(filter.hk[k], a)    obs.obs_data_array_release(a)  end  obs.remove_current_callback()endinfo.video_render = function(filter, effect)   -- called every frame  local target = obs.obs_filter_get_parent(filter.context)  if target ~= nil then    filter.width = obs.obs_source_get_base_width(target)    filter.height = obs.obs_source_get_base_height(target)  end  obs.obs_source_skip_video_filter(filter.context) endinfo.get_width = function(filter)  return filter.widthendinfo.get_height = function(filter)  return filter.heightend--info.load = function(filter,settings) -- restart required--... same code as in info.reg_htk, but filters will be created from scratch every time--obs restarts, there is no reason to define it here again becuase hotkeys will be duplicated--endinfo.save = function(filter,settings)  for k, v in pairs(filter.hotkeys) do    local a = obs.obs_hotkey_save(filter.hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endendobs.obs_register_source(info)

obspython


В OBS также доступен скриптинг через Python, для Windows только 3.6 версия, для Linux встроенная (т.к в настройках нельзя указать путь),
для MacOS Python не доступен для текущей (26.0.0) версии.
В отличии от Lua тут нельзя регистрировать источники, перебор фильтров не работает,
т.к не написан wrapper на функции с аргументом типа указатель-указатель.
Но в контексте скриптинга имеет место быть т.к:



Задачи


Перед тем как начать делать задачи, рекомендую сделать бэкап коллекции сцен,
с осторожностью использовать script_tick(вызывается раз в каждый кадр)
Проверять утечки памяти в папке logs, последняя строка последнего файла
пример время: Number of memory leaks: 0, если скрипт написан неправильно то
этой строчки там не окажется т.к OBS вылетит с ошибкой при закрытии.


3)[фильтры] "Динамическая прокрутка"
Создать программно или выбрать через интерфейс источник который будет фильтроваться,
к этом источнику добавить(если нет) фильтр Прокрутка (scroll_filter),
добавить интерфейс и/или горячие клавиши которые меняют значение вертикальной скорости
на случайную величину от 0 до 1000 при этом включать/выключать повторение с 50% шансом.


Гифка


4)[эвенты] "Проверка"
При переключении сцен проверять идёт ли запись.
Если нет вывести оповещение ( например через error())


5)[время и файлы] "Пост-продакшен"
Создать скрипт который при нажатии горячей клавиши записывает текущее время,
относительное время от старта записи, добавляет текст "МЕТКА",
а через интерфейс UI кнопку записать текст, и место для набора текста.
изображение


6)[предметы сцены] "Сумма"
Посчитать количество сцен и предметов сцен, записать ответ в названии первой сцены.
Не учитывать группы, т.к перебор предметов груп не работает.
Гифка


7) [фильтры и источники] "Нэйтив скриптинг"
Создать фильтр который будет с интервалом в 2 секунды включать и выключать источник за которым он закреплён.
Гифка


Ответы на задачи и код скриптов включая первую часть на Github


Ссылки


Подробнее..

Издательподписчик для распределённых отказоустойчивых бортовых систем реального времени в 1500 строк кода

28.07.2020 18:07:12 | Автор: admin

Сап, котятки.


Я пришёл рассказать о проекте UAVCAN новом сетевом стандарте для организации взаимодействия узлов и компонентов современных транспортных средств с высоким уровнем автономности/автоматизации. Название является акронимом от Uncomplicated Application-level Vehicular Communication And Networking (несложные бортовые сети и коммуникации уровня приложения).


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



Конъюнктура


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


Мы наблюдаем быстрый рост сложности бортовых систем, связанный с развитием функциональных возможностей транспортных средств (особенно беспилотных) в целом, и систем автоматического управления в частности. Когда мы говорим "бортовая система", мы подразумеваем совокупность автоматики, необходимой для реализации базовых функций транспорта; например, БСУ/ЭДСУ летательных аппаратов, всевозможные ЭБУ в автомобиле, полётный контроллер в дроне или космическом аппарате, сенсоры (радары, камеры), датчики, исполнительные механизмы, и т.п.


Бортовая электроника (электрика) автомобиля конца 20-го века может быть исчерпывающе описана довольно тривиальной схемой; вот, например, схема ВАЗ 21099:



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


Сегодняшние транспортные средства являются в значительной мере программно-определяемыми в том смысле, что существенная часть функциональности и поведений задаётся не столько электрической/механической конфигурацией, сколько программным обеспечением (ПО), что порождает соответствующий перекос концептуальной сложности в сторону бортового ПО. В контексте космических аппаратов это обстоятельство было подмечено ещё инженерным коллективом NASA, работающим над программой Аполлон. В равной мере это применимо и к современным автомобилям (показательна известная история ранней Tesla Model 3, где проблемы антиблокировочной системы были исправлены удалённым накатыванием обновлений без участия владельцев), и к летательным аппаратам (в особенности с ЭСДУ).


Абстракции позволяют нам обойти когнитивное ограничение на количество сущностей, единовременно удерживаемых в сознании. В теории систем этот принцип известен как "чёрный ящик". Любой человек, хоть раз державший в руках компилятор, знает, как это работает: сложные подсистемы описываются не непосредственно, а в виде ограниченных функциональных блоков со строго определённым интерфейсом, скрывающим их реализацию. В рамках дискурса общих информационных технологий безусловно делается предположение, что человеку, мыслящему на определённом уровне абстракции, нет нужды вникать в специфику реализации задействованных на данном уровне блоков, иначе нарушается принцип чёрного ящика. Это предположение не является безусловно корректным если речь идёт о критических системах, где необходима высокая живучесть/отказоустойчивость. Объясняется это тем, что второстепенные функциональные особенности различных компонентов в совокупности могут порождать потенциально опасные непредусмотренные поведения (как это демонстрируют былинные отказы Mars Climate Orbiter, Airbus A400M в Севилье, Ariane 5, и т.п.).


Растущая сложность бортового оборудования отражается в развитии стандартов безопасности. Более сложные системы создаются композицией более сложных подсистем, что формирует спрос на конкретные гарантии поведенческих характеристик компонентов (если у нас есть, скажем, радар, мы хотим точно знать, в каких условиях и как он будет работать, как его характеристики коррелируют с параметрами среды, и вообще неплохо бы убедиться, что его разработчики мышей ловят). Примером ответа индустрии на этот запрос будет концепция Safety Element out of Context (SEooC), введённая в новом автомобильном стандарте ISO 26262. Строго говоря, тема стандартизации не имеет прямого отношения к нашему сугубо техническому проекту, но она отражает общие тренды в индустрии к переходу к композициям более сложных компонентов и как следствие, более сложных интерфейсов.


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


Здесь следует внести разъяснения касательно специфики реального времени и высокой надёжности для читателя, не являющегося специалистом в этой области. Разработчик прикладного ПО, веб-сервера или типичной бытовой встраиваемой системы (вроде компьютерной периферии) сочтёт покрытие тестами достаточной гарантией адекватности ПО. Проблемы реального времени в сложных системах такого рода возникают редко, а когда они возникают, цена временных отклонений обычно достаточно мала, чтобы можно было пренебречь жёстким ресурсным планированием или формальным анализом планировки задач (schedulability analysis). Процессы жёсткого реального времени обычно либо просты, либо цена ошибки несущественна (в качестве примера бытового жёсткого реального времени можно принять логику работы печатающей головки струйного принтера, привод экструдера 3D печати или аудиокодек). Эмпирические методы в целом преобладают над формальными; повсеместно применяется бенчмаркинг и амортизационный анализ. Если продукт показывает приемлемые результаты в подавляющем числе случаев, он принимается соответствующим требованиям; более строгие подходы обычно нецелесообразны финансово.


Разработчик критических систем транспортного средства имеет дело с иным балансом стоимости создания ПО и потенциального ущерба от последствий его сбоев (это верно даже в случае средств микромобильности и малых БПЛА). Большинство таких систем работают в реальном времени, где несвоевременное исполнение задачи эквивалентно неисполнению. Изменение баланса стоимости оправдывает увеличение вложений в средства обеспечения функциональной безопасности с целью снижения эксплуатационных рисков. Как следствие, доказательные методы, верификация и валидация, широко распространены.



Говоря о балансе проектировочных затрат и рисков, интересная тенденция сейчас имеет место в космической отрасли: как метко отмечает Casey Handmer, наблюдаемое ныне снижение стоимости вывода космических аппаратов (КА) сдвигает оптимальный баланс в сторону решений с менее строгими гарантиями безопасности и менее затратной разработкой. В случае же БПЛА наблюдается обратный тренд ввиду распространения более ответственных применений и увеличения числа аппаратов в эксплуатации.


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


Различия в предпосылках также объясняют, почему прекрасно зарекомендовавшие себя в ИКТ решения (тысячи их: очереди сообщений, фреймворки, сетевые стеки с TCP/IP во главе, распределённые БД, операционные системы, etc.) обычно непригодны для ответственных применений и почему безопасные системы часто отдают предпочтение специализированным технологиям.


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


Обычный порошок


Картина положения дел в индустрии будет неполной без хотя бы поверхностного рассмотрения существующих технологий построения отказоустойчивых распределённых систем реального времени. Решения эти обычно интересны технически, созданы с оглядкой на многолетний опыт и проверены временем в реальных продуктах. Однако, тем не менее, горшки CiA/SAE/RTCA/EUROCAE/AUTOSAR/OMG/etc. обжигают отнюдь не боги.


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


1. Аналоговые схемы


Просто и прямолинейно. Электрические, пневматические, гидравлические, механические средства непосредственного взаимодействия между узлами и компонентами попадают в эту категорию. Приведённая ранее схема ВАЗ 21099 тоже отсюда.


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


2. Логическая шина


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


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


Начнём с первого. Если компонент А непрерывно сообщает компоненту Б больше одного параметра, имеет смысл временное разделение (мультиплексирование) сигналов. Такое уплотнение позволяет наращивать число параметров при постоянном числе физических межкомпонентных соединений, что удешевляет/облегчает конструкцию. Практическим примером будет ARINC 429 древний и незамысловатый авиационный протокол, реализующий обмен фиксированными 18-битными словами с щепоткой метаданных по выделенным (некоммутируемым) линиям. Типичная топология выглядит так:



Диаграмма адаптирована из "The Evolution of Avionics Networks From ARINC 429 to AFDX", Fuchs, 2012.


ARINC 429 довольно атипичен как бортовая шина тяжело привести другой пример использования физической топологии точка-многоточка (хотя причастные к малым дронам могли бы вспомнить здесь DShot и MAVLink; последний изначально предназначен для беспроводной связи с наземной станцией, но иногда применяется для внутрибортовой коммуникации). Этот подход имеет особый смысл в простых критических системах жёсткого реального времени, потому что временные свойства процесса доставки сигнала от отправителя к получателю абсолютно очевидны и не требуют сложного анализа. Среда передачи не разделяется с другими компонентами, поэтому нет нужды оценивать вклад каждого в загрузку среды и результирующие побочные эффекты. Однако, этот метод не масштабируется и делает логику взаимодействия сильно зависимой от физических параметров сети (если к компоненту не потрудились пробросить кабель при проектировании, соответствующих данных он никогда не получит).


Широкое распространение получила шинная топология (мы говорим о физическом уровне, не забывайте). Вероятно, CAN не нуждается в представлении; на нём основано множество протоколов и стандартов верхнего уровня. Здесь же FlexRAY, LIN, MIL-STD-1553 и ранние стандарты Ethernet (современный Ethernet используется только в коммутируемой конфигурации).


CAN показателен в контексте реакции отрасли на рост сложности продукции. Введённая в 1986 первая версия стандарта предлагала крайне ограниченный MTU в 8 байт на пакет. В 2012 появился CAN FD с MTU в целых 64 байта и увеличенной пропускной способностью. С конца 2018 года в активной разработке находится CAN XL с MTU 2 КиБ и ещё чуть более высокой скоростью (начало ISO стандартизации запланировано на 2021 год).


Говоря о физических шинах, нельзя не вспомнить интереснейшее начинание под названием Wireless Avionics Intra-Communications (WAIC). WAIC предлагает повысить отказоустойчивость бортовых критических сетей введением гетерогенной избыточности, где резервным каналом станет беспроводной. В целом, беспроводные бортовые сети можно считать фундаментально менее надёжными, чем бортовые проводные/оптические, ввиду слабого контроля за состоянием среды обмена (эфир один на всех). Однако, в совокупности с традиционными сетями, беспроводные позволяют поднять отказоустойчивость из-за устранения отказов общего вида, свойственных проводным сетям, ведь механическое повреждение элемента конструкции может с высокой вероятностью повредить все избыточные проводные соединения:



Диаграмма с сайта WAIC.


Физическая шина размещает всех участников на едином сегменте сети, что создаёт проблемы масштабируемости, ведь все узлы вынуждены организовывать обмен внтутри общего домена коллизий. Сложные транспортные средства на острие прогресса (скажем, современные авиалайнеры и космические аппараты) не в состоянии организовать работу систем в пределах ограничений существующих физических шин, поэтому в ход идут коммутируемые сети. Из значимых следует вспомнить SpaceWire (чрезвычайно узкоспециализированная технология; насколько мне известно, совершенно не представлена вне КА) и, конечно, Ethernet.


В современном аэрокосмосе широко применяется коммутируемый Avionics Full-Duplex Switched Ethernet (AFDX) как на стомегабитной медной паре, так и на оптике (см. Boeing 787). Несмотря на передовой физический уровень, логически это всё тот же ARINC 429, где физические соединения точка-точка заменены их виртуальными репрезентациями. Это решает проблемы масштабируемости, но не предоставляет новых инструментов проектирования логики. Сети AFDX проектируются со статическим планированием обмена с применением автоматических доказательств, что позволяет получить гарантированные временные характеристики доставки несмотря на привнесённые коммутацией сложности. Широко применяется полное дублирование сетевого аппаратного обеспечения (коммутаторов и кабельной системы) для отказоустойчивости. Ниже показан пример физической топологии AFDX подсети космического аппарата с дублированием; при этом логическая сеть ARINC 429, построенная поверх (не показана), определяется конфигурацией ПО коммутаторов вместо физической конфигурации кабельной системы:



Диаграмма из "Communications for Integrated Modular Avionics", Alena, 2007.


Гарантированные параметры сети объясняют почему в сетях жёсткого реального времени редко применяется подтверждение доставки. Вторая причина в том, что процессы реального времени часто предполагают сторого периодический обмен данными, где затраты времени и ресурсов сети (которые, замечу, под строгим учётом) на отправку подтверждения или второй копии данных оказываются неоправданными из-за скорой отправки очередного пакета с более новыми данными в рамках естественного течения процесса. Поэтому, в частности, AFDX построен на (слегка модифицированном) протоколе UDP/IPv4. Использование классических "надёжных" протоколов вроде TCP/IP в подобной среде было бы не просто излишним, а контрпродуктивным они несовместимы с особенностями процессов реального времени.


Общая характеристика рассмотренных технологий и построенных на их основе высокоуровневых протоколов заключается в их ориентированности на организацию низкоуровневых сценариев взаимодействия, где фокус внимания проектировщика сосредоточен на группах определённых параметров и их пересылке между конкретными аппаратными и программными компонентами. На логическом уровне мы всё так же имеем дело со жгутами виртуальных проводов, как на схеме ВАЗ 21099. Подобно тому, как рост сложности решений заставил индустрию ИКТ пережить несколько смен парадигмы за последние десятилетия, подходы к построению архитектуры распределённых бортовых систем претерпевают изменения под давлением спроса на автономность и автоматизацию транспортных средств. В 2020 мы наблюдаем первые симптомы несостоятельности традиционных методов и попытки к переходу на качественно более мощные средства, о чём будет следующий раздел.


3. Распределённые вычисления


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


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


Пожалуй, наиболее значимым на сегодня примером такого подхода будет граф распределённых вычислений из Robot Operating System (ROS) (строго говоря, ROS не является операционной системой, это скорее высокоуровневый фреймворк). Изначально ROS был создан в качестве SDK для окологуманоидного робота PR2 от Willow Garage, но исследователи быстро увидели потенциал фреймворка в других робототехнических системах (от пылесосов и манипуляторов до БПЛА и робоавтомобилей), и он превратился в самостоятельный проект. За несколько лет вокруг ROS развилась богатая экосистема программного обеспечения, решающего многие типовые задачи вроде компьютерного зрения, локализации и картографирования, взаимодействия с аппаратным обеспечением, и т.п. Если изначально фреймворк создавался для исследовательских задач, то интенсивное развитие его экосистемы (и отрасли в целом) со временем поставило вопрос о продуктизации и трансфере наработок из лабораторий в полевые условия, с чем возникли значительные трудности.



Пример визуализации распределённых процессов на ROS. На схеме показан фрагмент системы управления автономного БПЛА в режиме программно-аппаратного моделирования. Овалы обозначают процессы, прямоугольники и стрелки обозначают связи издатель-подписчик.


Описание полного спектра проблем продуктизации основанных на ROS изделий приведёно в статье Why ROS 2 [Gerkey], которая, как нетрудно догадаться из названия, решительно предлагает выпустить вторую версию с оглядкой на новые потребности индустрии. Одной из ключевых проблем здесь является неспособность изначально исследовательского фреймворка удовлетворить радикально более жёсткие требования продуктовых систем к предсказуемости и гарантиям безопасности, которые зачастую обусловлены не только коммерческим интересом, но и законодательным регулированием (особенно в случае автомобильной или аэрокосмической отрасли). Коммуникационная подсистема ROS, обеспечивающая межкомпонентные взаимодействия, является одной из наиболее критических и сложных частей фреймворка. В первой версии использовалась собственная реализация, созданная с нуля, принципиально несовместимая с ответственными применениями, из-за чего во второй версии в роли коммуникационной подсистемы использовали популярное готовое решение Data Distribution Services (DDS).


DDS является сильно отдалённым потомком CORBA, ориентированным на реальное время и модель издатель-подписчик (с недавних пор предлагается также встроенная поддержка клиент-серверных взаимодействий, но на практике первый тип наиболее востребован). DDS широко применяется не только в транспорте и робототехнике, но и в промышленности вообще, зачастую выступая в роли выделенного коммуникационного слоя (собственно, как в случае ROS 2) для вышележащих технологий. Особого упоминания здесь заслуживает Future Airborne Capability Environment (DDS FACE) для критической авионики; однако, на сегодняшний день, большая часть реальных применений DDS в аэрокосмосе приходится на немногочисленные военные системы, которые не следуют гражданским стандартам безопасности.


Как было упомянуто, DDS дальними корнями уходит в CORBA оба стандарта поддерживаются одной организацией. Последняя изначально не предназначалась для систем реального времени, но отраслевые реалии заставили исследователей начать рассматривать вопросы её адаптации для реального времени ещё в конце прошлого века. В работе "The Design of the TAO Real-Time Object Request Broker" [Schmidt et al, 1999] большое внимание уделяется тому факту, что проектирование адекватной сети реального времени самой сетью не ограничивается обязательному анализу подлежат вопросы реализации логики протокола на конечных узлах с соблюдением временных гарантий. В разрезе CORBA синопсис рассматриваемых проблем приведён ниже; эти же принципы легко переносятся на практически любую современную технологию того же толка:



Цифрами обозначены ключевые аспекты реализации, где предписан анализ временных характеристик внутренних алгоритмов протокола. Диаграмма из "The Design of the TAO Real-Time Object Request Broker", Schmidt et al, 1999.


Шмидт с коллегами воплотил идеи в популярной ныне C++ библиотеке TAO (The ACE ORB), которая легла в основу некоторых современных реализаций DDS. Сама по себе TAO насчитывает более двухсот тысяч строк кода без учёта специфики DDS, которая привносит ещё дополнительный код сверху. Из более современных и независимых от TAO инкарнаций DDS упомяну, пожалуй, наиболее многообещающую на сегодня eProsima Fast-DDS (это оценочное суждение, а не реклама) без сторонних зависимостей и тестов она занимает более трёхсот тысяч строк C++ кода (и реализует при этом не все опциональные возможности стандарта). Эти сведения приведены с целью иллюстрации порядка концептуальной сложности DDS.


Как нетрудно догадаться из вышеизложенного, DDS также отличается высокими требованиями к вычислительной платформе, что помимо прочего ограничивает использование во встраиваемых системах. Конкретно эта проблема отчасти решается специализированным подмножеством DDS For Extremely Resource Constrained Environments (DDS-XRCE). Но, согласно нашей модели, это решение уже выходит далеко за пределы концепции распределённых вычислений в силу своей глубокой зависимости от центрального координирующего агента и ограниченной функциональности. Для рассматриваемого здесь вопроса эта технология большой ценности не представляет и рассматривать мы её не будем, равно как мы обойдём стороной и связанный проект micro-ROS.


Из других решений есть смысл поверхностно упомянуть SOME/IP часть автомобильного стандарта AUTOSAR v4+, предлагающую сервисы построения распределённых систем поверх стека IP. В отличие от DDS, SOME/IP сфокусирован исключительно на автомобильных применениях и оперирует существенно более низкоуровневыми концепциями со слабой сегрегацией по уровням абстракции. В совокупности с довольно вольготным обращением с распределёнными состояниями (об этом поговорим далее) и значительным логическим зацеплением между коллабораторами это вызывает вопросы о будущем SOME/IP при наличии сильного конкурента в лице DDS.


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


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


Наш подход


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


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


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


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


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


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



Синопсис графически

В части погони за простотой как одной из ключевых характеристик можно усмотреть реминисценции известного в определённых кругах алгоритма распределённого консенсуса Raft, чьи создатели точно так же, как и мы, начали с вопроса о том, как сделать сложные вещи простыми. Хотя область их деятельности не имеет ничего общего с нашей, они, как и мы, в конечном итоге решали проблему восприятия, где единственной гарантированно достоверной метрикой является человеческий опыт. В отличие от авторов Raft, мы не проверяли трудность понимания наших спецификаций на больших массах людей (N.B.: они показали видео-лекцию 43-м студентам и потом оценили понимание при помощи теста, сравнив результаты с конкурирующей технологией). Однако, у нас есть вот такое практическое свидетельство, где господин зашёл с улицы и сделал минимальную реализацию UAVCAN с нуля за "пару недель" (с его слов):



Желающие увидеть код найдут его на гитхабе как libuavesp. Я, обратите внимание, умываю руки мы к этой реализации отношения не имеем. Заявление автора о том, что "UAV" в названии "UAVCAN" имеет отношение к БПЛА, не соответствует действительности и вызвано банальным недоразумением.


Как нетрудно догадаться из предваряющей этот раздел вводной, UAVCAN широко заимствует ценные принципы из флагманов современной индустрии, в первую очередь опираясь на ROS, DDS, AFDX, WAIC и множество высокоуровневых CAN протоколов, которые даже нет смысла здесь перечислять. Однако, вопросы организации распределённых вычислений одними транспортными протоколами, очевидно, не ограничиваются, особенно если учесть заявленную в ключевых целях потребность в "высокоуровневых абстракциях". UAVCAN удобно рассматривать в виде трёхуровневой модели (мы намеренно игнорируем семиуровневую модель OSI ввиду её чрезмерной детализации):


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


  • Уровень представления отвечает за маршалинг доменных объектов в связях издатель-подписчик и при удалённом вызове процедур. Этот уровень реализован средствами специального предметно-ориентированного языка, на котором даётся строгое определение типов данных для сетевого обмена: Data Structure Description Language (DSDL). На основе DSDL-дефиниций можно автоматически генерировать код (можно и не автоматически).


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


    • UAVCAN/CAN работает поверх классического CAN и CAN FD. Вероятно, в будущем также появится поддержка CAN XL, но это не точно.
    • UAVCAN/UDP работает поверх UDP/IP. По состоянию на 2020-й год, спецификация этого транспорта ещё находится в стадии ранней альфы и может быть изменена до стабилизации (хотя предпосылок к этому нет).
    • UAVCAN/serial работает поверх любого байт-ориентированного протокола (UART, RS-232/422/485, USB CDC ACM) и ещё подходит для хранения дампов в неструктурированных бинарных файлах. Этот транспорт тоже ожидает стабилизации.
    • Поскольку интерфейс между транспортом и верхними уровнями хорошо определён, в будущем возможно добавление новых транспортных протоколов. В числе таковых рассматривается, например, беспроводной IEEE 802.15.4.


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


Первое из исходных предположений таково: нижележащая транспортная сеть (например, CAN или Ethernet, в зависимости от выбранного транспорта) предлагает хорошо охарактеризованную минимальную кривую обслуживания и нулевую вероятность потерь пакетов при отсутствии неблагоприятных воздействий внешней среды. Последнее означает, что потери не могут возникнуть в результате процессов, протекающих внутри сети, как, например, переполнение буфера на сетевом узле; однако, допускаются кратковременные нарушения, вызванные внешними факторами, как, например, электромагнитная интерференция. Это предположение полностью совместимо с реалиями настоящих бортовых систем, и оно позволяет нам существенно упростить логику протокола. Компенсация потерь ввиду внешних воздействий выполняется путём превентивной отправки дубликатов (только в тех случаях, где требуется). Рассмотрение этого метода даётся в статье Idempotent interfaces and deterministic data loss mitigation. Хотя описанные особенности выглядят чуждыми для традиционных систем, они вполне оправданы для нашей области.


Крайне аккуратное обращение с разделяемым состоянием позволяет нам сильно сократить пространство состояний сетевых узлов в сравнении со схожими решениями. В результате сокращается техническая сложность реализации, упрощается её анализ и тестирование, о чём подробно сказано в официальном руководстве. Сетевой узел UAVCAN делает минимум предположений о состоянии своих коллабораторов; например, если в случае традиционного фреймворка издатель-подписчик обычно выделяется явная процедура установления подписки, где подписчик сообщает издателю о своей заинтересованности в конкретных данных (см. SOME/IP, DDS, ROS, практически все MQ*, etc.), в UAVCAN издатель слепо отправляет данные в сеть, позволяя заинтересованным агентам их принять или проигнорировать.


Последнее обстоятельство создало бы существенные преграды для масштабирования, если бы не широкое использование аппаратной фильтрации пакетов в обязательном порядке. Известные нам другие протоколы (кроме AFDX) необоснованно игнорируют тот факт, что всё современное аппаратное обеспечение для высокоскоростной коммуникации, за исключением лишь некоторых маргинальных представителей, предоставляет мощные аппаратные инструменты автоматической фильтрации. Разумная эксплуатация этого факта позволила нам ввести радикальные упрощения без ущерба функциональности, о чём говорится в статье Alternative transport protocols in UAVCAN.


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


Например, динамическое выделение адреса в сети поддерживается опциональным механизмом plug-and-play (впрочем, конкретно для UAVCAN/UDP он не определён ввиду наличия стандартного DHCP). Механизм этот также поддерживает избыточные аллокаторы для отказоустойчивых систем, где консенсус реплик обеспечивается при помощи упомянутого ранее алгоритма Raft.


Второй аспект статичности заключается в предоставлении ресурсного потолка для любой части системы на этапе проектирования. Так, определяемые при помощи упомянутого ранее DSDL типы всегда имеют верхний предел размера любого поля переменной длины, из чего следует, что максимальное время передачи, максимальное время сериализации/десериализации, и, в общем случае, максимальное время обработки всегда можно определить статически. Ниже показано DSDL-определение стандартного типа журнальной записи под именем uavcan.diagnostic.Record, где можно видеть, что максимальная длина сообщения задана явно и ограничена 112-ю байтами (кодировка всегда UTF-8):


# Generic human-readable text message for logging and displaying purposes.# Generally, it should be published at the lowest priority level.uavcan.time.SynchronizedTimestamp.1.0 timestamp# Optional timestamp in the network-synchronized time system; zero if undefined.# The timestamp value conveys the exact moment when the reported event took place.Severity.1.0 severityuint8[<=112] text# Message text.# Normally, messages should be kept as short as possible, especially those of high severity.@assert _offset_ % 8 == {0}@assert _offset_.max <= (124 * 8)     # Two CAN FD frames max

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


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


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


Для примера я продемонстрирую сериализацию и публикацию сообщения, определённого ниже, содержащего три константы и два поля. Константы не участвуют в обмене, поскольку они и так известны всем узлам, имеющим доступ к соответствующему определению типа. Поля сериализуются в плоский остроконечный бинарный формат (младший байт идёт первым) примерно как в ASN.1 UPER (другой порядок байт), но с местной спецификой (ценители сериализации данных должны посмотреть мою заметку, где я рассматриваю популярные форматы и сравниваю их с DSDL).


uint16 VALUE_LOW  = 1000uint16 VALUE_HIGH = 2000uint16 VALUE_MID = (VALUE_HIGH + VALUE_LOW) / 2# Рациональная арифметика произвольной точности!uint16 valueuint8[<=100] key  # Динамический массив от 0 до 100 элементов.

Если мы, скажем, присвоим полям значения value=1234 и key=Hello world!, результат в шестнадцатиричной нотации будет следующим:


D2 04 0C 48 65 6C 6C 6F 20 77 6F 72 6C 64 21

Где D2 04 соответствует 1234, 0C длина массива (если бы максимальная длина была более 255 элементов, тут было бы два или четыре байта), и остаток приходится на приветствие.


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


$ candump -decaxta any(7.925)  vcan2  TX - -  1013373B   [8]  D2 04 0C 48 65 6C 6C A0   '...Hell.'(7.925)  vcan2  TX - -  1013373B   [8]  6F 20 77 6F 72 6C 64 00   'o world.'(7.925)  vcan2  TX - -  1013373B   [4]  21 F9 02 60               '!..`'

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


Колонка со значением 0x1013373B здесь представляет CAN ID, что является битовой маской из нескольких полей с метаданными. Наиболее интересным здесь является значение 0x1337 (4919 в десятичной системе), которое называется идентификатором темы (subject-identifier) в отличие от некоторых более сложных протоколов (как DDS), UAVCAN не поддерживает именованные топики, предлагая вместо них нумерованные темы (похоже на SOME/IP и практически любой протокол поверх CAN). Это значение проектировщик выбирает произвольно, сообразно своим представлениям о системе.


Теперь мы можем повторить упражнение для UAVCAN/UDP на localhost. Wireshark, к сожалению, пока не имеет диссектора для UAVCAN, да и пёс с ним, ведь и так всё ясно:



Дотошный читатель спросит, откуда взялся порт назначения 21303, на что я отвечу, что он вычисляется как сумма идентификатора темы (4919 у нас) и фиксированного смещения 16384. Смещение выбрано таким образом, чтобы сдвинуть порты UAVCAN в эфемерный диапазон с целью минимизации конфликтов. Исходный порт полезной информации не несёт и выбирается произвольно. Нашу полезную нагрузку (D2 04 0C ...) предваряют 24 байта метаданных, добавленных стеком UAVCAN; там содержится информация о приоритете, фрагментах (тут их нет) и последовательном номере сообщения.


Будет ошибкой думать, что внедрение UAVCAN/UDP в обязательном порядке требует полного IP стека. Когда на практике поднимается вопрос об IP стеке, обычно подразумевается TCP/IP, сложность которого несопоставима с UDP/IP. Последний можно собрать с нуля на C в несколько сотен строк, как наглядно продемонстрировал Lifelover в 2011-м году в серии публикаций "Подключение микроконтроллера к локальной сети".


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


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


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


Поверх UAVCAN предполагается создание специализированных отраслевых стандартов уровня приложения, примерно как стандартные классы USB существуют поверх ядра USB, как профили CANopen или Bluetooth, или как DDS FACE поверх DDS. Схематически мы это изображаем следующим образом:



Из отраслевых стандартов сейчас в работе один так называемый Drone Standard 15, или DS-015, к которому активно прикладывают руки, среди прочих, компании из Dronecode Foundation. Мы предвидим появление других отраслевых спецификаций в будущем, поскольку UAVCAN сегодня можно встретить далеко за пределами одних только дронов но об этом позже.


Техническая сторона здесь прозрачна, но есть и другая. Сложные распределённые системы требуют дисциплинированного подхода к проектированию сетевых сервисов и их интерфейсов. Контакты с сообществом разработчиков встраиваемых систем показали, что эта аудитория может глубоко разбираться в вопросах, традиционно характерных для их области деятельности (реальное время, операционные системы, связующее ПО, и т.п.), но при этом иметь очень ограниченное представление о проектировании адекватных сетевых сервисов. Накопленный опыт работы с несколько более низкоуровневыми технологиями, по-видимому, подталкивает людей к неуместному заимствованию практик, что неоднократно на нашем опыте приводило к появлению дефектных интерфейсов, работа с которыми наполовину состоит из страдания. Решение этой нетехнической проблемы является столь же нетехническим мы опубликовали учебный материал, где подробно объясняется, как выглядит сетевой сервис здорового человека. Материал этот опубликован в официальном руководстве UAVCAN в главе Interface Design Guidelines.


Внедрение


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


UAVCAN полностью открыт для распространения и внедрения, не предписывает никаких лицензионных ограничений: вся документация распространяется под CC BY 4.0, а исходный код референсных реализаций под MIT. Вероятно, любой другой подход к лицензированию сегодня обрёк бы проект на забвение.


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


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


На гитхабе поддерживаются референсные библиотеки, среди которых Libcanard минимальная реализация UAVCAN/CAN для однокристалок на C11, объём кода которой фигурирует в названии этой статьи. Также там базируется uavcan.rs мультитранспортная реализация на Rust, которая по состоянию на июль 2020 ищет нового мейнтейнера.


Там же поддерживается Yukon десктопная программа на питоне-электроне для разработки, отладки и диагностики UAVCAN сетей, представляющая собой смесь RViz, Wireshark и LabView. Раньше у нас была ещё утилита на PyQt для предыдущей экспериментальной версии протокола, но теперь она устарела безнадёжно, и усилия сосредоточены на Yukon. На форуме есть бесконечно длинные треды с обсуждениями, но дальше обсуждений мы практически не продвинулись из-за острой недостачи фронтендеров. На сегодня последнее демо выглядит так:



Некоторый интерес представляет использование API ROS поверх UAVCAN вместо DDS. Смысл здесь в том, чтобы сделать развитую экосистему пакетов ROS доступной в системах реального времени и младших микроконтроллерах с использованием UAVCAN, обеспечив при этом также нативную совместимость с обычными UAVCAN устройствами, ничего не знающими о ROS. Краткая вводная дана в заметке на форуме "An exploratory study: UAVCAN as a middleware for ROS"; разыскиваются коллабораторы.


Среди множества компаний и учреждений, принимающих участие развитии стандарта, следует особо выделить NXP Semiconductors. На недавней конференции они представили неплохой доклад "Getting started using UAVCAN v1 with PX4 on the NXP UAVCAN Board", демонстрирующей, в том числе, кое-какие их новые референсы для UAVCAN приложений.


Не менее ценным партнёром является Amazon Prime Air со своим крутейшим автономным доставочным дроном. Эти господа производят не железо, а код копирайты Амазона щедро разбросаны по нашим исходникам.


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


Согласно опросу, проведённому в конце 2019 года, а также основываясь на наших личных контактах с интеграторами, UAVCAN сегодня применяется в пилотируемых (~10% компаний) и беспилотных (~80% компаний) летательных аппаратах, в малых космических аппаратах (~5% компаний, на 2020 год на орбите есть около 20 кубсатов, согласно доступным нам данным), в микро транспорте (вроде электросамокатов) и разнообразных робототехнических системах. Наша выборка, впрочем, подвержена систематической ошибке и приводится только в общеинформативных целях; распределение может не соответствовать действительности. Краткая сводка по опросу доступна отдельно.


Статус и будущее проекта


Наша глобальная амбициозная цель-максимум: стать полноценной альтернативой технологиям класса DDS для отказоустойчивых высоконадёжных систем реального времени; стать стандартом де-факто для новых видов интеллектуального транспорта.


Согласно опросу, главным препятствием на пути к цели являются проблемы не технические, а социальные: 47% респондентов в последнем опросе указало, что главным препятствием на пути внедрения UAVCAN в новых разработках является низкая представленность технологии в профессиональном дискурсе. Вероятно, просветительские публикации вроде этой проекту помогут.


uavcan.org


Источники и материалы
  • Digital Avionics Handbook (3rd edition) Spitzer, Ferrell, 2017
  • Computers in Spaceflight: The NASA Experience Kent, Williams, 2009
  • The Evolution of Avionics Networks From ARINC 429 to AFDX Fuchs, 2012
  • Communications for Integrated Modular Avionics Alena, 2007
  • Safety and Certification Approaches for Ethernet-Based Aviation Databuses Yann-Hang Lee et al, 2005
  • The Design of the TAO Real-Time Object Request Broker Schmidt, Levine, Mungee, 1999
  • In Search of an Understandable Consensus Algorithm Ongaro, Ousterhout, 2014
  • Starlink is a very big deal Handmer, 2019
  • Why ROS 2? Gerkey, 2015
  • ROS on DDS Woodall, 2015
  • Safe Micromobility Santacreu, 2020
  • Understanding Service-Oriented Architecture Sprott, Wilkes, 2009

Документация и спецификации рассмотренных технологий в списке источников не указаны.


Также см. наши публикации по теме:


Подробнее..

Разработчики встраиваемых систем не умеют программировать

02.05.2021 18:15:06 | Автор: admin

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

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

Обычно здесь можно встретить упрёк: "Ты чё пёс А MISRA? А стандарты AUTOSAR? Ты, может, и руководства HIC++ не читал? У нас тут серьёзный бизнес, а не эти ваши побрякушки. Кран на голову упадёт, совсем мёртвый будешь." Тут нужно аккуратно осознать, что адекватное проектирование ПО и практики обеспечения функциональной корректности в ответственных системах не взаимоисключающи. Если весь ваш софт проектируется по V-модели, то вы, наверное, в этой заметке узнаете мало нового хотя бы уже потому, что ваша методология содержит пункт под многозначительным названием проектирование архитектуры. Остальных эмбедеров я призываю сесть и подумать над своим поведением.

Не укради

Что, в конечном итоге, говорят нам вышеупомянутые стандарты в кратком изложении? Примерно вот что:

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

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

  • Делай свои намерения явными и избегай неявных предположений. Это касается проверки инвариантов, исключения платформно-зависимых конструкций, исключения UB, unsafe и схожих граблей, заботливо разложенных языком программирования и средой исполнения.

  • Не забывай об асимптотической сложности. Ответственные системы обычно являются системами реального времени. Адептов C++ призывают воздержаться от злоупотреблений RTTI и использования динамической памяти (хотя последнее к реальному времени относят ошибочно, потому что подобающим образом реализованные malloc() и free() выполняются за постоянное время и даже с предсказуемой фрагментацией кучи).

  • Не игнорируй ошибки. Если что-то идёт не так, обрабатывай как следует, а не надейся на лучшее.

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

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

Я имел несчастье ознакомиться с некоторым количеством встраиваемого ПО реального времени, к надёжности которого предъявляются повышенные требования, и в пугающем числе случаев я ощущал, как у меня шевелятся на голове волосы. Меня, например, сегодня уже не удивляет старая байка об ошибках в системе управления Тойоты Приус, или байка чуть поновее про Boeing 737MAX (тот самый самолёт, который проектировали клоуны под руководством обезьян). В нашем новом дивном мире скоро каждая первая система станет программно-определяемой, что (безо всякой иронии) здорово, потому что это открывает путь к решению сложных проблем затратой меньших ресурсов. Но с повальной проблемой качества системоопределяющего ПО нужно что-то делать.

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

  • Класс-бог, отвечающий за всё сущее.

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

  • Utils или helpers, без них никуда.

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

Инфоцыгане

Косвенным образом масла в огонь подливают некоторые поставщики программных инструментов для разработчиков встраиваемого ПО: Mbed, Arduino, и т.п. Их маркетинговые материалы вполне могут заставить начинающего специалиста поверить, что суть этой работы заключается в низкоуровневом управлении железом, потому что именно на этом аспекте диспропорционально фокусируются упомянутые поставщики ПО. Вот у меня на соседнем рабочем столе открыт в CLion проект ПО для одной встраиваемой системы; проект собирается из чуть более чем ста тысяч строк кода. Из этой сотни примерно три тысячи приходятся на драйверы периферии, остальное приходится на бизнес-логику и всякий матан. Моя скромная практика показывает, что за исключением простых устройств сложность целевой бизнес-логики приложения несопоставима с той его частью, что непосредственно работает с железом.

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

Смотри, что я нашёл! Есть крутая новая система, Mbed называется, значит, для эмбедеров. Гляди, как можно быстро прототипы лепить! Клац, клац, и мигалка готова! Вот же, на видео. А ты, Илья, свой алгоритм оптимизации CAN фильтров пилишь уже неделю, не дело это, давай переходить на Mbed.

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

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

Когда один бэкэндер лучше двух эмбедеров

Ранее я публиковал большую обзорную статью о нашем открытом проекте UAVCAN (Uncomplicated Application-level Vehicular Computing And Networking), который позволяет строить распределённые вычислительные системы (жёсткого) реального времени в бортовых сетях поверх Ethernet, CAN FD или RS-4xx. Это фреймворк издатель-подписчик примерно как DDS или ROS, но с упором на предсказуемость, реальное время, верификацию, и с поддержкой baremetal сред.

Для организации распределённого процесса UAVCAN предлагает предметно-ориентированный язык DSDL с помощью которого разработчик может указать типы данных в системе и базовые контракты, и вокруг этого затем соорудить бизнес-логику. Это работает примерно как REST эндпоинты в вебе, XMLRPC, вот это вот всё. Если взять одного обычного бэкендера человека, измученного сервис-ориентированным проектированием и поддержкой сложных распределённых комплексов и объяснить ему суть реального времени, то он в короткие сроки начнёт выдавать хорошие, годные интерфейсы на UAVCAN.

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

Допустим, ответ подопытного является вариацией на тему "измерение воздушной скорости, барометрической высоты и статического давления". Тогда на свет появляются примерно следующие строки DSDL:

# Calibrated airspeeduavcan.time.SynchronizedTimestamp.1.0 timestampuavcan.si.unit.velocity.Scalar.1.0    calibrated_airspeedfloat16                               error_variance
# Pressure altitudeuavcan.time.SynchronizedTimestamp.1.0 timestampuavcan.si.unit.length.Scalar.1.0      pressure_altitudefloat16                               error_variance
# Static pressure & temperatureuavcan.time.SynchronizedTimestamp.1.0 timestampuavcan.si.unit.pressure.Scalar.1.0    static_pressureuavcan.si.unit.temperature.Scalar.1.0 outside_air_temperaturefloat16[3] covariance_urt# The upper-right triangle of the covariance matrix:#   0 -- pascal^2#   1 -- pascal*kelvin#   2 -- kelvin^2

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

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

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

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

uint16 differential_pressure_readinguint16 static_pressure_readinguint16 outside_air_temperature_reading

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

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

Художника каждый может обидеть

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

Коллеги, одумайтесь.

Я вижу, как нашим микроскопом заколачивают ржавые гвозди, и представляю, сколько ещё подобного происходит за пределами моего поля зрения. В прошлом году уровень отчаяния в нашей скромной команде был столь высок, что мы опубликовали наноучебник, где объясняется, как выглядит сетевой сервис здорового человека: UAVCAN Interface Design Guidelines. Это, конечно, капля в море, но в один прекрасный день я всё-таки переведу его на русский язык ради подъёма уровня профессиональной грамотности.

Непонимание основ организации распределённых вычислений затрудняет внедрение новых стандартов на замену устаревших подходов. Наши наработки в рамках стандарта DS-015 (созданного в коллаборации с небезызвестными NXP Semiconductors и Auterion AG) встречают определённое сопротивление ввиду своей непривычности для целевой аудитории, в то время как ключевые принципы, на которых они основаны, известны индустрии информационных технологий уже не одно десятилетие. Этот разрыв должен быть устранён.

Желающие принять участие в движении за архитектурную чистоту и здравый смысл могут причаститься в телеграм-канале uavcan_ru или на форуме forum.uavcan.org.

Подробнее..

InterSystems IRIS универсальная AIML-платформа реального времени

24.08.2020 18:21:28 | Автор: admin
Автор: Сергей Лукьянчиков, инженер-консультант InterSystems

Вызовы AI/ML-вычислений реального времени


Начнем с примеров из опыта Data Science-практики компании InterSystems:

  • Нагруженный портал покупателя подключен к онлайновой рекомендательной системе. Предстоит реструктуризация промо-акций в масштабе розничной сети (допустим, вместо плоской линейки промо-акций теперь будет применяться матрица сегмент-тактика). Что происходит с рекомендательными механизмами? Что происходит с подачей и актуализацией данных в рекомендательный механизм (объем входных данных возрос в 25000 раз)? Что происходит с выработкой рекомендаций (необходимость тысячекратного снижения порога фильтрации рекомендательных правил в связи с тысячекратным возрастанием их количества и ассортимента)?
  • Есть система мониторинга вероятности развития дефектов в узлах оборудования. К системе мониторинга была подключена АСУТП, передающая тысячи параметров технологического процесса ежесекундно. Что происходит с системой мониторинга, ранее работавшей на ручных выборках (способна ли она обеспечивать ежесекундный мониторинг вероятности)? Что будет происходить, если во входных данных появляется новый блок в несколько сотен колонок с показаниями датчиков, недавно заведенных в АСУТП (потребуется ли и как надолго останавливать систему мониторинга для включения в анализ данных от новых датчиков)?
  • Создан комплекс AI/ML-механизмов (рекомендательные, мониторинговые, прогностические), использующих результаты работы друг друга. Сколько человеко-часов требуется ежемесячно для адаптации работы этого комплекса к изменениям во входных данных? Каково общее замедление при поддержке комплексом принятия управленческих решений (частота возникновения в нем новой поддерживающей информации относительно частоты возникновения новых входных данных)?

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

  • Устраивает ли нас оперативность создания и адаптации (к меняющейся ситуации) AI/ML-разработок в нашей компании?
  • Насколько используемые нами AI/ML-решения поддерживают управление бизнесом в режиме реального времени?
  • Способны ли используемые нами AI/ML-решения самостоятельно (без разработчиков) адаптироваться к изменениям в данных и в практике управления бизнесом?

Наша статья это обстоятельный обзор возможностей платформы InterSystems IRIS в части универсальной поддержки развертывания AI/ML-механизмов, сборки (интеграции) AI/ML-решений и обучения (тестирования) AI/ML-решений на интенсивных потоках данных. Мы обратимся к исследованиям рынка, к практическим примерам AI/ML-решений и концептуальным аспектам того, что мы называем в этой статье AI/ML-платформой реального времени.

Что известно из опросов: приложения реального времени


Результаты опроса, проведенного среди около 800 ИТ-профессионалов в 2019 году компанией Lightbend, говорят сами за себя:


Рисунок 1 Лидирующие потребители данных реального времени

Процитируем важные для нас фрагменты отчета о результатах этого опроса в нашем переводе:

Тенденции популярности средств интеграции потоков данных и, одновременно, поддержки вычислений в контейнерах дают синергетический отклик на запрос рынком более оперативного, рационального, динамичного предложения эффективных решений. Потоки данных позволяют быстрее передать информацию, чем традиционные пакетные данные. К этому добавляется возможность оперативного применения вычислительных методов, таких как, например, основанные на AI/ML рекомендации, создавая конкурентные преимущества за счет роста удовлетворенности клиентской аудитории. Гонка за оперативностью также влияет на все роли в парадигме DevOps повышая эффективность разработки и развертывания приложений. Восемьсот четыре ИТ-специалиста предоставили информацию по использованию потоков данных в их организациях. Респонденты находились преимущественно в западных странах (41% в Европе и 37% в Северной Америке) и были практически равномерно распределены между малыми, средними и крупными компаниями.

Искусственный интеллект не хайп. Пятьдесят восемь процентов тех, кто уже применяет обработку потоков данных в продуктивных AI/ML-приложениях, подтверждают, что их применение в AI/ML получит наибольший прирост в следующем году (по сравнению с прочими приложениями).

  • По мнению большинства опрошенных, применение потоков данных в сценариях AI/ML получит наибольший прирост в следующем году.
  • Применение в AI/ML будет прирастать не только за счет относительно новых типов сценариев, но и за счет традиционных сценариев, в которых данные реального времени применяются все интенсивнее.
  • В дополнение к AI/ML, уровень энтузиазма среди пользователей пайплайнов IoT-данных впечатляет 48% из тех, кто уже интегрировал IoT-данные, утверждают, что реализация сценариев на этих данных получит существенный прирост в ближайшем будущем.

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

Концепция AI/ML-платформы реального времени


Одной из типичных областей применения AI/ML реального времени является управление технологическими процессами на производстве. На ее примере и с учетом предыдущих размышлений, сформулируем концепцию AI/ML-платформы реального времени.
Использование искусственного интеллекта и машинного обучения в управлении технологическими процессами имеет ряд особенностей:

  • Данные о состоянии технологического процесса поступают интенсивно: с большой частотой и по широкому спектру параметров (вплоть до десятков тысяч значений параметров, передаваемых в секунду из АСУТП)
  • Данные о выявлении дефектов, не говоря уже о данных об их развитии, напротив, скудны и нерегулярны, характеризуются недостаточностью типизации дефектов и их локализации во времени (зачастую, представлены записями на бумажном носителе)
  • С практической точки зрения, для обучения и применения моделей доступно только окно актуальности исходных данных, отражающее динамику технологического процесса за разумный скользящий интервал, заканчивающийся последними считанными значениями параметров процесса

Эти особенности заставляют нас, помимо приема и базовой обработки в реальном времени интенсивного широкополосного входящего сигнала от технологического процесса, выполнять (параллельно) применение, обучение и контроль качества результатов работы AI/ML-моделей также в режиме реального времени. Тот кадр, который наши модели видят в скользящем окне актуальности, постоянно меняется а вместе с ним меняется и качество результатов работы AI/ML-моделей, обученных на одном из кадров в прошлом. При ухудшении качества результатов работы AI/ML-моделей (например: значение ошибки классификации тревога-норма вышло за определенные нами границы) должно автоматически быть запущено дообучение моделей на более актуальном кадре и выбор момента для запуска дообучения моделей должен учитывать как продолжительность самого обучения, так и динамику ухудшения качества работы текущей версии моделей (т.к. текущие версии моделей продолжают применяться, пока модели обучаются, и пока не будут сформированы их заново обученные версии).

InterSystems IRIS обладает ключевыми платформенными возможностями для обеспечения работы AI/ML-решений при управлении технологическими процессами в режиме реального времени. Эти возможности можно разделить на три основные группы:

  • Непрерывное развертывание (Continuous Deployment/Delivery, CD) новых или адаптированных существующих AI/ML-механизмов в продуктивное решение, функционирующее в режиме реального времени на платформе InterSystems IRIS
  • Непрерывная интеграция (Continuous Integration, CI) в единое продуктивное решение входящих потоков данных технологического процесса, очередей данных для применения/обучения/контроля качества работы AI/ML-механизмов и обменов данными/кодом/управляющими воздействиями со средами математического моделирования, оркестровку которых осуществляет в реальном времени платформа InterSystems IRIS
  • Непрерывное (само-)обучение (Continuous Training, CT) AI/ML-механизмов, выполняемое в средах математического моделирования с использованием данных, кода и управляющих воздействий (принимаемых решений), передаваемых платформой InterSystems IRIS

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

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

  • Continuous Integration (CI)
  • Continuous Delivery (CD)

Эти практики также применимы и к AI/ML-платформам в целях обеспечения надежной и производительной сборки продуктивных AI/ML-решений.

AI/ML-платформы отличаются от остальных информационных систем в следующих аспектах:

  • Компетенции команды: при создании AI/ML-решения, команда обычно включает дата-саентистов или экспертов-академиков в области исследования данных, которые проводят анализ данных, разработку и апробацию моделей. Эти участники команды могут и не быть профессиональными разработчиками продуктивного программного кода.
  • Разработка: AI/ML-механизмы экспериментальны по своей природе. Для того, чтобы решить задачу наиболее эффективным путем, требуется перебрать различные комбинации входных переменных, алгоритмов, способов моделирования и параметров модели. Сложность такого перебора заключается в трассировке что сработало/не сработало, обеспечении воспроизводимости эпизодов, генерализации разработок для повторяющихся внедрений.
  • Тестирование: тестирование AI/ML-механизмов требует большего спектра тестов, чем большинство других разработок. В дополнение к типовым модульным и интеграционным тестам тестируются валидность данных, качество результатов применения модели к обучающим и контрольным выборкам.
  • Развертывание: развертывание AI/ML-решений не сводится к предиктивным сервисам, применяющим единожды обученную модель. AI/ML-решения строятся вокруг многоэтапных пайплайнов, выполняющих автоматизированное обучение и применение моделей. Развертывание таких пайплайнов подразумевает автоматизацию нетривиальных действий, традиционно выполняемых дата-саентистами вручную для того, чтобы получить возможность обучить и протестировать модели.
  • Продуктив: AI/ML-механизмам может не хватать производительности не только из-за неэффективного программирования, но и вследствие постоянно изменяющегося характера входных данных. Иначе говоря, производительность AI/ML-механизмов может деградировать в связи с более широким спектром причин, нежели производительность обычных разработок. Что приводит к необходимости мониторинга (в режиме онлайн) производительности наших AI/ML-механизмов, а также рассылки оповещений или отбраковки результатов, если показатели производительности не соответствуют ожиданиям.

AI/ML-платформы схожи с другими информационными системами в том, что и тем, и другим необходима непрерывная интеграция кода с контролем версий, модульное тестирование, интеграционное тестирование, непрерывное развертывание разработок. Тем не менее, в случае с AI/ML, есть несколько важных отличий:

  • CI (Continuous Integration, непрерывная интеграция) больше не ограничивается тестированием и валидацией кода развертываемых компонент к ней также относится тестирование и валидация данных и AI/ML-моделей.
  • CD (Continuous Delivery/Deployment, непрерывное развертывание) не сводится к написанию и релизам пакетов или сервисов, а подразумевает платформу для композиции, обучения и применения AI/ML-решений.
  • CT (Continuous Training, непрерывное обучение) новый элемент [прим. автора статьи: новый элемент по отношению к традиционной концепции DevOps, в которой CT это, как правило, Continuous Testing], присущий AI/ML-платформам, отвечающий за автономное управление механизмами обучения и применения AI/ML-моделей.

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

Сценарий реального времени: распознавание развития дефектов в питательных насосах


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


Рисунок 2 Формулировка задачи по мониторингу развития дефектов

Особенностью большинства подобным образом поставленных задач на практике является то, что регулярность и оперативность поступления данных (АСУТП) должны рассматриваться на фоне эпизодичности и нерегулярности возникновения (и регистрации) дефектов различных типов. Другими словами: данные из АСУТП приходят раз в секунду правильные-точные, а о дефектах делаются записи химическим карандашом с указанием даты в общей тетради в цеху (например: 12.01 течь в крышку со стороны 3-го подшипника).

Таким образом, можно дополнить формулировку задачи следующим важным ограничением: метка дефекта конкретного типа у нас всего одна (т. е. пример дефекта конкретного типа представлен данными из АСУТП на конкретную дату и больше примеров дефекта именно этого типа у нас нет). Данное ограничение сразу выводит нас за рамки классического машинного обучения (supervised learning), для которого меток должно быть много.


Рисунок 3 Уточнение задачи по мониторингу развития дефектов

Можем ли мы каким-то образом размножить имеющуюся в нашем распоряжении единственную метку? Да, можем. Текущее состояние насоса характеризуется степенью подобия зарегистрированным дефектам. Даже без применения количественных методов, на уровне зрительного восприятия, наблюдая за динамикой значений данных, прибывающих из АСУТП, уже можно многое почерпнуть:


Рисунок 4 Динамика состояния насоса на фоне метки дефекта заданного типа

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


Рисунок 5 Применение статистического теста к поступающим данным на фоне метки дефекта

Статистический тест определяет вероятность того, что записи со значениями параметров технологического процесса в полученном из АСУТП поток-пакете подобны записям метки дефекта определенного типа. Вычисленное в результате применения статистического теста значение вероятности (индекс статистического подобия) преобразуется к значению 0 или 1, становясь меткой для машинного обучения в каждой конкретной записи в исследуемом на подобие пакете. Т. е. после обработки вновь поступившего к нам пакета записей состояния насоса статистическим тестом у нас появляется возможность (а) добавить данный пакет в обучающую выборку для обучения AI/ML-модели и (б) осуществить контроль качества работы текущей версии модели при ее применении к данному пакету.


Рисунок 6 Применение модели машинного обучения к поступающим данным на фоне метки дефекта

В одном из наших предыдущих вебинаров мы показываем и объясняем, каким образом платформа InterSystems IRIS позволяет реализовать любой AI/ML-механизм в виде непрерывно исполняемых бизнес-процессов, осуществляющих контроль достоверности результатов моделирования и адаптирующих параметры моделей. При реализации прототипа нашего сценария с насосами мы используем весь представленный в ходе вебинара функционал InterSystems IRIS имплементируя в процессе-анализаторе в составе нашего решения не классический supervised learning, а скорее обучение с подкреплением (reinforcement learning), автоматически управляющее выборкой для обучения моделей. В выборку для обучения помещаются записи, на которых возникает консенсус детекции после применения и статистического теста, и текущей версии модели т. е. и статистический тест (после трансформации индекса подобия к 0 или 1), и модель выдали на таких записях результат 1. При новом обучении модели, при ее валидации (заново обученная модель применяется к собственной обучающей выборке, с предварительным применением к ней же статистического теста), записи, не удержавшие после обработки статистическим тестом результат 1 (из-за постоянного присутствия в обучающей выборке записей из изначальной метки дефекта), из обучающей выборки удаляются, и новая версия модели учится на метке дефекта плюс на удержавшихся записях из потока.


Рисунок 7 Роботизация AI/ML-вычислений в InterSystems IRIS

В случае, если возникает потребность в своего рода втором мнении по качеству детекции, получаемой при локальных вычислениях в InterSystems IRIS, создается процесс-советник для выполнения обучения-применения моделей на контрольном датасете с помощью облачных сервисов (например Microsoft Azure, Amazon Web Services, Google Cloud Platform и т. п.):


Рисунок 8 Второе мнение из Microsoft Azure под оркестровкой InterSystems IRIS

Прототип нашего сценария в InterSystems IRIS выполнен в виде агентной системы аналитических процессов, осуществляющих взаимодействия с объектом оборудования (насосом), средами математического моделирования (Python, R и Julia), и обеспечивающих самообучение всех задействованных AI/ML-механизмов на потоках данных реального времени.


Рисунок 9 Основной функционал AI/ML-решения реального времени в InterSystems IRIS

Практический результат работы нашего прототипа:

  • Распознанный моделью образец дефекта (12 января):


  • Распознанный моделью развивающийся дефект, не вошедший в образец (11 сентября, сам дефект был констатирован ремонтной бригадой только через двое суток 13 сентября):


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

InterSystems IRIS универсальная платформа AI/ML-вычислений реального времени


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

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


Рисунок 10 Архитектура InterSystems IRIS в контексте AI/ML реального времени

Как и предыдущая диаграмма, нижеприведенная диаграмма сочетает новую систему координат (CD/CI/CT) со схемой потоков информации между рабочими элементами платформы. Визуализация начинается с макромеханизма CD и продолжается макромеханизмами CI и СТ.


Рисунок 11 Схема потоков информации между AI/ML-элементами платформы InterSystems IRIS

Суть механизма CD в InterSystems IRIS: пользователи платформы (разработчики AI/ML-решений) адаптируют уже имеющиеся и/или создают новые AI/ML-разработки с применением специализированного редактора программного кода AI/ML-механизмов: Jupyter (полное наименование: Jupyter Notebook; так же, для краткости, иногда называются и документы, созданные в данном редакторе). В Jupyter разработчик имеет возможность написать, отладить и убедиться в работоспособности (в т. ч., с использованием графики) конкретной AI/ML-разработки до ее размещения (развертывания) в InterSystems IRIS. Понятно, что создаваемая таким образом новая разработка будет получать только базовую отладку (т. к., в частности, Jupyter не работает с потоками данных реального времени) это в порядке вещей, ведь основным результатом разработки в Jupyter становится подтверждение принципиальной работоспособности отдельного AI/ML-механизма (на выборке данных показывает ожидаемый результат). Аналогичным образом, уже размещенный в платформу механизм (см. следующие макромеханизмы) перед отладкой в Jupyter может потребовать отката к доплатформенному виду (чтение данных из файлов, работа с данными через xDBC вместо таблиц, непосредственное взаимодействие с глобалами многомерными массивами данных InterSystems IRIS и т. п.).

Важный аспект имплементации CD именно в InterSystems IRIS: между платформой и Jupyter реализована двунаправленная интеграция, позволяющая переносить в платформу (и, в дальнейшем, обрабатывать в платформе) контент на языках Python, R и Julia (все три являются языками программирования в соответствующих ведущих open-source средах математического моделирования). Таким образом, разработчики AI/ML-контента имеют возможность осуществлять непрерывное развертывание этого контента в платформе, работая в привычном им редакторе Jupyter, с привычными библиотеками, доступными в Python, R, Julia, и выполняя базовую отладку (при необходимости) вне платформы.

Переходим к макромеханизму CI в InterSystems IRIS. На диаграмме изображен макропроцесс работы роботизатора реального времени (комплекс из структур данных, бизнес-процессов и оркестрируемых ими фрагментов кода на языках матсред и языке ObjectScript нативном языке разработки InterSystems IRIS). Задача этого макропроцесса: поддерживать необходимые для работы AI/ML-механизмов очереди данных (на основе потоков данных, передаваемых платформе в реальном времени), принимать решения о последовательности применения и ассортименту механизмов AI/ML (они же математические алгоритмы, модели и т. д. могут называться по-разному в зависимости от конкретики реализации и от терминологических предпочтений), поддерживать в актуальном состоянии структуры данных для анализа результатов работы AI/ML-механизмов (кубы, таблицы, многомерные массивы данных и т. д. для отчетов, дэшбордов и т. п.).

Важный аспект имплементации CI именно в InterSystems IRIS: между платформой и средами математического моделирования реализована двунаправленная интеграция, позволяющая исполнять размещенный в платформе контент на языках Python, R и Julia в их соответствующих средах с получением обратно результатов исполнения. Эта интеграция реализована как в режиме терминала (т. е. AI/ML-контент формулируется как код на ObjectScript, осуществляющий вызовы матсред), так и в режиме бизнес-процесса (т. е. AI/ML-контент формулируется как бизнес-процесс при помощи графического редактора, или иногда при помощи Jupyter, или при помощи IDE IRIS Studio, Eclipse, Visual Studio Code). Доступность бизнес-процессов для редактирования в Jupyter отражена при помощи связи между IRIS на уровне CI и Jupyter на уровне CD. Более детальный обзор интеграции со средами математического моделирования производится далее. На данном этапе, на наш взгляд, есть все основания для того, чтобы зафиксировать наличие в платформе всех необходимых инструментов для реализации непрерывной интеграции AI/ML-разработок (приходящих из непрерывного развертывания) в AI/ML-решения реального времени.

И главный макромеханизм: CT. Без него не получится AI/ML-платформы (хоть реальное время и будет имплементировано через CD/CI). Сутью CT является работа платформы с артефактами машинного обучения и искусственного интеллекта непосредственно в рабочих сессиях сред математического моделирования: моделями, таблицами распределений, векторами-матрицами, слоями нейросетей и т.п. Данная работа, в большинстве случаев, состоит в создании упомянутых артефактов в средах (в случае моделей, например, создание состоит из задания спецификации модели и последующего подбора значений ее параметров так называемого обучения модели), их применении (для моделей: расчет при их помощи модельных значений целевых переменных прогнозов, принадлежности к категории, вероятности наступления события и т.п.) и усовершенствовании уже созданных и примененных артефактов (например, переопределение набора входных переменных модели по результатам применения в целях повышения точности прогнозирования, как вариант). Ключевым моментом в понимании роли CT является его абстрагированность от реалий CD и CI: CT будет имплементировать все артефакты, ориентируясь на вычислительную и математическую специфику AI/ML-решения в рамках возможностей, предоставляемых конкретными средами. Ответственность за снабжение входными данными и доставку результатов будут нести CD и CI.

Важный аспект имплементации CT именно в InterSystems IRIS: пользуясь уже упомянутой выше интеграцией со средами математического моделирования, платформа имеет возможность извлекать из рабочих сессий, протекающих под ее управлением в матсредах, те самые артефакты и (самое важное) превращать их в объекты данных платформы. Например, таблица распределения, которая создалась только что в рабочей сессии Python может быть (без остановки сессии в Python) перенесена в платформу в виде, например, глобала (многомерного массива данных InterSystems IRIS), и использована для вычислений в другом AI/ML-механизме (реализованном уже на языке другой среды например, на R) или виртуальной таблицы. Другой пример: в параллель со штатным режимом работы модели (в рабочей сессии Python), на ее входных данных осуществляется авто-ML : автоматический подбор оптимальных входных переменных и значений параметров. И вместе со штатным обучением, продуктивная модель в режиме реального времени получает еще и предложение по оптимизации своей спецификации в которой меняется набор входных переменных, меняются значения параметров (уже не в результате обучения в Python, а в результате обучения альтернативной версии ее самой, например, в стеке H2O), позволяя общему AI/ML-решению автономно справляться с непредвиденными изменениями в характере входных данных и моделируемых явлений.

Познакомимся более подробно с платформенным AI/ML-функционалом InterSystems IRIS, на примере реально существующего прототипа.

На нижеприведенной диаграмме, в левой части слайда часть бизнес-процесса, имплементирующая отработку скриптов на Python и R. В центральной части визуальные логи исполнения некоторых из этих скриптов, соответственно, на Python и на R. Сразу за ними примеры контента на одном и другом языке, переданные на исполнение в соответствующие среды. В конце справа визуализации, основанные на результатах исполнения скриптов. Визуализации вверху сделаны на IRIS Analytics (данные забраны из Python в платформу данных InterSystems IRIS и выведены на дэшборд средствами платформы), внизу сделаны прямо в рабочей сессии R и выведены оттуда в графические файлы. Важный аспект: представленный фрагмент в прототипе отвечает за обучение модели (классификация состояний оборудования) на данных, поступающих в реальном времени от процесса-имитатора оборудования, по команде от процесса-монитора качества классификации, наблюдаемого в ходе применении модели. Об имплементации AI/ML-решения в виде набора взаимодействующих процессов (агентов) речь пойдет далее.


Рисунок 12 Взаимодействие с Python, R и Julia в InterSystems IRIS

Платформенные процессы (они же бизнес-процессы, аналитические процессы, пайплайны и т.п. в зависимости от контекста), прежде всего, редактируемы в графическом редакторе бизнес-процессов в самой платформе, причем таким образом, что создаются одновременно и его блок-схема, и соответствующий AI/ML-механизм (программный код). Говоря о том, что получается AI/ML-механизм, мы изначально подразумеваем гибридность (в рамках одного процесса): контент на языках сред математического моделирования соседствует с контентом на SQL (в т. ч., с расширениями от IntegratedML), на InterSystems ObjectScript, с другими поддерживаемыми языками. Более того, платформенный процесс дает очень широкие возможности для отрисовки в виде иерархически вложенных фрагментов (как видно в примере на приведенной ниже диаграмме), что позволяет эффективно организовывать даже весьма сложный контент, нигде не выпадая из графического формата (в неграфические методы/классы/процедуры и т. п.). Т. е. при необходимости (а она предвидится в большинстве проектов) абсолютно все AI/ML-решение может быть имплементировано в графическом самодукоментирующемся формате. Обращаем внимание на то, что в центральной части нижеприведенной диаграммы, на которой представлен более высокий уровень вложенности, видно, что помимо собственно работы по обучению модели (при помощи Python и R), добавляется анализ так называемой ROC-кривой обученной модели, позволяющий визуально (и вычислительно тоже) оценить качество обучения и этот анализ реализован на языке Julia (исполняется, соответственно, в матсреде Julia).


Рисунок 13 Визуальная среда композиции AI/ML-решений в InterSystems IRIS

Как уже упоминалось ранее, начальная разработка и (в ряде случаев) адаптация уже имплементированных в платформе AI/ML-механизмов будет/может производиться вне платформы в редакторе Jupyter. На диаграмме ниже мы видим пример адаптации существующего платформенного процесса (того же, что и на диаграмме выше) таким образом выглядит в Jupyter тот его фрагмент, который отвечает за обучение модели. Контент на языке Python доступен для редактирования, отладки, вывода графики прямо в Jupyter. Изменения (при необходимости) могут производиться с мгновенной синхронизацией в платформенный процесс, в т. ч. в его продуктивную версию. Аналогичным образом может передаваться в платформу и новый контент (автоматически формируется новый платформенный процесс).


Рисунок 14 Применение Jupyter Notebook для редактирования AI/ML-механизма в платформе InterSystems IRIS

Адаптация платформенного процесса может выполняться не только в графическом или ноутбучном формате но и в тотальном формате IDE (Integrated Development Environment). Такими IDE выступают IRIS Studio (нативная студия IRIS), Visual Studio Code (расширение InterSystems IRIS для VSCode) и Eclipse (плагин Atelier). В ряде случаев возможно одновременное использование командой разработчиков всех трех IDE. На диаграмме ниже показан пример редактирования все того же процесса в студии IRIS, в Visual Studio Code и в Eclipse. Для редактирования доступен абсолютно весь контент: и Python/R/Julia/SQL, и ObjectScript, и бизнес-процесс.


Рисунок 15 Разработка бизнес-процесса InterSystems IRIS в различных IDE

Отдельного упоминания заслуживают средства описания и исполнения бизнес-процессов InterSystems IRIS на языке Business Process Language (BPL). BPL дает возможность использовать в бизнес-процессах готовые интеграционные компоненты (activities) что, собственно говоря, и дает полные основания утверждать, что в InterSystems IRIS реализована непрерывная интеграция. Готовые компоненты бизнес-процесса (активности и связи между ними) являются мощнейшим акселератором сборки AI/ML-решения. И не только сборки: благодаря активностям и связям между ними над разрозненными AI/ML-разработками и механизмами возникает автономный управленческий слой, способный принимать решения сообразно ситуации, в реальном времени.


Рисунок 16 Готовые компоненты бизнес-процессов для непрерывной интеграции (CI) на платформе InterSystems IRIS

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


Рисунок 16 Работа AI/ML-решения в виде агентной системы бизнес-процессов в InterSystems IRIS

Мы продолжаем наш обзор InterSystems IRIS рассказом о прикладном использовании платформы для решения целых классов задач реального времени (довольно подробное знакомство с некоторыми лучшими практиками платформенного AI/ML на InterSystems IRIS происходит в одном из наших предыдущих вебинаров).

По горячим следам предыдущей диаграммы, ниже приведена более подробная диаграмма агентной системы. На диаграмме изображен все тот же прототип, видны все четыре процесса-агента, схематически отрисованы взаимоотношения между ними: GENERATOR отрабатывает создание данных датчиками оборудования, BUFFER управляет очередями данных, ANALYZER выполняет собственно машинное обучение, MONITOR контролирует качество машинного обучения и подает сигнал о необходимости повторного обучения модели.


Рисунок 17 Композиция AI/ML-решения в виде агентной системы бизнес-процессов в InterSystems IRIS

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


Рисунок 18 Непрерывное (само-)обучение (CT) на платформе InterSystems IRIS

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


Рисунок 19 Интеграция авто-ML в AI/ML-решение на платформе InterSystems IRIS

Диаграмма ниже немного сбивает кульминацию, но это хороший вариант завершения рассказа о классах решаемых задач реального времени: мы напоминаем о том, что при всех возможностях платформы InterSystems IRIS, обучение моделей именно под ее управлением не является обязательным. Платформа может получить извне так называемую PMML-спецификацию модели, обученную в инструменте, не находящемся под управлением платформы и применять эту модель в реальном времени с момента импорта ее PMML-спецификации. При этом важно учесть, что далеко не все AI/ML-артефакты могут быть сведены к PMML-спецификации, даже если большинство наиболее распространенных артефактов это позволяют сделать. Таким образом платформа InterSystems IRIS имеет открытый контур и не означает платформенного рабства для пользователей.


Рисунок 20 Интеграция авто-ML в AI/ML-решение на платформе InterSystems IRIS

Перечислим дополнительные платформенные преимущества InterSystems IRIS (для наглядности, применительно к управлению технологическими процессами), имеющие большое значение при автоматизации искусственного интеллекта и машинного обучения реального времени:

  • Развитые средства интеграции с любыми источниками и потребителями данных (АСУТП/SCADA, оборудование, ТОиР, ERP и т. д.)
  • Встроенная мультимодельная СУБД для высокопроизводительной транзакционно-аналитической обработки (Hybrid Transaction/Analytical Processing, HTAP) любых объемов данных технологических процессов
  • Средства разработки для непрерывного развертывания AI/ML-механизмов решений реального времени на основе Python, R, Julia
  • Адаптивные бизнес-процессы для непрерывной интеграции и (само-)обучения механизмов AI/ML-решений реального времени
  • Встроенные средства Business Intelligence для визуализации данных технологических процессов и результатов работы AI/ML-решения
  • Управление API для доставки результатов работы AI/ML-решения в АСУТП/SCADA, информационно-аналитические системы, рассылки оповещений и т. д.

AI/ML-решения на платформе InterSystems IRIS легко вписываются в существующую ИТ-инфраструктуру. Платформа InterSystems IRIS обеспечивает высокую надежность AI/ML-решений за счет поддержки отказоустойчивых и катастрофоустойчивых конфигураций и гибкое развертывание в виртуальных средах, на физических серверах, в частных и публичных облаках, Docker-контейнерах.

Таким образом, InterSystems IRIS является универсальной платформой AI/ML-вычислений реального времени. Универсальность нашей платформы подтверждается на практике отсутствием де-факто ограничений по сложности имплементируемых вычислений, способностью InterSystems IRIS совмещать (в режиме реального времени) обработку сценариев из самых различных отраслей, исключительной адаптируемостью любых функций и механизмов платформы под конкретные потребности пользователей.


Рисунок 21 InterSystems IRIS универсальная платформа AI/ML-вычислений реального времени

Для более предметного взаимодействия с теми из наших читателей, кого заинтересовал представленный здесь материал, мы рекомендуем не ограничиваться его прочтением и продолжить диалог вживую. Мы с готовностью окажем поддержку с формулировкой сценариев AI/ML реального времени применительно к специфике вашей компании, выполним совместное прототипирование на платформе InterSystems IRIS, сформируем и реализуем на практике дорожную карту внедрения искусственного интеллекта и машинного обучения в ваши производственные и управленческие процессы. Контактный адрес электронной почты нашей экспертной группы AI/ML MLToolkit@intersystems.com.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    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