Several ROS nodes through a single serial port
Suppose that I have some devices which can be assembled as a chain and which communicate with a single serial port (each device has its own unique id and a proper firmware). These devices can be also very different from each other, both in shapes and functionalities, but share the same hardware (i.e. the same low level API can be used for all of them).
Now you are a forward-looking programmer and you know that what you are developing for a specific purpose will be used for many other projects. You prefer modularity rather than the one-size-fits-all approach. And you also like ROS.
Suppose you develop a base interface to wrap the low level API and implement on top of it the specific device classes. Now, because of the multi-device environment, it is desirable to avoid putting everything inside a single ROS node, in favour of a modular and easily customizable one-node-for-one-device approach (i.e. using ad-hoc launch files for distinct configurations).
Everything is fine.
Everything but the managemant of the serial communication from distinct nodes. Indeed ROS is a multi-process environment and distinct processes do not share resources each other: the file descriptor of the single serial port cannot be shared.
Actually the open()
on the same resource can be called by distinct processes if the exclusive mode is not set (cf. ioctl()
with TIOCEXCL
and TIOCNXCL
options). However, this implies a synchronization mechanism, and again, sharing something among processes.
- How would you face this problem?
- Are there any workaround in ROS which I do not know?
- How much overhead w.r.t. to a single I/O operation would produce a communication handler "super-node" (e.g. with
read()
,write()
,...
ROS services)?
Asked by alextoind on 2017-02-02 05:40:38 UTC
Comments
Have you considered using plugins? The 'single node' could simply be in charge of managing your contended resource (ie: the serial port), and the plugins (nodelets?) could handle the actual traffic.
Asked by gvdhoorn on 2017-02-02 08:08:38 UTC
I've phrased what you are describing the facade (or service abstraction) versus the transparant bridge problem: a bridging approach will typically import domain concepts from 'beyond' the bridge into your ROS nodegraph, the facade completely hides everything behind a ROS API (svcs, topics).
Asked by gvdhoorn on 2017-02-02 08:10:15 UTC
This is not necessarily true (the multiprocess part): it just happens that most nodes get mapped onto processes (at deployment time, or by design), but they don't have to be (nodelets again).
Asked by gvdhoorn on 2017-02-02 08:11:48 UTC
Thank you for helping me once again! I was just reading about
nodelets
which I have never used before. It seems to do the trick, but I have to dig a bit more the get the whole picture.Asked by alextoind on 2017-02-02 08:33:46 UTC
Well nodelets won't avoid importing domain concepts from beyond the bridge into your ROS application (ie: node graph), but they will minimise potential communication overhead, while still supporting the distributed development that normal nodes allow.
Asked by gvdhoorn on 2017-02-02 08:50:15 UTC
Note that my initial comment (about plugins) is not tied to using nodelets. I merely meant that the plugins could 'behave' like nodelets.
Asked by gvdhoorn on 2017-02-02 08:50:58 UTC
Why should I use something which behave like
nodelets
instead of usingnodelets
itself? I mean, start from scratch takes time and probably leads to a similar result. Are there any particular reasons to prefer this way (apart the perfect fitting to my problems, if well designed)?Asked by alextoind on 2017-02-02 10:10:11 UTC
And - if I understand correctly - if I decide to switch to plugin approach, I'll use it "forever". Could this be a problem in some circumstances? Sorry if I'm boring you, but it's a remarkable restyle and I just want to be sure that it won't be useless.
Asked by alextoind on 2017-02-02 10:21:05 UTC
As I wrote earlier: nodelets are essentially nodes, but mapped on threads, so with a shared address space, making passing of pointers possible. That avoids communication overhead (but the advantages wrt jitter are probably more significant).
But, you still need to guard / expose your contended ..
Asked by gvdhoorn on 2017-02-02 10:27:22 UTC
.. resource, so you'll probably create a nodelet that offers those
read()
,write()
,...
services you mentioned. Result: you have a transparent bridge and all your ROS nodes now need to 'know' how to deal with domain concepts (ie: interpreting serial traffic). Personally I'm not sure that ..Asked by gvdhoorn on 2017-02-02 10:28:54 UTC
.. is a good thing.
The service proxy / facade pattern would basically 'hide' the entities behind the bridge, while exposing a ROS API that still allows interested ROS participants to interact with the components beyond the bridge. This style avoids leaking knowledge / implementation details.
Asked by gvdhoorn on 2017-02-02 10:30:38 UTC
Less knowledge / assumptions is always (I posit) a good thing in software components, as it increases their reusability.
Note that this issue is not limited to serial ports: the same issues come up with briding into fieldbus networks fi. It's also not a dilemma: hybrids are possible.
Asked by gvdhoorn on 2017-02-02 10:33:35 UTC
I know that I've been a bit slow on the uptake, but I got it. Thank you very much, you are great!
Asked by alextoind on 2017-02-02 11:07:17 UTC
No problem.
Btw: I feel these kind of things are more suited for a discussion, as there probably isn't one specific answer that is the answer.
discourse.ros.org
is good for discussions. ROS Answers is for straightforward Q&A style things.Asked by gvdhoorn on 2017-02-02 11:25:03 UTC
Hello.
I am facing a similar problem on a project. I need do communicate with some embedded board on a 485 bus. I tried with rosserial, but that individual use of the port and the multitask approach of rosserial_node is very trick for me.
Did you have any success on what you were developing?
Asked by Jefecito on 2017-05-11 13:25:01 UTC
The two main approaches described in the comments above are both valid. For my specific application I've chosen to create a distinct communication handler node to manage the serial port and to advertise the services I need. The interprocess message exchange is fast enough for my case.
Asked by alextoind on 2017-05-12 02:31:25 UTC