I just replaced a bunch of junk code used in a sorting machine that was based on FIFO stacks...
It would get "off" by a box or two at least once every 36-48 hours of production at up 21 cases per minute. The operators had to manhandle a bunch of product and perform an HMI reset sequence while the upstream conveyors accumulated product. The robot cell would keep palletizing sometimes unnoticed 'til quite a bit of stuff was in the wrong stack.
Sometimes this would halt our sausage packing department if it happened several times in quick succession, or the operator was busy doing paperwork or something and didn't baby sit the area really carefully.
I found to my surprise that cardboard cases are highly reflective and were fooling the fixed field photocells and therefore fouling up the FIFO stacks even with debounce timers in the PLC. It was quite erratic too, seemed to be affected by lots of environmental variables beyond my scope of control. Sometimes it would hiccup 6 or 8 times during a single day shift, and then run a whole 24 hours just fine.
I arrived at the conclusion (<- opinion) that dependence on multiple photocells with simple FIFO stacks to drive the PLC model of the product positions is a flawed design.
The PLC can estimate the product positions much more accurately with a more carefully put-together abstraction.
In my new logic, each box is "birthed" into PLC memory by being qualified by a single, reliable, polarized retroreflective photocell. The speed of the conveyor can be calculated or measured or both, so the PLC can easily predict the distance travelled based on time of birth and rate of travel.
I didn't have an encoder to drive my replacement logic as I have done in the past with fantastic results, so I used a handheld tach to build PLC "pseudo" encoders which keep the PLC informed as to the distance travelled by each belt during each PLC scan.
The new logic calculates the distance travelled every 100ms STI scan by all four conveyors including estimated accel and decel times and a routine in the main PLC scan cycle updates an array containing "Boxes_In_Process". I need to do away with the STI routine and just update the whole array every scan, but it was easy to implement that way and plenty accurate enough for this application, since I could easily convert motor starter statuses and carefully measured speed to 100ms chunks.
The array is a set of files: N (integer) file to hold the ID code for the box, N file for the lane assignment, F (floating point) file for the current position past the primary eye in inches, (and three more N files for the unnecessary redundant barcode readers my boss forced me to install....)
He still thinks that all four readers are involved in the tracking, but it has been running almost flawlessly in single reader mode for 3 months. Once in a while they break a kicker cylinder or valve or that one critical eye gets dirty, but no boxes get mis-sorted anymore.
If not for those added readers, the whole improvement only required the purchase of one $75 photocell and reflector.
I use that one single primary measuring eye to qualify the length of each product.
Now it cannot get out of sync unless a conveyor belt breaks (which has never happened, but a coupling broke once and it sent one wrong box down a lane and then stopped due to a photocell alarm). If the eye detects an "Irregular Size" box (outside my qualification limits) the line stops, and there is only one eye/reflector to check.
So I replaced a bunch of SLC code and one of the fixed field photocells with a polarized retroreflective style to eliminate more than 99% of the systems' previous problems.
My new logic uses indexed addressing liberally to update a hand-made SLC UDT that keeps up will all the boxes in transit between the redundant (4) barcode readers and the final lane conveyors.
I don't shift much data, just a pair of pointers that tell me where to POKE in the next new carton detected, and the index pointer for the farthest one on the sort belt. Each time a box is born (qualified), the low pointer is decremented (with wraparound) and the length value is popped into that Fn:Low_Pointer.
Each time a box is kicked into a lane, it's position is added to put it out of range of the update logic. If the high pointer position is greater than my end conveyor position, the high pointer is decremented (with wraparound).
So this way, I don't have to update 200 case positions unless there are really 200 cases in process. My system usually only has 6 or eight boxes in transit at any given moment, which makes this apprach very feasible. I have another method for situations where much more product is in process which uses less CPU time, but is more difficult for the layman to follow.
The barcode readers are triggered when this position reaches their trigger window limits, and then they populate the ID field for that array item. So I do dozens of indexed compares, and a lot of limit checks with indexed sources to manage all the products, the diverter assignments
I DO still rely on the old photocells to time the kicker SV outputs, but that's all they do.
Now you can't make the thing mis-sort. If you flag an eye and try to fool the system, it "knows" there isn't a box in that position range assigned to that eye and will halt the cartons and let them accumulate upstream until the PV+ "Photocell x Alarm" is ack'd.
The original code without STI routine and with sparse indexed addressing was about 25ms.
Now it averages about 40ms and peaks out around 50 once in a while when there are multiple interfaces beating up the DH+ on the 5/04.
Still, that is plenty fast enough for my box stops and kickers on local I/O to catch and kick boxes off. I was able to bump up throughput to 25 cases per minute and virtually eliminate line stoppages. The main sort belt runs at 91FPM and my products are from 14 to 30 inches in length, with about a 2' required gap required by the mechanical swing-down style box stopper and kicker design, or it could run much more product.
That's how this Okie does product sorting in a nutshell...
Paul