Produce/Consume question across Multiple CLX's

Join Date
Jul 2007
Location
Kiruna
Posts
600
Hi there,

I have 6 PLCs (Compact Logix) I want to share some data between.

I was hoping to add the shared data to an already shared UDT with some new members.

Taking PLC1 & PLC2....

PLC1 has a Produced tag PLC1_Data containing a member called VAL. I set this to 1 in PLC1.

PLC2 has a consumed tag PLC1_Data which reads from PLC1 and Val is 1. All is good.

The problem is based on a bit selection in each PLC only one controller should have the ability to write to VAL. If I set PLC2_Data Val in PLC2 (Produced ) to 2 then PLC2_Data in PLC1 (consumed) remains at 1.

They are fighting each other. I guess what I am asking is there anyway to tell the producer to stop "producing" based on a value. Only one controller can be the master and hence produce.

I guess a MSG is an alternative, just checking if this is possible. Hope it makes sense.
 
It sounds like PLC2_Data is not being consumed by PLC1 (i.e., named PLC2_Data in PLC1).

Are you talking about setting up a 6 x 6 arrangement of produced/consumed tags? If so, you might consider one server PLC that produces one tag which is commonly consumed by each of the clients, and then that server consumes separate tags from each client. The server will then need the logic around marshaling, and what to send to the clients. There are downsides to this, though it does reduce the number of connections.
 
What I have thinking was 6 structure tags in each controller as follows:

PLC1:
PLC1_Data -Produced
PLC2_Data -Consumed
PLC3_Data -Consumed
PLC4_Data -Consumed
PLC5_Data -Consumed
PLC6_Data -Consumed


PLC2:
PLC1_Data -Consumed
PLC2_Data -Produced
PLC3_Data -Consumed
PLC4_Data -Consumed
PLC5_Data -Consumed
PLC6_Data -Consumed


PLC3:
PLC1_Data -Consumed
PLC2_Data -Consumed
PLC3_Data -Produced
PLC4_Data -Consumed
PLC5_Data -Consumed
PLC6_Data -Consumed


And so on....

If a specific screen is opened on a SE Stand alone application pointing to PLC1, then the value written to Val will get written to the Val tag in all other controllers. Similarly if the same screen is opened on the SE application connected to the PLC2 controller then Val set here will overwrite it in all other controllers.

Essentially one controller cannot be designed as the server. They must all be capable of taking control of this tag (well one tag for simplicity, there is more involved)

Does this make sense?
 
The actual structure of produced and consumed tags is fairly rigid, and you can't just stop a producer from producing programatically (well, if there's a way, I don't know it).

Let me make sure I understand what you're trying to achieve. If you change a tag in PLCn, you want that change to be rolled out to the other 5 PLC's via produced/consumed tags as well. So, the "Val" tag in all PLC's = 1, but if PLC4 has the "Val" tag changed to "2" by the SCADA (or anything else), then the "Val" tag in all PLC's must update to be "2". Am I right?

If so, what I'd do is leave the produced/consumed part of it alone and handle the changeover with change-of-state logic. So, PLC1 has, as you say:

PLC1_Data -Produced
PLC2_Data -Consumed
PLC3_Data -Consumed
PLC4_Data -Consumed
PLC5_Data -Consumed
PLC6_Data -Consumed

Don't directly use the PLC2_Data...PLC6_Data tags to try and write back to other PLC's. Instead, just monitor them. If any of them change, update PLC1_Data to the changed value. What will happen in the background is that each PLC will update it's "Val" tag 5 times, as it sees the other 5 PLC's change from 1 to 2, but in each case it'll be updating to the same value, so there should be no problem.
 
Hi ASF,

Yes you are correct in how it should work. Having read your reply a few times I'm still not sure I get it.

I can't assume PLC1 will always be present on the network. This PLC controlling a machine may be down due to maintenance or communications failure for example.
 
It should still work, although that's a good point - you might have to add some logic to detect when a machine re-connects to the network, and have the other PLC's ignore it's value until it synchronises with the existing machines.

Let me try and explain in more detail. I'll simplify it down to three PLC's for now.

Let's create a UDT with two elements:
"Status" of type CONNECTION_STATUS
"MyValue" of type DINT

In PLC1, we will create the following:
Comms_Out (Produced Tag for consumption by PLC2 and PLC3)
CommsIn_PLC2 (Consumed Tag, linked to "Comms_Out" in PLC2)
CommsIn_PLC3 (Consumed Tag, linked to "Comms_Out" in PLC3)

In PLC2, we will create the following:
Comms_Out (Produced Tag for consumption by PLC1 and PLC3)
CommsIn_PLC1 (Consumed Tag, linked to "Comms_Out" in PLC1)
CommsIn_PLC3 (Consumed Tag, linked to "Comms_Out" in PLC3)

In PLC3, we will create the following:
Comms_Out (Produced Tag for consumption by PLC1 and PLC2)
CommsIn_PLC1 (Consumed Tag, linked to "Comms_Out" in PLC1)
CommsIn_PLC2 (Consumed Tag, linked to "Comms_Out" in PLC2)

All of these tags will be our UDT above.

In PLC1, we will monitor the status of CommsIn_PLC2.MyValue and compare it against the previous value. If it changes, we will update CommsOut.MyValue to match. So, create a DINT called "PLC2Value_LastScan" and a rung that does something like:

NEQ CommsIn_PLC2.MyValue PLC2Value_LastScan MOV CommsIn_PLC2.MyValue Comms_Out.MyValue MOV CommsIn_PLC2.MyValue PLC2Value_LastScan

What this rung does is check to see if the value reported from PLC2 is the same as last scan. If it is, nothing happens. If it's not, someone has used the SCADA to change the value in PLC2. So we get that new value, move it into PLC1's "MyValue" tag, and then update the "Previous Scan" value of PLC2 so that we can monitor again for future changes.

You will also have identical logic to monitor CommsIn_PLC3.MyValue. And in PLC3, you will have identical logic monitoring the MyValue tag in both PLC1 and PLC2. So, what will also happen is that PLC3 will update it's "MyValue" tag to whatever PLC2 just got changed to, and then PLC1 will see the change and update it's "MyValue" tag to whatever PLC3 just got changed to, which is of course what PLC2 just changed to. So although you won't see it, every time a value changes, each PLC will update it's value multiple times - one less time than the number of PLC's.

The other factor is, as you say, having one PLC come back online and synchronise with the existing "MyValue" tags, rather than have the other PLC's overwrite their values with the value from the PLC that just came back online. This is where your "Status" part of the UDT comes in.

This "Status" element to your UDT contains two BOOL's: ConnectionFaulted and RunMode. As you can probably guess, ConnectionFaulted is true if there is no connection to the producing PLC. So, if PLC1 goes offline, then "CommsIn_PLC1.Status.ConnectionFaulted" in both PLC2 and PLC3 will be set to 1. Likewise, if you switch PLC1 to program mode, "CommsIn_PLC1.Status.RunMode" will be set to 0 in both PLC2 and PLC3. This happens automatically in the background with no input from you.

So, you would need to use these tags to determine that PLC1 has come back online, and make sure that PLC1 still checks and updates it's "MyValue" based on what's in "CommsIn_PLC2.MyValue" and "CommsIn_PLC3.MyValue" (which should be identical), and that PLC2 and PLC3 ignore the "CommsIn_PLC1.MyValue" value change until the "CommsIn_PLC1.Status" tags indicate that it's back online, and that it has updated it's "MyValue" tag accordingly.

It all sounds a bit convoluted to write it out, but it should be reasonably simple from a code point of view. I hope. Does that help at all?
 
Last edited:
With a full set of produced and consumed tags, as described in reply #3, the idea is that only one PLC can be the "designated" producer at any given time. When that PLC receives an external input that needs to be distributed to the other five, it writes to its one and only produced tag. When it does this, it temporarily suspends consumed tag updating described next.
All of the PLCs continuously monitor the five consumed tags for any data changes to the critical value. When a data change is detected, the (non-original-producing) PLC moves the critical value from the changed consumed tag to its produced tag.
When the original producer detects that all consumed tags match the new value, then it has verified the critical value was fully distributed. In this scenario, it will be helpful to monitor connection status to know if a processor is not running, and therefore a response is not expected. Either that or timeout based on the consumers' RPI.
(This is pretty much what is described in reply #6)
 
Last edited:
Yes it does make sense and thanks for taking the time to explain it in detail.

Perhaps what I should mention now and I kept it to a single shared tag for simplicity is that it's a structure with a lot of data that I need to share.

What I'm trying to achieve is a Master program which can set up the relationship between each machine on the fly according to the plant.

For example each machine may all share the same water source (same tank,pump etc) , they may be paired in 2's, 3's or they may even have their own dedicated water source. This applies to other media such as air, feed material, discharging on conveyors.

Ideally this relationship could be configured on a master PLC and then sent to all partners but I cant assume this PLC will be present. I would like to be able to open this "Master config" HMI screen on any machine, set up the relationships. This when satisfied should get copied to all PLCs so each PLC knows its partner for each media source and can make its own decisions in specific steps of a sequence as to whether it can take media or wait based on the number of Max permitted user of that source. Of course I'll need to share what each machine is doing also, i.e Machine one = Feeding, then in each PLC I can decide whether i care or not and increment a count for the number of machines feeding in that partnership.

Is this still the way to go given that its not just a single tag now. I was hoping to have some form of block that depending on who is "deciding" only gets processed in its respective PLC and shares this to all the others that may need it if it needs to be reconfigured later from another PLC.

This will only change during commissioning and may never change again,so it could happen in the form of a "Download to all controllers" button if it simplifies the logic.
 
That being the case, I'd create a UDT that contains all of the information you need, plus a BOOL called "Load".

Each PLC has the same tags as before, e.g. PLC1 has:
Comms_Out (produced tag)
CommsIn_PLC2 (consumed tag, linked to Comms_Out in PLC2)
CommsIn_PLC3 (consumed tag, linked to Comms_Out in PLC3)
...
...
It also has an internal tag called, say, "CurrentRecipe"

All of these tags are instances of the UDT with all of your line parameters, plus that "Load" BOOL. The "Load" bit is set by a button on the SCADA.

PLC1 monitors the "Load" bit from each of the other PLC's, and if any one of them sets it, then you copy the whole UDT from the relevant CommsIn_PLCn tag to your internal "CurrentRecipe" tag, and that's the data structure your PLC actually uses to run.

Then you need to update your Comms_Out tag, so that all of the other PLC's know what PLC1 is up to. But, you need to do this WITHOUT forcing those changes back out to the other PLC's. So, unlatch CurrentRecipe.Load, and then copy it to Comms_Out.

Does that achieve what you need?
 
Thinking about this a bit more...if there is no high availability PLC to act as a data server, you might consider going with MSG instructions instead of produced/consumed tags after all. Each PLC will still need to have MSG rungs to every other processor, and will still need to monitor the incoming MSG tags for data changes. But it may end up less complex if it is sufficient for the PLC with an external event (i.e., the data source)to "broadcast" the new data set to all five peers via messages. Those on the receiving end will detect an incoming data change and move that data to the "active" configuration. Optionally, the receivers could reflect the message back to the sender, but only if the sender required confirmation.
In addition to potentially reducing unnecessary data traffic, the MSG approach avoids the "start-up/on-line" problem mentioned earlier. You don't need to worry about immediately producing data stored in your offline file following a program download. Though, you would have to come up with a way for a newly on-line processor to synchronize with all the others (i.e., force a set of incoming messages to initialize the data change detection logic). Seems like it might be a bit less fragile than the produced/consumed approach.
 
Why not just have the HMI set the new Val in all PLCs? That way the update happens because of operator action, not a complicated monitoring of each PLC by all the others.

If you have a PLC that is down when the config changes, it can detect that its Val doesn't match the others and then correct itself if all the other PLCs are in agreement. I'd have this process wait a bit (say 10 seconds) so that it doesn't try to fight a change by the operator.
 
I used ASFs method and it works perfect. Thanks for that. It was a little confusing until I started breaking it down and coding it. I understand now.

As its 200 byte UDT there is a lot of MOV instructions getting the data to/from each processor based on a "CMD_Load" bit. Perhaps I'll change to an Array of DINTs later and can use a COP instruction.

Right now what I am doing is when CMD_Load is triggered from HMI I set a Sts_Load bit for 5 seconds and during this time I write the data continuously to each PLC. I understand I need to change this now. How would you approach this?

Also if one PLC goes offline for a period, how do I ensure it gets issued with the same configuration when it comes back to life?

Edit: On further thinking if I leave it as it is.... The data can only change if the Sts_load bit is high. So if PLC1 was offline for a period and came back online, it would never write its "old" config data to the other consumers. I just need an event to sync it with the other controllers.
 
Last edited:
I used ASFs method and it works perfect. Thanks for that. It was a little confusing until I started breaking it down and coding it. I understand now.

No problem! 🍺

As its 200 byte UDT there is a lot of MOV instructions getting the data to/from each processor based on a "CMD_Load" bit. Perhaps I'll change to an Array of DINTs later and can use a COP instruction.

You can use a COP instruction on a UDT directly. A COP instruction is blind and dumb - if you tell it to copy a 200 byte UDT, it'll copy 200 bytes to wherever you tell it. Actually, that's not quite true - the length of the copy is in terms of the destination. There are a lot of threads on this topic if you go searching, or if you need more information just post back. But the long and short of it is, you can COP from a UDT to a UDT with a length of 1, and it will copy the entire structure as-is, be it DINT's, REAL's, STRING's, BOOL's, arrays, nested UDT's - you name it, it copies it.

Right now what I am doing is when CMD_Load is triggered from HMI I set a Sts_Load bit for 5 seconds and during this time I write the data continuously to each PLC. I understand I need to change this now. How would you approach this?

I would set it up so that you have a "load command" bit and a "load complete" bit. PLC1 turns on the load command bit, and PLC2 sees it, copies the data, and then turns on the "load complete" bit, at which point the transaction is complete. Once all PLC's have the updated value, you turn off your "load command" bit. I've done exactly this before, and the beauty of it is that it leads nicely into your next question...

Also if one PLC goes offline for a period, how do I ensure it gets issued with the same configuration when it comes back to life?

Edit: On further thinking if I leave it as it is.... The data can only change if the Sts_load bit is high. So if PLC1 was offline for a period and came back online, it would never write its "old" config data to the other consumers. I just need an event to sync it with the other controllers.

Correct - and if you use the method above, as soon as the other PLC comes online it will see that a load is required, and will perform the load.

The only thing to think about is what the effect will be if you load to all machines with PLCx offline, and then while PLCx is still offline, you need to perform another load. So perhaps rather than a single "load command" you should have individual load commands for each PLC. As each PLC responds, you turn off it's individual load command. Or, if another PLC tells that PLC to load something different, turn off all load commands as the other PLC now has the latest information.
 
I used a bunch of MOVs because I didn't want to produce /consume the entire structure.

I've used the Load and load_Completed as advised and it works a dream. Job done! Thanks ASF!
 
No worries! If you don't want to produce/consume the entire structure, but still want to get rid of all the MOV's, just create a UDT of the data that you DO want to produce/consume, then nest that inside a larger UDT. That way you can still use a single COP to copy all of the required data in one instruction, but still have discrete control over everything else. I've done that before - call the UDT with all your parameters "UDT_MachineParams" and then create another UDT called say "UDT_CommsData". In "UDT_CommsData" add your "UDT_MachineParams" as well as all the Load_Command, Load_Complete, ConnectionStatus, and other miscellanous bits and pieces, and then create produced/consumed tags of type UDT_CommsData.
 

Similar Topics

Hello, I am working on a ControlLogix project using RSlogix version 17 (software and flashed firmware). This will eventually have to talk over...
Replies
5
Views
4,075
I currently have a setup in Siemens S7 using I-Device connections over PROFINET and I am trying to investigate an equivalent setup using Rockwell...
Replies
7
Views
1,076
Recent Forum member and very-good-question-asker /DesertSurf520 has a thread that started a discussion about Compact 5000 I/O, but branched off...
Replies
11
Views
1,796
My PLC has a Boolean consume tag that gets data from another PLC via ethernet. Is there a way to make the consume tag fail to 0 when the ethernet...
Replies
6
Views
2,741
Hello Ladies and Gents, I have some PLC to PLC communications using Produce and Consume. The data is not time sensitive, and I really only need...
Replies
16
Views
4,614
Back
Top Bottom