dmroeder / pylogix

Read/Write data from Allen Bradley Compact/Control Logix PLC's
Apache License 2.0
598 stars 182 forks source link

Controllogix 1756-l71 support #84

Closed vasekjares closed 4 years ago

vasekjares commented 5 years ago

Hey guys!

I'm just looking into your software. We're getting Controllogix 1756-l71 PLC. Is there anyway how to verify compatibility with your software and eventually make a quick call and get some minor advisory? We don't have much experience with that.

Thanks!

TheFern2 commented 5 years ago

Hey @vasekjares the quickest way to verify compatibility is to use https://github.com/kodaman2/pylogix-tester once you get the plc. Though it should work fine with any Controllogix PLC.

chrisegge commented 5 years ago

I can verify that it works with the 1756-L72 v23. Shouldnt be any problem at all with 1756-L71

vasekjares commented 5 years ago

Thanks guys! This helps so much!

It's our first time implementing a PLC, would you please give us some basic suggestions / what to be aware of?

We got system of conveyors with 3 diverts managed by following tags: https://www.dropbox.com/s/3a1ce91fdcfevqm/Screenshot%202019-10-09%2014.45.02.png?dl=0

Our idea is to have 1 thread doing health-checks for all 3 diverts and second thread sequentially reading tags for all 3 diverts and after writing tags for all 3 diverts (if there is something to write).

a.) Is it good idea to write to PLC in parallel threads? b.) Is there any special error handling needed besides connection issues to PLC itself? c.) Are there some common mistakes to watch out for?

Thanks in advance!

evaldes2015 commented 5 years ago

Threading adds complexity and difficulty in debugging. You should probably avoid it in these types of applications.

Regarding the data exchange between the WCS and the PLC, you have structured things so that You have to do multiple reads and writes to exchange the data. At the very least you should change the response (WCS to PLC) from a UDT to a DINT array.

TheFern2 commented 5 years ago

I dunno much about threading to be honest, but if you can't sync states reliable between threads then it would be hard to implement unless if I am reading this correctly both threads are doing individual tasks and do not depend on each other at all. Threading in my opinion is just too much of a risk on heavy machinery.

The latest version it doesn't raise any exceptions for most of the functions, check the examples but for the most part a Response object is returned with TagName, Value, Status, if there are any issues Value can return None object so you have to handle that on your client application to make sure the value is not None, regarding connection I wanna say as long as you are reading the conection stays open until you do close() or the timeout occurs, I personally use ping3 for pinging. Maybe @dmroeder has a better idea on how to watchout for connection closing.

By the way is there any reason you are not writing the program in the PLC? It would definitely beat python multi-thread. Depending on the sort conveyor speed I don't think python would be the best implementation unless the sort conveyors are not that fast moving.

evaldes2015 commented 5 years ago

I doubt he's doing anything to directly control the machine from python. This is a common application. The PLC sees a package with a barcode. A python application is polling the PLC and reads this data and responds with a sort instruction. It's likely the sort instruction requires data that is not readily available in the PLC, or it requires a database lookup, which is something outside of the PLC's capabilities. I've been doing this kind of stuff for 20 years.

TheFern2 commented 5 years ago

Gotcha that makes more sense, now that you put it that way.

evaldes2015 commented 5 years ago

:)

vasekjares commented 5 years ago

Thanks guys!

@evaldes2015 why would you change UDT to DINT array? Because of atomicity of those writes? Is there any way how to do "multi-tag" write atomically?

Threading is basically just for health check (every second, write health-check tag), pre-fetching data from server for divert decisions and then main thread doing all the reads and writes for diverts.

Do you know of any production use of this lib? Eventually do you use it personally somewhere? Our system works 24/7 and will be doing up to maximum of 60 cartons / minute. But in average it's gonna be much lower (something like 10-15 a minute)

dmroeder commented 5 years ago

Regarding the connection, if you call read, for example, then do nothing for a long enough period of time (~90 seconds), the PLC will most likely drop the connection. On the occasions that I have a program where I don't know when the next time a read will happen, I'll have a loop that gets the PLC time every 30 seconds or so to keep the connection alive.

An example, I have a program right now that is using vision to detect something in the frame, it alerts the PLC of the object. I can't predict when the object will enter the frame, so I have a function that get's the PLC time every 30 seconds to keep the connection alive.

I think if you have a try/catch around your reads it will reestablish a connection. Probably the next time after the failure.

Maybe one of the more common things (I use "common" loosely) that I get emailed about is calling Close() unnecessarily. In the project I mentioned above, I'm only calling Close() when my program exits. I've had a couple of users call Close() after every read/write.

TheFern2 commented 5 years ago

@evaldes2015 why would you change UDT to DINT array? Because of atomicity of those writes? Is there any way how to do "multi-tag" write atomically?

Yes, that is correct. You can read/write arrays in one call, you can't do that with UDT's. read array write array

I use it in production though not 24/7 but I haven't had the need for everyday usage, I am sure it would handle just fine. https://github.com/kodaman2/Data_Preserve

Edit: You can read udt in one call but you'd have to know how to break the raw byte data https://github.com/dmroeder/pylogix/blob/master/pylogix/examples/40_read_timer.py

@dmroeder I know you told me about reading raw data from udt like the timer example, would the Write work the same for UDT with raw data too?

dmroeder commented 5 years ago

Thanks guys!

@evaldes2015 why would you change UDT to DINT array? Because of atomicity of those writes? Is there any way how to do "multi-tag" write atomically?

Threading is basically just for health check (every second, write health-check tag), pre-fetching data from server for divert decisions and then main thread doing all the reads and writes for diverts.

Do you know of any production use of this lib? Eventually do you use it personally somewhere? Our system works 24/7 and will be doing up to maximum of 60 cartons / minute. But in average it's gonna be much lower (something like 10-15 a minute)

He's recommending mapping everything from a UDT to a DINT array because you can read a DINT array in one request (ex. comm.Read("DintArray[0]', 100) where each individual tag in your UDT will have to be read. If you plan on sticking with the UDT, you can pass a list of tags to minimize the number of interactions to get all of your data in fewer reads...

tags = ["udt_tag.Member1", "udt_tag.Member2", "udt_tag.Member3"]
reply = comm.Read(tags)
dmroeder commented 5 years ago

@dmroeder I know you told me about reading raw data from udt like the timer example, would the Write work the same for UDT with raw data too?

Honestly, I just don't use UDT's when using pylogix, so I don't remember what it takes to write UDT's. I suspect that you'll have to write the data the hard way since I never made an example.

I think the problem is not only do you have to understand exactly how the data needs to be packed into into a byte stream, you have to know how to calculate the size in bytes. This can be pretty straightforward for a simple data type that uses DINT's, but can get very complex when using UDT's with mixed data types. It doesn't take one very long when dealing with this to realize why people hate BOOL/BOOL arrays. You also learn the importance of the order that various types are arranged within the UDT definition.

dmroeder commented 5 years ago

If you've never paid much attention to UDT structure, try an experiment:

Make 2 UDT's. In the first add members of data types like this:

In the second one:

Notice their size in bytes, also export them and look at their structure.

TheFern2 commented 5 years ago

If you've never paid much attention to UDT structure, try an experiment:

Make 2 UDT's. In the first add members of data types like this:

  • DINT
  • BOOL
  • DINT
  • BOOL

In the second one:

  • DINT
  • DINT
  • BOOL
  • BOOL

Notice their size in bytes, also export them and look at their structure.

Ok cool will try tomorrow in the lab, and let you know.

evaldes2015 commented 5 years ago

I haven't used pylogix in production yet. But it's coming. I have been running it 24/7 in a test system for several months (Raspberry PI 3+ talking to a L16ER) without any issues so I have no reservations about using in production.