// Функция управления частотными преобразователями для поддержания размеров петель в заданном диапазоне.
// Функция изменяет в массиве параметров петель значение скорости, предназначенной
// для отсылки приводу.
// Данная функция в цикле вызывает рассчётную функцию по числу датчиков петель.
// Для приводов, у которых датчики петель могут отключаться, скорость принимется равной заданной.
FUNCTION SynchronizeSpeed : VOID
TITLE = 'Функция управления частотными преобразователями для поддержания размеров петель в заданном диапазоне.';
CONST
DRIVESNUM := 18; // Количество приводов.
LOOPSNUM := 13; // Количество датчиков петель.
END_CONST
VAR_INPUT
SensorsType : ARRAY [1..LOOPSNUM] OF BOOL; // Массив типов датчиков петли: 0 - прямой, 1 - инверсный.
StartLoop : INT; // Номер петли, с которой начинать синхронизацию.
LoopAmount : INT; // Количество контуров управления (петля - частотник).
UseAllLoops : BOOL; // Использовать все петли, независимо от наличия датчиков.
LoopPresence : ARRAY [1..LOOPSNUM] OF BOOL; // Массив наличия петель.
InLoopData : ARRAY [1..DRIVESNUM] OF LOOPPARAMS; // Входной массив с параметрами петель.
AutoAndFillSensPosition : ARRAY[1..LOOPSNUM] OF BOOL; // Массив положений датчиков для автоматического режима и заправки.
ProtectorEndSensPosition : ARRAY[1..LOOPSNUM] OF BOOL; // Массив положений датчиков для режима "Конец протектора".
SimulatorEnable : BOOL; // Флаг работы симулятора узла реза.
StartSynchronize : BOOL; // Запустить режим синхронизации.
EndProtectorStarted : BOOL; // Режим работы линии "Конец протектора".
DisableHighRoller : BOOL; // Отключить верхний усадочный рольганг. (EnableBottomRoller)
EnableHighRoller : BOOL; // Включить верхний усадочный рольганг.(DisableBottomRoller)
CutTranspIndex : INT; // Индекс транспортёра резки заготовок в массиве параметров петель.
CuttingCycle : BOOL; // Идёт цикл отрезания заготовки. Петля №12 (индекс в массиве 12).
// Этот сигнал блокирует выдачу данной функцией сигнала нарушения синхронизации транспортёров
// из-за провисания петли за счёт остановки транспортёра ножа для отрезания заготовки.
LiftLoopSpeed : INT; // Скорость подъёма петли после цикла отрезания заготовки.
deltaT : INT; // Интервал времени на котором определяется величина приращения петли.
VdhFactor : REAL; // Коэффициент скорости изменения размера петли.
ShrinkRollerIndex : INT; // Индекс усадочного рольганга [3].
CheckRollerIndex : INT; // Индекс контрольного рольганга [4].
Cool3TranspIndex : INT; // Индекс 3-го транспортёра охлаждения.
LongitudalCutIndex : INT; // Индекс транспортёра продольного реза [11].
HWMLoaderIndex : INT; // Индекс питателя ВЧМ [2].
CoilTranspIndex : INT; // Индекс транспортёра закатки.
LineMaxSpeed : INT; // Максимальная скорость линии.
Jointly : ARRAY[1..(DRIVESNUM + 1)] OF BOOL; // Массив совместной-раздельной работы агрегатов, +1 - АМЧХ совместно-раздельно.
END_VAR
VAR_OUTPUT
OutLoopData : ARRAY [1..DRIVESNUM] OF LOOPPARAMS; // Выходной массив с параметрами петель.
LoopSizes : ARRAY [1..LOOPSNUM] OF INT; // Массив с размерами петель.
LoopBeforeDrive : ARRAY[1..13] OF BOOL; // Массив расположения датчиков перед приводами для рабочей станции.
LoopAfterDrive : ARRAY[1..13] OF BOOL; // Массив расположения датчиков сзади приводов для рабочей станции. //
OutOfSync : BOOL; // Нарушение синхронизации скоростей транспортёров.
ProtectorEnd : BOOL; // Признак подтверждения конца протектора.
HighRollerSelected : BOOL; // Выбран верхний усадочный рольганг.
LampHighRollerSelected :BOOL; // Лампа выбора верхнего яруса усадочного рольганга.
END_VAR
VAR_IN_OUT
CutCycleMemory : BOOL; // Память того, что был цикл отрезания заготовки.
BottomRollerSelected : BOOL; // Выбран нижний усадочный рольганг.
Hprevsize : ARRAY[1..LOOPSNUM] OF REAL; // Предыдущий размер петли.
END_VAR
VAR_TEMP
DrivesCounter : INT; // Счётчик контуров управления (петля - частотник).
LongLoopCounter : INT; // Счётчик расположенных подряд недопустимо удлинённых петель.
LoopBeforeTransp : INT; // Петля расположена перед транспортёром.
LoopAfterTransp : INT; // Петля расположена за транспортёром.
LoopPos : INT; // Положение петли, до или после транспортёра.
LoopSensorNumber : INT; // Номер датчика петли.
BoostSpeed : BOOL; // Флаг повышения скорости транспортёра ножа для поднятия петли после цикла резания.
Source : LOOPPARAMS; // Буфер для приёма элемента входного массива.
END_VAR
LABEL
M1;
END_LABEL
//---------------------------------------------------
BEGIN
//-> Индикация лампы выбора яруса усадочного рольганга:
IF DisableHighRoller = TRUE
THEN
LampHighRollerSelected := FALSE;
END_IF;
IF EnableHighRoller = TRUE
THEN
LampHighRollerSelected := TRUE;
END_IF;
//-> Заполнение информационного массива размерами петель:
DrivesCounter := 0;
WHILE DrivesCounter < LOOPSNUM
DO
DrivesCounter := DrivesCounter + 1;
IF LoopPresence[DrivesCounter] = TRUE OR
UseAllLoops = TRUE
THEN
LoopSizes[DrivesCounter] := InLoopData[DrivesCounter].H;
END_IF;
END_WHILE;
//-<
//-> Заполнение для рабочей станции массивов используемых приводами петель:
DrivesCounter := 0;
WHILE DrivesCounter < LOOPSNUM
DO
DrivesCounter := DrivesCounter + 1;
IF (LoopPresence[DrivesCounter] = TRUE OR
UseAllLoops = TRUE) AND
StartSynchronize = TRUE
THEN
LoopBeforeDrive[DrivesCounter] := InLoopData[DrivesCounter].LoopBefore;
LoopAfterDrive[DrivesCounter] := InLoopData[DrivesCounter].LoopAfter;
ELSE
LoopBeforeDrive[DrivesCounter] := FALSE;
LoopAfterDrive[DrivesCounter] := FALSE;
END_IF;
END_WHILE;
//-<
OutOfSync := FALSE;
ProtectorEnd := FALSE; // Признак подтверждения конца протектора.
//=> Запоминание текущей расчётной скорости для транспортёра охлаждения 3:
IF EndProtectorStarted = FALSE
THEN
OutLoopData[Cool3TranspIndex].Vautotoend := InLoopData[Cool3TranspIndex].V;
END_IF;
//=> Замена заданных скоростей движения трансп. охлаждения 3 и продольного реза для режима конца протектора:
IF EndProtectorStarted = TRUE
THEN
OutLoopData[Cool3TranspIndex].Vtask := OutLoopData[Cool3TranspIndex].Vautotoend;
OutLoopData[LongitudalCutIndex].Vtask := OutLoopData[Cool3TranspIndex].Vtask;
END_IF;
//=<
IF StartSynchronize = TRUE
THEN
LongLoopCounter := 0;
LoopBeforeTransp := 1;
LoopAfterTransp := 2;
//=> Оределение необходимости кратковременного увеличения скорости до максимальной возможной
// после завершения цикла реза для быстрого поднятия петли:
//-> Запоминание того, что был цикл отрезания заготовки:
IF CuttingCycle = TRUE
THEN
CutCycleMemory := TRUE;
END_IF;
//-> Определение необходимости ускорения работы транспортёра ножа для быстрого поднятия петли после цикла отрезания заготовки:
IF CutCycleMemory = TRUE AND
CuttingCycle = FALSE AND
(InLoopData[CutTranspIndex].H <= InLoopData[CutTranspIndex].Hminlim) // Петля ниже нижнего допустимого предела (для варианта инверсных петель).
THEN
BoostSpeed := TRUE;
END_IF;
IF CuttingCycle = FALSE AND
(InLoopData[CutTranspIndex].H > InLoopData[CutTranspIndex].Hminlim) // Петля ниже нижнего допустимого предела (для варианта инверсных петель).
THEN
BoostSpeed := FALSE;
CutCycleMemory := FALSE;
END_IF;
//=<
//-> Переключение на нижний усадочный рольганг:
IF DisableHighRoller = TRUE
THEN
BottomRollerSelected := TRUE;
END_IF;
//-> Переключение на верхний усадочный рольганг:
IF EnableHighRoller = TRUE
THEN
BottomRollerSelected := FALSE;
END_IF;
//-> Цикл рассчёта скоростей частотных преобразователей:
DrivesCounter := StartLoop;
WHILE DrivesCounter <= LoopAmount
DO
//--------------------------------------------------
//-> Автоматический режим или заправка.
// Номер петли управления совпадает с номером датчика:
IF EndProtectorStarted = FALSE
THEN
LoopSensorNumber := DrivesCounter; // Номер датчика совпадает с номером петли управления.
IF AutoAndFillSensPosition[DrivesCounter] = TRUE // Массив положений датчиков для автоматического режима и заправки.
THEN
LoopPos := LoopBeforeTransp; // Датчик перед транспортёром.
OutLoopData[DrivesCounter].LoopAfter := FALSE; // Индикация датчика, с которым работает транспортёр.
OutLoopData[DrivesCounter].LoopBefore := TRUE; //
ELSE
LoopPos := LoopAfterTransp; // Датчик после транспортёра.
OutLoopData[DrivesCounter].LoopAfter := TRUE; // Индикация датчика, с которым работает транспортёр.
OutLoopData[DrivesCounter].LoopBefore := FALSE; //
END_IF;
//--------------------------------------------------
//-> Режим "Конец протектора".
// У части петель управления номер датчика на 1 больше номера петли управления - переключение на расположенные сзади транспортёров датчики:
ELSE
IF ProtectorEndSensPosition[DrivesCounter] = FALSE // Массив положений датчиков для режима "Конец протектора".
THEN
LoopPos := LoopAfterTransp; // Датчик сзади транспортёра.
OutLoopData[DrivesCounter].LoopAfter := TRUE; // Индикация датчика, с которым работает транспортёр.
OutLoopData[DrivesCounter].LoopBefore := FALSE; //
IF DrivesCounter <= HWMLoaderIndex // [2] - питатели НЧМ и ВЧМ всегда работают с расположенными сзади датчиками.
THEN
LoopSensorNumber := DrivesCounter; // Номер датчика совпадает с номером петли управления.
ELSE
LoopSensorNumber := DrivesCounter + 1; // Переключение на расположенный сзади транспортёра датчик.
END_IF;
ELSE
LoopPos := LoopBeforeTransp; // Датчик перед транспортёром.
LoopSensorNumber := DrivesCounter; // Номер датчика совпадает с номером петли управления.
OutLoopData[DrivesCounter].LoopAfter := FALSE; // Индикация датчика, с которым работает транспортёр.
OutLoopData[DrivesCounter].LoopBefore := TRUE; //
END_IF;
END_IF;
//--------------------------------------------------
//===> Если датчик петли у привода имеется:
IF LoopPresence[DrivesCounter] = TRUE OR
UseAllLoops = TRUE
THEN
//-> Проверка, не начался ли цикл отрезания заготовки:
IF DrivesCounter <> CutTranspIndex OR
(DrivesCounter = CutTranspIndex AND
CuttingCycle = FALSE AND
BoostSpeed = FALSE)
THEN
//-1-> Автомат или заправка и включён (ON) верхний ярус усадочного рольганга, нижний не используется:
IF EndProtectorStarted = FALSE AND
BottomRollerSelected = FALSE
THEN
Source := InLoopData[DrivesCounter];
END_IF;
//-2-> Конец протектора и включён (ON) верхний ярус усадочного рольганга, нижний не используется:
IF EndProtectorStarted = TRUE AND
BottomRollerSelected = FALSE
THEN
Source.Hminlim := InLoopData[LoopSensorNumber].Hminlim;
Source.Hmaxlim := InLoopData[LoopSensorNumber].Hmaxlim;
Source.Hmin := InLoopData[LoopSensorNumber].Hmin;
Source.Htask := InLoopData[LoopSensorNumber].Htask;
Source.Hmax := InLoopData[LoopSensorNumber].Hmax;
Source.Vmax := InLoopData[DrivesCounter].Vmax;
Source.Vtask := InLoopData[DrivesCounter].Vtask;
Source.H := InLoopData[LoopSensorNumber].H;
Source.V := InLoopData[DrivesCounter].V;
Source.LoopVeryLong := InLoopData[LoopSensorNumber].LoopVeryLong;
Source.LoopVeryShort := InLoopData[LoopSensorNumber].LoopVeryShort;
Source.NullDivision := InLoopData[LoopSensorNumber].NullDivision;
Source.LoopBefore := InLoopData[DrivesCounter].LoopBefore;
Source.LoopAfter := InLoopData[DrivesCounter].LoopAfter;
Source.ReadingError := InLoopData[LoopSensorNumber].ReadingError;
Source.WritingError := InLoopData[LoopSensorNumber].WritingError;
Source.Vmin := InLoopData[DrivesCounter].Vmin;
END_IF;
//-3-> Автомат или заправка и отключён (OFF) верхний ярус усадочного рольганга, используется нижний:
IF EndProtectorStarted = FALSE AND
BottomRollerSelected = TRUE // Выбран нижний ярус усадочного рольганга.
THEN
IF DrivesCounter = ShrinkRollerIndex // Датчик петли верхнего яруса усадочного рольганга.
THEN
OutLoopData[ShrinkRollerIndex].V := 0; // Задание нулевой скорости неработающему верхнему ярусу.
GOTO M1; // Для этого случая функция ComputeSpeed() не вызывается, так как привод отключен.
END_IF;
IF DrivesCounter = CheckRollerIndex // Датчик петли верхнего яруса усадочного рольганга.
THEN
OutLoopData[DrivesCounter].LoopVeryLong := FALSE; // Блокировка выдачи сообщения о нарушении синхронизации движения транспортёров.
OutLoopData[DrivesCounter].LoopVeryShort := FALSE; //
Source.Hminlim := InLoopData[ShrinkRollerIndex].Hminlim;
Source.Hmaxlim := InLoopData[ShrinkRollerIndex].Hmaxlim;
Source.Hmin := InLoopData[ShrinkRollerIndex].Hmin;
Source.Htask := InLoopData[ShrinkRollerIndex].Htask;
Source.Hmax := InLoopData[ShrinkRollerIndex].Hmax;
Source.Vmax := InLoopData[DrivesCounter].Vmax;
Source.Vtask := InLoopData[DrivesCounter].Vtask;
Source.H := InLoopData[ShrinkRollerIndex].H;
Source.V := InLoopData[DrivesCounter].V;
Source.LoopVeryLong := InLoopData[ShrinkRollerIndex].LoopVeryLong;
Source.LoopVeryShort := InLoopData[ShrinkRollerIndex].LoopVeryShort;
Source.NullDivision := InLoopData[ShrinkRollerIndex].NullDivision;
Source.LoopBefore := InLoopData[DrivesCounter].LoopBefore;
Source.LoopAfter := InLoopData[DrivesCounter].LoopAfter;
Source.ReadingError := InLoopData[ShrinkRollerIndex].ReadingError;
Source.WritingError := InLoopData[ShrinkRollerIndex].WritingError;
Source.Vmin := InLoopData[DrivesCounter].Vmin;
END_IF;
IF DrivesCounter <> ShrinkRollerIndex AND
DrivesCounter <> CheckRollerIndex
THEN
Source := InLoopData[DrivesCounter];
END_IF;
END_IF;
//-4-> Конец протектора и отключён (OFF) верхний ярус усадочного рольганга, используется нижний:
IF EndProtectorStarted = TRUE AND
BottomRollerSelected = TRUE // Выбран нижний ярус усадочного рольганга.
THEN
IF DrivesCounter = ShrinkRollerIndex // Датчик петли верхнего яруса усадочного рольганга.
THEN
OutLoopData[DrivesCounter].V := 0; // Задание нулевой скорости неработающему верхнему ярусу.
OutLoopData[DrivesCounter].LoopVeryLong := FALSE; // Блокировка выдачи сообщения о нарушении синхронизации движения транспортёров.
OutLoopData[DrivesCounter].LoopVeryShort := FALSE; //
GOTO M1; // Для этого случая функция ComputeSpeed() не вызывается, так как привод отключен.
ELSE
IF DrivesCounter = CheckRollerIndex // Датчик петли контрольного рольганга.
THEN
OutLoopData[DrivesCounter].LoopVeryLong := FALSE; // Блокировка выдачи сообщения о нарушении синхронизации движения транспортёров.
OutLoopData[DrivesCounter].LoopVeryShort := FALSE; //
END_IF;
Source.Hminlim := InLoopData[LoopSensorNumber].Hminlim;
Source.Hmaxlim := InLoopData[LoopSensorNumber].Hmaxlim;
Source.Hmin := InLoopData[LoopSensorNumber].Hmin;
Source.Htask := InLoopData[LoopSensorNumber].Htask;
Source.Hmax := InLoopData[LoopSensorNumber].Hmax;
Source.Vmax := InLoopData[DrivesCounter].Vmax;
Source.Vtask := InLoopData[DrivesCounter].Vtask;
Source.H := InLoopData[LoopSensorNumber].H;
Source.V := InLoopData[DrivesCounter].V;
Source.LoopVeryLong := InLoopData[LoopSensorNumber].LoopVeryLong;
Source.LoopVeryShort := InLoopData[LoopSensorNumber].LoopVeryShort;
Source.NullDivision := InLoopData[LoopSensorNumber].NullDivision;
Source.LoopBefore := InLoopData[DrivesCounter].LoopBefore;
Source.LoopAfter := InLoopData[DrivesCounter].LoopAfter;
Source.ReadingError := InLoopData[LoopSensorNumber].ReadingError;
Source.WritingError := InLoopData[LoopSensorNumber].WritingError;
Source.Vmin := InLoopData[DrivesCounter].Vmin;
END_IF;
END_IF;
//-> Вызов функции рассчёта скорости частотного преобразователя:
IF Jointly[DrivesCounter] = TRUE AND
DrivesCounter <> CoilTranspIndex
THEN
ComputeSpeed( InLoopData := Source, // In: Элемент массива с параметрами просчитываемого контура регулирования.
LoopPosition := LoopPos, // In: Положение петли по отношению к транспортёру.
InverseSensors := SensorsType[LoopSensorNumber], // In: Признак перевёрнутых датчиков - укорочение петли - увеличение показаний датчика.
VdhFactor := VdhFactor, // In: Коэффициент скорости изменения размера петли.
deltaT := deltaT, // In: Интервал времени на котором определяется величина приращения петли.
Vfqc := OutLoopData[DrivesCounter].V, // Out: Вычисленная для текущей величины петли скорость привода транспортёра.
LoopVeryLong := OutLoopData[LoopSensorNumber].LoopVeryLong, // Out: Признак слишком длинной петли - обрыва петли.
LoopVeryShort := OutLoopData[LoopSensorNumber].LoopVeryShort, // Out: Признак слишком короткой петли.
NullDivision := OutLoopData[LoopSensorNumber].NullDivision, // Out: Деление на 0 - неправильно заданы параметры петли.
Hprevsize := Hprevsize[LoopSensorNumber] // InOut: Предыдущий размер петли.
);
END_IF;
//-> Формирование сигнала о нарушении синхронизации транспортёров линии из-за недопустимого поднятия одной из петель:
//-> Для петель, расположенных после транспортёров:
M1:
IF LoopPos = LoopAfterTransp
THEN
IF OutLoopData[LoopSensorNumber].LoopVeryShort = TRUE
THEN
OutOfSync := TRUE; // Если хотя бы одна петля выше допустимой величины, выставляется признак нарушения синхронизации транспортёров линии.
END_IF;
ELSE
//-> Для петель, расположенных перед транспортёрами:
IF OutLoopData[LoopSensorNumber].LoopVeryLong = TRUE
THEN
OutOfSync := TRUE; // Если хотя бы одна петля выше допустимой величины, выставляется признак нарушения синхронизации транспортёров линии.
END_IF;
//-> Формирование сообщения об обрыве протектора:
IF OutLoopData[LoopSensorNumber].LoopVeryLong = TRUE
THEN
LongLoopCounter := LongLoopCounter + 1;
IF LongLoopCounter > 2
THEN
ProtectorEnd := TRUE; // Если две петли подряд ниже допустимого значения, то протектор заканчивается.
END_IF;
ELSE
LongLoopCounter := 0;
END_IF;
END_IF;
END_IF;
//-> Форсирование или обнуление скорости транспортёра реза:
IF DrivesCounter = CutTranspIndex
THEN
IF BoostSpeed = TRUE
THEN
OutLoopData[CutTranspIndex].V := LiftLoopSpeed; // Скорость привода транспортёра для поднятия петли.
END_IF;
IF CuttingCycle = TRUE
THEN
OutLoopData[CutTranspIndex].V := 0; // Обнуление скорости привода транспортёра на время отрезания заготовки.
END_IF;
END_IF;
END_IF;
//===> Если датчика петли у привода нет:
IF LoopPresence[DrivesCounter] = FALSE AND
UseAllLoops = FALSE
THEN
// OutLoopData[DrivesCounter].V := Source.Vtask; // Вычисленная для текущей величины петли скорость привода транспортёра.
OutLoopData[DrivesCounter].LoopVeryLong := FALSE; // Признак слишком длинной петли - обрыва петли.
OutLoopData[DrivesCounter].LoopVeryShort := FALSE; // Признак слишком короткой петли.
OutLoopData[DrivesCounter].NullDivision := FALSE; // Деление на 0 - неправильно заданы параметры петли.
OutLoopData[DrivesCounter].H := Source.Hmaxlim; // Текущая величина петли.
//-> Задание скорости для транспортёра закатки, который всегда движется с максимальной возможной скоростью:
IF DrivesCounter = CoilTranspIndex
THEN
OutLoopData[DrivesCounter].V := LineMaxSpeed;
END_IF;
END_IF;
DrivesCounter := DrivesCounter + 1;
END_WHILE;
END_IF;
HighRollerSelected := NOT BottomRollerSelected;
END_FUNCTION
Скачать/Download - 000000e6.SCL
|