Extending an Existing Component
Now that we have a working component, we will use it to build another component. With 2 solenoids we can build a cylinder. We do have the choice of building a complex component that encompasses other components, building a component from scratch using the knowledge we have of another component, or we can build another standalone component that will be controlled in conjunction with the other components by the equipment module.
To help visualize this we can look at a simple declaration of each.
- A Cylinder Component that encapsulates 2 Solenoid Components In this case the Cylinder Component must implement the controls for each of the Solenoid Components, including calling the CyclicLogic method of each, and handling the HMI interactions. While this implementation allows for the reuse of the Solenoid code, it places the burden on the Cylinder component to properly implement all parts of both Solenoid components.
- A Cylinder Component that directly controls the 2 Solenoids Using the knowledge of the Solenoid Component to create a new component that directly controls the solenoid outputs is probably the simplest and fastest implementation. The downside is that the modularity of the Solenoid Component is lost. When the Solenoid Component is used for something other than a Cylinder, and a change is made, then that same change will have to be considered for the Cylinder Component. Whereas in the previous use case, the change to the Solenoid Component would be immediately available to the Cylinder Component.
- A Cylinder that is controlled and monitored by the Equipment module, but has no awareness of the Solenoid outputs Creating an instance of each component within the Equipment Module (EM) and letting the control be handled at this level is a viable option, however the implementation of the EM is not designed to be as portable as the Components. This means that each time you wish to add a Cylinder to an EM all the interactions will need to be handled/repeated, again. This lends itself to the potential for errors that could be avoided by keeping as much code as possible within the Component.
The recommendation is to take the time to develop a component that handles things in the most reuseable way possible. While the above examples may seem a bit simplistic, if you consider something more complicated than a Cylinder and its Solenoids you can start to see the benefits. Imagine that after the Cylinder is completed you need multiples of them, and then some of them will use sensors to know when the move is complete. Some with both extend and retract, while others with only retract. Then the Solenoid component is used for a clutch, but the clutch has opened and closed position sensors. The point of this drawn-out scenario is to highlight the fact that components need to be modular, reusable, and flexible. When you isolate yourself to the simple implementation, you will most likely find yourself wishing you had started things differently.
Encapsulating Components
This Cylinder Component contains 2 other components that it must manage in a similar way to how the Framework handles components. The FB_Component_Cylinder
must call the CyclicLogic()
method of each of them, call their Reset()
methods, and handle any possible HMI interactions.
- Create the
FB_Component_Cylinder
function block andExtend FB_CompnentBase
- Declare the 2 Solenoid components
FUNCTION_BLOCK FB_Component_Cylinder EXTENDS FB_ComponentBase 1 2 3 4
VAR ExtendSolenoid : FB_Component_Solenoid; RetractSolenoid : FB_Component_Solenoid; END_VAR
-
Add the CyclicLogic method and call the overridden method of the base class.
CycleLogic() 1 2 3
ExtendSolenoid.CyclicLogic(); RetractSolenoid.CyclicLogic(); SUPER^.CyclicLogic();
-
Previously we added code to call the Initialize method. This code exists in the
CyclicLogic()
method of the base class and can be copied from there.5. Add the Reset method and call the overridden method of the base class. Along with the reset of the 2 solenoids.CyclicLogic() 1 2 3 4 5 6 7 8
+IF NOT _InitComplete THEN + _InitComplete := Initialize(); + RETURN; +END_IF ExtendSolenoid.CyclicLogic(); RetractSolenoid.CyclicLogic(); SUPER^.CyclicLogic();
Reset() 1 2 3 4 5
Reset := FALSE; IF SUPER^.Reset() THEN ExtendSolenoid.Reset(); RetractSolenoid.Reset(); END_IF
Note
The
Reset()
method of the Solenoid classes both call theirDeenergize()
method. This might not be the desired outcome. Therefore, consider the possibility of creating a configuration parameter for theFB_Component_Solenoid
that allows the user to choose whether the solenoids should be de-energized or energized onReset()
, similar to how theHome()
method works.