Introducing delays is often needed in behavior modeling. Delays are usually required by the external circuit before which the data has to arrive at the output pin of the block with respect to reference clock. In the common case we have a signal on input that should appear on output after a period of time. This is the use case that I am addressing in this post.
So let's assume that we have a function block with one input and one output of type Real. The task is: input values should appear on output after a period of 5 seconds.
To implement such logic we need some sort of a structure that will hold the input values for the last 5 seconds. Then these values should be sent to the output. In our case we will use an array for this. The array should be large enough to store all input values. To calculate the size of it we divide the time for the delay by the sampling time (LB update rate). Example: to store the values for the last 5 seconds with a 100ms sampling rate we need an array of size 5000ms / 100ms = 50 elements. So we simply need this static variable definition:
VAR
buff: Array [0..49] of Real;
END_VAR
Now we need a way to measure time. Of course we'll use a timer for this. e.g. one more static variable:
VAR
buff: Array [0..49] of Real;
timer : TP_TIME;
END_VAR
Don't forget the input and output values:
VAR_INPUT
in : REAL;
END_VAR
VAR_OUTPUT
out : REAL;
END_VAR
How about the logic inside the FB? Simple: we push the input values at the end of the array. When the time elapses we start popping them out from the beginning of the array. Essentially we get a circular buffer holding the values.
Here is how this looks:
FUNCTION_BLOCK "MAIN"
VERSION:1.0
VAR_INPUT
in : REAL;
END_VAR
VAR_OUTPUT
out : REAL;
END_VAR
VAR
buff : Array [0..49] of REAL;
timer : TP_TIME;
front : UINT;
tail : UINT;
END_VAR
BEGIN
#timer(IN:=true, PT:=T#5000ms); // start the timer
if not #timer.Q then // timer elapsed ?
#out := #buff[#front]; // pop output values
#front := (#front + 1) MOD 50; // 0-49
end_if;
#buff[#tail] := #in; // push input values
#tail := (#tail + 1) MOD 50; // 0-49
END_FUNCTION_BLOCK
Once we have the logic in place we need a signal generator to test it. For this example I created a simple script that generates a sine wave.
To visualize the results I am using a fake kinematic device that assigns both values to its joints with another script. Then observe the joint values in Robot Viewer.
The result looks like this:
There you go! We have a block introducing output delays.
Can you think of an actual use-case for it?
Let me know how you use it.
Have a great day!
Comments