I'd like to know if there is an easy way to implement communication between multiple arduinos that avoids collisions using the RS485 module.

My setup would have multiple masters that send messages to only one slave that performs a task upon been given the message.

I've tried researching some libraries for this, but they normally don't fulfil the multimaster requisite, nevertheless I found this library which apparently does implement what I need, but I haven't been able to understand how it works.

My current options are either finding an easier library that is capable of doing what I need, learning how to make the linked library work (which I have already tried) or building my own serial communication protocol that implements collision avoidance and a multiple master configuration.

What path should I follow? Can you give me any recommendation for any of the paths I'm suggesting? Is there a better way of implementing this type of communication?

4 Answers
4

Collision avoidance is a tricky subject. You can never completely avoid collisions - all you can do is work out how to a) detect them, and b) recover from them.

There's many different ways of doing it, and how you implement it is very much dependent on what your hardware can do, and how you are actually using the protocol.

The best way of detecting a collision is to arrange it so that your master is always reading the bus even when it is sending. You require separate receiver and transmitter modules, so that as you place a byte on the bus you attempt to also receive that byte. If it doesn't get received, or the wrong byte gets received, then you have a collision.

That is a 100% guaranteed way of detecting a collision as it happens. If you know that what you sent didn't make it onto the wire properly then it collided.

A simpler scheme is to be watching the bus before you send. If there has been no sign of any traffic for more than a certain threshold time then you can assume that the bus is currently quiet. You can then try and send your data. You don't know if it got through OK though, since something else could have decided that the bus was quiet long enough for it to send too.

So you would have to have some kind of ACK signal coming back from the other end that says the packet got received OK. Keep retrying until you get that ACK back. Of course, the ACK could be colliding as well, so it may have been received, but you just haven't been told. So your remote device would have to be able to gracefully handle receiving the same packet multiple times and discarding (yet still ACKing) the repeated packets.

What you should do when you do detect a collision (or fail to receive an ACK) is also kind of tricky. You have to wait and try sending again. But if there are two devices both waiting to send again, how can you be sure that they won't both be waiting for the same time, and thus collide again?

You have to ensure that both devices delay for a random period - and make sure that the random period truly is random. Using the default random() function, unless you can seed it from a truly random source of entropy, will generate the same sequence of numbers for all the devices - so each device would get the same "random" number. And collisions ensue.

So you see, you can't just throw a random library at it and say "This library will stop collisions" - the best you can say is "This library can help reduce collisions, detect them when they do occur, and gracefully recover from them."

For the library you link to it appears to attempt to implement the latter system:

Collision avoidance is implemented through the assignment of a message priority. A node will not start transmission before the bus has been idle for a time determined by the priority. Note that the highest priority is given to messages with the lowest priority number.

Collision detection is implemented by read-verified-write, i.e. all data written is checked on the fly for proper echo-back. If the software detects a frame error or a data mismatch when the echo character is received, it will disable the RS485 transmission and flag the collision status. The included transaction management will resend the message after the bus is idle again.

It waits for the bus to be free of traffic for a specific amount of time (the time is variable depending on the message priority), and expects the message to be sent back again as a form of ACK.

It makes no mention of random back-off times though to avoid collisions between different masters sending messages with the same priority.

The problem is quite complex: collision avoidance, collision detection and message retrial, message priority and message filtering. But the library solves it all. The software even provides a solution to interface a host (PC or Android) to the RS485, providing the same features.

In ‘understanding the library’ there are two aspects: how it works, and how to make it work.

The library itself is non-trivial (because the problem is also non-trivial), so to understand how it works is also non-trivial (Majenko, in his answer, gave a nice functional description of some of the features that are implemented by the library. The actual implementation has additional complications due to the direct interaction with the USART at interrupt level.). I guess you do not want to know (in first instance) how it works in such details.

However, the author (me) went to quite some detail to document how to make it work. But I reckon that documentation may be difficult to follow if the documentation does not match the expectations of the reader.

So I would be very interested to improve the documentation and to match the expectations of new users. However, here I need your help (or anyone interested) in pointing me out what and where I can improve.

The preferred way to contact me on these matters is by creating an issue on my Github project page:

The general idea is that you can set up multiple Arduinos to take turns becoming a master, based on waiting for its own "turn" in a time-based sequence, with provision for recovering from one of the units not responding.

I thinks the easiest way for software is not use any software do this at all, using a hardware controller chip/module instead which dedicated to support multi-master and arbitration for RS485 (the same way as CAN bus).

There is a protocol, named CDBUS, witch has stand-alone controller to do the work for you, which is very simple, I can even transfer video stream through it, details: