песочница АСУ ТП программирование geek реактор образовательный длиннопост
Часть 3, каркас архитектуры
Часть 1, введение
Часть 2, приоритеты и базовые сигналы
Мда, я дико извиняюсь за большое количество опечаток в предыдщих постах. Руки не поспевают за мыслью, а при редактировании потеряется часть оформления регулярно. Не зналь(
Имея на руках пример того, с чем предлагается работать, впору поговорить об архитектуре, которая и будет обеспечивать корректное и стабильное исполнение кода, однако, перед этим сделаем ряд важных оговорок:1) концепт ориентирован на работу с жёстким распределением памяти (Siemens, OMRON CP/CJ series)
2) ввиду пункта 1 внутри одной структуры могут быть переменные которые И читаются, И пишутся, что существенно усложняет их проброс в коммуникацию(особенно тех, которые пишутся И с панели оператора, И из программы, например запуск в ручном режиме и сброс аварий в структуре управления)
3) объём памяти оперативность и для хранения кода, а также мощность CPU–считаются достаточно большими, чтобы не обращать на них внимания, в иных случаях требуется оптимизация кода
4) при работе с контроллерами, имеющими «классическое» распределение памяти, для обеспечения корректного управления моим кодом по ModBus RTU/TCP требуется дополнительная прослойка, которая будет пересобирать структуры в WORD и обратно, когда-нибудь я это исправлю, но явно не сейчас
5) вся концепция рассчитана на применение в обще-промышленной области, где потерять 10-20-30 мс роли не сыграет никакой, если вам нужна более высокая точность – добро пожаловать в чудный мир оптимизации и распределения кусков кода по разным циклам
Ещё одно лирическое отступление
Я осознанно не буду вам рассказывать как работает Промышленный Логический Контроллер (ПЛК), распределение его памяти, времени CPU по задачам системным и пользовательским, типы данных и прочую лабуду – это вы можете узнать на любых вводных курсах от любого производителя железа. Моя задача – показать пример прикладной реализации тех или иных задач.
Кстати, на ардуине в своё время использовал Union, который прекрасно решал проблему компоновки памяти, однако подавляющее большинство сред разработки для промышленного оборудования его или не поддерживают, или имеют кастрированную реализацию.
Генерация импульсов
Начнём с терминологии:
- импульс – это нечто, существующее предельно короткое время, в нашем случае сие ровно 1 цикл контроллера.
Большинство контроллеров предлагает свои системные генераторы импульсов в том или ином виде, но выглядят они следующим образом на примере 1 секунды:
Ёбушки воробушки, наш самописный таймер то проверяет когда сигнал = 1, а он равен 1 в течении 50 циклов, а за это время он насчитает 50 секунд, вместо 1! Лажа какая-то. Мы должны получить следующее:
Для этого есть несколько вариантов, и сначала мы отметём в сторону самый очевидный: мы НЕ будем в каждом таймере проверять фронт системного генератора импульсов, потому что каждая проверка фронта это +1 переменная в памяти ПЛК, а мы не хотим засирать его бесполезным хламом.
Итого остаётся:
1) вызывать системный импульс, проверять его передний или задний фронт и закидывать в pulse_1s;
2) вызвать стандартный таймер TON с длительностью 1 секунда и зациклить на самого себя, при срабатывании таймера взводить pulse_1s;
3) читать системное время и по внутренним часам ПЛК и при смене секунды однократно взводить pulse_1s, потребуется буфер для хранения и сравнения предыдущего времени;
4) прочитать из недр контроллера время предыдущего цикла, насуммировать несчастные наносекунды до 1 секунды и тоже записать в pulse_1s единичку, после чего очистить буфер.
5) ещё что-нибудь на ваше усмотрение.
Мне глубоко фиолетово, каким способом вы получаете в итоге pulse_1s, но вам достаточно получить его корректно 1 раз и все таймеры во всей программе сразу же заработают, причём корректно и, вау, синхронно. Т.е. если у вас в двух местах с разбегом менее 1 секунды начался счёт до 5, то закончится он тоже одновременно. В этом и плюс, и минус. Мы теряем точность. Но так ли она нужна?
Хотите точность до 100 мс? Пишем таймер Time_R для дробных значений генерируем pulse_01s.
Хотите точность до 10 мс? Ну… сделайте отдельный цикл ПЛК с такой частотой и там считайте. Или убедитесь, что ваше время цикла менее 10 мс на всю программу.Обратите внимание, что этот таймер сложнее – мы считаем прогресс времени от 0 до 1,который можно использовать для вспомогательных операций (типа на 30% всего времени моргнуть правой пяткой) и красивого прогресс-бара на экране.
Архитектура
Перейдём к тому, ради чего был затеян данный раздел. Следите за руками…
Где-то там приютилось ещё регулирование, типа ПИДов, но о них как-нибудь в другой раз.На повестке дня вопрос распределения переменных по областям памяти. Что будет глобальным, а что локальным?
К глобальным относится всё, что ранее было названо глобальным, а также туда настоятельно рекомендуется выносить:
- все структуры управления драйверами
- все структуры параметров драйверами
- все структуры состояний драйверами
- общие параметры техпроцесса
- общее управление техпроцессом, типа включить/выключить установку
Из них в раздел энергонезависимой памяти попадают только структуры параметров.
REQ – Request, запрос запуска. Сюда мы из авторежима будем писать команду для устройства, а затем скармливать драйверам в CMD.Start_A.
DONE – состояние устройств, если оно выключено или в аварии то соответствующий флаг =0, если успешно запущен = 1. Это хорошо заходит для минимизации алгоритма авторежима и всяких вспомогательных операций.
А что же тогда попадает в call’ы?Нерадивые любители звонков с автонабором? Увы, их неплохо бы там запереть, но места маловато. Там будут вызваны непосредственно экземпляры драйверов на исполнение со всей обвязкой. На примере уже рассмотренных дискретных входов это выглядит так… опс, в этом проекте их нет, вот вам выхода:
песочница geek АСУ ТП программирование реактор образовательный длиннопост
Часть 2, приоритеты и базовые сигналы
Часть 1,введение (отправил в политоту из-за двусмысленных высказываний, ибо было сложно удержаться)
Приоритеты команды
Итак, вы решили взяться за благое дело и сэкономить пару дефицитных рупей на найме программиста и запилить всё своими руками. Что же для этого надо?
1) скачайте среду разработки
2) откройте среду разработки3) закройте среду разработки и идите искать программиста
Для начала, давайте проясним одну вещь. То что я рассказываю не является аксиомой. Это концепция архитектуры, позволяющая сделать максимально гибкое и устойчивое решение, позволяющее безболезненно изменять различные прослойки кода внутри проекта, не роняя завод.
Итак, помните, я говорил что всё есть сигнал? Я наврал. Всё есть объект.
Вход - это объект.
Выход - это объект.
Бутылка - тоже объект, но более высокого порядка.
А дальше мы начинаем собирать пирамидку из кубиков:
- базовые сигналы нижнего уровня, дискретные и аналоговые
- простые устройства
- сложные устройства
- технологические участки
- технологические линии
- производственные участки
...
- планирование производства
Вот всё что лежит до троеточия и будем рассматривать. Начнём с базиса, но перед этим - а кто здесь главный? Ты, я? оператор? директор? да пошёл ты в жопу, директор! Главная здесь ОНА:
Мне лень рисовать пирамидки маслоу, поэтому обойдёмся блок-схемами. ГОСТы - для слабаков! Главное, чтобы было понятно...
УХ, ебать! Но это лёгкий вариант, извините.
Глобальные переменные
Обратите внимание на "Глобальные переменные". Что в них входит? А всё, что проходит красной нитью через весь код и существует в единственном экземпляре:
- Аварийный останов
- Общий сброс аварий
- Общий режим эмуляции
- Общий перевод в автоматический режим всех устройств (очень полезно, если оператор любит пошарить ручками где надо и забывает что делал в недрах нашей системы)
Как оно выглядит в объявлении переменных? Вот так:
All_Block:BOOL; //аварийная остановка
All_Reset :BOOL; //сброс всех аварий
All_Sim :BOOL; //общий режим эмуляции
All_Auto :BOOL; //перевести всё в автоматический режим
sys :system; //системные переменные
sec :REAL; //длительность одной секунды
Обратите внимание, на две последние переменные. Это наша опора и поддержка, которую мы будем гонять вместе с первой четвёркой по всем проектам.
sec - длительность секунды в часах, да, я знаю что считать в REAL повышает нагрузку на CPU, но пардон, у вас мощности позволяют то в 2к2+ году
sys - структура системных переменных, которая собирает в себя базовые компоненты, реализация которых отличает у разных производителей:
- флаг TRUE
- флаг FALSE
- импульсы с разным весом, которые живут ровно 1цикл программы
- прочая мелочёвка
Опс, опять что-то новенькое. 1 цикл программы. Да-да, ваш код всегда исполняется от начала и до конца сверху вниз, слевана право. За всякие go_to я лично вырываю руки, ибо нехер.
Итого, на текущий момент у меня в sys лежит:
Дану ёб твою мать, скажете вы, что это за херня? И будете правы!
- x - не потому что хуй, а потому что ON и OFF зарезервированы системой и их нельзя просто так применять;
- Hand - флаги, что хотя бы одно устройство данного типа переведено в ручной режим;
- Alm - флаги, что хоть одно устройство данного типа находится в аварии;
- Any - сборный флаг для всех флагов, привязанных к типам устройств;
- V - Valve, а не то что вы подумали. Клапан, заслонка, задвижка;
- M - не мудак, к сожалению, а Motor. Вентилятор, транспортёр, всё что вращается - всё Motor. Я иногда делю на MD и MDA, дикрестное и дискретно-аналоговое управления, но это личные заморочки, не более;
- DTL - DataTimeL.. хз что за L, типовая структура формата год-месяц-дата-час-минута-секунда, которую мы будем использовать при работе с расписанием и всем, что требует проверки системного времени.
Ну наконец-то! А где код-то? Хрена вам, а не код. Рано.
На очереди ещё одна структура, которая будет всегда и везде, обеспечивая работу вон той страшной картинки наверху, обычно я называю её CMD:
УправлениеУра! Наконец-то! Мы добрались! И теперь...
Видите вон там странный Alarm, которого раньше не было? Видите? И он есть!
А всё почему? Да потому что...
1) мы делаем универсальный код, который будет применим для всего и вся
2) программа - это не только программа, это ещё функциональный блоки функции
В чём же разница? Если кратко - функциональный блок может иметь свои внутренние, приватные, переменные, а функции - работает только с внешними и временными.
СтопЭ. временные и внутренние - какая в пень разница?
Внутренняя - сохраняет своё значения при переходе на новый цикл программы.
Временная - теряет своё значение может содержать случайную величину при переходе на новый цикл программы.
Таким образом, если вы внутри функции делаете А+Б=С и по значению С принимаете решение КАЖДЫЙ раз вызывая функцию, то можно использовать временную. А если делаете А+Б = С один раз и больше к этому не возвращаетесь, только читая С, то нужна внутренняя переменная. И опять таки... если вы хотите сохранить значение С при перезапуске контроллера - будьте добрый, сделать её энергонезависимой, т.е. Retain.
Вернёмся к Alarm. Для функциональных блоков (FB) и функций (FC) есть следующие виды переменных:
- входные - можно только читать
- выходные - можно только записывать
- входные-выходные - как тугая попка трапа, можно и читать и изменять значение
Это очень важно, когда у вас одна и та же внешняя переменная передаётся разныеFC/FB а вы сидите и хлопаете глазками, почему значение теряется посреди программы. Да потому что вы проебались и привязали не к тому типу. Наиболее наглядно сие видно в графических языках:
Слева- входные (input) и входно-выходные (input-output) переменные, справа -выходные.
Фух, разобрались, теперь вызовем нашу страшную функцию:
Драйвера, устройства и состояния
Расширим очко овертона терминологию: драйвер. Нет, это не виндовый драйвер. Но близко. Это некий алгоритм и набор переменных, описывающий работу базового или типового устройства. Входа, выхода, насоса, клапана. Оно беспечивает автомномный контроль:
- безопасности
- аварий
- ручного и автоматического управления
- наработки
Включает в себя все необходимые для жизни параметры и настройки, коих дофига и больше. Но это мы рассмотрим потом. Или не рассмотрим. Если микроскоп вдруг сломается.
Выглядит управление дискретным входом следующим образом:
Итак, для работы драйвера нам необходимы:
- CMD - структура команд, рассмотрена выше
- cfg - структура параметров
- state - структура состояний
Дискретный вход слишком прост и отдельный набор состояний ему не нужен. Состояния включают в себя коды аварий, подсчёт наработки, вспомогательные плюшки для удобства отображения оператору "что тут происходит, мамочки, почему оно встало?!"
use_NC...
NC - нормальной закрытый сигнал
NO - нормально открытый сигнал
Например, у вас есть дверь. Стоит датчик, контролирующий что "дверь закрыта".
Есликогда она закрыта сигнал = 0, а при открытии двери сигнал = 1, это нормально открытый сигнал.
Если когда она закрыта сигнал = 1, а при закрытии двери сигнал = 0, то это нормально закрытый сигнал.
Применение того или иного типа сигнала должно быть продиктовано соображениями безопасности. Например, аварийный стоп - должен быть нормально закрытым сигналом. Есть сигнал - всё хорошо, пропал - всё плохо. Почему так? Потому что Вася уронил топор на кабель и сигнал пропал - вы должны отключить всю систему, чтобы бедного Васю не намотало, превратив в инвалида пожизненно. Да-да, безопасность Васи - Ваша ответственность!
А если это не критичный сигнал, требующий контроля целостности сигнальной линии, то можно смело ставить нормально открытый датчик. Но это теория, а на практике ныне - что найдёте, то и поставите. Сорян.
УУУ, сука, сколько буков то! А это только начало! И я не ответил на главный вопрос - на кой хер нам вообще различать на уровне драйвера тип сигнала? В алгоритме основном поправим, да и делов то. НЕТ! Хватит! Не усложняйте себе жизнь!
Вам, как программисту, должно быть глубочайше насрать какой там тип датчика -сработал это всегда = 1, не сработал это всегда = 0. И именно эту задачу унификации решает драйвер дискретного входа. УНИ-ФИ-КА-ЦИИ, а не загрузки процессорного времени бесполезным хламом. Так менеджеру и ответите, что вы ускоряете дальнейший цикл разработки, ага.
ТаймерыАвтор, ты заебал, где код драйвера? Да вот он, только работать он у вас не будет:
А почему - угадаете? Не, вы не тупые, вы умные. Просто я хитрожопый и вместо системных таймеров использую самописные. Нахуа-хуа? Да потому что системные кривые. И их мало. И каждый системный таймер можно использовать только один раз(если они аппаратные, как в старых ПЛК).
Почему использовать системный таймеры, это грех:
- если вы измените во время работы таймера уставку времени и она окажется меньше, чем уже прошедшее время с момента запуска таймера, то он встанет раком
- нет паузы
- нет сброса
- нет контроля % отсчитанного времени
- и, самое главное, время в формате Time, которое очень неудобно выводить на панель оператора
Самописный таймер решает все эти задачи. Как вы уже догадались, там потребуется структура переменных для него и FC, вот они для самого простого таймера, который используется в драйвере выше:
И весь этот охреневший объём кода вам нужен в промышленном контроллере только для того, что проверить нажатие кнопочки или срабатывание маленького геркончика. Очень мило, не правда ли?)
Благодарю за терпение, забыл важную картинку и не смог отредактировать пост. В прошлом варианте поста были вопрос на тему, почему pulse_01s и pulse_1s имеют тип BOOL и как вообще эта мерзость должна работать. Не зря в начале было сказано об архитектуре, именно её мы затронем третьей части историй после кружечки кофе и предложим своё видение "как оно должно работать", что, естественно, не претендует на истину и даже не носит рекомендательного характера, потому что код каждого программиста индивидуален и уникален, но если мы сможем писать хотя бы так, чтобы сосед слева мог его прочитать - это уже хорошо.
песочница АСУ ТП программирование geek автоматика напитки завод политика длиннопост реактор образовательный
Часть 1, введение
Часть 2, приоритеты и базовые сигналы
Часть 3, каркас архитектуры
Последнее время свербит в одном месте сформулировать мысли, но цэ не очень уместно порою. Посему отвлечёмся на то, как работает маленький, но важный, кусочек нашего мира.
Почему здесь?
Да просто Хабросообщество асушников это унылые токсики, сующие минусы в карму по поводу и без, любящие брать мануалы и копировать как статью или ноу-хау... меня бесит, когда на профильном хабе тебе с умным видом изливают написанное в F1 да ещё обижаются, когда указываешь на сей момент.
О чём речь?
Итак, вот перед вами бутылка. Нет, пластиковая. Хотя любая сойдёт. Но посмотрим на пластик... ну, это могла бы быть кока-кола, но "почему-то" оказался дюшес. Прежде чем попасть к вам на стол, она была в магазине, на складе, в фуре, на складе, в контейнере, фуре... о, вот она, вышла со склада завода. Однако, чтобы туда попасть - её должны были сперва изготовить и налить продукт-с. О том, как она родилась и пойдёт речь. Технология будет чисто для примера и тайны никакой не представляет из себя уже дофига лет (состав напитка не в счёт).
Заебись, всем спасибо, пока.
Шутка.
Когда эти ампулы изготовлены, они отправляются на завод производства напитков. Например, вот рекламный ролик производителя линий розлив с внятным описанием технологии и что для чего используется.
Итак, мы ознакомились с тем как оно выглядит со стороны и пора заглянуть под капот.
Шкафы управления
Шкаф, сука, управления. Управления чем? А вон всей той хернёй, которая двигалась на роликах выше. Всё что шевелится - управляется из ШУ, а что не шевелится - жалкими смертными, вроде нас с вами. Их ещё "операторами" называют. А над ними стоят "технологи", которые должны разбираться в куче страшных циферок на тех маленьких экранчиках, что мелькали в видосиках, и правильно их настраивать. Одна ошибка - и ты ошибся. Спалил движок, погнул валы, испортил партию продукта.
Что живёт в шкафу?
Кратко:
Подробно:
Контроллер
Поскольку я не проектировщик, хоть и могу разобраться в схеме и даже от руки нарисовать, а сраный неИТ-шный программист, то и интересует меня лишь одна часть: МОООЗГИИИ... оу, у кого там от зомбицида лекарство? Нет, давайте без топора обойдёмся, пожалуйста.
Мозги бывают разные: серые, белые, красные...
Жёлтые - это, мать её, безопасность. А знаете сколько раз за мои 12 лет работы я видел их российских ШУ? Угадаете? Правильно. 0 ёбаных раз. Клали в эрафийском общепроме на ёбаную безопасность. Иногда ставят некое реле безопасности, но подключают его так, что лучше бы не ставили вообще, инвалиды безрукие... Может кто-то где-то и использует их, может даже правильно подключает, я за них искренне рад. Но когда в следующей схеме я увижу это дерьмо на текущей работе - мата будет много. Мат - двигатель процесса.
Пробежимся слегка по производителям железа, их особенностям и нюансам.
Siemens - божественный нектар, услада глаз моих...
# Имеет понтовые линейки с кодом "400", которые ставят атомщики и нефтяники. Горячий аппаратный резерв - это к ним.
# Линейка "300" - ...у тракториста. Уверенный середнячок, который уже лет пять пытаются снять с производства, но выходит как-то не очень. Слишком много их продали в 2000-х годах по всему миру.
# Линейка 1500 - пришла на смену 300 и 400, имеет монстров, способных в одну харю утянуть хороших размеров завод, но, сами понимаете - одна ошибка и весь завод ошибся. Не надо так.
# Линейка 1200 - самый ходовой продукт... был. Их вы видели в видео про шкафы.
=> языки: LAD, SFC, FBD, STL, SCL, Graph, ещё какая-то новая херня для очень тупых вышла в 2021 году, но я её не запомнил
=> среда разработки: закрытый проприентарный пакет Step7, WinCC, объединённый в новый TIA Portal
+ единственный в своём роде с полностью свободным доступом ко всей памяти внутри ПЛК, что позволяет творить офигенные вещи и очень сильно оптимизировать код
+ огромный форум со всеми вопросами и ответами, отличная документация, стабильный как кирпич, пока не ёбнешь молотком на 220
+ единственный в своём роде, кто позволяет загружать программу большими кусками без остановки контроллера (у остальных есть "нюансы" или ограничения)
- закрытая среда разработки, специфичный синтаксис с куче # и ", из-за чего прямой перенос кода на другие системы невозможен, всё ручками, будьте добры
$$$ дорого, но кря кря, 30 дней триала
ОВЕН - для диспетчеризации и садомазохистов
# Имеет широкое распространение среди любителей сэкономить
=> языки: LAD, FDB, CFC, ST
=> среда разработки базируется на CoDeSYS, что обеспечивает хорошую совместимость с большой кодовой базой, пока вам не нужно что-то специфичное
+ . . .
- их тоже больше не будет
- за его цену вы можете взять siemens 1200 и не знать горя
- теряет программу, слабый проц, мало памяти, нет внутренней шины для модулей ввода-вывода
- документация, техподдержка? не, не слышали
$$$ бесплатно, как сыр в мышеловке
OMRON - японцы, которым запретили хентай, решили поебаться сами с собой
# Старая линейка CJ/CP, которая что-то может, но лучше бы вам говнокодить, иначе не вывезет
# Новые линейки, в которых чёрт ногу сломит, много решений заточенных под координатное управление и перемещение
=> языки: LAD, FDB, ST
=> среда разработки: закрытый проприентарный пакет CX-Programmer и SYSMAC
+ оно шевелится и шевелится хорошо, только надо сперва придрочиться
- слабая документация
$$$ дорого, но кря
B&R - когда-то я считал, что хуже овна ничего быть не может...
# Большой спектр решений, много ОЕМ продукции
=> языки: LAD, ST, C
=> среда разработки: закрытый проприентарный пакет B&R Automation
+ хорошо умеют себя продавать
+ поддерживают С
- ошибки компилятора памяти
- программа управления может повредить ОС контроллера
- нельзя сохранить исходник в контроллере или скачать обратно загруженный код и отредактировать, нет проекта - нет проекта
$$$ 30 дней и плати
Shneider Electric - ваша головная боль и ваш бич, когда вы ловите ошибку, которой нет в документации
# Дичайший зоопарк железа и сред разработки, намешана прорва Legacy в одну кучу
=> языки: LAD, FDB, ST
=> среда разработки базируется на CoDeSYS, что обеспечивает хорошую совместимость с большой кодовой базой, пока вам не нужно что-то специфичные
+ большое количество фирменных библиотек для всей линейки дополнительного оборудования собственного производства
+ документация на уровне Siemens, но без форума техподдержки
- есть много мелких нюансов, которые никто нигде не раскроет, а вы разобьёте себе голову о стену пока в них разбираетесь
$$$ 30 дней и плати, привязка к аккаунту
Carel - для вентиляции и отопления самый торт, много готовых программ и решений. ST, LAD, FDB. Бесплатно на 30 дней. Считается импортозамещением, лол.
Beckhoff - Win10+виртуальный контроллер сверху. Хорошо работает, но дела с ними не имел.
Rockwell, Honeywell - что-то слышал, пару раз видел, дорого-богато.
В целом на этом список ходовых прошлогодних решений заканчивается. Наступает 2022...
Со временем, когда остынет мой пукан, я внятно расскажу о китайских и новых импортозамещённых решениях, но не сейчас.
Разработка
Итак, как программиста, нас интересует раздел "языки":
LAD, FBD, SFC/CFC, ST
Как мы видим, все кроме ST - графические языки. Ах да, все они - группа языков стандарта IEC 61131-3. Перенести графические языки между средами разработки - адская, невыносимая боль, потому каждый гад считает нужным делать собственный визуальный редактор с извращённым функционалом и заморочками. К слову, самый крутой редактор LAD - у Seiemens. Для FDB мне больше всего понравился Carel cSuite.
В связи с этим, мы обратим свой взор на ST и будем дальше ковыряться исключительно в нём. Для Siemens это будет SCL (а STL у них - мерзотный древний язык, который вроде как может дофига всего, но только для сименса и вы без глаз останетесь во время его отладки, когда одна переменная / команда - одна строка, а ещё они зеброй подсвечены, фу, чур меня чур).
И теперь, с этого момента мы перейдём к сути...
Всё есть дискрета и аналог. Всё. Без исключений.
Дискретный вход.
Дискретный выход.
Аналоговый вход.
Аналоговый выход.
Дискретный - он либо есть, либо нет. Как секс.
Аналоговость - определяется качество, условно говоря.
И то, и другое нужно обработать, перед тем как использовать. Те кто пытается в user-friendly, как овно, берёт самостоятельно на себя первичную обработку сигнала, что вызывает адские муки когда надо что-то изменить, потому что это нельзя вывести на ту кнопочную панельку и сказать: "Чел, зайди туда, нажми это и отъебись." Нееет, нихуя, вы должны собирать монатки, закупать билеты и пиздюхать в жопу мира ради 5 минут правок и 100 минут поиска "где этот ебаный бэкап". Ну вот надо ли оно вам, а?
Из всех этих сигналов, как из кубиков и складывается управление всем процессом и его контроль. Кажется, я слегка разбежался, а дальше на рассмотрении недра "под капотом", которые будут интересны не всем. Нырнём в них в следующей части.)