Table of Contents

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.