Indirect Addressing: Can Enough be Said about this Powerful Tool?

Re: Optimizing sorts.

Peter Nachtwey said:
If a chute is activated each encoder count then maybe it can't.
A chute CAN be activated each encoder count. Is this the same thing?
Peter Nachtwey said:
However, one should only need to index through the array each time a chute is activate. If this is only once in about 10 counts then then indexing can be reduce by 90%.
How will I know when a chute is to be activated if I don't index through the file?

Peter Nachtwey said:
For starters, keep only one minimum count for all carriers that represent the number of counts till the next event. When this minimum count reaches 0 then subtract the original value of the minimum count from each carrier. Now all carriers that have their count reduced to 0 should have their chute activate.
What must be estimated is before implementing this procedure is how often will the minimum count be decrement to 0. If it happen almost every encoder count then your method works well and can't be improved. It the typical value of the minimum count is 10 then you can reduce the indexing through the arrays by a factor of ten.
In my perception of this, each encoder pulse is an event. There are usually one but sometimes two pulses accumulated per scan (via STI program). I looked at using zero, or, preferably the sign bit as the trip signal but I can't discover why the original programmer used 0 <= count <= 8 as the criteria. Figuring there must be a reason I left it alone. One point I neglected to mention is that the original code went through the file (list) every scan, when I put in the condition 'is counts greater than zero?' scan time dropped significantly.

Peter Nachtwey said:
Now all carriers that have their count reduced to 0 should have their chute activate.
The original program used a variation of this. Carriers needing tripped on any given scan were moved to a hand built stack and tripped all on one scan. It may be a good theory but the implementation left something to be desired!
Peter Nachtwey said:

I use doubly linked lists which is very efficient when there many items on the list like in your application. Each item is insterted into the list in the order in which it will be executed. This way only the first item at the beginning of list needs to be checked. This works well when there are large periods of time between items being inserted on the list.
To me, 'large periods of time between items being inserted on the list' equates with 'not much being put on the sorter'. It's very variable - on one revolution there may be only twenty or thirty items. On another there may be upwards of three hundred fifty. Quite a bit considering there are four hundred thirty-six carriers.

I can see the advantage of this but, wouldn't it complicate the file management aspect? I'm thinking I'd need ways to insert to the list; keep track of the quantity on the list; (randomly) delete items when their time is up. Probably other stuff I haven't thought of.
 
I can’t imagine a customer telling me how to program. Sure, if the machine is very small with only a few IO, then indirect addressing is not necessary. But if a machine is made up of multiple sections that more or less do the same thing, then it only makes sense to come up with standard functions. It is much quicker to program this way, and the resulting code is much safer and robust (no “cut and paste” errors). Plus, it’s much more likely that I can use the same code in multiple projects, which makes me more competitive.

Indirect addressing can be difficult to troubleshoot if it is not done well, but that is the fault of the programmer, not the methodology. For instance, let’s say that a machine has 40 conveyor sections, each with its own drive and remote I/O. I would write a generic function to control the conveyors, but I would have to call these functions is a manner which would allow simple commissioning and troubleshooting. One way to do this (and I’m looking at this from the S7 perspective, although it applies to most PLC types), is to make create duplicate functions, one to be used for an “Auto Mode” and the other for “Test Mode”, and then change the function number dynamically. In S7, it might look like this (I’ll use FB10, FB11, and a 1000 byte array of conveyor data):

L P#0.0
LAR 2 //Initialize Pointer

AN #TestModeConveyor1
CC FB10 //Conveyor Control
A #TestModeConveyor1
CC FB11 //Conveyor Control Test Mode

+AR2 P#1000.0
AN #TestModeConveyor2
CC FB10 //Conveyor Control
A #TestModeConveyor2
CC FB11 //Conveyor Control Test Mode

+AR2 P#1000.0
AN #TestModeConveyor3
CC FB10 //Conveyor Control
A #TestModeConveyor3
CC FB11 //Conveyor Control Test Mode

+AR2 P#1000.0
AN #TestModeConveyor4
CC FB10 //Conveyor Control
A #TestModeConveyor4
CC FB11 //Conveyor Control Test Mode

Etc…….

Each time FB10 is called, it points to bits in the data block with a 1000 byte offset. But let’s say I want to look only at Conveyor 3. I would just set the TestModeConveyor3 bit, and I would execute FB11 instead of FB10. The code is identical, and each function uses the same physical bits, so the indirect addressing concept is still maintained. It would also allow me to test changes on only one conveyor, and if they panned out when using FB11, then I would just copy the block over to FB10, and the changes would take effect everywhere. This could even be done right in the middle of production.

That said, the ultimate goal should be to write the code so that the technicians don’t have to go online to see what is wrong anyway. That may have not been as easy in 1984 before the days of cheap HMIs (anyone remember using 7-segs to display fault codes? :) ), but now I can display exhaustive diagnostic info for every bit of a system. It’s rare than anyone has to go online to troubleshoot if I supply enough info.
 
Re: Re: Optimizing sorts.

Doug-P said:

A chute CAN be activated each encoder count. Is this the same thing?

How will I know when a chute is to be activated if I don't index through the file?


In my perception of this, each encoder pulse is an event. There are usually one but sometimes two pulses accumulated per scan (via STI program). I looked at using zero, or, preferably the sign bit as the trip signal but I can't discover why the original programmer used 0 <= count <= 8 as the criteria. Figuring there must be a reason I left it alone. One point I neglected to mention is that the original code went through the file (list) every scan, when I put in the condition 'is counts greater than zero?' scan time dropped significantly.


The original program used a variation of this. Carriers needing tripped on any given scan were moved to a hand built stack and tripped all on one scan. It may be a good theory but the implementation left something to be desired!

To me, 'large periods of time between items being inserted on the list' equates with 'not much being put on the sorter'. It's very variable - on one revolution there may be only twenty or thirty items. On another there may be upwards of three hundred fifty. Quite a bit considering there are four hundred thirty-six carriers.

I can see the advantage of this but, wouldn't it complicate the file management aspect? I'm thinking I'd need ways to insert to the list; keep track of the quantity on the list; (randomly) delete items when their time is up. Probably other stuff I haven't thought of.

The point is that you shouldn't need to index through the array each count. If the next chute to be activated is going to happen in 10 counts then just decrement the counter 10 times on each encoder pulse AND THEN scan through the array to find a all the carriers that are activating chutes. At the same time you should also subtract 10 from each of the carriers AND use a minimum function to find out how many counts will occur before the next chute is activated. This means you only index through the array when a chute is activated. Not on every encoder count. This can lead to big time savings UNLESS a chute is activated on nearly every encoder count.
 
chavak,

It has been many years since I wrote that Rubik's Cube program as a training exercise, but what I remember is that I tried to simulate what you do by hand on the computer. I set up six 3 x 3 matrix arrays of numbers, one array for each side of the cube. It is the indirect addressing capability that makes it possible to manipulate number arrays on a PLC. I assigned a number to represent each of the 6 colors (1=Red, 2=Yellow, and so on). Then I wrote logic rungs to simulate each of the 6 possible ways to rotate the sections. Then you start it running and wait for it to find the correct combination, where each face of the cube has all of the 9 numbers being the same number (color).

The reason I even remembered that program was because I had to do another one, for a real project, where I needed to check all possible combinations of nine motor leads, for a motor tester. The same techniques of number arrays and indirect addresses that I learned for the Rubik's Cube problem worked well to make it possible to use a PLC. This was with a relatively low-end PLC, the Automation Direct 205, but it takes only 2 minutes to check over 64,000 combinations, determine the wire numbers for the 9 leads, check for open, shorted, and grounded leads, and display the results on a text screen.
 
Last edited:
Lancie,

Thank you for the explanations on the cube beerchug . I would really like write the logic myself to solve the cube on my own :unsure: . I know it is quite tough with my limited knowledge.

But I enjoyed very much solving the cube. beerchug
 
Lancie1

Let say you have a 30 Hp duel voltage motor, and some idiot cut off all the leads behind the tags. So you have 12 leads and no tags. Pairing the leads is easy, but how do you determine which lead is T1, T2 - T12, etc..?

Also does your motor tester do a megger test also?

Thanks, Mike.
 
Put a analog voltmeter in series with a battery on a pair, and give the rotor a quick spin. Get the needle flicking the same direction on all pairs and voila you have the ends right.
 
Arrays used in indirect addressing are not visible in search, so someone can say: I did search, this address in not used and I will use it now.
OUCH! Be careful. With the SLC processors, I like to set up a memory file specifically for indexed/indirect addressing. If the memory location is in that file, HANDS OFF!!!

I agree with Pierre:
Some times it's easy to copy and paste 50 similar rungs and see all of them instead of using indirect addressing.
Ditto! Pick your battles. Is it better to see the program executing, or to save ladder logic. It depends on the circumatances. I wrote a program once that could have been only few rungs long, turned out to be page-after-page-after-page because I'd never though to use indirect addresses. Since it was a communication related program, I really wish I'd used indirect (it would have been a BREEZE to add new nodes later).

Also don't forget to make a check for index limits before applying to indirect logic, or PLC will stop one day trying to find non-existing address pointed by indirect logic.
It's not a bad idea to run range checks in the ladder, just in case. I do this any time I repeatedly add, subtract, or multiply into the same register.


By the way, my favorite way to use indirect addressing is to eliminate those loops that were talked about earlier. Those things can eat scan time! If you can get away with not having all the information by the end of the scan (eg. scanning network nodes), then use indexed addressing or some kind of incremental logic. And, be sure to document!!!

AK
 
elevmike,

You asked about how the motor tester determines the lead numbers. It uses several different routines. The operator screen first asks some questions about the horsepower range, necesssry because the PLC applies a certain voltage across each of the coils and the larger the motor the smaller this voltage has to be to avoid overheating the coils. Then the program asks if you know ANY of the leads, and if so, you can mark which ones that you know, and the program uses that information and this shortens the run time. If you know none of the lead numbers, then the program will still work, because then there are several exact solutions, any one of which will be correct. I don't think I should give the ladder logic here (at least not without checking), as the company I did this for is still trying to sell the tester on their site: forsytheandlong.com

2. No, the motor tester does not do a megger test, but does check for open, shorted, and grounded coils using a lower AC voltage. My budget limited me to a 120 VAC power supply, so I did not have 600 volts available for the megger test. A megger test would be a good Version 2 addition!
 
Last edited:
What all of you have to say has merit.

I have had customers specify "no indirect addresses". They want the program to be useful to the plant floor personnel and that generally is the maintenance guys.

I've been around machinery since '60 and I see again and again that mechanical and electrical designers lose site of the big picture. To make the customer money it has to run reliably and be easily and quickly repairable. Often by saving themselves time they loose in the long term.

Often designers will use techniques and devices for what an old boss called the "Mt Everest" reason. Because it "was there" NOT because it was the most appropriate.

 
I like indirect and indexed addressing as long as I wrote it(LOL), but it can be a pain in the rear figuring out what other programmers were thinking.

I had a panelview 550 connected to a servo controlled tire bead former. It has 6 axis of motion. The Panelview has 5 pages of teach functions, 6 engineering screens with accel rates, decel rates, and maximum speeds, and several pages of manual functions and alarms. One night, (it's always about 2 a.m. for some reason) a technician inadvertently adjusted an accel rate to zero which caused the program to hang with no faults. I figured that out quickly and got the machine running. I thought I'd modify the panelbuilder program real quick and change the entry limits in the tag database to limit the minimum input to >0. There were only twelve tags in the whole PanelBuilder file with strange generic names! I found in the SLC that the page number was used to obtain the base address for display and entry items. It took me over an hour to track down the exact logic that copied the values I wanted to edit, and I had to shoehorn in some limit checking in the SLC to get it done.

The programming technique is slick and efficient, but modifications to it are daunting.

As for sorting with a PLC. I have written sorting algorithms using conveyors with encoder feedback. I had one conveyor 210' long that had 16 tire drop chucks at various intervals along its length. These tires were diverted randomly to four different lining cement lines with manual sorting conveyors. My manager, who was very versed in ladder logic and an excellent technician in general, wanted to be able to assign specific destinations to each tire, and control where they went to make it easier on the manual laborers downstream who catch all these tires.

He tried bit shifting and FIFO stacks and all sorts of other code, but he couldn't make it buletproof. After two weeks, I had finished my latest project and took over from him.

I created a data table with 210 integers. I scaled the encoder from the belt into feet and programmed a pointer, with wrap around, so the conveyor can run forward or backward at any speed without losing accuracy. This value is called "EOL Index" end of line index and it represents the position of the end of the conveyor belt where tires enter a zone with roller bed conveyors. Each time the EOL index integer increments (by the motion of the encoder), I check that position in the data table. If it contains a destination, it is moved to a FIFO stack and cleared. Each time a tire is dropped on the conveyor, I insert its destination into the data table at an index equal to the current end of line position plus the fixed offset representing the distance from the end of the conveyor to the drop chuck (with wrap around). In this way, the sorting occurs without moving a bunch of values around. The entire algorithm amounts to two branches per drop zone and about 12 rungs to maintain the data table. I could not have achieved this without indirect addressing. It simply would have killed scan time and been an ugly bunch of spaghetti. It's very efficient, and runs flawlessly, but the next guy who has to understand it is gonna go HUH? unless i'm there to explain it.

I left behind good comments and a Word document explaining the concept, but my abstraction is usually different than some one else's, and that's the crux of the problem with indirect addressing or any other programming style that must be maintained by electricians.

With good documentation and planning it can be painless. In RSLogix, the CDM can be used to display values that are difficult to monitor using indexed addressing. You can show the indexed address contents, and the value of the index directly below it along with comments explaining things. This can aid troubleshooting for the layman who needs to montior PLC code.

I use it only when required for efficiency. I often write code with it, then when it's all debugged, I'll re-write it without indirect addressing (just copy the same rungs n times and search and replace) I then compare the two programs. 9 of 10 times the plain logic ends up winning for its user friendliness.

Just my 25 cents
Paul C.
 
Last edited:
I am finding this thread interesting.

I am following the love/hate relationship you guys have with indirect and index addressing. It seems that debugging is the major problem. What would make life easier? When I am programming ladder, I like to over ride or disable for loops and use a coil that I toggle to trigger a one shot that increments the index slowly under my control. It is my version of a single step like I use when debugging DSPs and microcontrollers. Some PLCs have a single step feature. Does any body use it?

BTW, I work with TI TMS320C33 DSPs that have 26 addressing modes.

ABs indexed and indirect addressing should be called memory indexed and memory indirect addressing. This is slow because memory must be accessed to get the index or address. DSPs and microcontrollers use register indirect and indexed address where special registers are use for addressing purposes.

Do not using index or indirect address in a for loop if the index does not change. If the value pointed to a index is used more than once it should be copied to a temporary variable were it can be accessed quicker using normal methods.

Finally, indirect or indexed address is necessary when using our product because there are usually multiple axes.
 
Indirect Addressing for Unit Relativity

I've used indirect addressing a number of times for processes that are unit-relative. Unit relativity is DCS-speak for controlling multiple processes which have identical function. So, for instance, you've 10 identical reactors with 50 I/O each. Carefully map out your memory (and allow spares of both memory and future reactors). There's a block of memory allocated to the 'state' of each reactor, the state-space. There's a block of workspace memory allocated on which the logic is solved. And it goes like this:
Copy inputs for a reactor to a portion of its dedicated state-space memory.
Copy the state-space for the reactor (inputs, timer values, counter values, recipe values, etc) to the workspace.
Perform logic on the workspace.
Copy the resulting workspace back to the reactor's state space
Copy the output section of this state-space to the physical output address of the reactor.
Increment index (or pointer) and repeat until all reactors are complete.

To do this well takes a lot of planning and comprehensive testing. It also necessitates excellent built-in application diagnostics; the HMI will show all pertinent permissives, interlocks, machine states, and timeouts. This way (hopefully), rather then troubleshooting the program logic to find out why the machine hangs or aborts, the diagnostic trail will spell out the problem directly on the HMI. So, some of the economies realized from programming this way need to be spent on improved diagnostics, annotation, and upfront planning. Benefits are faster commissioning, easier program changes, a more reliable application, and decreased memory utilization. Downside is a relative increase in complexity.
 
One time, I had to "pinch hit" on a project for a week for a vacationng programmer. In his program, he had done several file COP statements where the source files were floats and the targets were integers. This is a no-no as the data is not converted as with a MOV instruction--a copy is a bit for bit copy--a source float element actually writes to two consecutive integer elements. Needless to say, his data was all screwed up when it arrived in the integer file.

Anyhow, my solution was to use indirect pointers and move the data, one element at a time--cumbersome, but effective. One move per scan, until the pointer is at max, then do it again.

The point of the whole story is, however, not the solution, not the problem, but the confusion it caused. When the week was over, and the original guy came back, he was bumfazzled--had absolutely no idea what the code was doing or why it was in there. And he is an experienced programmer.

Imagine what a floor electrician goes through when he encounters such things.
 
jamesau said:
...Copy inputs for a reactor to a portion of its dedicated state-space memory.
Copy the state-space for the reactor (inputs, timer values, counter values, recipe values, etc) to the workspace.
Perform logic on the workspace.
Copy the resulting workspace back to the reactor's state space
Copy the output section of this state-space to the physical output address of the reactor.
Increment index (or pointer) and repeat until all reactors are complete.

jamesau:

That is basically what a function block does. When you write a function block you create one copy of the code. When you instantiate the function block multiple times, there are multiple copies of the data but still only one copy of the code. The PLC does all the state-space swapping for you.
 

Similar Topics

Good day. I firmly believe there are stupid questions. This may be one of them. I haven't found a clear solution on the other indirect...
Replies
8
Views
2,583
Howdy folks, I am an Allen Bradley guy currently living in an Emerson world. Working with Rx3i on PacSystems Machine Edition v. 9.6? i think...
Replies
3
Views
629
Hello, I'm very new to programming with absolutely zero schooling in this field and pretty hands off training in my new role, it's been fun...
Replies
4
Views
673
Hello Friends, I am trying to index M Bits, however GX Works2 is not allowing it with following message. https://ibb.co/zPcqj6M...
Replies
3
Views
1,391
Hi All, which the best way to do the indirect addressing in an optimize DB? Ccurrently this is my partial code inside an FB...
Replies
7
Views
2,280
Back
Top Bottom