Collision avoidance is quite common and effective.
I'm using this on Uart & RS485 over CAT5 wiring @ 115k2baud.
First you packetize your data, and just for good measures you also add a CRC, just to be sure.
Then, when you want to send, you start by listening for silence on the bus, and you do this for the time of a byte.
If you've detected a silence, then you switch as fast as you can to sending the data.
This means there is only an opportunity of 100ns for an collision to start happening, that means that if you send one packet per second on average, the collision rate will be one in ten million.
Collisions are still possible, and that is where the checksum adds further reliability.
On top of that, you may add a requirement for an acknowledge response. If a node sends a packet and it does not get an Ack within some reasonable time (few ms) then it assumes the packet was not received properly and it resends the packet.
If reception of the same packet twice can be a problem, you have to add a packet numbering or timestamp feature.
Another possibility is to use CAN.
because this has an active and a passive state, collisions can be detected (and remedied) CAN peripherals in uC's should detect collisions in hardware and back off to prevent data corruption.
Reading back the data with RS485 to detect data corruption does not work.
Even if the data is severely corrupted down the line, a uC node tends to read back it's own data perfectly all right because of the cable resistance between itself and the noise source (for example another node sending).