FB_MultiCam - General Information
Type: |
Function block |
Available as of: |
V1.0.3.0 |
Inherits from: |
- |
Implements: |
- |
Perform the curve-based motion sequence.
Function block for motion tasks that can be defined by presetting the motion processes in segments. The description of the motion sequence is stored in a structure (type ST_MultiCam). It comprises the number of motion points (diNumberOfCamPoints maximum 32), and an array of points (type ST_CamPoint). By changing the existing structure, it is possible to switch various motion sequences to event-driven (for example, start cycle, continuous cycle, stop cycle, etc.).
Cold Start
Cold start means starting at the beginning of the motion sequence.
A cold start is executed with input i_xStart = TRUE and input i_xWsSelect = FALSE. There are various options (input variables i_etCsModeSlave and i_etCsModeMaster) for the cold start.
Analytical profile application
The analytical profiles of the PacDrive controller (simple sine, inclined sine, modified sine, modified acceleration trapezoid or the polynomial of the fifth degree) can be used as Rest-Rest, Rest-Velocity and Velocity-Rest profiles.
User profile application
In addition, any user profiles can be used. The profiles must be available as “<Name>.pp3 and can then be loaded in a normal manner.
NOTE: Used user profiles must be available on the flash disk. When replacing the flash disk, make sure that all profile data are copied.
NewCam
This abort is triggered using the input Iq_xNewCam. Setting the iq_xNewCam signalizes that a new profile is to be used in the next cycle. The function block resets the input iq_xNewCam at the start of the new profile.
NewCam
NOTE: If the signal iq_xNewCam is set too late, the cam switchover is not executed at the subsequent cycle but at the one after that.
If the signal is set by an asynchronous program task, the cycle time of the task must still be added to the time in which the FB is called.
The input iq_xNewCam is only evaluated at the end of the current cam.
Example:
Program cycle time = 5 ms, SERCOS CycleTime = 2 ms, then TXend must be >= 7 ms.
InstantNewCam
If the current profile shall be interrupted to run another profile instead, this can be carried out at the master position i_lrInstantXLimMax. For this purpose, a new structure ST_MultiCam must be loaded. Also, the position, slope and curvature of both profiles must be equal for i_lrInstantXLimMax and the input iq_xInstantNewCam must be set. The function block resets the input iq_xInstantNewCam at the start of the new profile.
NOTICE |
SETPOINT JUMPS |
oThe iq_xInstantNewCam signal must be set before reaching the master encoder position i_lrInstantXLimMax. oPosition, gradient and curvature of the old and new profiles must match at the master encoder position i_lrInstantXLimMax. |
Failure to follow these instructions can result in equipment damage. |
InstantNewCam
Input |
Data type |
Description |
---|---|---|
i_xEnable |
BOOL |
A rising edge FALSE -> TRUE activates the POU, a falling edge TRUE -> FALSE deactivates the POU. A deactivated POU does not execute any actions. |
i_ifDrive |
IF_Drive |
Input for the axis that shall be controlled. |
i_xStart |
BOOL |
Starts the drive motion With i_xStart = FALSE, the running cycle is stopped at the end. If the end slope of the final motion section is not zero, progress is stopped with i_lrWsAcc. Further parameters relevant for stopping (e.g. xStopPositionSelect), can be found in iq_stExt. |
i_xWsSelect |
BOOL |
A "warm start" is executed with input i_xStart = TRUE and input i_xWsSelect = TRUE. "Warm start" means that it starts in the middle of a motion sequence (e.g., after an emergency stop). The FB orients itself to the master position and moves to the curve position. As soon as the drive position is back at the cam position, the output q_xSynActive is set. This signal can be used to start the master encoder. The master encoder must be at a standstill during "warm start". If the master encoder or axis position is outside of its period during "Warm start", it will be brought into the period (Position = Position MOD Period). |
i_etCsModeSlave |
Cold start mode of the slave axis |
|
i_etCsModeMaster |
Cold start mode of the master encoder. |
|
i_etWsMode |
Warm start mode |
|
i_lrWsWindow |
LREAL |
Warm start window (slave axis +/-) |
i_lrWsVel |
LREAL |
Velocity for moving to the warm start position (slave position) in units/s. |
i_lrWsAcc |
LREAL |
Acceleration for moving to the warm start position (slave position) in units/s2. |
i_lrWsJerk |
LREAL |
Jerk for moving to the warm start position (slave position) in units/s3. |
i_xWsStart |
BOOL |
The input starts the motion upon the warm start if i_xWsStart = TRUE. |
i_diTXEnd |
DINT |
Determines the setting of the outputs q_xXHighEnd and q_xXLowEnd. TXEnd is a time specification in ms. TXEnd determines the last possible takeover of the iq_xNewCam signal. TXEnd is limited to 1.5 * program cycle time. TXEnd is extended internally by one program cycle in order to ensure that q_xXHighEnd comes at least TXEnd before the end. This is only effective if the parameter iq_stExt.lrXEndWidth = 0. |
i_lrInstantXLimMax |
LREAL |
Abort position of the current motion profile and taking over the new motion profile with iq_xInstantNewCam. |
Output |
Data type |
Description |
---|---|---|
q_xActive |
BOOL |
TRUE: The POU is active and has to be executed further. FALSE: The POU is inactive. |
q_xReady |
BOOL |
TRUE: The POU is ready to operate and can accept user commands. FALSE: The POU is not ready to accept user commands. |
q_etDiag |
General library-independent statement on the diagnostic. A value not equal to ET_Diag.Ok corresponds to an diagnostic message. |
|
q_etDiagExt |
POU-specific output on the diagnostic. q_etDiag = ET_Diag.Ok -> Status message q_etDiag <> ET_Diag.Ok -> Diagnostic message |
|
q_sMsg |
STRING[80] |
Event-triggered message which gives more detailed information on the diagnostic state. |
q_xInWsWindow |
BOOL |
The output indicates whether the slave axis is inside the defined warm start window i_lrWsWindow. q_xInWsWindow is only set in i_etWsMode 2, 3, 12 and 13 if the slave position (axis) is inside the window around the cam position. Only the current period is affected. The window is not valid for the previous or the subsequent period. The output q_xInWsWindow is only reset with the output q_xSynActive. |
q_xSynActive |
BOOL |
TRUE: The master axis and the slave axis run synchronously (curve is active). |
q_lrPositionX |
LREAL |
Output of the position X. (Master position) |
q_lrPositionY |
LREAL |
Output of the position Y. (Slave position) |
q_xXLowEnd |
BOOL |
XlowEnd signals the lower end of the curve. If iq_stExt.lrXEndWidth = 0 then the output i_diTXEnd msec is set before the lower end of the curve. If iq_stExt.lrXEndWidth > 0 then the output i_diTXEnd units is set before the lower end of the curve. |
q_xXHighEnd |
BOOL |
XHighEnd signals the upper end of the curve. If iq_stExt.lrXEndWidth = 0 then the output i_diTXEnd msec is set before the upper end of the curve. If iq_stExt.lrXEndWidth > 0 then the output i_diTXEnd units is set before the upper end of the curve. |
q_stActualCamData |
Active travel profile data. The output returns the data of the running profile. This can be helpful when wanting to abort the running profile in order to add another profile. The data are collected in a stActualCamData structure and can be used directly as input data for the function block FB_ProfilPoint(). |
Input/Output |
Data type |
Description |
---|---|---|
iq_lencMaster |
L_ENC |
Input for the logical encoder which defines the master motion. |
iq_stExt |
Contains the parameters for options. |
|
iq_xNewCam |
BOOL |
Starts a new motion profile based on the current motion profile xNewCamDirectAccept = TRUE: The synchronization of the iq_xNewCam signal with q_xXLowEnd and q_xXHighEnd is canceled. iq_xNewCam is accepted immediately. The iq_xNewCam signal can therefore come later. It now is enough to set iq_xNewCam one program cycle + one SERCOS cycle before the end of the cam. |
iq_xInstantNewCam |
BOOL |
Cancels the current motion profile with i_lrInstantXLimMax and starts a new motion profile. |
iq_stMultiCamData |
Information on the course of the cam. |
q_etDiag |
q_etDiagExt |
Enumeration value |
Description |
---|---|---|---|
OK |
9 |
The POU is disabled. |
|
OK |
4 |
The POU is being initialized. |
|
OK |
151 |
The cam position is displayed. |
|
OK |
155 |
Waiting for the next cam command. |
|
OK |
5 |
Waiting for starting command. |
|
OK |
148 |
Waiting for a WsStart signal. |
|
OK |
157 |
Waiting until cam is finished. |
|
OK |
160 |
Waiting until cam position is reached. |
|
OK |
152 |
Waiting until cam is started. |
|
OK |
8 |
Waiting until the POU is deactivated. |
|
OK |
154 |
Waiting until the first cam has started. |
|
OK |
149 |
Waiting until start position has been reached. |
|
OK |
159 |
Waiting until the drive has stopped. |
|
OK |
156 |
Waiting until stop position has been reached. |
|
DriveConditionInvalid |
10 |
The drive is not ready for motion commands. |
|
InputParameterInvalid |
12 |
Acc is outside the valid range. |
|
InputParameterInvalid |
125 |
The boundary conditions are invalid. |
|
InputParameterInvalid |
13 |
Dec is outside the valid range. |
|
InputParameterInvalid |
3 |
The connected drive is invalid. |
|
InputParameterInvalid |
14 |
Jerk is outside the valid range. |
|
InputParameterInvalid |
162 |
The connected logical encoder is invalid. |
|
InputParameterInvalid |
121 |
NumberOfCamPoints is outside the valid range. |
|
InputParameterInvalid |
129 |
K is outside the valid range. |
|
InputParameterInvalid |
130 |
M is outside the valid range. |
|
InputParameterInvalid |
126 |
The cam type is indeterminable. |
|
InputParameterInvalid |
164 |
CsModeMaster is indeterminable. |
|
InputParameterInvalid |
181 |
CsModeSlave is indeterminable. |
|
InputParameterInvalid |
153 |
The WSMode is indeterminable. |
|
InputParameterInvalid |
11 |
Vel is outside the valid range. |
|
InputParameterInvalid |
122 |
XFactor is too small. |
|
InputParameterInvalid |
158 |
YEqualCheck was unsuccessful. |
|
SercosConditionInvalid |
19 |
The Sercos bus is not in phase 4. |
|
UnexpectedProgramBehavior |
116 |
The profile is already in use. |
|
UnexpectedProgramBehavior |
127 |
The memory for tables from system profiles is full. |
|
UnexpectedProgramBehavior |
123 |
The system profile table is full. |
|
UnexpectedProgramBehavior |
1 |
An unintended detected error occurred during execution. |
|
UnexpectedProgramBehavior |
2 |
The POU is in an undefined state. |
|
WarmStartConditionInvalid |
150 |
The position of the drive is outside of WsWindow. |
|
WarmStartConditionInvalid |
161 |
The master has moved. |
|
WarmStartConditionInvalid |
326 |
A user-defined Cam profile has been deleted. |
Enumeration name: |
AccRange |
Enumeration value: |
12 |
Description: |
Acc is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_lrWsAcc, an invalid value has been transferred. |
The following must hold: 0 < i_lrWsAcc < drive parameter MaxAcc For the valid value range for i_lrWsAcc, see output q_sMsg |
- |
If iq_stExt.xStartPositionSelect = TRUE: At the iq_stExt.lrStartAcceleration, an invalid value has been transferred. |
The following must hold: 0 < iq_stExt.lrStartAcceleration < parameter MaxAcc of the drive For the valid value range for iq_stExt.lrStartAcceleration, see output q_sMsg |
- |
If iq_stExt.xStopPositionSelect = TRUE: At the iq_stExt.lrStopAcceleration, an invalid value has been transferred. |
The following must hold: 0 < iq_stExt.lrStopAcceleration < parameter MaxAcc of the drive For the valid value range for iq_stExt.lrStopAcceleration, see output q_sMsg |
Enumeration name: |
BoundaryConditionInvalid |
Enumeration value: |
125 |
Description: |
The boundary conditions are invalid. |
Issue |
Cause |
Solution |
---|---|---|
- |
When defining the motion profile in iq_stMultiCamData, the set boundary conditions cannot be complied with. |
Verify the definition of the motion profile and particularly the boundary conditions of the sub-segments. As an alternative, select different profiles for the sub-segments to be able to comply with all desired boundary conditions. |
Enumeration name: |
DecRange |
Enumeration value: |
13 |
Description: |
Dec is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
If iq_stExt.xStartPositionSelect = TRUE: At the iq_stExt.lrStartDeceleration, an invalid value has been transferred. |
The following must hold: 0 < iq_stExt.lrStartDeceleration < parameter MaxAcc of the drive For the valid value range for iq_stExt.lrStartDeceleration, see output q_sMsg |
- |
If iq_stExt.xStopPositionSelect = TRUE: At the iq_stExt.lrStopDeceleration, an invalid value has been transferred. |
The following must hold: 0 < iq_stExt.lrStopDeceleration < parameter MaxAcc of the drive For the valid value range for iq_stExt.lrStopDeceleration, see output q_sMsg |
Enumeration name: |
Disabled |
Enumeration value: |
9 |
Description: |
The POU is disabled. |
The function block is disabled and executes no actions whatsoever. i_xEnable and q_xActive are set to FALSE
Enumeration name: |
DriveInvalid |
Enumeration value: |
3 |
Description: |
The connected drive is invalid. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_ifDrive, no drive was applied. |
At the input i_ifDrive, a valid drive must be transferred. |
- |
The connected drive does not support all required functionalities. |
Establish which functionalities are not supported by the drive by means of output q_sMsg. Use a drive which supports all required functionalities. |
Enumeration name: |
DriveNotReady |
Enumeration value: |
10 |
Description: |
The drive is not ready for motion commands. |
Issue |
Cause |
Solution |
---|---|---|
- |
The axis is not in position control. |
Verify the state of the axis. |
Enumeration name: |
DrivePositionOutOfWsWindow |
Enumeration value: |
150 |
Description: |
The position of the drive is outside of WsWindow. |
Issue |
Cause |
Solution |
---|---|---|
- |
The axis has been moved beyond i_WsWindow while switched off. |
Move the axis back into the warm start window. Extend the limits of the warm start window. Perform a cold start. |
Enumeration name: |
Initializing |
Enumeration value: |
4 |
Description: |
The POU is being initialized. |
The function block is being initialized and thus is not yet ready to receive commands at its inputs.
The function block will signalize that it is ready for operation with the signal q_xReady = TRUE.
Enumeration name: |
JerkRange |
Enumeration value: |
14 |
Description: |
Jerk is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_lrWsJerk, an invalid value has been applied. |
At the input i_lrWsJerk, a value greater than 0 and smaller than or equal to Gc_lrMaxJerk must be transferred. |
- |
The input iq_stExt.xStartPositionSelect has been set to TRUE and at the input iq_stExt.lrStartJerk, an invalid value has been transferred. |
At the input iq_stExt.lrStartJerk, a value greater than 0 and smaller than or equal to Gc_lrMaxJerk must be transferred. Do not move to a start position by setting iq_stExt.xStartPositionSelect to FALSE. |
- |
The input iq_stExt.xStopPositionSelect has been set to TRUE and at the input iq_stExt.lrStopJerk, an invalid value has been transferred. |
At the input iq_stExt.lrStopJerk, a value greater than 0 and smaller than or equal to Gc_lrMaxJerk must be transferred. Do not move to a stop position by setting iq_stExt.xStopPositionSelect to FALSE. |
Enumeration name: |
LencInvalid |
Enumeration value: |
162 |
Description: |
The connected logical encoder is invalid. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input iq_lencEncoder, no encoder has been applied. |
At the input iq_lencEncoder, a separate logical encoder must be transferred. |
Enumeration name: |
MasterMoved |
Enumeration value: |
161 |
Description: |
The master has moved. |
Issue |
Cause |
Solution |
---|---|---|
- |
The master has moved during the warm start. |
Ensure that the master does not move during the warm start motion. |
Enumeration name: |
NumberOfCamPointsRange |
Enumeration value: |
121 |
Description: |
NumberOfCamPoints is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input iq_stMultiCamData.diNumberOfCamPoints, an invalid value has been transferred. |
At the input iq_stMultiCamData.diNumberOfCamPoints, a value greater than 0 and smaller than or equal to SystemInterface.MAX_NO_OF_SEG + 1 must be transferred. |
Enumeration name: |
ProfileAlreadyInUse |
Enumeration value: |
116 |
Description: |
The profile is already in use. |
Issue |
Cause |
Solution |
---|---|---|
- |
The motion profile is already in use. |
Verify the motion data. |
Enumeration name: |
ProfileMemoryFull |
Enumeration value: |
127 |
Description: |
The memory for tables from system profiles is full. |
Issue |
Cause |
Solution |
---|---|---|
- |
The system profile memory is full. |
Delete any profiles that are no longer needed using the SystemInterface.FC_ProfileDelete function |
Enumeration name: |
ProfileTableFull |
Enumeration value: |
123 |
Description: |
The system profile table is full. |
Issue |
Cause |
Solution |
---|---|---|
- |
The maximum number of system profiles has been exceeded. |
Delete any profiles that are no longer needed using the SystemInterface.FC_ProfileDelete function |
Enumeration name: |
RangeK |
Enumeration value: |
129 |
Description: |
K is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input iq_stMultiCamData.astCamPoint[ ].lrK, an invalid value has been applied. |
Verify the values for iq_stMultiCamData.astCamPoint[ ].lrK |
Enumeration name: |
RangeM |
Enumeration value: |
130 |
Description: |
M is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input iq_stMultiCamData.astCamPoint[ ].lrM, an invalid value has been applied. |
Verify the values for iq_stMultiCamData.astCamPoint[ ].lrM |
Enumeration name: |
SercosNotInPhaseFour |
Enumeration value: |
19 |
Description: |
The Sercos bus is not in phase 4. |
Issue |
Cause |
Solution |
---|---|---|
- |
The parameter State of the SERCOS bus is not 4. |
Set the SERCOS bus parameter PhaseSet to 4. Verify the SERCOS bus for errors. |
Enumeration name: |
ShowCamPosition |
Enumeration value: |
151 |
Description: |
The cam position is displayed. |
At output q_lrPositionY, the cam position is displayed.
Enumeration name: |
UnexpectedFeedback |
Enumeration value: |
1 |
Description: |
An unintended detected error occurred during execution. |
Issue |
Cause |
Solution |
---|---|---|
- |
An error occurred in the internal execution. |
Please inform the support team about this error. |
Enumeration name: |
UnknownCamType |
Enumeration value: |
126 |
Description: |
The cam type is indeterminable. |
Issue |
Cause |
Solution |
---|---|---|
- |
The cam type of a point iq_stMultiCamData.astCamPoint is assigned with an invalid cam profile. |
The cam types etCamType of all used cam points at the input iq_stMultiCamData.astCamPoint must be assigned with an element of the enumeration ET_CamType. |
Enumeration name: |
UnknownCsModeMaster |
Enumeration value: |
164 |
Description: |
CsModeMaster is indeterminable. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_etCsModeMaster, an invalid value has been transferred. |
At the input i_etCsModeMaster, an element of the enumeration ET_MultiCamCsModeMaster must be transferred. |
Enumeration name: |
UnknownCsModeSlave |
Enumeration value: |
181 |
Description: |
CsModeSlave is indeterminable. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_etCsModeSlave, an invalid value has been transferred. |
At the input i_etCsModeSlave, an element of the enumeration ET_MultiCamCsModeSlave must be transferred. |
Enumeration name: |
UnknownState |
Enumeration value: |
2 |
Description: |
The POU is in an undefined state. |
Issue |
Cause |
Solution |
---|---|---|
- |
An error occurred in the internal execution. |
Please inform the support team about this error. |
Enumeration name: |
UnknownWsMode |
Enumeration value: |
153 |
Description: |
The WSMode is indeterminable. |
Issue |
Cause |
Solution |
---|---|---|
- |
At the input i_etWSMode, an invalid value has been applied. |
At the input i_etWSMode, elements of the enumeration ET_MultiCamWsMode must be applied. |
Enumeration name: |
UserCamHasBeenDeleted |
Enumeration value: |
326 |
Description: |
A user-defined Cam profile has been deleted. |
Issue |
Cause |
Solution |
---|---|---|
- |
An active Cam profile has been deleted by calling SystemInterface.FC_ProfileDelete(). |
Verify that Cam profiles are available when being executed. |
Enumeration name: |
VelRange |
Enumeration value: |
11 |
Description: |
Vel is outside the valid range. |
Issue |
Cause |
Solution |
---|---|---|
- |
The axis cannot reach the warm start velocity. |
Apply a value to i_lrWsVel which is smaller than the axis parameter MaxVel. |
- |
The axis cannot reach the velocity of the start motion. |
Apply a value to iq_stExt.lrStartVelocity which is smaller than the axis parameter MaxVel. Set iq_stExt.xStartPositionSelect to FALSE so that no start motion is executed. |
- |
The axis cannot reach the velocity of the stop motion. |
Apply a value to iq_stExt.lrStopVelocity which is smaller than the axis parameter MaxVel. Set iq_stExt.xStopPositionSelect to FALSE so that no stop motion is executed. |
Enumeration name: |
WaitForNewCam |
Enumeration value: |
155 |
Description: |
Waiting for the next cam command. |
The cams are moved according to their task sequence.
Enumeration name: |
WaitForStart |
Enumeration value: |
5 |
Description: |
Waiting for starting command. |
The function block has completed its initialization and is waiting for a positive edge at the input i_xStart before continuing the processing.
Enumeration name: |
WaitForWsStart |
Enumeration value: |
148 |
Description: |
Waiting for a WsStart signal. |
After a signal at the input i_xWsStart, the warm start motion is started.
Enumeration name: |
WaitUntilCamFinished |
Enumeration value: |
157 |
Description: |
Waiting until cam is finished. |
The axis moves on until the end of the current cam is reached.
Enumeration name: |
WaitUntilCamPositionReached |
Enumeration value: |
160 |
Description: |
Waiting until cam position is reached. |
The axis is moved to its position on the cam.
Enumeration name: |
WaitUntilCamStarted |
Enumeration value: |
152 |
Description: |
Waiting until cam is started. |
The function block waits for the cam to be moved.
Enumeration name: |
WaitUntilDisabled |
Enumeration value: |
8 |
Description: |
Waiting until the POU is deactivated. |
The function block is disabled. All internal states are reset and connected resources (e.g. axes) are transferred to a safe state. The function block has to be called up continuously until it reports q_xActive = FALSE.
Enumeration name: |
WaitUntilFirstCamStarted |
Enumeration value: |
154 |
Description: |
Waiting until the first cam has started. |
The function block waits for the first cam to be started.
Enumeration name: |
WaitUntilStartPositionReached |
Enumeration value: |
149 |
Description: |
Waiting until start position has been reached. |
The axis is moved to its start position.
Enumeration name: |
WaitUntilStopped |
Enumeration value: |
159 |
Description: |
Waiting until the drive has stopped. |
The axis is stopped.
Enumeration name: |
WaitUntilStopPositionReached |
Enumeration value: |
156 |
Description: |
Waiting until stop position has been reached. |
The axis is moved to its stop position and comes to a halt there.
Enumeration name: |
XFactorTooSmall |
Enumeration value: |
122 |
Description: |
XFactor is too small. |
Issue |
Cause |
Solution |
---|---|---|
- |
Two successive cam points iq_stMultiCamData.astCamPoint[ ].lrX have a distance of less than 0.1 units. |
Verify the definition of the cam and, if necessary, remove cam profiles that are too short. |
Enumeration name: |
YEqualCheckFailed |
Enumeration value: |
158 |
Description: |
YEqualCheck was unsuccessful. |
Issue |
Cause |
Solution |
---|---|---|
- |
If iq_stExt.xYEqualCheck = TRUE: The verification on whether the new cam directly follows the old cam was unsuccessful. |
Configure the new cam such that its start deviates by less than 0.0001 units from the end of the old cam. Deactivate the verification by setting iq_stExt.xYEqualCheck = FALSE. |
Name |
Description |
---|---|
The method registers the internal logger point in the Application Logger. |