SRT is there a better way?

Here is the FSC code. Simple, Fast, "Elegant" (inside joke). Could be combined onto a single rung, but for easy readability, multiple rungs.

To initiate, simply toggle Start_Find to ON.
Thank you for the elegant solution Robert. I am a big fan of elegant solutions (as you know).

After reading your FSC suggestion, i read up on what it is here:
https://literature.rockwellautomation.com/idc/groups/literature/documents/rm/1756-rm003_-en-p.pdf
Page 457.

After reading this description, i imagine this is exactly what i am looking for. According to the manulal,
1716982146643.png
This tells me the instruction will iterate until the expression evaluates True.
For this reason, after generating B_Next_Water[...] values, i SRT them from small to high. This way, the first value that the expression evaluates to be is TRU is the first positive value after 0. The .POS will show which position in the B_Next_Water[...] array is the Ntarget.

I gave it a shot, but .POS never moved past 0.

I reviewed what values are greater than 0, these are the first few:

1716982559326.png

I thought maybe PLC identified B_Next_Water[0] = 0 to be expression TRUE.
To test, i changed the expression to find the first value greater than 300.
Same result as before; .POS never moved past 0.

This is my code after i changed the expression:
1716982709902.png

I cannot seem to make the FSC process the data.
 

Attachments

  • 1716982698434.png
    1716982698434.png
    31.3 KB · Views: 1
If you code the three rungs exactly as I did for the FSC, you don't need to sort at all.
 
I think people might be hung up on the term sort. A sort means manipulating the order of elements in a list to achieve some goal pertaining to the members of the list's values. This is not a sort and shouldn't be thought as such.

I think the FSC is the best solution proposed so far, but it is still not perfect. My issue with the FSC solution is does not necessarily execute in one scan. In fact, the only way it can execute in one scan is if the last element in the list is the only element less than 30000. This opens you up to scan order issues unless you rely on your later logic checking if the trigger bit is set to zero after initially setting it to logical one. In other words, this solution, while elegant and leverages native Rockwell instructions as best as possible for the given task, requires other code to account for deficiencies in this solution. If it is just you programming this PLC, that's typically not an issue as you understand what is going on; but if you work in a team or if someone will eventually modify the PLC after your work is done, this complicates the next programmer's job and opens them up for introducing a scan order bug into the code.

Some people are leery of them, but truthfully as long as you are compact and clear with your programming, I'd go with a loop, which can be implemented in any language you'd like, including RLL.

The RLL pseudocode looks like this (Minimum can be any numerical datatype, Array is an array of the same datatype as Minimum, Index is a DINT, ArraySize is a DINT):

---CLR(Minimum)---CLR(Index)---SIZE(Array,ArraySize)

---LBL(Search)---GRT(Array[Index],0)---LES(Array[Index],Minimum)---MOV(Array[Index],Minimum)

---ADD(Index,1,Index)

---LES(Index,ArraySize)---JMP(Search)

This solution should come with a nice comment at the top of the first rung. IMO it is the clearest way to do it, as many PLC techs aren't comfortable with the FSC instruction; and the most robust, as it executes in a single scan. Also as note, it's not easy to indicate branches in RLL pseudocode, but a lot of this logic can (and I argue should) be logically grouped into branches. Typically I would group the 2nd, 3rd, and 4th rungs together, with only the LBL instruction in front of all the branches. That way the loop is one initialization rung (the rung with the CLR at the beginning) and one rung with the actual loop logic).
 
I think people might be hung up on the term sort. A sort means manipulating the order of elements in a list to achieve some goal pertaining to the members of the list's values. This is not a sort and shouldn't be thought as such.

I think the FSC is the best solution proposed so far, but it is still not perfect. My issue with the FSC solution is does not necessarily execute in one scan. In fact, the only way it can execute in one scan is if the last element in the list is the only element less than 30000. This opens you up to scan order issues unless you rely on your later logic checking if the trigger bit is set to zero after initially setting it to logical one. In other words, this solution, while elegant and leverages native Rockwell instructions as best as possible for the given task, requires other code to account for deficiencies in this solution. If it is just you programming this PLC, that's typically not an issue as you understand what is going on; but if you work in a team or if someone will eventually modify the PLC after your work is done, this complicates the next programmer's job and opens them up for introducing a scan order bug into the code.

Some people are leery of them, but truthfully as long as you are compact and clear with your programming, I'd go with a loop, which can be implemented in any language you'd like, including RLL.

The RLL pseudocode looks like this (Minimum can be any numerical datatype, Array is an array of the same datatype as Minimum, Index is a DINT, ArraySize is a DINT):

---CLR(Minimum)---CLR(Index)---SIZE(Array,ArraySize)

---LBL(Search)---GRT(Array[Index],0)---LES(Array[Index],Minimum)---MOV(Array[Index],Minimum)

---ADD(Index,1,Index)

---LES(Index,ArraySize)---JMP(Search)

This solution should come with a nice comment at the top of the first rung. IMO it is the clearest way to do it, as many PLC techs aren't comfortable with the FSC instruction; and the most robust, as it executes in a single scan. Also as note, it's not easy to indicate branches in RLL pseudocode, but a lot of this logic can (and I argue should) be logically grouped into branches. Typically I would group the 2nd, 3rd, and 4th rungs together, with only the LBL instruction in front of all the branches. That way the loop is one initialization rung (the rung with the CLR at the beginning) and one rung with the actual loop logic).

I agree mostly, however, I'm not a fan of JMP instructions, due to the possibility of infinite loops and watchdog major faults. If doing a loop, use a FOR-NEXT.

As for the FSC limitation, if data change during execution is a concern, do a simple CPS into a buffer array and operate on the buffer instead. Different strokes for sure, and we all have different biases. I've experienced the exact opposite in regards to loops vs FSC and technicians. Easy to read the help on FSC. Technicians hate manual loops in my experience as it's jumping around code and not following the natural linear scan.
 
Indirect is pretty simple you already sort of do it for example your array[0] (first tag in the array) is directly pointed to by the 0 in the brackets, all you do is put a variable i.e. a tag of type integer
if you set that My_pointer tag to say 0
then array[my_pointer] points to the first tag in the array, incrementing the pointer or putting any value in it will then poin to the relevant tag in the array, the things you have to be careful of is make sure the pointer does not point to a value out of bounds of the array for example if you have an array of 20 then setting the pointer to 21 & try to retrieve that there is no array 21 so faults, it is normal to make your array at least one more i.e. 21 but ensure the pointer only goes to 20 that way you can be confident the PLC will not fault.
So what the program is doing is setting the pointer to 0 (which corresponds to My_array[0])
When you do the compares it loads My_array[0] i.e. My_array[pointer]
then after the check for greater than 0 AND if the array value is less than the previous one (first pass we have set the temp tag to the highest expected value so it will move a positive value into temp, we then increment (add 1) to the pointer then loop back (in this case a for next loop) and test the next array word i.e. next time round the pointer is a one so My_Array[pointer] loads array[1] & so it keeps going until the for loop has completed.
At the same time you check for a lower value perhaps have a second variable called position & when it copies the lowest value into the temp update the position variable so you then have not only the lowest value but also it's position in the array.

As for functions like search or sort they probably do something similar but wrapped up in a function. if you look at compiled code of any program there are jumps all over the place as well as calls to subroutines. so not much different than doing jumps & loops
 
My issue with the FSC solution is does not necessarily execute in one scan. In fact, the only way it can execute in one scan is if the last element in the list is the only element less than 30000.
So loop the FSC until DN is set :p

Is doing it in a single scan even needed though? If not then just start the FSC again on the next scan each time it finds the new lowest value, and only use the result once DN is true.
 
P.S. I am assuming the SRT completes in one scan cycle
P.P.S. I am not sure about the correct choice of the XICs (.IN vs. .FD) in that last branch.
 
I agree mostly, however, I'm not a fan of JMP instructions, due to the possibility of infinite loops and watchdog major faults. If doing a loop, use a FOR-NEXT.

As for the FSC limitation, if data change during execution is a concern, do a simple CPS into a buffer array and operate on the buffer instead. Different strokes for sure, and we all have different biases. I've experienced the exact opposite in regards to loops vs FSC and technicians. Easy to read the help on FSC. Technicians hate manual loops in my experience as it's jumping around code and not following the natural linear scan.
Totally fair to not like JMP. It is easily (and often) abused. I always recommend using it only in highly limited situations where a programmer or tech can see the entire the loop from a small laptop screen. If you program it right the first time, it'll only go wrong if it is modified. If you program it compactly, clearly, and using the SIZE instruction instead of hardcoding the upper bound of the loop, the only real chance of getting stuck in the loop is if someone incorrectly modifies the interior of the loop, like by putting a condition in front of the index incrementor.

FOR in RLL is kind of annoying, because then you are forcing the programmer to abandon putting all subroutine calls in the main routine as JSRs. Not everyone subscribes to this methodology, but it is a bummer that Rockwell handles FOR this way. I usually don't bother with FOR, as in RLL it causes more confusion than it solves from what I have seen. Outside of RLL is another story of course.
 
P.P.S. I am not sure about the correct choice of the XICs (.IN vs. .FD) in that last branch.
Based on the documentation in the Logix help file either one should work here:
- FD: Set when a match is found
- IN: Set when a match is found. Inhibits FSC operation.

iow if you manually clear the IN bit and then re-scan the FSC, it will pick up where it left off.

IN and FD are always set by the FSC together though, so since you're evaluating them immediately after running the FSC it doesn't really matter which one you use -- either it found a match and set both to true, or it didn't and set both to false (and DN to true since we are in ALL mode)
 
Can anyone suggest why the program worked after i relocated the OTU? I cannot understand why it affected the FSC the way it did.
more than that was changed; we'd have to see both programs.

Btw, the 500ms OSF is only for debugging i.e. so you can watch the difference values as they get loaded into the B_Next_Water array? A one- (or minimum-)scan solution is the ultimate goal?
 

Similar Topics

I am storing values into an array. I am wanting to find an average of the highs and an average of the lows. Something like this... After 50...
Replies
36
Views
10,273
Hello dear forum users. I am at a dead end in solving a simple problem for self-education. There are 6 fans available, as well as engine hours...
Replies
3
Views
2,361
I have a machine with a tag called SP_FLT[57] with a data type of DINT. Each bit in each DINT is a machine fault of some sort. I need a way to...
Replies
12
Views
3,904
Hi! Due to age and things are going obsolete, our team is going to upgrade the system where a Daifuku SRT-4231A is installed. But right now I...
Replies
0
Views
1,412
hi its my first time to this site finding it very helpfull and learning a lot. Can anyone explain the plcs storage, scanning, memory and its...
Replies
2
Views
1,874
Back
Top Bottom