Unit
Applications that are developed with the Zeugwerk Framework are broken down into small, manageable units. A unit is a combination of hardware objects that can be used to do a repeatable sequence of actions to perform a partial job of a machines main objective, i.e. a handling unit that moves parts from A to B. While for small applications there may be only one Unit, for large-scale applications there may be numerous Units that are used in conjunction. The actual peculiarity of a unit is always application specific and one of the first tasks to design a new automation application.
States (predefined and userdefined)
Each unit may utilize various states to perform its task.
- Booting initial state that each unit is in after activating the PLC. This state is used for getting the unit's equipment ready to work. To be specific, the fieldbus parameters are written and stuff similar to this.
- Init [non-active] state after the boot process has finished. Units, if not explicitly configured differently, wait in this state until the machine operator references the machine by starting the homing sequence.
- GoHome this state is used for referencing the unit, such that it is in a safe, definied state to switch to automatic mode.
- Idle [non-active] this state indicated that the unit is ready to work, but it is waiting for an instruction by the machine operator or another unit that controls this one.
- Automatic the unit is performing its main purpose, i.e. move something from A to B.
- Stop this state stops the unit in a fast, controlled fashion. It is interrupting any state, even other active ones.
- Stopped [non-active] after the unit gets out of its Stop state, it directly transitions to the stop state indicating that the stop process has finished.
- FaultReaction this state is used for a fast, controlled stop of the unit that is interrupting any state, even active states. In contrast to the Stop state, this state does should not wait for any subobject that is stopped while the unit is in this state. If the the sequence of this state is aborted, the unit directly transitions into Fault, this however should usually be avoided by ignoring potential errors that are popping up in this state.
- Fault [non-active] after the unit gets out of its FaultReaction state, it directly transitions to the Fault state indicating that the FaultReaction process has finished.
In addition to these states, userdefined states can be configured that can be used in large applications to split up a very large automatic sequence into smaller parts like calibration, (...).
Transition between states follow a state machine. While this statemachine has proofen its worth, it may actually be overwritten with a user-defined state machine (not recommended for standardization issues).
sequenceDiagram
participant Init
participant GoHome
participant Idle
participant Automatic
participant UserdefinedX
participant Stop
participant Stopped
participant FaultReaction
participant Fault
alt Getting ready
Init ->> GoHome: GoHome button pressed
activate GoHome
GoHome ->> Idle: done
deactivate GoHome
else Successful operation
Idle ->> Automatic: start button pressed
activate Automatic
Automatic ->> Idle: done
deactivate Automatic
Idle ->> UserdefinedX: buttonX pressed
activate UserdefinedX
UserdefinedX ->> Idle: done
deactivate UserdefinedX
else Interrupt states by Stop
GoHome ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
Idle ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
Automatic ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
UserdefinedX ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
Stopped ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
else Error handling of Faults
GoHome ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
Idle ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
Automatic ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
UserdefinedX ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
Stopped ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
else Reference
Idle ->> GoHome: GoHome button pressed
activate GoHome
GoHome ->> Idle: done
deactivate GoHome
Stopped ->> GoHome: gohome button pressed
activate GoHome
GoHome ->> Idle: done
deactivate GoHome
Fault ->> GoHome: gohome button pressed
activate GoHome
GoHome ->> Idle: done
deactivate GoHome
end
Action
Actions are similar to userdefined states, but follow a more relax state-transition diagram. While userdefined-states can only be started if a Unit is in its Idle state, actions can started from any non-active state (Init, Idle, Stopped and Fault). There are no actions implemented by default, because they are always application specific and are therefore userdefined.
Actions can be utilized to implement mechanisms that are usually used by the operators or service personal to get a machine in its home state in case of mechanical errors (open gripper after a mechanical error, ...).
sequenceDiagram
participant Init
participant GoHome
participant Idle
participant Stopped
participant Fault
participant ActionX
alt normal, successful operation of actions
Init ->> ActionX: buttonY pressed
activate ActionX
ActionX ->> Init: done
deactivate ActionX
Idle ->> ActionX: buttonY pressed
activate ActionX
ActionX ->> Idle: done
deactivate ActionX
Stopped ->> ActionX: buttonY pressed
activate ActionX
ActionX ->> Stopped: done
deactivate ActionX
Fault ->> ActionX: buttonY pressed
activate ActionX
ActionX ->> Fault: done
deactivate ActionX
else interrupt action by Stop
ActionX ->> Stop: stop button pressed
activate Stop
Stop ->> Stopped: done
deactivate Stop
else error handling of Faults
ActionX ->> FaultReaction: aborted
activate FaultReaction
FaultReaction ->> Fault: done
deactivate FaultReaction
end
Halt
While not an actual state, it is advised to implement the halt mechanism of a unit. This is a flag which gets propagated to every sequence or subsequence. If the flag is active, all active states should react to it as soon as possible. Halt may also be referred to as a soft stop. In contrast to the Stop state, which interrupts active processes, a soft stop should always leave a unit in a resumable state.
Sequences
Each state (predefined states, userdefined states and actions) may be associated with a sequence. Sequences are implemented within the context of an application. While there are sequences that are usually implemented for any application, there also exist sequences that are application specific. Such sequences are associated with user-defined states.
Usually at least the following sequences should be implemented for every Unit
- Automatic implements the main task of the Unit (i.e. for a handling unit, move part from A to B)
- GoHome
- Stop
- FaultReaction (FaultReaction and stop may utilize the same sequence)
Sequences are usually implemented in the form of a step sequence.
FUNCTION_BLOCK PickerAutomaticSequence EXTENDS PickerSequence IMPLEMENTS ZCore.ISequence
VAR_INPUT
DelayAufnehmen : LREAL := 0.5; // s
DelayAblegen : LREAL := 0.2; // s
TransportSpeed : LREAL := 70; // %
END_VAR
VAR
_step : ZCore.Step(PickerStep.AutomaticBegin, PickerStep.AutomaticEnd);
_timer : ZAux.Timer;
END_VAR
(* -------------------------------------------------------------------------------------------------- *)
IF(OnStart(_step)) THEN
// init custom sequence variables here ...
END_IF
REPEAT
LogStep();
CASE _step.Index OF
(* ------------------------------------------------------------- *)
PickerStep.AutomaticBegin:
(* ------------------------------------------------------------- *)
_step.SetNext(PickerStep.AutomaticBeginVerticalUp);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticBeginVerticalUp:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_actuator.VerticalLift.MoveUpAsync(THIS^);
END_IF
Await(_actuator.VerticalLift, nextStep:=PickerStep.AutomaticWaitPartAtEnd);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticWaitPartAtEnd:
(* ------------------------------------------------------------- *)
IF _io.PartIsAtEnd.Enabled THEN
_step.SetNext(PickerStep.AutomaticMoveRight);
END_IF
(* ------------------------------------------------------------- *)
PickerStep.AutomaticMoveRight:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_actuator.HorizontalMove.MoveRightAsync(THIS^);
_actuator.VerticalLift.MoveDownAsync(THIS^);
END_IF
Await2(obj1:=_actuator.HorizontalMove, obj2:=_actuator.VerticalLift, nextStep:=PickerStep.AutomaticVerticalDown);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticSwitchMagnetOn:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_io.MagnetEin.Enable(TRUE);
_timer.RunAsync(THIS^, DelayAufnehmen);
END_IF
Await(obj1:=_timer, nextStep:=PickerStep.AutomaticAufnehmenVertikalAuf);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticFetchVerticalUp:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_actuator.VerticalLift.MoveUpAsync(THIS^);
END_IF
Await(obj1:=_actuator.VerticalLift, nextStep:=PickerStep.AutomaticMoveLeft);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticMoveLeft:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_actuator.HorizontalMove.MoveLeftAsync(THIS^);
_actuator.VerticalLift.MoveDownAsync(THIS^);
END_IF
Await2(obj1:=_actuator.HorizontalMove, obj2:=_actuator.VerticalLift, nextStep:=PickerStep.AutomaticMoveDown);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticSwitchMagnetOff:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_io.MagnetEin.Enable(FALSE);
_timer.RunAsync(THIS^, DelayAblegen);
END_IF
Await(obj1:=_timer, nextStep:=PickerStep.AutomaticReleaseVerticalUp);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticReleaseVerticalUp:
(* ------------------------------------------------------------- *)
IF _step.OnEntry()
THEN
_actuator.VerticalLift.MoveUpAsync(THIS^);
END_IF
Await(obj1:=_actuator.VerticalLift, nextStep:=PickerStep.AutomaticEnd);
(* ------------------------------------------------------------- *)
PickerStep.AutomaticEnd:
(* ------------------------------------------------------------- *)
// repeat the automatic sequence, and exit could be triggered by calling SetBusy(FALSE);
_step.SetNext(PickerStep.AutomaticBegin);
ELSE
Abort('sequence contains unhandled step');
END_CASE
UNTIL _step.IsNotRepeatable() OR_ELSE NOT Busy END_REPEAT
Note
This implementation allows to run multiple steps per cycle because of the REPEAT UNTIL statement arround the steps. This makes a sequencer a lot faster but can lead to problems sometimes. If this is not suitable simply remove the REPEAT UNTIL loop and every step is executed in one separate PLC-cycle.