Connecting multiple Arduinos with the exact same code

Hello!

I have a project called STBS (Simple Train Blocking System) the goal of this project is to prevent a crash.
I've already got another project (ATBS) who do the same thing, but the issue with this second project is that this was centralized so, when we needed to add a new block and a new train into the system I needed to rewrite the whole code and start the project from scratch, again.

STBS works with 1 Arduino Nano per block, I want to make them communicate with the next Arduino and the precedent one.

There will be 2 major functions:

  1. When a train is going out the block, power off the current block and send a "start" signal to the precedent one
  2. When I receive a "start" signal from the next block, power up the current block.

The Arduino will be separated by a quite large distance, so the communication system needs to be reliable.

Somebody talked me about BUSi2c but this system requires an ID and one of the main goal of STBS is to be the same code and hardware for every single block to be easier to build and use.

Have you got ideas about other communication devices that would fit my needs?

Also, If you want further information about the project itself this is the link to the repository: EZTrain/STBS: The simple train blocking system. An easy to install train blocking system using Arduino. Compatible for MFX and DCC++ decoders. - STBS - Gitea: Git with a cup of tea

Thanks in advance!

SnowCode

PS: I would also want to be able to send a message to the whole circuit in once in the future. A message like "shut down", "test mode" or "reset".

chopin2712:
The Arduino will be separated by a quite large distance, so the communication system needs to be reliable.

Maybe a CAN bus. It's a differential bus, unsensitive to EMI, very reliable. Distances up to hundreds of meters.

I don't think you can avoid the need for an ID if you're going to use a bus. Each Nano will need to send signals to its two neighbours and it will need to indicate which they are. You can still keep the code identical, but you would need to be able to put the IDs in EEPROM before you put the Nano into service.

wildbill:
I don't think you can avoid the need for an ID if you're going to use a bus. Each Nano will need to send signals to its two neighbours and it will need to indicate which they are. You can still keep the code identical, but you would need to be able to put the IDs in EEPROM before you put the Nano into service.

I don't understand how I can keep my code identical and having IDs. Can you explain?

chopin2712:
I don't understand how I can keep my code identical and having IDs. Can you explain?

Industry standard for many decades is to use a set of input pins with jumpers to identify each board. The number of jumpers needed depends on the number of boards you need in your project. The code will read the set of pins as it starts and know the identity to use in communications. All the code is identical.

Paul

Paul_KD7HB:
Industry standard for many decades is to use a set of input pins with jumpers to identify each board. The number of jumpers needed depends on the number of boards you need in your project. The code will read the set of pins as it starts and know the identity to use in communications. All the code is identical.

Paul

Thank you, have you got good resources about it? I will get into it, this is a good idea!

Each Nano needs to know its own ID so it can identify messages addressed to it and also the IDs of the previous and next Nanos.

If you store these IDs in EEPROM, the sketch that uses them will be the same on every Nano, it'll read the IDs when it starts and can then operate just communicating over the bus with its two siblings.

You can have a configuration program that you use to write the IDs to EEPROM before you put the main sketch onto each Nano that you commission. Alternatively, the main sketch itself can have a configuration mode where you provide the IDs over the serial port and it writes them to EEPROM.

wildbill:
Each Nano needs to know its own ID so it can identify messages addressed to it and also the IDs of the previous and next Nanos.

If you store these IDs in EEPROM, the sketch that uses them will be the same on every Nano, it'll read the IDs when it starts and can then operate just communicating over the bus with its two siblings.

You can have a configuration program that you use to write the IDs to EEPROM before you put the main sketch onto each Nano that you commission. Alternatively, the main sketch itself can have a configuration mode where you provide the IDs over the serial port and it writes them to EEPROM.

An elegant and useful solution Mr Bill, and clearly would allow you to install very many blocks (I assume a block is a block or length of train track).
An alternative, but less scaleable solution, could be to reserve several digital inputs, an external 'identification' circuit made up of links to Vcc or 0V being added to otherwise identical Arduino Nanos. Thus by reserving 4 dig-in pins a total of 16 blocks could be individually addressed, extra dig-ins being utilised if more blocks are needed.
The (pseudo) code in SETUP would be something like:

Read input pins 1, 2, 3, 4
Compare with 0000; if input = 0000 then assign address 0 to this Nano;
Compare with 0001; if input = 0001 then assign address 1 to this Nano;
Compare with 0010; if input = 0010 then assign address 2 to this Nano;
Compare with 0011; if input = 0011 then assign address 3 to this Nano;

...and etc.

Forgive my poor command of the code, we're all learning!
In this way you would hardware code a unique i.d. into otherwise identical block controllers.

I like the idea of preconfiguring each Nano with an ID in EEPROM.
Then just put a simple pin read in setup(), if it's low hang out and wait for a serial message and write data to EEPROM, if it's high, run the sketch.

Thank you so much!

I will try this, have you got systems with jumpers for Arduino?

Like this? For an Uno:

Or this, for a Nano:
http://www.gravitech.us/
Search Nano, look on 3nd page.
I believe they are trustworthy, I have ordered from them before.
I can't open the picture, Win7 is complaining about:
"www.gravitech.us uses an unsupported protocol.

ERR_SSL_VERSION_OR_CIPHER_MISMATCH"

While agree with the EEPROM or linked address ideas, there is another method that requires zero configuration...

A daisy-chained serial buss, where each device learns its own numerical position on the bus at power up, and only responds to messages for its own ‘position’ after that. (a bit like DHCP without the MAC address, but using the sequence of waking up to acquire an identity.)

The controller identifies each node by ‘pinging.’ the buss repeatedly until it gets no further replies.
Of course, that requires the main node to ‘know’ the order of devices on the wire, and their role in the overall system.

There are more advanced examples of this method which are used in high density control & monitoring systems.

OK, an Oh so common blunder in posting questions here; you have failed to adequately explain your requirement. :roll_eyes:

chopin2712:
STBS works with 1 Arduino Nano per block, I want to make them communicate with the next Arduino and the precedent one.

You have failed in that sentence to make clear what "communicate" means.

chopin2712:
There will be 2 major functions:

  1. When a train is going out the block, power off the current block and send a "start" signal to the precedent one
  2. When I receive a "start" signal from the next block, power up the current block.

So in fact, as per a standard sort of "block" signalling, this communication is in fact one way only. Information is passed back from each block to the previous one. Unless there is a need for acknowledgements because of unreliable communication, there is no requirement for communication in the other direction.

In fact, you are only communicating an occupancy status, so you only require a binary status, not a "message". Whichever it is, you simply need to send an output from one module to an input on the one preceding it. If it is a status, nothing else need be done; if you require a message then you need to use the serial output and input. Each device has one of each, so that is not a problem. Use Pro Minis rather than Nanos and the serial connections are free; you attach a USB adapter when you need to program them.

There is no requirement for separate identification - the module is defined purely by its position in the chain.

chopin2712:
The Arduino will be separated by a quite large distance, so the communication system needs to be reliable.

Again, a fail to explain the context. If it is merely a metre or two, the 5 V logic levels will do. Your reference to DCC suggests it is an indoor arrangement. If it was an outdoor layout on a larger scale, you would want to use RS422 modules to carry the link.

chopin2712:
PS: I would also want to be able to send a message to the whole circuit in once in the future. A message like "shut down", "test mode" or "reset".

If you are using serial message communications, this is no problem; a supervisory message inserted at any node can simply be relayed along the chain until it is received back at the originator.

The chain can branch as necessary, same as any block signalling system.

chopin2712:
There will be 2 major functions:

  1. When a train is going out the block, power off the current block and send a "start" signal to the precedent one
  2. When I receive a "start" signal from the next block, power up the current block.

So blocks only have to communicate with the one before, and th one after? And just signalling a train present or no train present?

Then you don't need any fancy bus. Just a high/low signal. Connect pins and GND together; enable the pull-up resistor on the receiving end, and done.

If you have a problem with noise: add a stronger external pull-up (10k, 4k7, maybe even down to 330Ω), with the last number you basically turn it into a 15/0 mA signal. Gonna take a LOT of noise to turn mess with that signal, and that again can be filtered in software (debounce).

Hi,
Great project... :slight_smile: :slight_smile:

I am developing a similar system for my brothers T-Track display.
Still in its infancy, but I am using CANBUS with NANO in each module.
A DIP switch on each Nano will give each module its own address.
This means when a layout is assembled, you can make sure addresses don't clash.

CANBUS is ideal for this as the anti-collision protocol is taken care of in the CANBUS shield.
google Arduino Canbus

You can customise the packet you send/receive.

In my setup, I will have two end modules and will assign them address 00 and FF, anything between them can be either configured numerically from 01 to FE or in any order.
If any order, I will get the loco to go from 00 to FF module and do a cal run to remember the module order.
I have made a prototype module PCB for basic signal and boom gates control, but may implement a port expander.

Tom.. :slight_smile:

Hey Tom,
that sounds really cool can you post some of it here as you develop it ?

TomGeorge:
Hi,
Great project... :slight_smile: :slight_smile:

I am developing a similar system for my brothers T-Track display.
Still in its infancy, but I am using CANBUS with NANO in each module.
A DIP switch on each Nano will give each module its own address.
This means when a layout is assembled, you can make sure addresses don't clash.

CANBUS is ideal for this as the anti-collision protocol is taken care of in the CANBUS shield.
google Arduino Canbus

You can customise the packet you send/receive.

In my setup, I will have two end modules and will assign them address 00 and FF, anything between them can be either configured numerically from 01 to FE or in any order.
If any order, I will get the loco to go from 00 to FF module and do a cal run to remember the module order.
I have made a prototype module PCB for basic signal and boom gates control, but may implement a port expander.

Tom.. :slight_smile:

Thank you!

Sorry for the late answer I didn't check the forum for a while.

I don't really understand how you define the addresses, do you need to do it manually or is it automatic?

During this period of time when I was away I tested something with 2 boards, it is really basic, but I am not sure this will work on longer distances.
This is just connecting 2 Arduino pins, one is OUTPUT and the other is INPUT.

For instance:
CIRCUIT: A wire connect the pin 7 of the first Arduino to the pin 8 of the second Arduino.

  1. First, when the train is detected the Arduino will send a HIGH signal to the precedent block (pin 7).
  2. Then, when the precedent block receive a signal on pin 8 it put the traffic lights to green and unlock the trains.
  3. Finally, when the train is not in front of the detector, the first Arduino set the pin 7 to LOW.

What do you think? Is this circuit will be able to connect 2 Arduino by meters or is it unstable on long range?

Cordially.

SnowCode

Paul__B:
OK, an Oh so common blunder in posting questions here; you have failed to adequately explain your requirement. :roll_eyes:
You have failed in that sentence to make clear what "communicate" means.
So in fact, as per a standard sort of "block" signalling, this communication is in fact one way only. Information is passed back from each block to the previous one. Unless there is a need for acknowledgements because of unreliable communication, there is no requirement for communication in the other direction.

In fact, you are only communicating an occupancy status, so you only require a binary status, not a "message". Whichever it is, you simply need to send an output from one module to an input on the one preceding it. If it is a status, nothing else need be done; if you require a message then you need to use the serial output and input. Each device has one of each, so that is not a problem. Use Pro Minis rather than Nanos and the serial connections are free; you attach a USB adapter when you need to program them.

There is no requirement for separate identification - the module is defined purely by its position in the chain.
Again, a fail to explain the context. If it is merely a metre or two, the 5 V logic levels will do. Your reference to DCC suggests it is an indoor arrangement. If it was an outdoor layout on a larger scale, you would want to use RS422 modules to carry the link.
If you are using serial message communications, this is no problem; a supervisory message inserted at any node can simply be relayed along the chain until it is received back at the originator.

The chain can branch as necessary, same as any block signalling system.

Oh, sorry.

  1. By communicate I understand sending start signal to the precedent Arduino, and if possible being able to send a signal all the Arduino connected to the network.
  2. In deed there is no need to send a signal to the next block, only to the precedent. There is no need to send a message, only HIGH or LOW.
  3. For the distance, this will be like maximum 15 meters between 2 Arduino. This is all indoors.
  4. Yes, I thought about that.

This is the easiest thing to do, but I don't know if this will work properly over 15 meters:

This is just connecting 2 Arduino pins, one is OUTPUT and the other is INPUT.

For instance:
CIRCUIT: A wire connect the pin 7 of the first Arduino to the pin 8 of the second Arduino.

  1. First, when the train is detected the Arduino will send a HIGH signal to the precedent block (pin 7).
  2. Then, when the precedent block receive a signal on pin 8 it put the traffic lights to green and unlock the trains.
  3. Finally, when the train is not in front of the detector, the first Arduino set the pin 7 to LOW.

chopin2712:
There will be 2 major functions:

  1. When a train is going out the block, power off the current block and send a "start" signal to the precedent one
  2. When I receive a "start" signal from the next block, power up the current block.

I think we need to go back to basics.

I can't make sense of that and I suspect it is a conceptual snippet from a larger concept of train control. A clear description of YOUR block control process would be a good start.

For example,

  • what is purpose of powering off a block?
  • How does a block know that a train is leaving?
  • If a train is in the process of leaving BlockA won't BlocKB need to be already powered up?

It seems to me most likely that the communication system will need to be either more complex or simpler than what you seem to envisage.

I'm building a system for one of the layouts in my model railway club. It will have several slave boards with Atmega 328s to control servos for turnouts and uncouplers and LEDs for signals. Each slave will have identical hardware and software with a few pairs of pins to which jumpers can be fitted to indicate the ID of the board. The "knowledge" about which turnout is controlled by which pin on which slave board will all be in a simple .h file that is part of the program for the master.

Think of the jumpers (or a DIP switch) as setting the bits in a byte. The program reads the values of the pins at startup - HIGH if there is no jumper and LOW if there is a jumper. It then assembles the values into a byte and that defines its ID. In my project the values will range from 0 to 7 (3 pairs of pins) and I use them to associate IDs of 'A' to 'G' with the boards.

...R

The Arduino Nano comes with its own, internal serial number. Perhaps, if possible, the internal serial number can be used as an ID? Time to use that internet search engine.