How to effectively work with devices over a serial connection?
Asked Answered
H

5

6

I have struggled with this for a long time, and I did get a solution working eventually but it wasn't pretty, and I am hoping to gain a little wisdom from the stackoverflow community about how this should be done.

Basically I am working with motors that connect to the computer using a daisychained USB connection and I have to communicate with them using the SerialPort class in .Net and it goes through some driver installed on the computer to talk with the motors over USB.

The problem is that the motors are daisy chained, and when I ask

for information from one, or tell it to do something, i have to wait on the result to come back before doing something else with that motor or with any of the others.

I've just had a generally hard time with it, and I'm sure there are better ways of working with serial communication that I've just never been exposed to. Are there any good guidelines or best practices for this kind of thing? Is this a fairly standard thing to do be doing (serial communication -> usb via a driver installed on computer)

I'm working with six of the MDrive23Plus Motion Control motors from IMS.

I can provide plenty more details, but I'm not really sure where this will lead. I hope this is specific enough for StackOverflow, though I know it is sort of vague. I just don't really know how to ask it any better.

Really what it comes down to is how do I synchronize communication effectively, and how do I wait and read the data coming back effectively? I know this is probably very simple to some people, but it just hasn't been working well for me.

Hatchway answered 8/12, 2009 at 20:27 Comment(0)
S
1

You might need multiple threads and/or asynchronous operations. In the past, when doing serial comms (not in .NET), we would queue up reads on the port(s). When a read would complete, the callback function (delegate) would fire, the processing of the read would be carried out, potentially changing the control state - our typical example was a barcode read, while simultaneously having a keyboard read and a timer. One of the events would complete, which would cause an action (potentially leaving the other queued reads in place or cancelling them, depending on what the state was moving to.)

You might want to look into using state machine(s). In this case, the state machine knows what operations are going on, which transitions are allowed and how to get between them and what actions the transitions cause.

Shackleton answered 8/12, 2009 at 20:34 Comment(0)
A
2

this is the limit of working multi drop serial networks.....there is no magic to it, you can ease some of the pain

Generally the best approach is to put in an abstraction layer where you have a message queue of things you want to send, and each of those have a callback that gets called when it gets a response.

Abcoulomb answered 8/12, 2009 at 20:35 Comment(0)
S
1

You might need multiple threads and/or asynchronous operations. In the past, when doing serial comms (not in .NET), we would queue up reads on the port(s). When a read would complete, the callback function (delegate) would fire, the processing of the read would be carried out, potentially changing the control state - our typical example was a barcode read, while simultaneously having a keyboard read and a timer. One of the events would complete, which would cause an action (potentially leaving the other queued reads in place or cancelling them, depending on what the state was moving to.)

You might want to look into using state machine(s). In this case, the state machine knows what operations are going on, which transitions are allowed and how to get between them and what actions the transitions cause.

Shackleton answered 8/12, 2009 at 20:34 Comment(0)
R
1

I work for Zaber Technologies, and I built a control library for our precision stepper motor controllers that communicate over a daisy-chained serial connection. I used three layers:

  1. The port - this layer is just concerned with the communication protocol. It exposes methods for sending a message, and it converts the message parameters into a byte stream. It also listens on the incoming line, converts the byte stream into a message structure, and raises an event when the complete message has been received.
  2. The device - this layer knows how to send messages to a specific device in the daisy chain and how to filter out responses from other devices in the daisy chain.
  3. The conversation - this layer coordinates requests and responses and lets calling code make a request that will block the thread until a response comes back.

Calling code then has the choice of whether to use synchronous requests with the conversation layer, or use asynchronous requests with the device layer.

If you're interested in more details, you can download the source code or look at the user documentation that talks about writing scripts against the library.

Romney answered 8/12, 2009 at 21:7 Comment(3)
The link you provided is for the binary and not the source code.Duff
That's odd, @gonzo, I wonder why I did that. I've updated the link now to point to the latest source code.Romney
Thanks. Can you click +1 on my link for helping you out? ;) I'm going to check out your source code now. I'm really interested in figuring out how to best implement a threaded SerialPort solution.Duff
M
1

Many devices are fickle on their serial comms. There are devices whose comms cannot behave properly with a line read at the baud rate they specified.

I find that I have to characterize the comms of a device. There are vendors where the comms characteristics of two devices of the same model are different. Characterization is a rather tedious affair. Characterization involves discovering various combination of situations and then think of the possibilities.

  1. the lowest threshold number of bytes read/written continuously before inserting a delay. The possibility is one character at a time.
  2. the safest least delay before resuming a read/write.
  3. the variation of minimum delay required from initialising comms till steady state comms.
  4. the variation of threshold number of bytes writable at specified baud before inserting a delay.

The worst case scenario is a proliferation of states/combinations of possibilities influencing the cleanliness of the read/write operations and you reduce the number of states by compromising to use the slowest common denominator among groups of read/write operations. There must be a science behind all this but I just try my voodooistic best using brute force testing.

Which, of course, would lead to having a read/write layer separating the routines needing communication from directly communicating with the port.

Alternatively, we all know the quick and lazy but inefficient way is inserting a 10 ms wait after every byte.

Malia answered 8/12, 2009 at 21:48 Comment(0)
C
1

I have also been using the .net serial port class since 2004, i agree state machines are probably the way to go here, that along with sending out command, then wait for the associated response in the handshake(device will respond when it is ready to respond).

Consider your serialPort.DataReceived() event handler as your front end. then have DataReceived do a BeginInvoke(), not an Invoke() as serial port is asynchronous interface to a method, AddReceive() next, in AddReceive() count the number of bytes that it sees if more than 0, then append data to stringbuilder container, say sbReceived finally fire a timer handler to pickup any 'left over' data in the stream where it also does a 'beginInvoke' on method, ReadData() now we are ready to parse data out and pass to terminal display(best to use richtext box here), color code various prompts to indicate >> out data, << in data, configuration, error, status since you have various ports to monitor and i/o status on each one, you could do so inside of one terminal display.

I agree state machine is good idea here, process is very stateful anyways; you are waiting for output of serial1 parsed output to match what you need, before sending serial port commands on other ports. doing it this way would keep things organized and different serial port activities are nicely partitioned out. in the other case where you might have several subsequent command/query out and device response cycles happening, it might be better to do while(serial1.ByteCount==0){}; in between to just let the device control the timing of the response in the handshake. it can also be helpful to have a debug digital i/o device hooked up so you can toggle line to monitor latency times and watch on DSO to verify timing requirement is being met.

finally, be certain to purge your port on each write/read cycle so you don't experience overflow issues, along with re-initialization of data buffers, stringbuilder containers and the like.

have a good day

Craniotomy answered 11/9, 2011 at 0:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.