NI Labs Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

NI LabVIEW Modbus API Discussion

Jason2010 wrote:

Hi Daniel,

Error 56 scared me when I saw it at the first time. My perspective is that something seriously wrong with slave.

One question about this error. For my understanding, slave in Modbus communication setting should only response to master's request. Why does it need to wait for an incoming request. If there is no request, it will be fine, just waiting. Or is there any way to set this waiting timeout to -1 (infinity)?

Jason

Yeah, sorry for the confusion there. The property node initially came out of a need for me to be able to debug the code, and I never really thought about what error 56 would look like. I would argue that it does have value, however, as it lets me know that the slave is *not* getting any requests. That having been said, the error should be cleared if we do get a valid request, so maybe that is a change I can make to make the situation less confusing.

The reason the timeout has to exist in the slave is to allow for a safe and relatively rapid shut-down of the system. When you hit stop we want the daemon in the background to stop relatively quickly and without fuss, so we have to periodically check to see if anyone asked the daemon to stop. If we had an infinite timeout you could never close a modbus instance.

That having been said if you want that, you can modify or copy the "create modbus instance" function for the slave. You should see the calculations I used for the timeout in there, and you can replace it with some much larger number.

Short version:

  • I see the point of confusion and when I have time I'll try to make it more clear that the timeout is expected
  • The timeout is required to shut down the system

Thanks,

Danie

0 Kudos
Message 151 of 529
(1,949 Views)

Hi Daniel,

Thanks for your time.

I'm trying to implement a VI that simulates 2 modbus slave devices, hanging from the same serial port.

I've tried by "almost" duplicating your example, but it doesn't work.

Is it possible to do it using the API, or when creating an instance for Modbus serial slave, the serial port gets locked?

Thanks!

0 Kudos
Message 152 of 529
(1,949 Views)

Hi EduGal,

Short version is that no, with serial there is no way to do that. Since serial is kind of a dumb layer (as opposed to TCP for example which has defined connections), each serial slave daemon must assume it has full control over the network layer. In general, this makes sense. Multiple slaves should not exist on one port, because that means you have multiple slave devices on a single processor and that is not really a common use case.

All this having been said, I understand you're trying to simulate devices and there may be some workarounds. What you really want is a way to take the data coming in off a single physical port and map it to two virtual ports, and then create a slave on each virtual port. With some googling, you may be able to find a tool which does exactly that. If not, you can probably use what I use for testing serial connections on my development computer (I don't have any real serial ports), which is a tool called Com0Com. Basically it creates 2+ ports and maps them together with a virtual null modem cable. You could then make a VI in LabVIEW which sits there and passes data between the physical and virtual ports.

To be specific, lets say com1 is your physical port. Com0Com would produce com2 linked to com3, and com4 linked to com5. You could configure your modbus slaves to listen on com3 and com5, and you would write your helper process such that it copies any data incoming on com1 onto both com2 and com4. You would have another loop which reads from com2 and com4 and copies any data coming from those daemons back over to com1. Provided both serial slaves have different unit IDs, this should get the job done. However, com0com has some weirdness to it, and making the process will take some time, so I'd google around for a bit to see if there is a tool that does it for you.

Hope this helps

-Daniel

0 Kudos
Message 153 of 529
(1,949 Views)

Thanks for the workaround.

I already used com0com in the past, so I will try.

0 Kudos
Message 154 of 529
(1,949 Views)

Thanks for this library, i've successfully deployed the TCP master portion in 2 different production systems over the last 3 months and they've worked without a hitch.

However, I have a different application where I need to implement a light weight modbus slave on crio 9074 and I would like to have a way for the modbus slave object to raise notifications or enqueue a message when a master writes new values. That way I can synch some single process shared variables or notify other parallel loops that thier value may have changed or perhaps fire off a other events that need to happen as quickly as possible after a write (i.e. perhaps a critical control command change). For instance, in an QMH style application where parallel loops communicate back and forth via messages I'd rather not have to submit a 500 "read multiple input coils" messages to the modbus loop queue if the master only updates the the coil values every 10 minutes. It would be nice to have the modbus loop send a message to an appropriate dispatcher for further processing.

Any ideas where I can "hook in" that that functinality. I dug around the TCP Slave class a bit but I obviously couldn't get past the password protection to extend it.

Philip
CLD
0 Kudos
Message 155 of 529
(1,949 Views)

Hey P-rose,

Where you should be hooking in is at the data model, which handles what code gets called when a request comes in. I've placed an example of this here:

https://decibel.ni.com/content/message/61104#61104

It should work as-is, except you'll need to wire a non-zero timeout to the TCP master init function if you have the most recent version of the code (Known issue on main page).

Without knowing more specifics (for example, do you want to fire an event when *any* request comes in, or just a certain type, or just accessing a certain register through any function code, etc.) I can't give you more details, but the example should hopefully show you where the hook is and then we can talk in more detail once you've taken a look, if you have any follow-up questions.

Thanks,

Daniel

0 Kudos
Message 156 of 529
(1,949 Views)

Piece of cake, thanks! I'm also pondering ideas on how to integrate this library with something like the CVT so I can quickly reference the modbus variables by name throughout my application and use a common memory map config file across my HMI app and crio's. Right now, when ever I need the current value of a modbus variable I send a send a messaage the modbus loop to read a coil, register or multiple registers and that message includes a refnum to a 'disposable' notifier. That way, the calling code blocks until the modbus loop retrieves the value and sends it back through the notifier (or timesout) but it seems like this method is not very scalable, especially in high speed/high channel count applications.

Any ideas on how I can make the data space visible to other parts of my application?

Philip
CLD
0 Kudos
Message 157 of 529
(1,949 Views)

Thats a tougher question, and I don't have a ready-made answer for you yet. In the early stages of development on this api we focused just on the actual communication--that is, we didn't want to step on the toes of the DSC I/O servers, which have the behavior you're talking about--except that you can't map things dynamically.

I can say that we have something like what you want on the horizon, but its not there yet. And, in fact, its relatively complicated to get into a good API, which is why we haven't done it yet.

That having been said, I have already done something similar with another customer (a more cut down version than what I have planned for the future). While I can't share the code with you, I can share what I know. To get something like this working, you really have one of two options:

The easier option is to let the library work as-is and perform a scan at some periodic rate or on a value change. This is pretty easy because your configuration really just has to consist of a few items:

  • Data type
  • Start register
  • Count
  • <array of processing steps>

Here, array of processing steps can take one of two forms depending on what you are optimizing for. If CVT access time is something you're worried about, you can organize data by type. That is, within the set of  holding registers from 25 to 101, pull out pairs of registers <25,26>, <32,33>, etc., cast them into floats, and then write that array of floats in bulk into the cvt using the index lookup functions. The other option is organizing by register. Here, you walk linearly through the input data and convert it element by element according to a configured specification. If you organize the specification and the group correctly, you could probably use the attached function and the CVT group write to do this for you.

The much harder option is basically re-writing the data model to use the CVT as your model. This is very feasible, and a lot of the configuration would actually look very similar to the option above...except that start register and count are variable, and thus the specification has to be looked up at runtime based on the specific modbus request. In addition, you'd have to have a facility for skipping sections of registers. Right now the core data model is locked down, but if you were interested in taking this on, I think we could probably work something out.

Thanks,

Daniel

0 Kudos
Message 158 of 529
(1,949 Views)

I'm not too concerned about writing data to the modbus slave loop because the calling code can just send a message to the modbus loop and move on, it's a "set it and forget it" kind of operation. On the other hand, reading data out of the modbus slave data space from multiple places  presents a scalability challenge  because the entire application is throttled by how fast the modbus slave loop can process simultaneous requests. It's one giant dependency. Calling code has to wait to be serviced.

To try and decouple it, I need to copy the modbus variable data into a super fast mechanism that uses key (string)-value pairs so that I can quickly get a value by "tag name". Maybe a solution is to use a variant attribute lookup table in my custom data model's "execute function" vi. The details are still a bit fuzzy but I think it could work. I would have to use your unpack PDU vi's to give me the function code and start address. From that I would form a string to do a lookup on a variant attribute LUT which would return a cluster containing the "tag" name and data type (size inferred from the datatype). Then I'd have to get the new value from the PDU data or perhaps after calling the parent "execute function" and then shove it inside another variant LUT which resides inside of a FGV that I can use throughout my application to get the value by "tag" name. Obviously this would only work if my HMI only writes one value at a time.

Maybe your idea to update all variables on any write would be OK for me. I only have 50 or so variables at this point. That would certainly be easier.

I would be intersted in unifying the CVT and this library. I find myself needing these two technologies fairly regularly. It would be nice to combine the best of both worlds.

Philip
CLD
0 Kudos
Message 159 of 529
(1,949 Views)

Hi everybody,

I just played around with the Modbus API today and this is a very cool library.

It is a very intuitive API and very efficient.

However, in the case of using an Ethernet to RS485 gateway with several RS485 slaves chained together the TCP/IP Master is not usable because we cannot set the slave ID (Set Unit ID.vi) since it is ignored with a TCP/IP transmission data unit according to the VI documentation.

Is there a way to modify the library to take it into account ? Is there a workaround ?

My thoughts are that you created the TCP/IP Master to only adress one slave that is also a TCP/IP slave and not a gateway.

Thanks in advance for your answers.

Have a nice day !

Regards,

Da Helmut
Voir le profil de Maxime M. sur LinkedIn - View Maxime M.'s profile on LinkedIn
0 Kudos
Message 160 of 529
(1,949 Views)