AB ControlLogix Count for Last 30 days, scalable

RafaelNY

Member
Join Date
Dec 2022
Location
New York
Posts
3
Hello,

I am looking for a good way to count parts for the last 30 days to track production. Our customer frequently powers down the machine. It is OK if value represented is within a 30-day timestamp, or last 30 days of ON time.

I have attached an image representing the production screen. Each hour box shows count for that hour. The boxes at right would display historical counts for last 7 days, 30 days, etc.

I could imagine making a custom data type with a DINT for day, and the other element could be the counter for that day. Next, make an array CountData[365] of this type. Newest date is always at the top. If CountData[0].Date does not match current date, then shift data down. Assuming the machine is always on, 29 days previous should be stored in CountData[29]. Looping and summing the elements would result in desired count. Loop could exit when checked date is older than the range, which should only occur if the machine is powered off for a whole day.

After writing all of that down, it doesn't sound too bad. Is there a more efficient, or integrated way of doing this?

Any good way to store date in days when doing comparisons? Using GSV and WallClockTime, I have Year, Month, and Day, and I would probably need to store and compare all three for each element for it to work properly. It would be better to store days since 2000, for example. Perhaps this is already available using a different system variable?

5069-L306ERS2, Logix Designer 34.01.00
2713P-T12WD1, View Designer 8.02

Thanks in advance for any ideas or insights.

Kind regards,
Rafael

Production Screen.png
 
Consider using a FIFO. The principle is simple; the implementation is straightforward bookkeeping.

This assumes you want to do the logic in the PLC. It might be simpler to send the daily total to a database and then calculate the sums from there with a higher-level, PLC-external method.

TL;DR


Assume there is an array that has the part count for .LEN=366 days up through yesterday, and there is a running count of today.

As you say, when the current date (GSV seconds since epoch / 86400) increases, after first FFUing the oldest day out of the array if the array is full (.POS = 366 or .DN = 1), the "running count of today" becomes the "final count of yesterday" and is FFLed onto the array, and the "running count of today" is zeroed out.

Along with that, there are scalar totals of the last 7, 30, 60, 90, 180, and 365 days.

Every time the date changes and the oldest value is FFUed and new value is FFLed,

  • the value of the element at array[.POS-8] IFF .POS>7 is subtracted from, and the value of the element at array[.POS-1] is added to, the 7-day total
  • the value of the element at array[.POS-31] IFF .POS>30 is subtracted from, and the value of the element at array[.POS-1] is added to, the 30-day total,
  • ditto for 60d, 90d,
  • the value of the element at array[.POS-366] IFF .POS>365 is subtracted from, and the value of the element at array[.POS-1] is added to, the 356-day total.
The ugliest part of the code will be the code that initializes, if necessary, each N-day total if the PLC reboots or the total becomes corrupted, but that can simply work its way backwards from .POS to day .POS-N at one day per scan cycle, and within one or a few seconds all of the totals will be up to date. Putting the adding and subtracting and initializing code into an AOI that uses a global array and has input arguments N and the previous total, and an output argument of the new total (or the total could be an InputOutput argument), means the code is only written once.

Another ugly part would be whatever deals with full missing days of data e.g. if the system is down for a complete day or more.

The efficiency of this approach is that for each scan and running total there are no more than the AOI call, a few compares, one subtract, one or two adds, per total per day, plus one FFL and one FFU per day, and some indirect array lookups. Then again, running the SUM instruction over ~732 elements will probably not trigger the scan cycle watchdog timeout, in which case the totaling is even simpler.
 
Last edited:
I wouldn't have a 365 array and instead break it into 52 arrays of CountData[7] OR 12 arrays of CountData[31]. This way you'd get finer control over weekly averages as well.

I'd then use the Day and month field from the GSV instruction to point you to the correct structure.

To know which one of the weeks to fill the data in, you'd have to keep track of it.

I would add the further statistics fields on the higher level UDTs as well. For example, when the day changes you could recalculate the highest/lowest count per day as well as the average of the month and store it on the higher level UDT. You could, if you have that data available as well, count the operation time and stopping time and add it into another variable too.

Then you'd have everything ready to display for the operator or trip a trigger to get your Historian to pull the data over.

Mind that you could still display a trend of the different days or the average of the months. After a year, you'd have a rolling window.
 
I wouldn't have a 365 array and instead break it into 52 arrays of CountData[7] OR 12 arrays of CountData[31]. This way you'd get finer control over weekly averages as well.


That would be messy, but not impossible, to code, but if OP is defining "Last 7 days" as "most recent Monday through Sunday" then maybe yeah. Even so, it would be easier to stay with the 366-element array and simply keep track of the start index into that array of each week and month.
 
@drbitboy,

Is there a function that shifts the array downward, and adds the new data to element 0? Using FFL/FFU shifts data up, so the oldest data would always be in element 0.

Kind regards,
 
@drbitboy,

Is there a function that shifts the array downward, and adds the new data to element 0? Using FFL/FFU shifts data up, so the oldest data would always be in element 0.

Kind regards,

I don't think so, not directly anyway, why are you limited to shifting in one direction?

You can COP contiguous elements of data from [0:N-1] to [1:N], but not directly, those data to be shifted need to be copied to a separate buffer first.

It could also be done without shifting any data and managing the most recent index instead.
 
All,

Here is what I came up with. I have a structure with a DINT for days since 1970, and a DINT[8] for each part count. I have an array of this type with 366 elements. First image is the array shift and For Loop call. Second image is the conditional summing. Third image displays how I made an Exit For. It looks like the changes I made resulted in a 30000 block increase in capacity.

Kind regards,

Array Shift, Loop Call.png For Loop1.png Exit For Loop.png
 

Similar Topics

We are looking to use an event driven task to count meters of material on a machine from a proximity switch. Every pulse of the switch initiates...
Replies
14
Views
4,307
Why does the controllogix redundancy modules use a single mode fiber vs multimode fiber?
Replies
1
Views
51
Hello, I have two 16 point input cards and 1 16 point output card showing module faulted on my IO tree in Logix Designer. The fault code is...
Replies
7
Views
203
Hello, My associate and I are trying to sync up two ControlLogix racks (7-slot chassis) with identical modules. We are able to see the secondary...
Replies
4
Views
182
Trying to setup a message read via Ethernet. I have the path setup as 1, 1, 2, 192.168.66.10 I get an error code 1, ext err 315. I am beating...
Replies
9
Views
224
Back
Top Bottom