Turning on Pumps based on runtime

jnagle039

Member
Join Date
Mar 2022
Location
PA
Posts
6
I need to sort pumps based on runtime from shortest to longest then turn them on in order that they are sorted. I know I can create an array for the pumps then sort them using the SRT function.but from there how do I turn them on in order?? Rslogix 5000

Thank you
 
I need to sort pumps based on runtime from shortest to longest then turn them on in order that they are sorted. I know I can create an array for the pumps then sort them using the SRT function.but from there how do I turn them on in order?? Rslogix 5000

Thank you


how many pumps?


Show your code that will create (load?) an array and "sort them," and we can go from there.
 
I know I can create an array for the pumps then sort them using the SRT function.but from there how do I turn them on in order?
You have to maintain knowledge of which accumulated running time is associated with each pump. Then you check which pump's running time matches the lowest value from the sorted array.

One thing to take into account when doing something like this. If you're doing it to even out the wear on each pump, keep in mind that you might just be setting yourself up for a situation where all of your pumps fail at around the same time.
 
Sorting an array doesn't solve any issue as you need a reference between run time and pump number.
I would go down the route of creating a UDT to match runtime and pump number and an array of said UDTs. I would then write a sort function, sorry AOI/subroutine, to take into account the pump number.

As Steve mentioned, you need to be careful about wear leveling. One other aspect is that your sort (change pumps) function should run once per day or perhaps even per week or you can find your pumps changing at every time unit lapses.

Additionally, I'd imagine that you'd want to have an enable selection to remove pumps from the sorting/starting logic to avoid wear levelling.

To actually start them, create a sequence that runs through your UDT array and starts them with a timer in between each pump.

Would there be any demand logic for this application?
 
Sorting an array doesn't solve any issue as you need a reference between run time and pump number.
I would go down the route of creating a UDT to match runtime and pump number and an array of said UDTs. I would then write a sort function, sorry AOI/subroutine, to take into account the pump number.


Would there be any demand logic for this application?

That sort function is what I'm having a hard time figuring out how to make, or what to do.

And yes another part of the project is turning on the pumps base on the total system pressure
 
That sort function is what I'm having a hard time figuring out how to make, or what to do.

And yes another part of the project is turning on the pumps base on the total system pressure

Off the top of my head (and bearing in mind I haven't done this sort of thing on AB PLCs), you can have an array with runtimes where the index is the pump number. The array is called runtimes, so runtime[1] holds the number of hours pump 1 ran, runtime[2] holds the number of hours that pump 2 ran and so on.
You then create an array of INT/DINT with as many positions as the number of pumps + 1 to account for 0. Name it runOrder an fill it with zeros or holding the index value (runOrder[1] := 1).

Then you compare the runtimes against each other and sort them. The runOrder array holds the pump with least amount of hours ran in position 1 (forget zero). So if we think of something like this:

runtime [1] = 800 hours
runtime [2] = 250 hours
runtime [3] = 300 hours
runtime [4] = 750 hours
runtime [5] = 345 hours
runtime [6] = 600 hours
runtime [7] = 500 hours

runOrder [1] = 2
runOrder [2] = 3
runOrder [3] = 5
runOrder [4] = 7
runOrder [5] = 6
runOrder [6] = 4
runOrder [7] = 1

To go from one array to the other there are all sorts of algorithms online that you can use with more or less computing power. You can also cut back on the processing if you have pumps disabled for example.

For the number of pumps running based on pressure also keep in mind that pressure spikes happen, so it's worth filtering and leaving the pump running for a bit longer should something start up again... like a predecessor of mine that thought it was a brilliant idea to control a condenser temperature with a thermostat control... the condenser line was 8" and the pumps went absolutely bananas trying to keep up. A very expensive proportional did the job nicely in the end (it was mains water used to cool it).
 
You might not have to make it that hard. You probably don't need to sort the pumps; you may only need to start the next pump that follows the following criteria:
- Isn't currently running.
- Has the smallest run-time hours
- is "Available" (i.e, not in Hand mode (or locked out or however you want to define it))
- Isn't "Faulted" (Failed-to-Start or Drive alarm active).

It's easy to set 2 registers -- one for pump number, one for hours -- and then the following logic:
Clear NEXT_PUMP; set RUNTIME_CHK to 99999999999.
7 lines of repetitive code (one for each pump):
If Not(PumpX.Running) and Not(PumpX.Faulted) and PumpX.Available and LES (PumpX.Runtime < RUNTIME_CHK) then Move X >> NEXT_PUMP, MOV PumpX.Runtime >> RUNTIME_CHK.

At the end of this, NEXT_PUMP will tell you which pump to start.

Once that pump is running, determine if you need another pump. If you do, run through the logic again.

Similar logic can text you which would be the next one to shut down if your pressure is too high.
 
Last edited:
What determines the number of pumps that should be running at any given time? E.g. is it [all off] or [all on]? Or is it [run none], [run 1], [run 2], ..., [run 7]?

If the runtime of a pump that is running goes from less than to greater than the runtime of a pump that is not running, how do you plan to avoid swapping their run state at that point, and also avoid swapping them back the next time the runtimes are updated?
 
Not sure if this will work, but as long as runtime units are integral minutes, and any one pump's runtime is less than ~268Mmin (~510y), the concept is valid.
runtimes: DINT[7]
sorted_ids: DINT[7]
number_of_pumps_to_run: DINT


XIC trigger ...

### Put the value ((runtime * 8) + pumpID) into DINT array element sorted_ids[pumpID], where pumpID runs from 0 to 6, inclusive

BST FAL ctl_presort 7 0 ALL sorted_ids[ctl_presort.POS] ((runtimes[ctl_presort.POS]*8) + ctl_presort.POS) ...


### Sort those values by runtime and pumpID

NXB SRT sorted_ids[0] 0 7 0 ...


### Mask out the runtimes' bits from DINT array sorted_ids, leaving the IDs sorted by runtime

NXB FAL ctl_presort 7 0 ALL sorted_ids[ctl_presort.POS] (sorted_ids[ctl_presort.POS] AND 7) ...

BND

### Run the [number_of_pumps_to_run] pumps with the lowest runtimes

LES 0 number_of_pumps_to_run MOV sorted_ids[0] pumpID OTE run_pump[pumpID]
LES 1 number_of_pumps_to_run MOV sorted_ids[1] pumpID OTE run_pump[pumpID]
...
LES 6 number_of_pumps_to_run MOV sorted_ids[6] pumpID OTE run_pump[pumpID]



 
Last edited:
It's easy to set 2 registers -- one for pump number, one for hours -- and then the following logic:
Clear NEXT_PUMP; set RUNTIME_CHK to 99999999999.
7 lines of repetitive code (one for each pump):
If Not(PumpX.Running) and Not(PumpX.Faulted) and PumpX.Available and LES (PumpX.Runtime < RUNTIME_CHK) then Move X >> NEXT_PUMP, MOV PumpX.Runtime >> RUNTIME_CHK.

At the end of this, NEXT_PUMP will tell you which pump to start.

Once that pump is running, determine if you need another pump. If you do, run through the logic again.

Similar logic can text you which would be the next one to shut down if your pressure is too high.


I like the way this looks and it makes sense to me for this application. I assume when you say "MOV X" in your statement you mean MOV that pumps runtime into the RUNTIME_CHK??? or do have that wrong
 
What determines the number of pumps that should be running at any given time? E.g. is it [all off] or [all on]? Or is it [run none], [run 1], [run 2], ..., [run 7]?

If the runtime of a pump that is running goes from less than to greater than the runtime of a pump that is not running, how do you plan to avoid swapping their run state at that point, and also avoid swapping them back the next time the runtimes are updated?

total system pressure will determine that. The runtime wont switch the pumps while they are running, only when a pump starts up is the goal
 
I like the way this looks and it makes sense to me for this application. I assume when you say "MOV X" in your statement you mean MOV that pumps runtime into the RUNTIME_CHK??? or do have that wrong

What I mean is, if pump 1 passes the criteria (lowest runtime, etc.,) move "1" into NEXT_PUMP and it's current runtime (say '800' hrs from cardosocea's post) replaces the 99999999 in RUNTIME_CHK.

Now the pump 2 check will see if it can beat, not 99999999, but 800. If it can, then NEXT_PUMP = 2 and RUNTIME_CHK becomes that lower number (250). No one else will beat 250, so at the end, NEXT_PUMP = 2, which should trigger the start logic for pump 2. It will also reset some bit or timer before executing those 8 rungs of logic again, until the system has had time to verify whether the addition of pump 2 has or has not brought your pressure back in line.

Just as you clear NEXT_PUMP with a zero to verify that something won, you need to seed RUNTIME_CHK with a ridiculously large number, since you are looking for something to be lower. If float, then 10^34; if DINT, then 2147483647, etc. I just used lots of 9's for simplicity.
 
Last edited:
What I mean is, if pump 1 passes the criteria (lowest runtime, etc.,) move "1" into NEXT_PUMP and it's current runtime (say '800' hrs from cardosocea's post) replaces the 99999999 in RUNTIME_CHK.

Now the pump 2 check will see if it can beat, not 99999999, but 800. If it can, then NEXT_PUMP = 2 and RUNTIME_CHK becomes that lower number (250). No one else will beat 250, so at the end, NEXT_PUMP = 2, which should trigger the start logic for pump 2. It will also reset some bit or timer before executing those 8 rungs of logic again, until the system has had time to verify whether the addition of pump 2 has or has not brought your pressure back in line.

Just as you clear NEXT_PUMP with a zero to verify that something won, you need to seed RUNTIME_CHK with a ridiculously large number, since you are looking for something to be lower. If float, then 10^34; if DINT, then 2147483647, etc. I just used lots of 9's for simplicity.


Okay I understand. I will give this logic a try. Seems more simple then trying to sort them. And I think it will work for the application.
Thanks!
 
Okay I understand. I will give this logic a try. Seems more simple then trying to sort them. And I think it will work for the application.
Thanks!


+1


@Aardwizz's algorithm is one pass of the Selection Sort algoritm (https://en.wikipedia.org/wiki/Selection_sort). You only need to run it when you need to increase or decrease the number of running pumps.

I think it's possible to do with in one FAL instruction, but it is easier to understand with the seven rungs.

To decrease the number of pumps, I am pretty sure it need only change the Not(Pump[X].Running) to Pump[X].Running. Or you could go really nuts and change that to
IF ( (Current_pumps_running < Desired_pumps_running AND Not(Pump[X].Running)) OR (Current_pumps_running > Desired_pumps_running AND Pump[X].Running) ) \
AND Not(Pump[X].Faulted) and Pump[X].Available and LES (Pump[X].Runtime < RUNTIME_CHK) THEN
NEXT_PUMP:= X;
RUNTIME_CHK := Pump[X].Runtime ;
END_IF;

IF NEXT_PUMP > 0 THEN
IF Current_pumps_running < Desired_pumps_running THEN
Pump[NEXT_PUMP].Running := 1;
Current_pumps_running := Current_pumps_running + 1;
ELSE IF Current_pumps_running > Desired_pumps_running THEN
Pump[NEXT_PUMP].Running := 0;
Current_pumps_running := Current_pumps_running - 1;
END_IF;
END_IF;


It is going to get a little messy elsewhere because you should probably not be updating Pump[].Runtime, so the code will need to cache the per-pump accumulations somewhere else while at least one pump is running.
 
Last edited:

Similar Topics

Hi! I am trying to run the 'SimpleSample' (https://infosys.beckhoff.com/content/1033/TF5100_TC3_NC_I/Resources/3438746891/.zip ) to understand the...
Replies
2
Views
106
We have a Pinnacle power supply from Advanced Energy which we'd like to control using TwinCAT 3, via an EL6002 and RS-232. I got the...
Replies
2
Views
747
I have 3 koyo PLC's in series. The 1st and 3rd are reporting values correctly but the 2nd is reporting negative values. The values in the PLC and...
Replies
3
Views
1,421
I'm very new to the PLC world, and was wondering if I could take an .apb file and turn it into a .mer file. Is this possible? And if so, how would...
Replies
4
Views
1,268
I have a weird situation here, maybe I am missing something easy. So first, parts being used: - G.E (Emerson) Rx3i controller -IC200MDL330L Iso...
Replies
12
Views
3,926
Back
Top Bottom