Pull to refresh

Comments 31

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

Ну, обычные & и &mut, и хороший компилятор, который бы такой фигни не допустил.

Но зачем на Rust, если можно продолжать кушать этот вкусный колючий кактус?

PLC - это другой мир. Там ваши стоны просто не поймут.

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

Сценарии, которые просто описать на релейном языке, не менее просто описать и на любом другом языке. Это ж тупо логическое выражение. Живучесть IEC 61131-3 меня просто поражает. Кому это вообще удобно?

Тем, кто привык делать ещё настоящие релейные схемы, которые потом на электромеханических реле реализовывались. Но для тех же Siemens S7 язык релейных схем -- просто один из возможных вариантов написания схем, никто не заставляет им пользоваться.

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

Поиск такой неисправности осуществляется анализом в отладчике. И тут язык LD подходит идеально.

Ну вот вам реальный пример логического выражения в LD (Step7)

Пример

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

А вот что можно увидеть в этом примере:

  • Логическое выражение с дюжиной элементов представлено очень компактно. Сразу видно логические связи между компонентами. Одна из самых типовых задач поддержки - выяснить, почему нажатие кнопки не запускает механизм. При запущенном отладчике вы сразу увидите, какие "контакты" замкнуты, а какие - нет. Кнопка - слева, выход - справа. Сразу видно, где не проходит "сигнал". А теперь представьте, как вы будете отлаживать это же выражение в языке программирования на основе текста.

  • В логике автоматизации есть свои паттерны и стандартные элементы: "передний фронт", "задержка включения", "триггер" и т.д. В примере элемент -(P)- выделяет передний фронт. Да, это тоже можно реализовать в "обычном" ЯП. Но код будет гораздо менее читаемым. В качестве паттерна здесь же можно увидеть так называемый "подхват": по нажатию кнопки I762.6 логический сигнал на механизм M440.4 "закорачивает" кнопку и удерживает механизм в рабочем состоянии, пока он не доедет до конца. В LD этот паттерн виден с первого взгляда. Чтобы это же увидеть в логическом выражении из &&, II, if, вам нужно будет прочитать его целиком.

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

Я бы не сказал, что "релейная логика" очень уж удобная. Самый адский недостаток - невозможность использования со стандартным инструментарием типа git. Но достоинства LD-логики **в её области применения** перевешивают недостатки, и никто пока не спешит предоставить достойной алтернативы.

Отмечу также, что, по моим наблюдениям, логика промышленной установки процентов на 80..90 состоит из выражений, подобных приведенному примеру, и "релейная логика" работает в них очень хорошо. Но в некоторых частях программы больше подходит как раз "традиционный" императивный код. Например, без этого сложно обойтись, когда реализуешь коммуникацию с приводами. И конкретно в Step7 тут засада: приходится писать на ассемблероподобном STL. В других реализациях МЭК с этим попроще: есть язык ST. К чему это я? МЭК-языки создавали неглупые люди, и всем тамошним инструментам есть свое применение.

Прошу прощения за пропущенный рис.3:

Рис. 3. Функциональные блоки управления штабелером
Рис. 3. Функциональные блоки управления штабелером

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

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

А что с терминологией не так?

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

удалось установить, что флаг изменяется еще в одном месте.

Я так и не понял, какой флаг - то ли вы на состояние гонки налетели (что в ПЛК вполне возможно), то ли на баг в самом ПЛК (что тоже бывает).
Мы делаем подобную автоматику на двух датчиках обычно (штабелер открыт/штабелер закрыт) и двух управляющих сигналах (открыть штабелер/закрыть штабелер) - сильно упрощает жизнь.
В LD я уже давно не заходил, с тек пор как мы переехали на ПЛК от B&R.
Я тоже всеми руками за автоматы, и мы программируем всё в основном на С/С++, благо Automation Studio это позволяет. Кое-что ещё на ST.
Соответственно всё строится на основе switch структуры, как-то так:

switch (currentState) {
   case ST_IDLE:
       // do something in the idle state
       break;

    case ST_STOP:
       // do something in the stop state
       break;

    // etc...
}

Я так и не понял, какой флаг - то ли вы на состояние гонки налетели (что в ПЛК вполне возможно), то ли на баг в самом ПЛК (что тоже бывает).

Почти согласен. Но только выше шла речь о реле "пауза". Ниже я его обозвал флагом. Это путает. Все дело в спешке. Надо, конечно, вычитывать и быть внимательнее (речь обо мне, естественно).

Я тоже всеми руками за автоматы, и мы программируем всё в основном на С/С++

И это правильно. Только попробуйте реализовать автоматы так, как описано у меня, т.е. не спешить изменять состояние в пределах case, а запоминать его где-то (у меня - массивы), а уж потом делать его текущим. У вас, во-первых, появится параллелизм, а, во-вторых, будет понадежнее. А чтобы было совсем надежно, нужно действия привязывать к состоянию, т.е. по типу автоматов Мура. В этом случае просто исключаются "гонки" в пределах параллельных переходов множества автоматов. Такой прием заменяет собой теневую память для действий.

А, тогда ясно, если речь шла о реле "пауза".
С параллелизмом у нас всё хорошо и так - у B&R это работает "из коробки" - есть таски-задачи, которым я даже могу задать различное время цикла, между задачами можно обмениваться данными и так далее. Всё это детерминированно и в реалтайме. Там можно местами к среде разработки придраться, но в общем норм. Мне Automation Studio даже чем-то больше чем TIA Portal нравится (хотя и не всем).

С параллелизмом у нас всё хорошо... 

Если это так, то Вы счастливый человек ;) Но, может, все же проверим?

Создайте модель RS-триггера, которую я привел. А к нему для полноты еще и счетчик.

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

Ну, что - попробуем?.

У меня дома нет B&R Automation Studio, так как я живу под Линукс, а виртуалку ставить честно говоря немножко лень.
Но мне не очень понятно ваше ТЗ - что именно вы хотите проверить в смысле параллелизма?
В простейшем случае, если я захочу ловить фронты некоторого сигнала и считать их, то я сделаю это буквально парой строчек:

if (Signal ^ oldSignal && Signal) Counter++;
oldSignal = Signal;

oldSignal это локальная переменная, хранящая предыдущее состояние сигнала. Вот и всё. Какого, собственно, результата вы ожидаете "такого же как у вас"?

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

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

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

Ах вот что вы имеете ввиду. Ну, полагаю, что я сумею воссоздать то, что у вас, практически один в один. Мне даже с визуализацией проще будет, так как время цикла у меня легко настраивается.
Что касается простейшего счётчика, считающего мне фронты, то вот как это примерно у B&R выглядит:

ну и результат:

Понятно, что тут я бы и ST мог обойтись, но если я имею возможность программировать ПЛК прямо на плюсплюсах, то почему бы и нет. А реализацию на LD я сделаю как-нибудь на досуге, но тут интерес чисто "академический".

Мне кажется я понял Вас. Выше это так - прикидка. Т.е. движемся по заданному ранее плану. 1) реализуем И-НЕ. 2) Создаем два процесса на их базе 3) устанавливаем между ними "триггерные связи". 4) Запускаем, тестируем, анализируем результаты. И пусть это будет на С++. Не возражаю.

Что-то мешает реализовать триггер?

Подобная "магическая" ошибка у меня возникала после некоректного использования указателя. Проблема была в том, что на вход библиотечной функции был передан адрес переменной не того типа. Функция просто писала 4 байта по указанному адресу, не обращая внимания, что затирала 2 байта следующей переменной. Такие ошибки компилятор отловить не в состоянии. Поиск их в большом проекте, тот еще квест.
К сожелению традиция использовать указатели где угодно, живет и процветает. Для себя сделал вывод, что указатели всегда можно заменить ссылкой или переменной типа VAR_IN_OUT, когда ссылки не доступны. Указатели только при написании универсальных функций, для передачи данных размер которых не известен заранее.

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

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

Я так понял - вставить вместо переменнй таймер TMR , с переменной задержкой, если требуется, по условиям работы не подходит?

Подпрограммы у ПЛК Дельта все же есть (за другие ПЛК не отвечаю). Только параметров они не имеют. Подпрограммы используются достаточно активно, а как выкручиваются с передачей параметров можно подсмотреть, если, например, 1) реализовать любую программу в ISP Soft с использованием ФБ, 2) загрузить программу в ПЛК, а затем 3) считать ее в ПЛК, используя уже WPL Soft (не ISP Soft!). И тайное станет явным. Описывать все достаточно муторно - лучше посмотреть.

Штабелер-крыло

.

Объект текущего реального проекта. Тоже штабелер, но только посложнее. Именно в таком виде реализуется документирование проекта. Представить (да и реализовать) этот же алгоритм в форме блок-схемы, а, не дай Бог, на LD просто не очень реально. А уж тем более пытаться разобраться в подобном алгоритме даже немного погодя... С алгоритмом в форме автомата это очень даже реально.

Именно в таком виде реализуется документирование проекта

Я не могу позитивно оценить такой подход к документации. Хотя в нотации Харела строгости и академичности поменьше, но она гораздо понятнее неспециалисту, поддерживается в UML и её можно пихнуть в систему контроля версий.

Я не могу позитивно оценить такой подход к документации.

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

Например, к нотации Харела у меня есть конкретные замечания. Первое и самое главное - она искажает понятие конечного автомата, а потому выпадает из теории автоматов. Это плохо. От слова совсем. Практика без науки - кустарщина. Скорее всего, неспециалисту это не известно, но любой специалист это должен знать и понимать. Исходя из этого, тот же UML служит, скорее, хорошим примером "автоматоподобной" технологии, которую при желании не так уж сложно превратить в автоматную. А в систему контроля версий можно впихнуть все что угодно. Было бы желание.

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

Самое важное — для кого эта документация. Если это документация не для программиста, который будет штабелер дорабатывать, а для конечного пользователя: сотрудника склада, интегратора и прочее — в общем, человека, который хочет предсказать, как штабелер отреагирует на конкретное воздействие. Здесь во главу угла встает читабельность и удобство понимания, чтобы технолог мог посмотреть и сказать «вот тут неправильно». Для себя вы можете использовать нотацию любой академичности, но на этапе сбора требований, проектирования и пусконаладки надо все-таки пойти навстречу специалисту не-программисту.
Ну и имена функций и прочего… как будто doxygen никогда не существовало. Нафиг мне имя функции, да ещё в двуязычном формате и с непонятными индексами? Поставьте ссылку, на группу и на функцию,

Самое важное — для кого эта документация.

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

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

1.     Захаров В.Н., Поспелов Д.А., Хазацкий В.Е. Системы управления. Задание. Проектирование. Реализация. Изд. 2-е, перераб. и доп. М., “Энергия”, 1977. -424с.

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

Заметим, что предложено это было авторами книги задолго до всяких UML.

Вопрос не в модели, а в её представлении. Вы используете представление Мили, которое требует некоторых базовых знаний, а нотация Харела более человекочитаемая (и обычно не содержит однобуквенных обозначений).
Я не спорю, что многие важные вещи не изменились, но часть изменилась очень сильно. Процессы из 70х годов СССР нельзя переносить один к одному, как минимум из-за изменения требований к срокам и числу задействованных людей. Даже законтачить разработчика с технологом может быть проблемой, о том, что кто-то будет раскуривать неинтуитивную нотацию, которую видит в первый и скорее всего последний раз, речи вообще не идет.
EDIT: не то что сдаточную, я даже для себя документацию понятнее пишу, просто чтобы понять через полгода — а что имелось в виду? С точки зрения текущих практик групповой разработки под спойлером выше «как не надо делать».

...нотация Харела более человекочитаемая

Но для детальной проработки она не годится. Попробуйте представить граф под спойлером в нотации Харела? Я знаком с данной нотацией (и по UML и по МАТЛАБу) и считаю, что это вряд ли возможно. Но я не истина в последней инстанции, а потому мне было бы интересно посмотреть на результат ;) Например, текстовое описание алгоритма явно будет более "человекочитаемым", чем автоматный граф, но последний мне больше даст информации об алгоритме при одном только беглом взгляде на него..

С точки зрения текущих практик групповой разработки под спойлером выше «как не надо делать».

Во-первых, текущие практики меняются и, скорее всего, то, что под спойлером, скоро станет "как надо" ;) Тот же UML тому пример. Нужно только убрать из него диаграммы Харела и адаптировать под классические автоматы. Делов-то! Так что Вы свои представления уж, пожалуйста, не переносите на то, что предлагается мною. А они - моя практика, которой уже много (очень-очень много! :)) лет. И эти автоматы (кстати, это не Мили, а смешанные автоматы Мили-Мура) легко понимаются специалистами любого уровня подготовки.

Но я так и не дождался конструктивной критики... То, что более академичны - только плюс автоматам. Что не столь "человекочитаемы" - дело привычки к языку представления. Есть ли серьезные претензии, которые были бы приняты специалистом? Но только не таким, который с автоматами знаком лишь по нотации Харела ;)

И главное. Главное - модель, а представление ее может быть разным У тех же автоматов несколько форм описания, а не только одни графы. "Человекочитаемость" - понятие субъективное. Формальная модель - объективное. Что из этого важнее - вопрос, наверное, риторический.

Есть ли серьезные претензии, которые были бы приняты специалистом?
Кто такой настоящий шотландец?) Куда-то мы не совсем мимо конструктива сползаем. Если для ваших задач хватает этого инструмента — это замечательно, но для меня он неудобен.

...для меня он неудобен

Это уже другое дело. Это Ваша личная проблема, мнение. Выше же Вы обобщали, утверждая:

С точки зрения текущих практик групповой разработки под спойлером выше «как не надо делать».

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

Мне было, признаюсь, очень неудобно переходить с языка С++ на язык LD. С языка, где я создал комфортную автоматную среду проектирования. Ну, очень удобную ;) Пришлось потратить много времени, чтобы что-то подобное создать на LD. Получилось. Все получилось настолько просто и так, что теперь мне достаточно удобно работать и на LD даже. Да, это не С++, но это уже и не обычный LD. Это LD автоматный и даже параллельный. А это, как раз, то, что мне нужно, чтобы было не только комфортно работать, но и быть уверенным в результатах работы. Конечно, без С++, что там говорить, "скучновато", но автоматы позволяют пережить и это :)

Так что наши предпочтения и понятия "удобно" и "неудобно" - это то, что называется субъективным фактором, но есть еще и объективные, против которых, что говорится, "не попрешь". И вот последние - в пользу автоматной технологии.

А то, что кому-то что-то не удобно, то ... я со своей стороны пытаюсь сделать прежде всего так, чтобы было удобно мне, надеясь, что это станет/будет удобным и для кого-то другого ;).

Sign up to leave a comment.

Articles