Hopper High/Low Priority Request Logic

First it's hard to do with just 2 level sensors you really should have 3
How are you filling the hoppers it dose make a differance
Vacuum transport, Gated conveyor, Blower, Gravity eact have to be handled differently
i have done many fill systems and the best way is a FIFO how you set then up maked the differance
 
Again lack of info is making us jump to conclusions, I too assumed some analogue level or weight, but it seems there are digital probes, no idea if there is 2 or 3 or more.
To get valid replies the more information given the better the replies.
 
Extended queries in blue:

  • What are all of the inputs to the PLC?
    • Analog
      • range and accuracy (noise level)
      • significance to the process
      • are there any trigger values or rates above or below which some action should be taken? If yes, describe the trigger and the action.
    • Digital
      • assessment of hysteresis vs. noise
      • significance to the process
        • what does a 1 mean?
        • what does a 0 mean?
        • what does a 0-to-1 transition mean?
        • what does a 1-to-0 transition mean?
  • What are all of the outputs from the PLC?
    • Analog
      • What does it control?
      • What is its range?
      • How do changes in other inputs or outputs affect how it should change?
    • Digital
      • What does it control?
      • What does a 1, a 0, a 0-to-1, a 1-to-0, do?
      • How do changes in other inputs or outputs affect how it should change?
  • How does the infeed and conveyor system work?
    • Are there multiple conveyors (one per hopper) with the infeed system able to direct product to one conveyor at a time,
    • or is there one conveyor fed by the infeed system that can be moved or directed to fill one hopper at a time?
    • What are the inputs from (if any) and outputs to the infeed and conveyor system?
  • In the first post (#1), 75% was the Normal Priority level, below which filling might be initiated. In the last post (#14), there is also a Full Sensor, levels above which will initiate a stop to any current filling. Is the Full Sensor at the same level as the Normal Priority level, in which case start/stop would be on a knife edge that could be triggered by noise, or is there some hysteresis between those levels?


As @GaryS notes, there is a lot about this process we do not know.

To this point, it seems like this will not take a lot of code. A FIFO should work, as @GaryS notes, but how that is implemented is TBD. It could be an actual pair of FIFOs (one for normal priority, one for high priority).

the FIFO could also be a ten-element array of per-hopper [priority,timestamp] pairs that is searched for the [highest priority, earliest timestamp] pair whenever no filling is active* to determine the next hopper to fill. Such an approach would allow using the scan cycle to implement looping over the array, as a delay of ten or so scan cycles to start the next fill might not be a problem. Here is a thread with an example of this approach: https://www.plctalk.net/qanda/showthread.php?t=134096

* e.g. after a hopper being filled reaches full
 
If level sensors are digital then you could try something like this. It fills all your requirements to give anything less than 25% priority and keeps up with order in which signals become active. Then fill 75% request after all 25% is completed.

it's an exported subroutine.
 
I like this version better if anybody is interested. Not sure OP is still involved in this thread, but I thought I would post it.
 
PDFs of that code would be more universally useful: not everyone either can open, or has enough time to interpret, .L5Xs.
 
Here you go Doc per your request I have attached .pdf of logic and tags. Looking forward to your review.:site:
 
I have 10 Hoppers each with 2 level sensors; one is at the 75% full level and the other is at the 25% full level.
I need to fill hoppers that fall below the 25% level (High Priority) first, then any that fall below the 75% level (Normal Priority).
That is all the information that seat14 has given us.
Clearly, there are only 2 sensors per hopper, and filling does not mean fill from under low level to high level in one go, but merely prioritize the hoppers that are below low level, then the hoppers that are between low and high, and then the hoppers that are over high level.

I do it in this way:
First there is a master clock that initiates a hopper change, for example every 30 seconds. I dont want the hopper switch over happens too often just because some sensor switches a little too often.
When the master clock says "change now", the next hopper is found this way: First filtering out the hoppers that are unavailable for filling, i.e. the operator has set the hopper to "do not fill", or there is an issue with some device associated with the hopper, i.e. sensor discrepancy or hardware used for the filling.
On the remaining hoppers, I then check if there is any available hopper below low level, and if so select a subsequent hopper in series after the active hopper.
If there is no hopper below low level, I check if there is any hopper between low and high level, and if so select a subsequent hopper in series after the active hopper.
If there is no hopper below high level, I check if there are any available hoppers, and if so select a subsequent hopper in series after the active hopper.
I create an alarm if there are no available hoppers at all.
I create a warning if all available hoppers are above high level for a longer time.
I create a warning if all available hoppers are below low level for a longer time.
The operator cannot select all hoppers to 'do not fill'. There must be at least one available hopper.

The program uses an array for representing the hoppers. The code uses the index to circulate from 1st to last and back to 1st again.

It becomes more complex if you also have to switch over without 'spilling'. If for example you switch from hopper 1 to 3 and no spillage may fall in hopper 2.

I cannot post my code, it is the property of my company, but the actual coding is not such a big deal. It is the precise description of what the code must do that is important. When you have done that the code almost writes itself.

edit: I see that seat14 probably do not want to fill unless at least there is a hopper that is below high level.
In that case, the filling shall stop when there is no available hopper, but the state shall be remembered by the code, so that the filling sequence starts from the same state when hopper(s) becomes available again.
In my case the hoppers are used as a storage of material that is in perpetual circulation, and I cannot interrupt the filling.
 
Last edited:
just a FYI there is a typo in rung 34 on the NEQ instruction. Hopper25_FAL.Pos should be Hopper75_FAL.Pos
 
After further testing I found changes were needed to meet all the requirements. This subroutine now will track entry order of 75% low hoppers. The entry order of the 25% low hoppers and give priority to the 25% as required. It's been a fun exercise and helped pass the time of a boring day. I have attached an exported subroutine and a pdf.
 
Hmmm

1) @cwal61's post noting a typo is still relevant, rung 36.

2) there is a bit of redundancy. For example,
 XIC Hopper_Level25.2 XIC Hopper_Level75.2


If the first XIC is true because the Hopper 2 level is below 25%, then the second also must be true because the level must is below 75% (because 25% is below 75% i.e. if A<B and B<C then A<C, so level<25% and 25%<75% then level<75%). So the second XIC in series is unnecessary since it never affects the result (excluding sensor failure, of course, but that is a whole 'nuther thing).

2.1) Then, later on:
XIO Hopper_Level25.2 XIO Hopper_Level75.2


Similar logic here, only the polarity is reversed: if level>75% (per second XIO) and 75%>25%, then level>25%, so the first XIO is unnecessary.

3) The FAL runs on a rising edge if it's input rung (cf. here), so the [XIO Hopper_Detect25.bit] instructions feeding the Hopper25_FAL would normally be redundant, however in this case, where there are multiple FAL instruction using the same Control structure (Hopper25_FAL), it seems necessary. However, this does raise another issue: what if multiple (adjacent?) hopper levels, as determined by their [XIC Hopper_Level25.bit] instructions, go below 25% on the same scan? It is a low probability to be sure, but I, and I'll bet a large number of the more experienced denizens of this forum, are all pretty sure it will happen one day, and with this code I think that the higher-numbered hopper(s) will not get onto the fill queue, because on following scans its Hopper_Detect25.bit will be 1, which will prevent the FAL from ever seeing that rising edge.

3.1) The fix is not clear to me, but it seems like this code is using the FAL more or less to implement a FIFO e.g. Rungs 3 and 14 are equivalent to an FFL and a FFU, respectively, so I would start there. When one is modifying the .POS of a Control Structure and the corresponding array outside of the instructions that usually uses that control structure and that maintains the Control Structure's and the array's consistency, then it may be time for a different approach.

3.2) Now that I ponder it some more, the only thing the FAL in INC mode brings to the table is the transition logic (via the .EN bit of the Control Structure), and this has been bypassed/overridden/rendered unnecessary by the [XIC Hopper_Detect25.bit FAL ... BST OTL Hopper_Detect25.bit ...] logic, so the only thing it is doing is MOVing a constant into the .POS index of the array, and incrementing that .POS index. So perhaps a MOV/ADD combination would achieve the same thing, no? Or just use FFL/FFU like they were intended.

4) Not that there is anything wrong with Latch/Unlatch (Set/Reset), but it is usually good to put a bit's OTL and OTU near each other for debugging, although I can see why in this case they are separate.

4.1) That said, why bother with OTL/OTU on separate rungs when the Start/Stop Circuit pattern (cf. link #3 on this page) would do the same thing on one rung? The [XIC Hopper_Level25.bit] would be the Start condition, [XIC Hopper_Level75.bit] would be the (not-)Stop condition, and Hopper_Detect25.bit would be the Seal-in/Run bit. This would eliminate at least 20 rungs from the program with no change in functionality.
 
1) @cwal61's post noting a typo is still relevant, rung 36.

Noted: I restarted with a backup copy and forgot to correct that error. My mistake.

2) there is a bit of redundancy. For example,
XIC Hopper_Level25.2 XIC Hopper_Level75.2


If the first XIC is true because the Hopper 2 level is below 25%, then the second also must be true because the level must is below 75% (because 25% is below 75% i.e. if A<B and B<C then A<C, so level<25% and 25%<75% then level<75%). So the second XIC in series is unnecessary since it never affects the result (excluding sensor failure, of course, but that is a whole 'nuther thing).

2.1) Then, later on:
XIO Hopper_Level25.2 XIO Hopper_Level75.2

Not sure this is really an issue. But it did allow me to toggle the bits to simulate the filling and the unloading of the hopper without scrolling up and down. But you're entitled to your opinion.

3) The FAL runs on a rising edge if it's input rung (cf. here), so the [XIO Hopper_Detect25.bit] instructions feeding the Hopper25_FAL would normally be redundant, however in this case, where there are multiple FAL instruction using the same Control structure (Hopper25_FAL), it seems necessary. However, this does raise another issue: what if multiple (adjacent?) hopper levels, as determined by their [XIC Hopper_Level25.bit] instructions, go below 25% on the same scan? It is a low probability to be sure, but I, and I'll bet a large number of the more experienced denizens of this forum, are all pretty sure it will happen one day, and with this code I think that the higher-numbered hopper(s) will not get onto the fill queue, because on following scans its Hopper_Detect25.bit will be 1, which will prevent the FAL from ever seeing that rising edge.

This observation is true, and I did not consider it. But this issue can be easily solved by adding a XIO of the FAL.EN bit in series with the level sensors if all FAL instructions are in the same subroutine. If the OP's program has the hoppers separated in individual subroutines putting the FAL's in 10 different subroutines would also allow all to be added to the Array during a single scan cycle. I tested the XIO of the FAL.EN and all were added. I did this by placing 2046 in the Hopper_Level DINT's. They did not go in order 1-10 but all were put in the array. But if all 10 come true during the same scan cycle I don't see why it matters who goes first or the order of fill.

3.1) The fix is not clear to me, but it seems like this code is using the FAL more or less to implement a FIFO e.g. Rungs 3 and 14 are equivalent to an FFL and a FFU, respectively, so I would start there. When one is modifying the POS of a Control Structure and the corresponding array outside of the instructions that usually uses that control structure and that maintains the Control Structure's and the array's consistency, then it may be time for a different approach.

Show your work because talk is cheap. I fail to see how using a FIFO for the 25% and 75% will work without manipulating the control.pos or clearing of values in the FIFO arrays and shifting remaining values to realign let alone finding the correct value. Given the fact that multiple hoppers could become true for a low 75% level and either one could reach the 25% level before either fill cycle starts. When that happens that would put hopper numbers in different elements of each FIFO array. Once that hopper is full it must be removed from both FIFO's. My logic does that. Let me see yours.

4) Not that there is anything wrong with Latch/Unlatch (Set/Reset), but it is usually good to put a bit's OTL and OTU near each other for debugging, although I can see why in this case, they are separate.

If you separate the rungs into separate hopper subroutines, then the rungs would be together. This logic is not a finished product only a concept.

4.1) That said, why bother with OTL/OTU on separate rungs when the Start/Stop Circuit pattern (cf. link #3 on this page) would do the same thing on one rung? The [XIC Hopper_Level25.bit] would be the Start condition, [XIC Hopper_Level75.bit] would be the (not-)Stop condition, and Hopper_Detect25.bit would be the Seal-in/Run bit. This would eliminate at least 20 rungs from the program with no change in functionality.

I can see that but again, this is a concept not a finished product. If the OP wants to change the logic to holding circuits, he is more than welcome to do it.

Doc, I appreciate your time and comments but if you test the logic, it meets the requirements and solves the issues expressed in the original post. It might not be the way you would program it, but I have not seen you or anyone else post logic to solve the problem. We all benefit from the shared knowledge on this forum and you above all have done more than your fair share. Thanks for your feedback and just know your contributions are appreciated.

Chris

I have 10 Hoppers each with 2 level sensors; one is at the 75% full level and the other is at the 25% full level.
I need to fill hoppers that fall below the 25% level (High Priority) first, then any that fall below the 75% level (Normal Priority).
I’m thinking I need two ques one for High Priority and one for Low Priority. If the High Priority que is 0 look at the Low Priority que. If a hopper is filling and another goes to High Priority, it will need to be moved out of the low priority que into the high. But before the high priority can start filling the current hopper must finish filling.
I need help understanding how to set up the que. I had considered using two FFL Instructions, but that will not work since I have two priorities. And it will always look first at the low before the high priority. Once it went high I could not figure out how to remove it from the low priority FFL
Just in case it maters I am using a CompactLogix processor.


I've been out on a job and just got back.
I see some people have comments about not having enough information.
If you can be more specific I will try and answer.
The hoppers get product from upstream at an inconstant rate, and the Hoppers get pulled from at different rates. If all hoppers are full then I will send a signal to stop upstream supply, but I am unable to stop conveyors between the infeed and hoppers, so this is why the full sensor is below the top of the hopper. I will have enough room to finish filling the current hopper. So I do not want to switch hoppers before it reaches a sensor.

I hope I am not confusing people even more.
 
Last edited:
I tested the XIO of the FAL.EN and all were added. I did this by placing 2046 in the Hopper_Level DINT's. They did not go in order 1-10 but all were put in the array. But if all 10 come true during the same scan cycle I don't see why it matters who goes first or the order of fill.

Agreed, order does not matter if multiple bits become 1 on the same cycle.

Also, only item 3 was an operational issue; the redundant instructions do not affect normal operation, even if they add unnecessary complexity for someone reading the code; and OTL/OTU vs. a holding circuit is a preference.

Like I said, I did not think through the solution for item 3 and show my work, but at the time I did assume it would involve the FAL.EN. Another approach would be to unlatch FAL.EN downstream of the [XIO Hopper_Detect25/75.bit] instruction, so the FAL is always armed. I think this approach may make it possible to put all of this into a one-rung loop, but as you note, talk is cheap.

Either will work because the Hopper_Detect25/75.bits are taking over the normal function of FAL.EN. The [XIO FAL.EN] approach is why, for a a contiguous sequence of rising Hopper_Detect25/75.bits (e.g. 2046), every other FAL sees a rising edge to add an INT to the FIFO on the first scan, and then adds the INTs of the odd elements that contiguous sequence on the next scan, which it why they are not added in order, but as agreed the order does not matter.

Btw, a sans FIFO approach is here that only determines the next single hopper to fill when the previous filling hopper completes its fill. It does not have a two-level priority scheme at this point, and I would normally suggest that that could be trivially added, but talk is cheap, and anyway then the problem becomes how to not interrupt the filling of a low-priority hopper when a high-priority request comes in.
 
Last edited:
I fail to see how using a FIFO for the 25% and 75% will work without manipulating the control.pos or clearing of values in the FIFO arrays and shifting remaining values to realign let alone finding the correct value. Given the fact that multiple hoppers could become true for a low 75% level and either one could reach the 25% level before either fill cycle starts. When that happens that would put hopper numbers in different elements of each FIFO array. Once that hopper is full it must be removed from both FIFO's. My logic does that. Let me see yours.

Instead of all the folderol of shifting FIFO values and adjusting .POS, why not instead simply overwrite a patently nonsense value (0? -1? 11?) into the 75% FIFO at the location with any hopper number that hits the 25% limit?

Then all that is needed is filler code that ignores the nonsense values when they are FFUed, and pick up the next FIFO element a scan or two later.

But yes, talk is cheap ;).
 
Instead of all the folderol of shifting FIFO values and adjusting .POS, why not instead simply overwrite a patently nonsense value (0? -1? 11?) into the 75% FIFO at the location with any hopper number that hits the 25% limit?

Then all that is needed is filler code that ignores the nonsense values when they are FFUed, and pick up the next FIFO element a scan or two later.

But yes, talk is cheap ;).


Whoa, I just realized your code is not finding the arbitrary 75%-FIFO location of a hopper to remove it, but the code rather assumes that, for a hopper that reached 25% and was filled, that when its entry in the 75%-FIFO reaches position 0, it will still be filled, and that is what will trigger the FIFO shift (COP) to remove that hopper.

I am not sure that is a valid assumption, but talk is cheap ;).
 

Similar Topics

Hey guys, I am looking at upgrading a machine from an old PCB controlled process with a membrane button control interface, to a PLC with a...
Replies
8
Views
2,282
I have a client that has burnt up their brake chopper resistors twice in the last few weeks with the drives idle but the disconnects on. The...
Replies
6
Views
2,233
Hi friends, I have a customer that is looking for some advice on upgrading the level system in their coal hopper. It is at a coal bagging plant...
Replies
14
Views
7,790
I'm installed a Powerflex 700 in place of a 1336F drive, but I'm still using the 1336F braking chopper with a same brake resistors. On the...
Replies
4
Views
4,857
Hello guys, Can someone please suggest me good alternative to this amplifier? Basically I need input signal 0-20 mA to amplify to 0-200mA (and...
Replies
5
Views
2,473
Back
Top Bottom