Dual Output
We can modify the Cylinder component to use two digital outputs for controlling a double-acting pneumatic cylinder. This example will demonstrate how to create a reusable Cylinder component that can be easily integrated into various projects. The cylinder will have separate outputs for extending and retracting.
Step 1: Define the Interface
Create an interface I_Cylinder that defines the methods for the Cylinder component. Note that this interface remains the same as in the single output example.
| INTERFACE I_Cylinder
METHOD Extend
METHOD Retract
END_INTERFACE
|
Step 2: Create the Cylinder Component
Create a function block CylinderDualOutput that implements the I_Cylinder interface. This component will depend on two Digital Output components through the I_DigitalOutput interface, adhering to the Dependency Inversion Principle (DIP).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | FUNCTION_BLOCK CylinderDualOutput IMPLEMENTS I_Cylinder
VAR
ExtendOutput : I_DigitalOutput; // Dependency Injection of Digital Output component for extending
RetractOutput : I_DigitalOutput; // Dependency Injection of Digital Output component for retracting
END_VAR
METHOD FB_Init : BOOL
VAR_INPUT
bInitRetains : BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
bInCopyCode : BOOL; // TRUE: the instance will be copied to the copy code afterward (online change)
ExtendOutput : I_DigitalOutput;
RetractOutput : I_DigitalOutput;
END_VAR
THIS^.ExtendOutput := ExtendOutput;
THIS^.RetractOutput := RetractOutput;
END_METHOD
METHOD Extend
ExtendOutput.On := TRUE;
RetractOutput.On := FALSE; // Ensure retract output is off
END_METHOD
METHOD Retract
RetractOutput.On := TRUE;
ExtendOutput.On := FALSE; // Ensure extend output is off
END_METHOD
END_FUNCTION_BLOCK
|
Step 3 : Using a Null Object for the Digital Output Dependencies
To adhere to the Dependency Inversion Principle (DIP) and avoid null reference issues, we
can create Null Object implementations of the I_DigitalOutput interface. These Null Objects will provide default behavior when no actual digital outputs are injected.
In the CylinderDualOutput function block declare the Null Object variables for the digital output dependencies:
| FUNCTION_BLOCK CylinderDualOutput IMPLEMENTS I_Cylinder
VAR
ExtendOutput : I_DigitalOutput; // Dependency Injection of Digital Output component for extending
RetractOutput : I_DigitalOutput; // Dependency Injection of Digital Output component for retracting
// Null Objects for Digital Output dependencies
NullEO : BOOL;
NullExtendOutput : DigitalOutput(Output := NullEO);
NullRO : BOOL;
NullRetractOutput : DigitalOutput(Output := NullRO);
END_VAR
|
Then, in the FB_Init method, check if the ExtendOutput and RetractOutput inputs are provided. If not, assign the respective Null Objects to the references.
1
2
3
4
5
6
7
8
9
10
11
12
13 | METHOD FB_Init : BOOL
IF ExtendOutput = 0 THEN
THIS^.ExtendOutput := NullExtendOutput;
ELSE
THIS^.ExtendOutput := ExtendOutput;
END_IF
IF RetractOutput = 0 THEN
THIS^.RetractOutput := NullRetractOutput;
ELSE
THIS^.RetractOutput := RetractOutput;
END_IF
END_METHOD
|
Step 4: Using the CylinderDualOutput Component
To use the CylinderDualOutput component, create instances of it in your main program or another function block. Initialize it with actual digital output variables for extending and retracting the cylinder.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | PROGRAM MAIN
VAR
ExtendOutputVar at %Q* : BOOL; // Must be declared before injected into the component
RetractOutputVar at %Q* : BOOL; // Must be declared before injected into the component
ExtendOutput : DigitalOutput(Output := ExtendOutputVar);
RetractOutput : DigitalOutput(Output := RetractOutputVar);
Cylinder : CylinderDualOutput(ExtendOutput := ExtendOutput, RetractOutput := RetractOutput);
ExtendCylinder : BOOL;
RetractCylinder : BOOL;
END_VAR
// Extend the cylinder
IF ExtendCylinder THEN
ExtendCylinder := FALSE;
Cylinder.Extend();
END_IF
// Retract the cylinder
IF RetractCylinder THEN
RetractCylinder := FALSE;
Cylinder.Retract();
END_IF
END_PROGRAM
|
Conclusion
The CylinderDualOutput component provides a reusable and maintainable way to control a double-acting pneumatic cylinder using two digital outputs. By adhering to the Dependency Inversion Principle (DIP) and utilizing Null Object patterns, we ensure that the component is robust and can be easily integrated into various projects without null reference issues.