782 lines
24 KiB
Markdown
782 lines
24 KiB
Markdown
|
|
## 1. System Architecture
|
|
|
|
### 1.1 Call Structure
|
|
```
|
|
OB1
|
|
├── FC_Ttop_Run
|
|
│ ├── FC_Table_Motor_M316() → "DB Motor M316"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M317() → "DB Motor M317"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M318() → "DB Motor M318"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M319() → "DB Motor M319"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M328() → "DB Motor M328"(FB_Motors_Manage) // Channel 1
|
|
│ ├── FC_Table_Motor_M329() → "DB Motor M329"(FB_Motors_Manage) // Channel 2
|
|
│ ├── FC_Table_Motor_M330() → "DB Motor M330"(FB_Motors_Manage) // Channel 3
|
|
│ ├── FC_Table_Motor_M331() → "DB Motor M331"(FB_Motors_Manage) // Channel 4
|
|
│ ├── FC_Table_Motor_M332() → "DB Motor M332"(FB_Motors_Manage) // Channel 5 (center)
|
|
│ ├── FC_Table_Motor_M333() → "DB Motor M333"(FB_Motors_Manage) // Channel 6
|
|
│ ├── FC_Table_Motor_M334() → "DB Motor M334"(FB_Motors_Manage) // Channel 7
|
|
│ ├── FC_Table_Motor_M335() → "DB Motor M335"(FB_Motors_Manage) // Channel 8
|
|
│ ├── FC_Table_Motor_M336() → "DB Motor M336"(FB_Motors_Manage) // Channel 9
|
|
│ ├── FC_Table_Motor_M340() → "DB Motor M340"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M341() → "DB Motor M341"(FB_Motors_Manage)
|
|
│ ├── FC_Table_Motor_M342() → "DB Motor M342"(FB_Motors_Manage)
|
|
│ └── FC_Table_Motor_M343() → "DB Motor M343"(FB_Motors_Manage)
|
|
└── FC_Table_Devices
|
|
└── "DB Table"(FB_Table)
|
|
```
|
|
|
|
### 1.2 Component Mapping
|
|
- **M316, M317**: Input feeders (left, right)
|
|
- **M318**: Format change input feeders
|
|
- **M319**: Input selector
|
|
- **M328-M336**: Channels 1-9 (1=leftmost, 5=center/bypass, 9=rightmost)
|
|
- **M340**: Output selector
|
|
- **M341, M342**: Output feeders (left, right)
|
|
- **M343**: Format change output feeders
|
|
|
|
## 2. Data Structures
|
|
|
|
### 2.1 Format Data Structure
|
|
```pascal
|
|
TYPE T_Format_Data:
|
|
STRUCT
|
|
Format_Number : Int; // Format number (1 or 2)
|
|
Accumulation_Side : Int; // 1=Left (channels 1-4), 2=Right (channels 6-9)
|
|
Bottle_Dimension_mm : Real; // Bottle dimension in mm
|
|
Max_Speed_mm_min : Real; // Maximum speed in mm/min
|
|
Target_Channels : Array[1..4] of Int; // Channels to use for this format
|
|
END_STRUCT;
|
|
```
|
|
|
|
### 2.2 External Exchange Database
|
|
```pascal
|
|
DB_ATable_Exchange:
|
|
STRUCT
|
|
// === INPUT SIGNALS (from external systems) ===
|
|
IN : STRUCT
|
|
// From Ring/Divider
|
|
Ring_Input_Product_Available : Bool; // Product available at input
|
|
Ring_Output_Request : Bool; // Ring requests product output
|
|
Ring_Empty_And_Auto : Bool; // Ring empty and divider in auto
|
|
Ring_Bypass_Speed_Request : Real; // Requested bypass speed
|
|
|
|
// Commands
|
|
Load_Request : Bool; // Request to start loading
|
|
Format_Change_Command : Bool; // Format change command from HMI
|
|
Unload_Enable : Bool; // Enable automatic unload after format change
|
|
|
|
// System status
|
|
System_Auto_Mode : Bool; // System in automatic mode
|
|
Emergency_Stop : Bool; // Emergency stop signal
|
|
END_STRUCT;
|
|
|
|
// === OUTPUT SIGNALS (to external systems) ===
|
|
OUT : STRUCT
|
|
// To Ring/Divider
|
|
Input_Request_Product : Bool; // Table ready and requesting input
|
|
Format_Change_Allowed : Bool; // Loading complete and ring empty
|
|
Output_Speed_Reference : Real; // Speed reference for output motor
|
|
Table_In_Bypass : Bool; // Table in bypass mode
|
|
|
|
// Status
|
|
Table_State : Int; // Current table state
|
|
Current_Format : Int; // Currently stored format
|
|
Table_Ready : Bool; // Table ready for operation
|
|
Loading_Complete : Bool; // Loading sequence complete
|
|
Unloading_Complete : Bool; // Unloading sequence complete
|
|
END_STRUCT;
|
|
END_STRUCT;
|
|
```
|
|
|
|
### 2.3 Table States
|
|
```pascal
|
|
CONST
|
|
TABLE_STATE_STOPPED : Int := 0;
|
|
TABLE_STATE_LOADING : Int := 1;
|
|
TABLE_STATE_BYPASS : Int := 2;
|
|
TABLE_STATE_UNLOADING : Int := 3;
|
|
TABLE_STATE_ERROR : Int := 4;
|
|
END_CONST;
|
|
```
|
|
|
|
## 3. Main Function Block - FB_Table
|
|
|
|
### 3.1 Interface
|
|
```pascal
|
|
FB_Table:
|
|
VAR_INPUT
|
|
Enable : Bool; // Table enable
|
|
Target_Format : Int; // Target format (1 or 2)
|
|
Manual_Mode : Bool; // Manual operation mode
|
|
END_VAR
|
|
|
|
VAR_IN_OUT
|
|
// Motor structure references (pointers)
|
|
Motor_M316 : UDT_Motor_Manage; // Input feeder left
|
|
Motor_M317 : UDT_Motor_Manage; // Input feeder right
|
|
Motor_M318 : UDT_Motor_Manage; // Format change input
|
|
Motor_M319 : UDT_Motor_Manage; // Input selector
|
|
Motor_M328 : UDT_Motor_Manage; // Channel 1
|
|
Motor_M329 : UDT_Motor_Manage; // Channel 2
|
|
Motor_M330 : UDT_Motor_Manage; // Channel 3
|
|
Motor_M331 : UDT_Motor_Manage; // Channel 4
|
|
Motor_M332 : UDT_Motor_Manage; // Channel 5 (center)
|
|
Motor_M333 : UDT_Motor_Manage; // Channel 6
|
|
Motor_M334 : UDT_Motor_Manage; // Channel 7
|
|
Motor_M335 : UDT_Motor_Manage; // Channel 8
|
|
Motor_M336 : UDT_Motor_Manage; // Channel 9
|
|
Motor_M340 : UDT_Motor_Manage; // Output selector
|
|
Motor_M341 : UDT_Motor_Manage; // Output feeder left
|
|
Motor_M342 : UDT_Motor_Manage; // Output feeder right
|
|
Motor_M343 : UDT_Motor_Manage; // Format change output
|
|
|
|
Exchange : DB_ATable_Exchange; // External communication
|
|
END_VAR
|
|
|
|
VAR_OUTPUT
|
|
Table_State : Int; // Current state
|
|
Error_Code : Word; // Error code
|
|
Diagnostics : T_Table_Diagnostics; // Diagnostic information
|
|
END_VAR
|
|
|
|
VAR_STAT
|
|
// === COMMAND STRUCTURE (Read by FC motors) ===
|
|
Status : STRUCT
|
|
// Input feeders
|
|
Input_Feeders_Enable : Bool;
|
|
Input_Feeders_Speed_mm_min : Real;
|
|
Input_Feeders_Stop_After_Bottle : Bool;
|
|
|
|
// Output feeders
|
|
Output_Feeders_Enable : Bool;
|
|
Output_Feeders_Speed_mm_min : Real;
|
|
Output_Feeders_Stop_After_Bottle : Bool;
|
|
|
|
// Input selector
|
|
Input_Selector_Enable : Bool;
|
|
Input_Selector_Target_Channel : Int;
|
|
Input_Selector_Positioning_Mode : Bool;
|
|
|
|
// Output selector
|
|
Output_Selector_Enable : Bool;
|
|
Output_Selector_Target_Channel : Int;
|
|
Output_Selector_Positioning_Mode : Bool;
|
|
|
|
// Channels
|
|
Channel_Enable : Array[1..9] of Bool;
|
|
Channel_Speed_mm_min : Array[1..9] of Real;
|
|
|
|
// Format change motors
|
|
Format_Change_Input_Enable : Bool;
|
|
Format_Change_Input_Target_mm : Real;
|
|
Format_Change_Output_Enable : Bool;
|
|
Format_Change_Output_Target_mm : Real;
|
|
END_STRUCT;
|
|
|
|
// === INTERNAL LOGIC VARIABLES ===
|
|
Current_State : Int;
|
|
Previous_State : Int;
|
|
Loading_Step : Int;
|
|
Unloading_Step : Int;
|
|
Current_Loading_Channel : Int;
|
|
Current_Unloading_Channel : Int;
|
|
|
|
// Format configuration
|
|
Format_Data : Array[1..2] of T_Format_Data;
|
|
Current_Format_Stored : Int;
|
|
|
|
// Timers
|
|
State_Timer : TON;
|
|
Operation_Timeout : TON;
|
|
|
|
// Area management instances
|
|
Area_Input_Selector : FB_Area_Management;
|
|
Area_Channel : Array[1..9] of FB_Area_Management;
|
|
Area_Output_Selector : FB_Area_Management;
|
|
|
|
// Virtual encoders for position tracking
|
|
Encoder_M332 : FB_Virtual_Encoder; // Center channel for bypass tracking
|
|
Encoder_Input_Selector : FB_Virtual_Encoder;
|
|
Encoder_Output_Selector : FB_Virtual_Encoder;
|
|
END_VAR
|
|
```
|
|
|
|
### 3.2 Main Logic (Pseudocode)
|
|
```pascal
|
|
// === STATE MACHINE MANAGEMENT ===
|
|
CASE Current_State OF
|
|
TABLE_STATE_STOPPED:
|
|
IF Enable AND Exchange.IN.System_Auto_Mode THEN
|
|
IF Exchange.IN.Load_Request THEN
|
|
Current_State := TABLE_STATE_LOADING;
|
|
Loading_Step := 1;
|
|
ELSIF Exchange.IN.Ring_Output_Request AND (Current_Format_Stored > 0) THEN
|
|
Current_State := TABLE_STATE_UNLOADING;
|
|
Unloading_Step := 1;
|
|
END_IF;
|
|
END_IF;
|
|
|
|
TABLE_STATE_LOADING:
|
|
Execute_Loading_Sequence();
|
|
IF Loading_Complete THEN
|
|
Current_State := TABLE_STATE_BYPASS;
|
|
Exchange.OUT.Loading_Complete := TRUE;
|
|
END_IF;
|
|
|
|
TABLE_STATE_BYPASS:
|
|
Execute_Bypass_Mode();
|
|
IF Exchange.IN.Format_Change_Command AND Exchange.IN.Ring_Empty_And_Auto THEN
|
|
Current_State := TABLE_STATE_UNLOADING;
|
|
Unloading_Step := 1;
|
|
END_IF;
|
|
|
|
TABLE_STATE_UNLOADING:
|
|
Execute_Unloading_Sequence();
|
|
IF Unloading_Complete THEN
|
|
Current_State := TABLE_STATE_BYPASS;
|
|
Exchange.OUT.Unloading_Complete := TRUE;
|
|
Current_Format_Stored := 0;
|
|
END_IF;
|
|
|
|
TABLE_STATE_ERROR:
|
|
Execute_Error_Recovery();
|
|
END_CASE;
|
|
|
|
// === UPDATE EXTERNAL SIGNALS ===
|
|
Exchange.OUT.Table_State := Current_State;
|
|
Exchange.OUT.Current_Format := Current_Format_Stored;
|
|
Exchange.OUT.Table_Ready := (Current_State <> TABLE_STATE_ERROR);
|
|
Exchange.OUT.Format_Change_Allowed := (Current_State = TABLE_STATE_BYPASS) AND
|
|
(Current_Format_Stored > 0) AND
|
|
Exchange.IN.Ring_Empty_And_Auto;
|
|
|
|
// === AREA MANAGEMENT UPDATES ===
|
|
FOR i := 1 TO 9 DO
|
|
Area_Channel[i](
|
|
Motor := Get_Channel_Motor_Reference(i),
|
|
Enable := Status.Channel_Enable[i],
|
|
Area_Length_mm := Get_Channel_Length(i),
|
|
Bottle_Length_mm := Format_Data[Target_Format].Bottle_Dimension_mm
|
|
);
|
|
END_FOR;
|
|
```
|
|
|
|
## 4. Loading Sequence Logic
|
|
|
|
### 4.1 Loading Sequence Steps
|
|
```pascal
|
|
PROCEDURE Execute_Loading_Sequence:
|
|
VAR
|
|
Target_Channels : Array[1..4] of Int;
|
|
Current_Channel : Int;
|
|
Channel_Index : Int;
|
|
BEGIN
|
|
// Get target channels for current format
|
|
Target_Channels := Get_Target_Channels_For_Format(Target_Format);
|
|
|
|
CASE Loading_Step OF
|
|
1: // Initialize loading
|
|
Current_Loading_Channel := Get_Outermost_Channel(Target_Format);
|
|
Channel_Index := 1;
|
|
Position_Input_Selector(Target_Channels[Channel_Index]);
|
|
Loading_Step := 2;
|
|
|
|
2: // Wait for selector positioning
|
|
IF Input_Selector_In_Position THEN
|
|
Enable_Channel_Motors_For_Loading(Current_Loading_Channel);
|
|
Enable_Input_Feeders();
|
|
Loading_Step := 3;
|
|
END_IF;
|
|
|
|
3: // Load current channel
|
|
IF Channel_Loading_Complete(Current_Loading_Channel) THEN
|
|
Disable_Input_Feeders();
|
|
Channel_Index := Channel_Index + 1;
|
|
IF Channel_Index <= 4 THEN
|
|
Current_Loading_Channel := Target_Channels[Channel_Index];
|
|
Position_Input_Selector(Current_Loading_Channel);
|
|
Loading_Step := 2;
|
|
ELSE
|
|
Loading_Step := 4; // All channels loaded
|
|
END_IF;
|
|
END_IF;
|
|
|
|
4: // Loading complete
|
|
Disable_All_Channel_Motors();
|
|
Position_Selectors_To_Bypass();
|
|
Current_Format_Stored := Target_Format;
|
|
Loading_Complete := TRUE;
|
|
END_CASE;
|
|
END_PROCEDURE;
|
|
|
|
FUNCTION Get_Target_Channels_For_Format(Format : Int) : Array[1..4] of Int:
|
|
BEGIN
|
|
IF Format_Data[Format].Accumulation_Side = 1 THEN // Left side
|
|
RETURN [1, 2, 3, 4]; // Load from outside to inside
|
|
ELSE // Right side
|
|
RETURN [9, 8, 7, 6]; // Load from outside to inside
|
|
END_IF;
|
|
END_FUNCTION;
|
|
|
|
FUNCTION Get_Outermost_Channel(Format : Int) : Int:
|
|
BEGIN
|
|
IF Format_Data[Format].Accumulation_Side = 1 THEN
|
|
RETURN 1; // Leftmost channel
|
|
ELSE
|
|
RETURN 9; // Rightmost channel
|
|
END_IF;
|
|
END_FUNCTION;
|
|
|
|
PROCEDURE Enable_Channel_Motors_For_Loading(Target_Channel : Int):
|
|
BEGIN
|
|
// Enable all channels from center to target channel
|
|
FOR i := 5 TO Target_Channel DO // or FROM Target_Channel TO 5
|
|
Status.Channel_Enable[i] := TRUE;
|
|
Status.Channel_Speed_mm_min[i] := Format_Data[Target_Format].Max_Speed_mm_min;
|
|
END_FOR;
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
## 5. Unloading Sequence Logic
|
|
|
|
### 5.1 Unloading Sequence Steps
|
|
```pascal
|
|
PROCEDURE Execute_Unloading_Sequence:
|
|
VAR
|
|
Stored_Channels : Array[1..4] of Int;
|
|
Current_Channel : Int;
|
|
Channel_Index : Int;
|
|
BEGIN
|
|
// Get channels where current format is stored
|
|
Stored_Channels := Get_Target_Channels_For_Format(Current_Format_Stored);
|
|
|
|
CASE Unloading_Step OF
|
|
1: // Initialize unloading - start from innermost channel
|
|
Channel_Index := 4; // Start from innermost
|
|
Current_Unloading_Channel := Stored_Channels[Channel_Index];
|
|
Position_Output_Selector(Current_Unloading_Channel);
|
|
Unloading_Step := 2;
|
|
|
|
2: // Wait for selector positioning
|
|
IF Output_Selector_In_Position THEN
|
|
Enable_Channel_Motors_For_Unloading(Current_Unloading_Channel);
|
|
Enable_Output_Feeders();
|
|
Unloading_Step := 3;
|
|
END_IF;
|
|
|
|
3: // Unload current channel
|
|
IF Channel_Unloading_Complete(Current_Unloading_Channel) THEN
|
|
Disable_Output_Feeders();
|
|
Channel_Index := Channel_Index - 1;
|
|
IF Channel_Index >= 1 THEN
|
|
Current_Unloading_Channel := Stored_Channels[Channel_Index];
|
|
Position_Output_Selector(Current_Unloading_Channel);
|
|
Unloading_Step := 2;
|
|
ELSE
|
|
Unloading_Step := 4; // All channels unloaded
|
|
END_IF;
|
|
END_IF;
|
|
|
|
4: // Unloading complete
|
|
Disable_All_Channel_Motors();
|
|
Position_Selectors_To_Bypass();
|
|
Unloading_Complete := TRUE;
|
|
END_CASE;
|
|
END_PROCEDURE;
|
|
|
|
PROCEDURE Enable_Channel_Motors_For_Unloading(Target_Channel : Int):
|
|
BEGIN
|
|
// Enable all channels from target channel to center
|
|
FOR i := Target_Channel TO 5 DO // or FROM 5 TO Target_Channel
|
|
Status.Channel_Enable[i] := TRUE;
|
|
Status.Channel_Speed_mm_min[i] := Format_Data[Current_Format_Stored].Max_Speed_mm_min;
|
|
END_FOR;
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
## 6. Bypass Mode Logic
|
|
|
|
### 6.1 Bypass Operation
|
|
```pascal
|
|
PROCEDURE Execute_Bypass_Mode:
|
|
BEGIN
|
|
// Enable only center channel for bypass
|
|
Status.Channel_Enable[5] := TRUE;
|
|
Status.Channel_Speed_mm_min[5] := Exchange.IN.Ring_Bypass_Speed_Request;
|
|
|
|
// Disable all other channels
|
|
FOR i := 1 TO 9 DO
|
|
IF i <> 5 THEN
|
|
Status.Channel_Enable[i] := FALSE;
|
|
END_IF;
|
|
END_FOR;
|
|
|
|
// Position selectors to bypass (channel 5)
|
|
Status.Input_Selector_Target_Channel := 5;
|
|
Status.Output_Selector_Target_Channel := 5;
|
|
Status.Input_Selector_Enable := TRUE;
|
|
Status.Output_Selector_Enable := TRUE;
|
|
|
|
// Update external signals
|
|
Exchange.OUT.Table_In_Bypass := TRUE;
|
|
Exchange.OUT.Output_Speed_Reference := Exchange.IN.Ring_Bypass_Speed_Request;
|
|
Exchange.OUT.Input_Request_Product := Exchange.IN.Ring_Input_Product_Available;
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
## 7. Auxiliary Function Blocks
|
|
|
|
### 7.1 FB_Virtual_Encoder
|
|
```pascal
|
|
FB_Virtual_Encoder:
|
|
VAR_IN_OUT
|
|
Motor : UDT_Motor_Manage; // Motor structure reference
|
|
END_VAR
|
|
|
|
VAR_INPUT
|
|
Enable : Bool; // Enable calculation
|
|
Ratio_Hz_to_mm_min : Real; // Conversion factor Hz to mm/min
|
|
Reset_Position : Bool; // Reset total position
|
|
END_VAR
|
|
|
|
VAR_OUTPUT
|
|
Displacement_mm : Real; // Displacement since last call
|
|
Current_Speed_mm_min : Real; // Current speed in mm/min
|
|
Total_Distance_mm : Real; // Total accumulated distance
|
|
Motor_Running : Bool; // Motor running status
|
|
END_VAR
|
|
|
|
VAR_STAT
|
|
Last_Frequency_Hz : Real;
|
|
Last_Scan_Time : Time;
|
|
Position_Accumulated : Real;
|
|
END_VAR
|
|
|
|
// Pseudocode:
|
|
BEGIN
|
|
IF Enable THEN
|
|
Current_Frequency := Read_Motor_Frequency(Motor);
|
|
Current_Time := Get_System_Time();
|
|
|
|
IF First_Scan THEN
|
|
Last_Frequency_Hz := Current_Frequency;
|
|
Last_Scan_Time := Current_Time;
|
|
ELSE
|
|
Time_Delta := Current_Time - Last_Scan_Time;
|
|
Avg_Frequency := (Current_Frequency + Last_Frequency_Hz) / 2;
|
|
Speed_mm_min := Avg_Frequency * Ratio_Hz_to_mm_min;
|
|
Displacement_mm := Speed_mm_min * Time_Delta_In_Minutes;
|
|
|
|
IF NOT Reset_Position THEN
|
|
Total_Distance_mm := Total_Distance_mm + Displacement_mm;
|
|
ELSE
|
|
Total_Distance_mm := 0;
|
|
END_IF;
|
|
|
|
Last_Frequency_Hz := Current_Frequency;
|
|
Last_Scan_Time := Current_Time;
|
|
END_IF;
|
|
|
|
Current_Speed_mm_min := Current_Frequency * Ratio_Hz_to_mm_min;
|
|
Motor_Running := Motor.STATUS_RUN;
|
|
ELSE
|
|
Displacement_mm := 0;
|
|
Current_Speed_mm_min := 0;
|
|
END_IF;
|
|
END_FUNCTION_BLOCK;
|
|
```
|
|
|
|
### 7.2 FB_Area_Management
|
|
```pascal
|
|
FB_Area_Management:
|
|
VAR_IN_OUT
|
|
Motor : UDT_Motor_Manage; // Motor of this area
|
|
END_VAR
|
|
|
|
VAR_INPUT
|
|
Enable : Bool; // Area enable
|
|
Area_Length_mm : Real; // Total area length
|
|
Bottle_Length_mm : Real; // Bottle dimension
|
|
Photocell_Pulse : Bool; // Entry photocell pulse
|
|
Reset_Bottles : Bool; // Reset bottle tracking
|
|
END_VAR
|
|
|
|
VAR_OUTPUT
|
|
First_Bottle_Position : Real; // Position of first bottle
|
|
Last_Bottle_Position : Real; // Position of last bottle
|
|
Area_Empty : Bool; // Area completely empty
|
|
Bottles_In_Initial_Zone : Bool; // Bottles in initial zone
|
|
Bottles_In_Final_Zone : Bool; // Bottles in final zone
|
|
Bottle_Count : Int; // Number of bottles in area
|
|
END_VAR
|
|
|
|
VAR_STAT
|
|
Virtual_Encoder : FB_Virtual_Encoder;
|
|
Bottle_Positions : Array[1..50] of Real; // Track up to 50 bottles
|
|
Active_Bottles : Int;
|
|
Photocell_Pulse_Edge : R_TRIG;
|
|
END_VAR
|
|
|
|
// Pseudocode:
|
|
BEGIN
|
|
Virtual_Encoder(
|
|
Motor := Motor,
|
|
Enable := Enable,
|
|
Ratio_Hz_to_mm_min := Calculate_Area_Ratio()
|
|
);
|
|
|
|
// Detect new bottle entry
|
|
Photocell_Pulse_Edge(CLK := Photocell_Pulse);
|
|
IF Photocell_Pulse_Edge.Q THEN
|
|
Add_New_Bottle_To_Tracking();
|
|
END_IF;
|
|
|
|
// Update all bottle positions
|
|
FOR i := 1 TO Active_Bottles DO
|
|
Bottle_Positions[i] := Bottle_Positions[i] - Virtual_Encoder.Displacement_mm;
|
|
|
|
// Remove bottles that have exited the area
|
|
IF Bottle_Positions[i] <= 0 THEN
|
|
Remove_Bottle_From_Tracking(i);
|
|
END_IF;
|
|
END_FOR;
|
|
|
|
// Calculate outputs
|
|
IF Active_Bottles = 0 THEN
|
|
Area_Empty := TRUE;
|
|
First_Bottle_Position := 0;
|
|
Last_Bottle_Position := 0;
|
|
ELSE
|
|
Area_Empty := FALSE;
|
|
First_Bottle_Position := Find_Minimum_Position();
|
|
Last_Bottle_Position := Find_Maximum_Position();
|
|
END_IF;
|
|
|
|
Bottles_In_Initial_Zone := Check_Bottles_In_Zone(Area_Length_mm * 0.8, Area_Length_mm);
|
|
Bottles_In_Final_Zone := Check_Bottles_In_Zone(0, Area_Length_mm * 0.2);
|
|
Bottle_Count := Active_Bottles;
|
|
END_FUNCTION_BLOCK;
|
|
```
|
|
|
|
## 8. Motor-Specific Function Examples
|
|
|
|
### 8.1 FC_Table_Motor_M316 (Input Feeder Left)
|
|
```pascal
|
|
FC_Table_Motor_M316:
|
|
VAR_IN_OUT
|
|
Motor : UDT_Motor_Manage;
|
|
Table_Status : T_Table_Status_Commands; // Reference to FB_Table.Status
|
|
END_VAR
|
|
|
|
// Pseudocode:
|
|
BEGIN
|
|
// === MOTOR CONFIGURATION ===
|
|
Motor.CFG_VFD := TRUE;
|
|
Motor.CFG_PN := TRUE;
|
|
Motor.CFG_Inverter_Type := Inverter_Type_MINIMOTOR;
|
|
Motor.CFG_Min_Speed_Hz := 10;
|
|
Motor.CFG_Max_Speed_Hz := 500;
|
|
|
|
// === READ COMMANDS FROM TABLE LOGIC ===
|
|
Motor.REQ_EN_Run := Table_Status.Input_Feeders_Enable;
|
|
|
|
IF Table_Status.Input_Feeders_Enable THEN
|
|
Motor.REQ_Speed_Fix_01 := TRUE;
|
|
Motor.OUT_VFD_REQ_Speed_User := Convert_mm_min_to_User_Units(Table_Status.Input_Feeders_Speed_mm_min);
|
|
|
|
// Feeder-specific logic: synchronized operation with M317
|
|
Check_Synchronization_With_M317();
|
|
|
|
// Stop after bottle detection if requested
|
|
IF Table_Status.Input_Feeders_Stop_After_Bottle THEN
|
|
Implement_Stop_After_Bottle_Logic();
|
|
END_IF;
|
|
ELSE
|
|
Motor.REQ_Speed_Fix_01 := FALSE;
|
|
END_IF;
|
|
|
|
// === CALL MOTOR MANAGEMENT FB ===
|
|
FB_Motors_Manage(Motor);
|
|
END_FUNCTION;
|
|
```
|
|
|
|
### 8.2 FC_Table_Motor_M319 (Input Selector)
|
|
```pascal
|
|
FC_Table_Motor_M319:
|
|
VAR_IN_OUT
|
|
Motor : UDT_Motor_Manage;
|
|
Table_Status : T_Table_Status_Commands;
|
|
END_VAR
|
|
|
|
// Pseudocode:
|
|
BEGIN
|
|
// === MOTOR CONFIGURATION ===
|
|
Motor.CFG_VFD := TRUE;
|
|
Motor.CFG_PN := TRUE;
|
|
Motor.CFG_Inverter_Type := Inverter_Type_MINIMOTOR;
|
|
|
|
// === POSITIONING MODE SETUP ===
|
|
IF Table_Status.Input_Selector_Positioning_Mode THEN
|
|
Setup_Positioning_Mode();
|
|
Target_Position := Get_Position_For_Channel(Table_Status.Input_Selector_Target_Channel);
|
|
Motor.REQ_Target_Position := Target_Position;
|
|
Motor.REQ_Positioning_Enable := Table_Status.Input_Selector_Enable;
|
|
ELSE
|
|
Setup_Velocity_Mode();
|
|
Motor.REQ_EN_Run := Table_Status.Input_Selector_Enable;
|
|
END_IF;
|
|
|
|
// === CALL MOTOR MANAGEMENT FB ===
|
|
FB_Motors_Manage(Motor);
|
|
END_FUNCTION;
|
|
```
|
|
|
|
### 8.3 FC_Table_Motor_M332 (Center Channel - Bypass)
|
|
```pascal
|
|
FC_Table_Motor_M332:
|
|
VAR_IN_OUT
|
|
Motor : UDT_Motor_Manage;
|
|
Table_Status : T_Table_Status_Commands;
|
|
END_VAR
|
|
|
|
// Pseudocode:
|
|
BEGIN
|
|
// === MOTOR CONFIGURATION ===
|
|
Motor.CFG_VFD := TRUE;
|
|
Motor.CFG_PN := TRUE;
|
|
Motor.CFG_Inverter_Type := Inverter_Type_G120C_SIEMENS;
|
|
|
|
// === READ COMMANDS FROM TABLE LOGIC ===
|
|
Motor.REQ_EN_Run := Table_Status.Channel_Enable[5]; // Channel 5 = center
|
|
|
|
IF Table_Status.Channel_Enable[5] THEN
|
|
Motor.REQ_Speed_Fix_01 := TRUE;
|
|
Motor.OUT_VFD_REQ_Speed_User := Convert_mm_min_to_User_Units(Table_Status.Channel_Speed_mm_min[5]);
|
|
ELSE
|
|
Motor.REQ_Speed_Fix_01 := FALSE;
|
|
END_IF;
|
|
|
|
// === CALL MOTOR MANAGEMENT FB ===
|
|
FB_Motors_Manage(Motor);
|
|
END_FUNCTION;
|
|
```
|
|
|
|
## 9. Error Handling
|
|
|
|
### 9.1 Basic Error Detection
|
|
```pascal
|
|
PROCEDURE Check_Basic_Errors:
|
|
BEGIN
|
|
Error_Code := 0;
|
|
|
|
// Check motor inverter errors
|
|
IF Motor_M316.Alarm_02 OR Motor_M317.Alarm_02 THEN
|
|
Error_Code := Error_Code OR 16#0001; // Input feeders inverter error
|
|
END_IF;
|
|
|
|
IF Motor_M341.Alarm_02 OR Motor_M342.Alarm_02 THEN
|
|
Error_Code := Error_Code OR 16#0002; // Output feeders inverter error
|
|
END_IF;
|
|
|
|
// Check selector positioning errors
|
|
IF Motor_M319.Alarm_02 THEN
|
|
Error_Code := Error_Code OR 16#0004; // Input selector error
|
|
END_IF;
|
|
|
|
IF Motor_M340.Alarm_02 THEN
|
|
Error_Code := Error_Code OR 16#0008; // Output selector error
|
|
END_IF;
|
|
|
|
// Check channel motor errors
|
|
FOR i := 1 TO 9 DO
|
|
IF Get_Channel_Motor_Alarm(i) THEN
|
|
Error_Code := Error_Code OR (16#0010 SHL i); // Channel motor error
|
|
END_IF;
|
|
END_FOR;
|
|
|
|
// Transition to error state if errors detected
|
|
IF Error_Code <> 0 THEN
|
|
Current_State := TABLE_STATE_ERROR;
|
|
END_IF;
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
## 10. Configuration and Initialization
|
|
|
|
### 10.1 Format Configuration Example
|
|
```pascal
|
|
PROCEDURE Initialize_Format_Data:
|
|
BEGIN
|
|
// Format 1 - Left side accumulation
|
|
Format_Data[1].Format_Number := 1;
|
|
Format_Data[1].Accumulation_Side := 1; // Left side
|
|
Format_Data[1].Bottle_Dimension_mm := 85.0;
|
|
Format_Data[1].Max_Speed_mm_min := 12000.0;
|
|
Format_Data[1].Target_Channels := [1, 2, 3, 4];
|
|
|
|
// Format 2 - Right side accumulation
|
|
Format_Data[2].Format_Number := 2;
|
|
Format_Data[2].Accumulation_Side := 2; // Right side
|
|
Format_Data[2].Bottle_Dimension_mm := 65.0;
|
|
Format_Data[2].Max_Speed_mm_min := 15000.0;
|
|
Format_Data[2].Target_Channels := [9, 8, 7, 6];
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
### 10.2 Area Configuration
|
|
```pascal
|
|
PROCEDURE Initialize_Area_Management:
|
|
BEGIN
|
|
// Configure each area with its specific dimensions
|
|
Area_Input_Selector.Area_Length_mm := 500.0;
|
|
Area_Output_Selector.Area_Length_mm := 500.0;
|
|
|
|
FOR i := 1 TO 9 DO
|
|
Area_Channel[i].Area_Length_mm := Get_Channel_Length(i);
|
|
END_FOR;
|
|
END_PROCEDURE;
|
|
```
|
|
|
|
## 11. Integration Points
|
|
|
|
### 11.1 FC_Table_Devices Integration
|
|
```pascal
|
|
FC_Table_Devices:
|
|
BEGIN
|
|
// Call Table FB with all motor references and exchange data
|
|
"DB Table"(
|
|
Enable := System_Enable,
|
|
Target_Format := HMI_Selected_Format,
|
|
Manual_Mode := System_Manual_Mode,
|
|
|
|
Motor_M316 := "DB Motor M316".Manage,
|
|
Motor_M317 := "DB Motor M317".Manage,
|
|
Motor_M318 := "DB Motor M318".Manage,
|
|
Motor_M319 := "DB Motor M319".Manage,
|
|
Motor_M328 := "DB Motor M328".Manage,
|
|
Motor_M329 := "DB Motor M329".Manage,
|
|
Motor_M330 := "DB Motor M330".Manage,
|
|
Motor_M331 := "DB Motor M331".Manage,
|
|
Motor_M332 := "DB Motor M332".Manage,
|
|
Motor_M333 := "DB Motor M333".Manage,
|
|
Motor_M334 := "DB Motor M334".Manage,
|
|
Motor_M335 := "DB Motor M335".Manage,
|
|
Motor_M336 := "DB Motor M336".Manage,
|
|
Motor_M340 := "DB Motor M340".Manage,
|
|
Motor_M341 := "DB Motor M341".Manage,
|
|
Motor_M342 := "DB Motor M342".Manage,
|
|
Motor_M343 := "DB Motor M343".Manage,
|
|
|
|
Exchange := "DB ATable Exchange"
|
|
);
|
|
|
|
// Additional device coordination logic if needed
|
|
END_FUNCTION;
|
|
```
|
|
|
|
This specification provides a complete framework for implementing the table accumulation system while maintaining consistency with the existing motor management framework. The design allows for clear separation of concerns, easy debugging, and flexible implementation of motor-specific behaviors.
|
|
|
|
|
|
|