Instantiating of numerous function block in CODESYS (IEC61131) - real-time

I have made a function block using CODESYS to perform energy metering. The inputs of the function block is current and voltage and the output is energy.
Now, we need to have 1000 instances of this function block to run the code for 1000 meter we have. Writing (and possibly copy and pasting) of these instances doesn't seem to be the most interesting work.
Wondering if anybody has a smarter way of doing this numerous instantiation.
For example, here is how the code (in CODESYS) looks like for 2 instances:
meter_instance1(CURRENT:=I1, VOTAGE:=V2);
Energy1:= meter_instance1.ENERGY;
meter_instance2(CURRENT:=I2, VOTAGE:=V2);
Energy2:= meter_instance2.ENERGY;
And we like to have 1000 instances of it.
Any idea is highly appreciated.

Just make an array of the function block:
aEnergyMeter : array [0..999] of FB_EnergyMeter;
Also make arrays of the voltage and the current:
aVoltage : array [0..999] of INT; //if you use INT as type
aCurrent : array [0..999] of INT;
Then you can use it like that:
aEnergyMeter[0](CURRENT:= aCurrent[0], VOLTAGE := aVoltage[0]);
As you use different arrays with the same size, I would prefer to define some global constant:
VAR GLOBAL CONSTANT
firstDevice : UINT := 0;
lastDevice : UINT := 999;
END_VAR
Then you can define the array like that:
aEnergyMeter : array [firstDevice..lastDevice] of FB_EnergyMeter;

I agree with Arndt that you should use an array of function blocks and an array for voltage and current. Depending on your scan rate of your task you should be able to use a for loop to scan through all of your function blocks in a couple lines of code
var
meterInstance : array[1..1000] of FB_EnergyMeter;
voltage : array[1..1000] of int;
current : array[1..1000] of int;
energy : array[1..1000] of int;
end_var
for i:=1 to 1000 by 1 do
meterInstance[i](Voltage := voltage[i],Current:= current[i]);
energy[i] := meterInstance.Energy;
end_for;
in that for loop you could also combine some error checks while you're at it
for i:=1 to 1000 by 1 do
meterInstance[i](Voltage := voltage[i],Current:= current[i]);
if meterInstance.Energy > MaxEnergy then
//sound alarm
end_if;
end_for;
The only caveat with this approach is if the scan time is too fast for your task. You could possibly get a watch dog error as the task would overrrun. However since you are only doing 1000 elements and I am assuming your function block is not extremely complex you should be ok with this approach. If you have problems try extending scan time or watch error time.

Related

Counter in contiki

I'm trying to program Zolertia z1 node in Contiki, i need counter to go from 0 to 120, etimer should be set to 1 second delay(etimer_set(&et, CLOCK_SECOND)), and when i try to do counting it's constantly printing out same number (0 or 1), i think i should use PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)) and probably etimer_restart,and after each second counter should be incremented and printed out (1, 2 ,3 ...), but obviously I'm not doing something correct in while loop or functions are not good?
This code works for me:
PROCESS_THREAD(hello_world_process, ev, data)
{
static struct etimer et;
static int counter;
PROCESS_BEGIN();
etimer_set(&et, CLOCK_SECOND);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
printf("timer called, counter=%u\n", counter++);
etimer_reset(&et);
}
PROCESS_END();
}
Potential pitfalls:
there is no process-local storage for in-process variables in Contiki
processes. Meaning - if you want to save the values of local
variables across yields (such as PROCESS_WAIT_EVENT_UNTIL), declare
them as static. Most likely this is the problem you're facing, as it woul lead to the counter value being reset.
etimer_restart will drift, use etimer_reset instead to get the duration of exactly 120 seconds.

MATLAB Structure array blackjack

I'm writing a program to play blackjack and one of the functions calculates the score. It takes in an input which is a structure array of cards and one of the attributes is value (for an ace the value is 11). My function is supposed to determine if the total of the values is over 21 and if 1 of the cards is an ace, then the ace's value is changed to 1. Can anyone help me figure this out please?
for index=1:length(input)
if(input(input).value == 11)
input(index).value = 1;
end;
end;
You're not actually summing the cards in your original snippet. You also seem to have a typo in input(input), I think this should be input(index). If you wanted to do it with a for loop like you have, you'd do something like this:
total = 0;
for index=1:length(input)
if(input(index).value == 11)
input(index).value = 1;
end;
total = total + input(index);
end;
The more MATLAB way of doing things would be to avoid loops by using the sum in-built command.

z3py: How to implement a counter in z3?

I want to design logics similar to a counter in Z3py.
If writing python script, we usually define a variable "counter" and then keep incrementing it when necessary. However, in Z3, there is no variant. Therefore, instead of defining an variant, I define a trace of that variant.
This is a sample code. Suppose there is an array "myArray" of size 5, and the elements in the array are 1 or 2. I want to assert a constraint that there must be two '2's in "myArray"
from z3 import *
s = Solver()
myArray = IntVector('myArray',5)
for i in range(5):
s.add(Or(myArray[i]==1,myArray[i]==2))
counterTrace = IntVector('counterTrace',6)
s.add(counterTrace[0]==0)
for i in range(5):
s.add(If(myArray[i]==2,counterTrace[i+1]==counterTrace[i]+1,counterTrace[i+1]==counterTrace[i]))
s.add(counterTrace[5]==2)
print s.check()
print s.model()
My question is that is this an efficient way of implementing the concept of counter in Z3? In my real problem, which is more complicated, this is really inefficient.
You can do this but it is much easier to create the sum over myArray[i] == 2 ? 1 : 0. That way you don't need to assert anything and you are dealing with normal expressions.

Change system time of Beckhoff controller by programming

For the last couple of hours, I am facing problems with changing system date and time by structured-text programming. I have used function block FB_LocalSystemTime where I can read the system time. But I could not find any function or function block to write new system time. I have checked NT_SetLocalTime, that also did not work. Do you have any idea how can I do that?
For further information: I have included the sample code like:
/**
Declaration Part
**/
fbLocalSystemTime:FB_localSystemTime;
fbSetLocalTime:NT_SetLocalTime;
newTime:TIMESTRUCT:=(wHour:=5);
/**
DEFINITION PART
**/
fbLocalSystemTime(); /*This gives system time */
fbSetLocalTime.TIMESTR:=newTimne; /* New time to set */
fbSetLocalTime.START:=TRUE;
fbSetLocalTime(); /** This does NOT set the system time which I guess should set **/
I understand the question, but unfortunately I don't have much experience with beckhoff plcs. Have you tried calling their support line? This should be a non application specific question that should be easy for them to help you with.
You may consider using FB_LocalSystemTime in the way indicated below. This will synchronize the local PLC time with the system with the given AMS ID passed to the parameter sNetID. If you do not pass sNetID parameter local OS system will be used as reference for setting the local PLC time. The time will be synchronized on rising edge of the signal bEnable and then in the interval given by the parameter dwCycle
VAR
{attribute 'hide'}
LocalSysTime : FB_LocalSystemTime;
SynchNodeAmsId : STRING := '10.10.10.1.1.1';
END_VAR
LocalSysTime(
sNetID:= SynchNodeAmsId,
bEnable:= TRUE,
dwCycle:= 60,
dwOpt:= ,
tTimeout:= ,
bValid=> ,
systemTime=> ,
tzID=> );
You are correct. You should be using NT_SetLocalTime.
If you open the function block fbSetLocalTime(), you will realize your function block returns an error with error ID 1862.
The definition of the errors can be found here: https://infosys.beckhoff.com/english.php?content=../content/1033/tcplclib_tc2_utilities/18014398544490635.html&id=
1862 means error in win32 system.
This is because TIMESTRUCT consists of Year, Month, Week, etc, but you only initialize the Hour as 5. This means that other things will become 0. The Year needs to be between 1970 and 2106, and there are many things to follow, shown below:
After you use a valid TIMESTRUCT variable, your code should be able to execute without problem and your computer system will be changed.
Had a similiar problem, using TwinCat3. Sometimes it works to change local system time, sometimes not.
I use a small state machine to solve that (also there could be a more advanced solution) - just write 3 times the new time....
Here is an code example:
VAR
nState : BYTE := 0; //local state machine
ntSetLocalTime : Tc2_Utilities.NT_SetLocalTime;
tTimestructSet : Tc2_Utilities.TIMESTRUCT; // time to set
nErrId : UDINT;
nRetryCnt : BYTE := 0;
and the state machine:
CASE nState OF
0: //wait for change
bBusy := FALSE;
nRetryCnt := 0;
1: //trigger change
bBusy := TRUE;
ntSetLocalTime(
NETID:= '',
TIMESTR:= tTimestructSet,
START:= TRUE,
TMOUT:= ,
BUSY=> ,
ERR=> ,
ERRID=> );
nState := 2; //wait for writing
2: //wait till written
ntSetLocalTime(
START:= FALSE,
ERRID => nErrId);
IF NOT ntSetLocalTime.BUSY THEN
nState := 3;
END_IF
3: //retry and after some retries go back to init
nRetryCnt := nRetryCnt + 1;
IF nRetryCnt >=3 THEN
nState := 0;
ELSE
nState := 1;
END_IF
END_CASE
Otherwise you could call Beckhoff hotline, in most cases they have a really good support.

How do I declare a list of fixed length in specman?

In E (specman) I want to declare variables that are lists, and I want to fix their lengths.
It's easy to do for a member of a struct:
thread[2] : list of thread_t;
while for a "regular" variable in a function the above doesn't work, and I have to do something like:
var warned : list of bool;
gen warned keeping {
it.size() == 5;
};
Is there a better way to declare a list of fixed size?
A hard keep like you have is only going to fix the size at initialization but elements could still be added or dropped later, are you trying to guard against this condition? The only way I can think of to guarantee that elements aren't added or dropped later is emitting an event synced on the size != the predetermined amount:
event list_size_changed is true (wanted.size() != 5) #clk;
The only other thing that I can offer is a bit of syntactic sugar for the hard keep:
var warned : list of bool;
keep warned.size() == 5;
I know nothing of specman, but a fixed sized list is an array, so that might point you somewhere.