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

Сигнал — это не просто 0 или 1
Первое, что пришлось принять: одинаковое значение 1 у разных сигналов может означать совершенно разные вещи.
Условно:
X— входы PLC. Часто это датчики, кнопки, аварийные цепи, концевики.Y— выходы PLC. Это не датчик, а состояние выходной команды.M— внутренние биты, в том числе аварии и события.D,W,GD— регистры и слова, где могут быть параметры, состояния, аналоговые значения и прочая «небитовая» история.L/Mвнутри ladder-логики — отдельная боль, потому что это может быть не физический сигнал, а промежуточное условие.
Самая опасная ошибка — смотреть на адрес и сразу делать вывод. Например, если Y320 = 1, это не значит, что мы что-то включили. Это значит только: PLC держит выходную команду включенной. Мы её читаем. Не пишем, не форсим, не управляем.
Это важная граница, особенно на реальном оборудовании.
Сначала я собрал карту мира
Данных было много: выгрузки, Excel-файлы, карты сигналов, следы из интерфейсов, фрагменты логики. Я не пытался сразу превратить всё это в production-сборщик. Сначала сделал более скучную, но полезную вещь: разложил сигналы по справочникам и сохранил связь с исходными строками.
Один из сырых индексов получился на 4710 записей:
X: 372Y: 287M: 450D: 3393W: 188GD: 20
Но читать всё подряд — плохая идея. Такой индекс нужен скорее как аудит: откуда взялся адрес, какая была исходная строка, какой confidence, какой priority. Если потом две книги спорят между собой, можно вернуться к источнику, а не гадать по памяти.
После дополнительных документов справочники уточнились. Например, по входам остался один дополнительный X, который пришёл из электрической схемы. По аварийным M появился один новый бит вне основного диапазона — M6475, как гипотеза из активной трассировки. По аналоговому слою добавились несколько регистров ошибок модулей.
То есть финальная сводная карта не дала новых физических входов/выходов, но помогла проверить, что текущие справочники не разваливаются.
Самый полезный слой — аварии
Отдельная большая часть работы была вокруг M-битов аварий и событий.
Сначала это были просто адреса. Например:
M6001 = 1
Как диагностировать такое? Никак, если нет контекста. Максимум можно сказать: «какой-то M-бит включился». Для человека у станка это почти бесполезно.
Поэтому я усилил справочник аварий:
- добавил человекочитаемые тексты аварий;
- разложил аварии по категориям;
- добавил экран интерфейса, где это может отображаться;
- добавил связи с устройствами, если они были в источниках;
- добавил активные трассировки;
- добавил поля вроде «что проверить» и «какой процесс затронут».
В итоге книга аварий выросла до 451 M-бита:
M6001–M6450
+ M6475
= 451
Плюс добавились 58 строк active alarm trace. Из них часть с высокой уверенностью, часть — с низкой. И это нормально. Лучше честно хранить confidence, чем делать вид, что всё известно точно.

Важная поправка: авария не всегда напрямую связана с датчиком
Наивная схема выглядит так:
датчик X сработал
→ авария M включилась
→ нашли причину
Иногда так и есть. Например, часть аварий действительно напрямую связана с X.
Но часть аварий приходит через внутреннюю логику: servo-биты, L/M-условия, D/W-регистры или вообще пока без понятного физического источника.
Поэтому правильная диагностика выглядит скорее так:
если M = 1
→ получить текст аварии
→ получить категорию
→ найти экран интерфейса
→ посмотреть related X/D/W, если они есть
→ посмотреть внутренние условия
→ понять, что реально проверять руками
Это уже не просто сбор данных. Это перевод с языка PLC на человеческий язык.
Y-выходы: читать можно, трогать нельзя
Следующий важный слой — Y.
Я хотел проверить, можно ли безопасно читать состояния выходных команд PLC. Для этого сделал smoke-test по справочнику Y: 287 выходов, только read-only.
Правило было жёсткое:
Y читаем
Y не пишем
Y не форсим
Y не используем как управляющий канал
В коде не должно быть write, force, reset, remote control и прочих опасных вещей. Только чтение.
Тест шёл через MC/SLMP 3E Binary, командой 0401 batch read, в bit-режиме.
Результат smoke-test:
Y signals planned: 287
read_ok: 287 / 287
all_cycles_ok: 287 / 287
batch reads ok: 40 / 40
batch reads failed: 0
errors: 0
За 5 циклов чтения:
- в последнем цикле активны были 61 Y-адрес;
- 4 выхода менялись за время теста:
Y081,Y084,Y1A0,Y32B.
Для диагностики это полезно: значит слой Y не просто формально читается, а отражает живое состояние выходных команд PLC.
Но ещё раз: это не управление. Это контекст.
Хорошая диагностическая цепочка может выглядеть так:
PLC command Y
→ feedback X
→ alarm M
Например, PLC дал команду, дальше мы смотрим, пришла ли обратная связь, и если нет — какая авария поднялась.
Немного про команды чтения
Я не буду углубляться в протоколы, но одну мысль зафиксирую.
Для разных задач подходят разные команды:
0401— читать большие последовательные диапазоныX/Y/M/L/D;0406— читать несколько разнесённых блоков одним запросом;0403— читать редкие одиночные адреса;0801 + 0802— monitor registration/execution для стабильного набора, но с ограничениями;0601— читать buffer memory intelligent modules, например для аналогового слоя, если стандартные device memory не подтверждены;0613— buffer memory Ethernet-модуля, скорее для диагностики коммуникации.
И рядом всегда лежит красная табличка: существуют команды записи и remote-control. Их легко случайно перепутать, если работать невнимательно. На заводе такая невнимательность может стоить слишком дорого.
Что я для себя вынес
Главный вывод: диагностика начинается не с модели и не с дашборда. Она начинается с нормального словаря сигналов.
Если коротко, практический порядок такой:
- Собрать сырой индекс всех адресов и не потерять ссылку на источник.
- Разделить сигналы по смыслу: входы, выходы, аварии, регистры, внутренние условия.
- Не читать всё подряд — сначала понять, что можно читать и зачем.
- Для аварий хранить человеческий контекст: текст, категорию, экран, связи, что проверить.
- Для Y зафиксировать read-only правило на уровне данных и кода.
- Хранить confidence. Если связь гипотетическая, пусть так и будет написано.
- Проверять чтение smoke-test’ами, а не верить Excel-файлам/инструкциям/записочкам с производства на слово.
- Не путать наблюдение и управление.
Для ML-инженера это, может быть, не самая гламурная часть работы. Тут нет нейросети, которая красиво предсказывает аварию за час. Зато без этой базы любая модель будет учиться на каше из непонятных битов.
А когда сигнал превращается из M6001 = 1 в понятное событие с категорией, экраном, связями и списком проверок — у диагностики появляется шанс быть полезной до того, как ситуация станет аварийной.
И вот это уже похоже на нормальную инженерную работу: не просто собрать данные, а сделать так, чтобы по ним можно было принять правильное решение.