В логах запуска нашего стенда давно живёт строка:

Failed SDO download 0x6060 (-22)

Мы её лечили. Всерьёз: разбирали шаблон конфигурации, спорили, куда переносить запись режима, прикидывали обходные пути. Потом заметили то, с чего стоило начать: та же строка печатается и в удачных запусках. Оси выходят в Operation enabled, статусворды чистые, станок ездит — а строка на месте. Ошибка оказалась шумом — а мы на неё убили пару вечеров.

Это второй текст про наш стенд (первый — про то, почему EtherCAT в LinuxCNC держится на компоненте из 9 коммитов). В комментариях к нему я пообещал разобрать тему «принял ≠ сделал»: почему подтверждение на полевой шине почти никогда не означает того, что от него ждёт человек, глядящий в лог. Обещал — разбираю. Всё на живых примерах с того же стенда: три сервопривода Inovance IS620N в режиме CSP, сервопривод Wecon VD3E в режиме скорости (он у нас играет роль шпинделя — настоящего шпинделя на стенде нет), каплер Omron под дискретное IO, LinuxCNC поверх IgH-мастера.

Пометки те же, что в прошлый раз: [замерено] — проверили железом, [из паспорта] — из документации, [не знаем] — честно не знаем.

Четыре разных «принял»

Когда мастер что-то пишет в привод, подтверждений на пути несколько, и каждое отвечает на свой узкий вопрос. Беды начинаются, когда ответ одной ступени принимают за ответ другой.

Ступень

Что подтверждает

Чем проверяется

На что НЕ отвечает

Кадр вернулся

слейв жив, датаграмма прошла по кольцу

working counter (WKC)

принял ли слейв данные

SDO ack

объект записан в словарь

ответ мейлбокса

применилось ли значение

Состояние перешло

машина состояний сменила ступень

statusword, 0x6061

здорова ли система в целом

Железо сделало

вал крутится, как велели

независимый замер

Каждая ступень нас в своё время укусила. Дальше по порядку.

SDO ack: ошибка бывает в обе стороны

Начнём с той самой строки. -22 — это EINVAL из ядра Linux. У наших приводов она появляется, когда объект уже замаплен в PDO: привод отвергает SDO-запись в то, что и так едет циклическим обменом. Диагноз, замечу, поставлен по поведению, а не по документации — ни Inovance, ни Wecon этот случай в мануалах не описывают. Работает ли то же правило у других вендоров — [не знаем].

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

Интереснее зеркальный случай: ack есть, а дела нет. Классика профиля CiA 402 — режим работы. Запрашиваешь его записью в 0x6060 (Modes of operation), а фактический режим привод показывает в другом объекте — 0x6061 (Modes of operation display). Запись в 0x6060 может пройти с ack и не изменить ничего: привод вправе не принять режим, который не поддерживает или не может включить сейчас. Правильная процедура — написал в 0x6060, жди совпадения в 0x6061. Пара «команда в одном объекте, факт в другом» в профиле повсюду: controlword/statusword устроены так же. Команда и состояние — принципиально разные вещи, и профиль их разводит по разным объектам.

Третья история про ту же ступень — сброс ошибок. На Wecon VD3E мы снимали Er.40 (протухшая батарея мультиоборотного энкодера при первом включении) прямо по шине, из PREOP, через мейлбокс [замерено]: запись 0x200A:06 = 1 сбрасывает счётчик оборотов энкодера, затем 0x200A:03 = 1 снимает сам fault. Обе записи возвращают ack независимо от того, наступил ли эффект. Порядок важен, а после сброса счётчика позиция прыгает — дальше обязателен homing. Ack на каждую команду при этом безупречен.

А самый чистый случай нам подарили приводы Inovance. Однажды все три разом зажгли Er.E08. По шине читается 0x603F = 0x0E08, statusword 0x0218 — бит fault поднят. В мануале это EE08.0, «потеря сигнала SYNC», и там же чёрным по белому: сбрасываемая.

Шлём fault reset. Запись проходит, ошибок нет. Statusword не меняется. Шлём ещё раз — тот же результат.

Причина оказалась в том, что фолт сетевой. Приводы стояли в OP и ждали сигнал синхронизации, а мы уронили мастер, не сняв с них перед этим enable. SYNC исчез — все три защёлкнули ошибку. Снять её командой по той же сети, которая лежит, невозможно: условием снятия является восстановленный SYNC, а его нет. Ack при этом приходит исправно: мейлбокс живой, сообщение он принял и записал. На фолт это не влияет никак.

Лечится двумя способами [замерено]: передёрнуть питание приводов (энкодеры абсолютные, привязка нуля не теряется) либо поднять полноценный циклический мастер с валидным DC — и тогда ровно та же команда, которая только что была бесполезна, сбрасывает фолт штатно.

Одна и та же команда, одинаковый ack — и разный результат, смотря есть на шине SYNC или нет.

Состояние перешло — это ещё не здоровье

Привод по CiA 402 включается лесенкой: Shutdown → Switch on → Enable operation, команды уходят словом controlword, ответ читается битами statusword. Отправленный controlword не значит ничего — состояние сменится через несколько тактов, а может и не смениться. Ждать нужно биты, и ждать с таймаутом. Этим, собственно, и занимается компонент cia402.comp из первой статьи.

У нас из этого выросло жёсткое правило платформы: «момент снят» означает соответствующие биты statusword, прочитанные из железа, — и никогда не «команда disable отправлена». Пока железо не подтвердило, привод считается под моментом, со всеми вытекающими для того, кто собрался лезть к станку руками.

Но самый поучительный укус был выше по лестнице. Приводы то доходили до OP, то отваливались, в dmesg сыпалось:

Unexpected realtime delay on task 0 with period 1000000

Мы копали HAL. Потом период. Потом порядок функций в servo-thread. Виноват оказался сам компьютер: на машине с мастером параллельно крутились тяжёлые сборки, и спайки планировщика срывали цикл. Разгрузили машину — всё прошло. Формально каждый слейв честно сообщал своё состояние, и ни одно из этих состояний не говорило «у вашего мастера нет времени на шину».

Железо сделало: замер не должен проверять сам себя

Верхняя ступень — единственная, где вопрос закрывается: вал действительно крутится так, как велели? Здесь своя ловушка.

Когда мы калибровали шкалу скорости VD3E, первым желанием было прочитать скорость обратно из привода — объект 0x606C — и сравнить с уставкой. Нельзя: обратная скорость проходит через ту же шкалу, которую мы проверяем. Такой замер подтвердит любую ошибку — обе величины посчитаны одной формулой.

Мерить надо по сырому счётчику вала (0x6064) и обычным часам: задал скорость, взял прирост за интервал, поделил.

Для этой статьи мы собрали такой замер в отдельный скрипт — сотня строк python поверх утилиты ethercat, без LinuxCNC, без PDO-цикла, без вендорного софта. Все скрипты из этой статьи выложены здесь: sdo-probing, там же разбор каждой грабли. Попутно выяснилась приятная вещь: VD3E разрешает пройти всю лесенку CiA 402 и крутить мотор в Profile Velocity одними SDO прямо из PREOP [замерено] — Мастер IgH при этом нужен — скрипт зовёт его утилиту, — но довольно фазы Idle: ни realtime-ядра, ни циклического обмена. Сам скрипт устроен по чеклисту этой статьи: пишет 0x6060 — ждёт 0x6061, шлёт controlword — ждёт биты statusword, а «мотор остановлен» проверяет чтением statusword, не фактом отправки команды.

Результаты. На уставках 0.2–0.5 об/с заданная и измеренная скорости сошлись с точностью +0.01% [замерено] — привод отрабатывает уставку в counts/s очень точно. Оговорюсь сразу, потому что это важно и я сам споткнулся об это ниже: такой замер подтверждает линейность и стабильность, но не абсолютное число отсчётов на оборот — уставку я задавал через ту же константу, на которую потом делил. Абсолютную шкалу мы подтвердим в конце статьи, и совсем другим способом. Внятного ответа про единицы (counts/s) в документации нет — добывали замером.

Первый прогон малых уставок дал пугающие числа: на 0.01 об/с среднее разошлось с уставкой на 6%. «Шкала плывёт на малых оборотах» — вывод уже почти поехал в текст. Потом посмотрели на график мгновенной скорости: первые полсекунды мотор разгоняется, и весь этот разгон сидел внутри окна усреднения. Выкинули из окна первую секунду — на 0.5 об/с осталось +0.01%, а на 0.01 об/с — минус 3.5% [замерено]. Разгон тут ни при чём: это рябь регулятора, период её колебания около двух секунд [по графику], пятисекундное окно ловит неполные периоды и не даёт ей усредниться.

Мгновенная скорость подтвердила диагноз: на 0.2 об/с она держится в пределах ±5% от уставки, а на 0.01 об/с гуляет ±12% [замерено]. Отсюда два правила: масштаб меряется на приличной скорости, где рябь тонет в сигнале, и окно замера не должно содержать разгон.

Редуктор, которого мы чуть не объявили декоративным

Пока мотор был под рукой, проверили объект 0x6091 (gear ratio) — стандартный электронный редуктор профиля. У обоих наших вендоров он с завода 1:1 [замерено]. Пишем в числитель двойку: запись проходит, обратное чтение честно показывает 2. Повторяем замер скорости — числа ровно те же, что при 1:1.

Вывод напрашивался: объект принимается, подтверждается чтением и ни на что не влияет. Так и записали в черновик.

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

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

Настройка 0x6091

Прирост счётчика за 5 оборотов

На один оборот

1:1

42 203 264

8 440 653 (номинал 8 388 608, +0.6%)

2:1

20 787 053

4 157 411 (ожидалось 4 194 304, −0.9%)

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

Попутно рука закрыла и второй вопрос. Разрешение энкодера привод по шине не сообщает: стандартные объекты 0x608F (encoder increments) и 0x6092 (feed constant) у VD3E отсутствуют — «object does not exist» [замерено]. То есть 8 388 608 было у нас только из паспорта. Теперь оно подтверждено физически, с точностью 0.6% на пяти оборотах рукой.

Неподвижный вал даёт дрожание счётчика в пределах ±7 отсчётов из 8 388 608 [замерено]. Три десятитысячных градуса — разрешение, на котором виден электрический шум.

Сколько стоит спросить привод

Раз уж «ack приходит мгновенно, а дело делается позже» — попробуем измерить это самое «позже». Двадцать раз проходим лесенку CiA 402 и засекаем, сколько миллисекунд проходит от записи controlword до появления нужных битов в statusword.

Результат: ровно 64 мс на каждой ступени, на всех двадцати прогонах, с разбросом в единицы миллисекунд. Подозрительно ровно.

Так и есть: 64 — это две наши же SDO-транзакции, запись и чтение. Одно пустое чтение statusword стоит 32 мс, и весь замер упёрся в собственный прибор. Привод переключается быстрее, чем мы способны заметить; насколько быстрее — этим методом [не знаем].

Зато попутно выяснилось кое-что полезнее. Раскладываем эти 32 мс на составляющие — медианы двадцати пяти повторов [замерено]:

Операция

Время

запуск процесса (/bin/true)

0.57 мс

ethercat version

1.5 мс

ethercat master — состояние, шину не трогает

1.4 мс

ethercat sdos — перечислить весь словарь

5 мс

ethercat upload — прочитать один параметр

32 мс

переход лесенки CiA 402 (= две транзакции)

64 мс

Запуск процесса — полмиллисекунды. Утилита ethercat со всей инициализацией — полтора. Чтение состояния мастера, которое не трогает шину, — те же полтора. А одна SDO-транзакция — 32 миллисекунды, в двадцать с лишним раз дороже всего локального.

Дело не в скорости провода: мейлбокс обслуживается мастером в его собственном ритме, и у мастера, который просто стоит в Idle без циклического обмена, этот ритм неспешный. То есть 32 мс характеризуют режим, в котором мы спрашиваем. К скорости привода и к EtherCAT это число отношения не имеет. Сколько это будет при поднятом цикле — мы не мерили [не знаем], но ожидаем заметно быстрее.

Мы читаем у привода полный паспорт — три сотни параметров — и делаем это по SDO. Время растёт линейно:

Сколько читаем

Время

Что это

60 параметров

1.97 с

реальный замер

109

3.5 с

объектов в словаре VD3E

300

9.6 с

паспорт привода целиком

437

14 с

все читаемые записи с субиндексами

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

Перечислить весь словарь объектов (ethercat sdos) стоит 5 миллисекунд — мастер отдаёт его из своего кеша, собранного при сканировании шины.

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

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

У привода есть два способа представиться. Первый — сервис SdoInfo: мастер спрашивает «перечисли свои объекты», привод отвечает списком. Второй — конкретный объект 0x608F, в котором по стандарту лежит разрешение энкодера, самое нужное число для расчёта масштабов.

Четыре привода на нашем стенде — четыре разных ответа [замерено]:

Привод

Словарь по SdoInfo

0x608F (разрешение энкодера)

Битность

Режимы 0x6502

Mitsubishi MR-J4-20TM

809 объектов

отдаёт: 4 194 304

22

0x3AD

Schneider LXM28E

не отдаёт

отдаёт: 1 048 576

20

0xED

Wecon VD3E

109 объектов

объекта нет

23

0x3AD

Inovance IS620N

не отдаёт

объекта нет

23

0x3AD

Mitsubishi выгружает почти весь свой параметрический мир — та самая «тысяча параметров», которой славится серия. Wecon отдаёт компактный словарь ровно в 109 объектов — столько же, сколько объявлено в его ESI: заявленное совпало с фактическим, что бывает не всегда. Schneider словарь не перечисляет, зато честно сообщает разрешение энкодера. А Inovance молчит по обоим каналам: объекты у него есть и читать их можно, но ни перечислить себя, ни назвать разрешение он не умеет — потому в экосистеме LinuxCNC под него и живут плагины со списками объектов, вбитыми из документации.

Ни один не самоописывается полностью, и ломается каждый в своём месте. Поэтому «подключил привод — мастер сам всё узнал» у нас не вышло ни с одним из четырёх.

Зато 0x6502 — маска поддерживаемых режимов — у Inovance, Mitsubishi и Wecon совпадает до бита: 0x3AD, то есть PP, PV, TQ, homing, CSP, CSV и CST. Три вендора, три ценовых сегмента, одинаковый набор возможностей. У Schneider маска другая (0xED): циклических режимов по скорости и моменту у него нет вовсе, только CSP. Это к вопросу о том, что «поддерживает CiA 402» — фраза с очень разным наполнением.

(Schneider на момент замеров стоял обесточенным, его числа — с июньской сессии, когда он был на шине. Остальные три перепроверены сегодня.)

Та же лестница — в наших собственных тестах

Честное признание из прошлой статьи, теперь с подробностями. Нам захотелось больше телеметрии, и мы добавили приводу второй TxPDO. Тесты конфигурации — зелёные. Запуск — слейв падает.

Тесты проверяли, что нужные строки присутствуют в сгенерированном XML. Строки присутствовали. А то, что IS620N принимает только один TxPDO, — знание про привод, и в тестах его не было. Зелёный тест уровня «строка есть» — это ack: он подтверждает работу нашего генератора, но молчит о том, съест ли конфигурацию железо.

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

Что у Wecon получилось хорошо

Раз уж VD3E дал половину примеров, скажу о нём отдельно: по-русски об этом приводе почти ничего нет.

Сначала о том, как он вообще попал на стенд. Мы написали производителю напрямую, тогда ещё как частное лицо — без юрлица, без партнёрских статусов, просто «хотим попробовать ваш EtherCAT-серво». Ожидали вежливого отказа или требования минимальной партии. Оказалось, минимальная партия — одна штука: менеджер собрала комплект (мотор с 23-битным энкодером и тормозом + привод + три кабеля), оплата прошла через их экспедитора, и коробка из Фуцзяни доехала до стенда. Весь комплект 750 Вт обошёлся в 26 тысяч рублей с доставкой до Москвы [замерено на своём кошельке]. Документация у завода открытая — онлайн-портал docs.we-con.com.cn: оттуда мы брали и мануал VD3E с картой суффиксов энкодера, и прошивочные архивы. ESI-файлы и конфигуратор — на прямой странице Servo → Download, её нам прислал сам завод в ответ на вопрос. Контакты завода публиковать здесь не буду; кому интересно повторить — пишите в личку, поделюсь.

Плюсы:

  • словарь объектов честно читается с шины (SdoInfo), и он же целиком лежит в ESI — каталог параметров собирается офлайн, без железа;

  • вся лесенка CiA 402 работает по SDO из PREOP — привод проверяется скриптом при мастере в Idle, без циклического обмена и realtime-ядра [замерено];

  • 0x603F отдаёт номер ошибки как на индикаторе (прочитал 0x28 — это Er.40), сброс ошибок — тоже по шине из PREOP;

  • режим момента живой: 0x6071 маппится в PDO [из паспорта];

  • 23-битный абсолютный многооборотный энкодер: 8 388 608 отсчётов на оборот подтверждены физическим замером (+0.6% на пяти оборотах рукой);

  • 0x6091 (электронный редуктор) работает строго по стандарту [замерено];

  • завод отвечает на технические вопросы: наши ответы про SdoInfo и битность энкодера пришли от их инженера, с прямыми ссылками на файлы.

Минусы (по большей части формальности, но знать их надо заранее):

  • нет SDO Complete Access — параметры с субиндексами пишутся по одному;

  • ESI строго парный к прошивке: мастер сличает vendor/product/revision, свежая прошивка без свежего ESI не поднимется [из паспорта];

  • единицы скорости (counts/s) внятно не документированы — мы добывали их замером;

  • один TxPDO, как и у Inovance: вся циклическая телеметрия — в один набор;

  • разрешение энкодера по шине не сообщается: 0x608F и 0x6092 отсутствуют в словаре [замерено] — автоматике придётся брать его из ESI или из паспорта;

  • первый пуск мультиоборотного энкодера встречает Er.40 (батарея) — лечится по шине, но об этом надо знать.

Чего мы до сих пор не знаем

  • Что означает -22 на SDO-записи у других вендоров. У наших двух это «объект замаплен в PDO», и то — диагноз по поведению.

  • Есть ли у Er.E08 штатный путь снятия без поднятия полного циклического мастера и без передёргивания питания — в мануале мы его не нашли, вопрос вендору отправлен.

  • Джиттер под мейлбокс-нагрузкой. Мы читаем полный паспорт привода — три сотни параметров по SDO — на живой шине, вперемешку с циклическим трафиком, и ни разу не мерили, что это делает с джиттером. Вопрос прилетел в комментариях к прошлой статье и уже стоит в списке замеров.

  • Шаг коррекции Distributed Clocks. В комментариях называли 20 нс — не проверяли, врать не будем.

  • Природу двухсекундной ряби на сверхмалых оборотах: регулятор, механика, дискретность — не разбирали.

  • Передаточное число механики. В нашей модели станка у шпинделя записан редуктор 1:50, и проверить его сейчас нечем: на стенде мотор с голым валом, никакого шпинделя за ним нет. Всё измеренное здесь живёт до редуктора. Пока это число — замысел, а не факт, и помечено соответственно.

Чеклист вместо выводов

  • Ack транспорта ≠ запись. Запись ≠ применение. Применение ≠ здоровье. Здоровье ≠ результат.

  • Написал в 0x6060 — прочитай 0x6061. Послал controlword — жди биты statusword, с таймаутом.

  • «Момент снят» — это биты statusword, а не отправленная команда.

  • Ошибка в логе ≠ отказ: сначала проверь, нет ли её в успешных прогонах.

  • OP у слейва ≠ здоровье системы: слейв не знает, что твой мастер перегружен.

  • Замер не имеет права проходить через проверяемую шкалу. Эталон ищите снаружи цепочки — иногда это просто рука на валу.

  • Тест «строка в конфиге есть» проверяет твой генератор, а не привод.

Скрипты всех замеров из этой статьи — в папке sdo-probing: проверка шкалы, замер редуктора рукой на валу, тайминг лестницы CiA 402. Запускаются без нашего софта, приводу достаточно PREOP. Рядом лежат рабочие конфигурации стенда — XML для lcec, HAL, кинематика, настройка реального времени в виртуалке, — и разбор граблей к каждой. Карты объектов по вендорам собраны в открытый реестр: synctwin.ru/ethercat/.

Комментарии (0)