ООО «СинкТвин Технологии» +7 925 353-56-35 info@synctwin.ru
Документация / Станок и программы / Программы автоматики

Программы автоматики: устройство и примеры

Программа узла — машина состояний: шаги и переходы между ними по условию. Внутри шага оборудование работает ОДНОВРЕМЕННО, каждое на своей дорожке. Ниже — как это устроено, какие бывают условия и пороги, и три программы целиком, взятые из каталога узлов дословно.

Скелет

Шаг и дорожка

machine({
  initial: 'загрузка',
  states: {
    'загрузка': {
      lanes: { X: [move(120, { v: 0.5 })], зажим: [on()], датчик: [waitFor('↑')] },
      entry: [on(5)], exit: [off(5)],        // мгновенно на входе и на выходе
      on: { 'датчик ↑': 'резка', 'X >= 120': 'резка' },
      after: { 8: 'авария' },                // предел времени в этом шаге
    },
    'резка': { wait: 2 },
  },
})
Вид шагаЧто этоОсобенность
обычныйдорожки оборудования, действия на входе и выходе, переходыдлится по самой долгой дорожке
составнойшаг со вложенными шагами: сам не исполняется, исполняются детиего переходы наследуются всеми вложенными — общая авария объявляется один раз
параллельныйзапускает несколько соседних шагов одновременно как независимые веткидве ветки, держащие одну ось или один порт, — это конфликт ресурса, и он называется
выдержкафиксированная пауза без оборудования вовседлительность объявлена полем, а не выведена из дорожек
ДорожкаЧто на неё кладётсяЗамечание
дорожка осиход в позицию · вращение · прижим моментом · торможение · удержаниедвижения кладутся только сюда
дорожка выходавключить · выключить · импульс · мигание фоном · удержаниепорт известен из имени дорожки
дорожка входаждать фронт или уровень · удержаниеожидание эластично: дорожка стоит, пока сигнала нет

Все дорожки шага стартуют одновременно, а сам шаг длится по самой долгой: остальные заканчивают раньше и ждут. Это и есть способ выразить «качаем и зажимаем разом» без второй программы.

Оборудование блока доступно по именам сразу. Код пишется словами — «лента», «зажим», «в позиции», — а с каким приводом и пином они связаны, знает паспорт стенда. Та же программа переносится на соседний участок сменой паспорта, а не переписыванием логики.

Счётчик — именованный объект программы. Один шаг прибавляет, другой сбрасывает; прибавка происходит на входе в шаг, ровно раз за проход. Памяти между пусками у счётчика пока нет: пуск начинает счёт с нуля.

Переходы

Условия: чем шаг заканчивается

Условия проверяются непрерывно, каждый такт — как скан ПЛК, а не как обработчик одиночного события. Срабатывает первый подошедший переход в порядке объявления.

ВидКак пишетсяЧто значит
шаг доигралdoneвсе дорожки шага закончились, включая эластичное ожидание входа
время в шаге'5s' · after: { 5: … }секунды с момента входа В ЭТОТ шаг, а не с начала программы
вход'датчик ↑' · 'датчик ↓' · 'датчик =1' · 'датчик =0'фронт или уровень; по имени из паспорта блока либо по номеру порта
позиция оси'X >= 90 град' · 'X >= 2 об'ось доехала; единица в строке решает, какая это величина
скорость оси'лента >= 1500 об/мин'ось разогналась
момент оси'пресс момент >= 380'ось нагрузилась. Без единицы число читается в ПРОМИЛЛЕ номинала: 380 — это 38 %
счётчик'счётчик детали >= 6'именованный счётчик программы: один шаг считает, другой сбрасывает
составное'деталь =1 и зажим =1' · 'или' · 'не'до пяти простых условий на переход; не влезло — это уже состояние, назовите его шагом
формула'|задатчик момент - ведомый момент| >= 120'арифметика над величинами: до трёх действий, делить можно только на число
уставка рецепта'пресс момент >= @момент'порог берётся из рецепта смены — программа одна, порог меняет выбор рецепта на пульте
аварияпереход по авариипревышение порога момента или рассогласования на любой оси шага
предел ожидания{ to: 'зажим', timeout_s: 5, on_timeout: 'error' }страховка условия, которое ждёт мира: не наступило за N секунд — исход называет автор (skip — продолжить · stop — остановить · error — отказ). Предела нет — шаг ждёт без конца, и лаборатория предупреждает об этом до пуска
ВеличинаЕдиницаЗамечание
позиция в ходе осиоборотыградусы переводятся конвертером: deg(90)
скорость вращенияоб/соб/мин переводятся конвертером: rpm(1500)
прижим моментом% номиналазнак задаёт направление
момент в условии перехода‰ номинала40 % прижима соответствует условию «момент >= 400»
времясекундывезде, включая пределы ожидания

Программу исполняет один из двух слоёв, и это видно по её содержимому. Чистая логика — выходы, ожидание входов, паузы, счётчики, формулы и рецепты — уезжает в логический слой и живёт ТАКТОМ стенда. Программа, которая двигает оси, исполняется плеером движения: генерация траектории — работа интерполятора, и логический слой такую программу принимать отказывается, называя конкретные блоки с движением.

Граница проведена явно в обе стороны. Условие по СЧЁТЧИКУ умеет только логический слой: плееру движения такая программа не отдаётся молча — он отказывает и называет слой, в который её надо доставить. Составное условие, формула и порог-уставка — из того же логического набора.

Аварии

Пороги и что считается аварией

ПределПо умолчаниюЗамечание
порог момента600 ‰ номиналапревышение считается аварией, только если ДЕРЖИТСЯ дольше выдержки — на разгоне момент штатно уходит за предел
порог рассогласования0,05 оборотана виртуальных осях не проверяется вовсе: рассогласование там — штатная работа модели, а не факт привода
выдержка аварии0,2 ссколько превышение должно продержаться

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

Момент на виртуальных осях считает МОДЕЛЬ, а не привод. Он выводится из рассогласования «велено» и «есть»: свободный ход — момент холостого хода, нагрузка — рост пропорционально ошибке, упор — насыщение на уставке программы. Это годится, чтобы отладить логику поиска упора и затяжки, но замером не является и цитировать его как факт нельзя.

Нет паспортного номинала — в кадре ПРОЧЕРК, и это правильно. Шкала промилле отсчитывается от номинала двигателя; номинал не задан — точки отсчёта нет, и платформа показывает прочерк вместо правдоподобного числа. «Перегруз» при этом не объявляется: сравнивать не с чем. Условие перехода по моменту на такой оси не сработает — гоняйте такую программу на железе, там момент приходит от привода.

Пример 1

Сварочный позиционер: две оси в одном шаге

Образец «Позиционер CRP WB2S-250»: стол наклоняется, планшайба делает оборот под швом, стол возвращается. Показывает приём «две дорожки в одном шаге»: в шагах «исходная» и «обратный наклон» обе оси едут одновременно, шаг длится по той, что дольше.

// @rig

machine({
  title: 'WB2S-250 — наклон и оборот планшайбы',
  initial: 'исходная',
  states: {
    'исходная': {
      lanes: {
        'наклон': [move(deg(0), { v: 0.1 })],
        'вращение': [move(deg(0), { v: 0.1 })],
      },
      on: { done: 'наклон' },
    },
    'наклон': {
      lanes: { 'наклон': [move(deg(45), { v: 0.1 })] },
      on: { done: 'оборот' },
    },
    'оборот': {
      lanes: { 'вращение': [move(deg(360), { v: 0.15 })] },
      on: { done: 'обратный наклон' },
    },
    'обратный наклон': {
      lanes: {
        'наклон': [move(deg(0), { v: 0.1 })],
        'вращение': [move(deg(0), { v: 0.15 })],
      },
      on: { done: 'пауза' },
    },
    'пауза': {
      wait: 0.5,
      on: { done: 'исходная' },
    },
  },
})

Углы идут через deg(): сама ось считает в оборотах. Пределы хода — из механизма (наклон ±85°, вращение ±360°); диапазоны вендор не публикует, и в файле это названо предположением.

Пролог rig() в файле не написан — на место метки // @rig его печатает платформа из паспорта и механизма. Имена «наклон» и «вращение» — подписи каналов паспорта.

Пример 2

Рука: несколько ходов очередью в одной дорожке

Образец «Рука KUKA KR16»: обход всех шести осей группами — карусель, плечо с локтем, кисть. Показывает приём «очередь в дорожке»: три move подряд играются один за другим, следующий начинается там, где кончился предыдущий.

// @rig

machine({
  title: 'KR16 — обход осей',
  initial: 'исходная',
  states: {
    'исходная': {
      lanes: {
        A1: [move(deg(0), { v: 0.2 })], A2: [move(deg(0), { v: 0.2 })],
        A3: [move(deg(0), { v: 0.2 })], A4: [move(deg(0), { v: 0.2 })],
        A5: [move(deg(0), { v: 0.2 })], A6: [move(deg(0), { v: 0.2 })],
      },
      on: { done: 'карусель' },
    },
    'карусель': {
      lanes: { A1: [move(deg(60), { v: 0.2 }), move(deg(-60), { v: 0.2 }), move(deg(0), { v: 0.2 })] },
      on: { done: 'плечо и локоть' },
    },
    'плечо и локоть': {
      lanes: {
        A2: [move(deg(-45), { v: 0.15 }), move(deg(0), { v: 0.15 })],
        A3: [move(deg(50), { v: 0.15 }), move(deg(0), { v: 0.15 })],
      },
      on: { done: 'кисть' },
    },
    'кисть': {
      lanes: {
        A4: [move(deg(90), { v: 0.3 }), move(deg(-90), { v: 0.3 }), move(deg(0), { v: 0.3 })],
        A5: [move(deg(45), { v: 0.2 }), move(deg(-45), { v: 0.2 }), move(deg(0), { v: 0.2 })],
        A6: [move(deg(120), { v: 0.3 }), move(deg(-120), { v: 0.3 }), move(deg(0), { v: 0.3 })],
      },
      on: { done: 'пауза' },
    },
    'пауза': {
      wait: 0.5,
      on: { done: 'исходная' },
    },
  },
})

Оси зовутся так же, как шарниры в файле механизма (A1…A6) — через карту имён, потому что донор назвал их по-своему. Та же программа у образца «Рука CRP RA18-25» отличается только именами J1…J6.

Пример 3

Трек: переезды и выдержки

Образец «Трек CRP WD250-6000» — седьмая ось робота: каретка едет по местам и стоит на каждом. Показывает шаг-выдержку (wait) без оборудования вовсе.

// @rig

machine({
  title: 'WD250-6000 — переезды каретки',
  initial: 'у упора',
  states: {
    'у упора': {
      lanes: { 'каретка': [move(0, { v: 10 })] },
      on: { done: 'место 1' },
    },
    'место 1': {
      lanes: { 'каретка': [move(100, { v: 20 })] },   // прямая ось: обороты винта, не мм
      on: { done: 'работа 1' },
    },
    'работа 1': {
      wait: 0.5,
      on: { done: 'место 2' },
    },
    'место 2': {
      lanes: { 'каретка': [move(200, { v: 20 })] },
      on: { done: 'работа 2' },
    },
    'работа 2': {
      wait: 0.5,
      on: { done: 'у упора' },
    },
  },
})

Выдержка вместо подтверждения — это заглушка, а не решение. «Работа 1» здесь — пол-секунды паузы; в своём узле на её месте стоит ожидание входа: «дождись детали», «захват сомкнут». Пауза на глазок выдаёт «команда подана» за «сделано», и роль входа grip_ok заведена ровно затем, чтобы условие перехода звучало как «захват сомкнут», а не «прошло 0,5 секунды».

Приём

Ехать до упора и остановиться по усилию

rig({ axes: { зажим: 0 }, outputs: { готово: 0 } })

machine({
  title: 'Зажать до упора',
  initial: 'подвод',
  states: {
    'подвод': {
      lanes: { зажим: [move(3, { v: 0.5 })] },
      // 300 ‰ = 30 % номинала. Момент читается с самого привода —
      // отдельный датчик усилия для этого не нужен.
      on: { 'зажим момент >= 300': 'упор', done: 'упор' },
    },
    'упор': {
      lanes: { зажим: [push(40, { sec: 1 })] },
      entry: [on(0)],
      on: { done: 'отвод' },
    },
    'отвод': {
      entry: [off(0)],
      lanes: { зажим: [move(0, { v: 0.8 })] },
      on: { done: 'подвод' },
    },
  },
})

Единицы здесь разные намеренно: прижим говорит в процентах номинала, условие перехода — в промилле. 40 % прижима соответствует условию «момент >= 400».

Состав узлов и словарь ролей каналов — на странице блоков автоматики. Путь навесного органа робота — в глаголах движения.