Too many opinions, roads to Ardu success?

After my first Ardu forum experience (wrong posting) I took a break and studied Purdum, Davis, Margolis and other publications.
Lots of examples, lots of solutions.
Still uncertain what level of sophistication applies to use for:
My model railroad vintage analog shift register turnout and signal control transition to Arduino Uno R3 seems to be of little or no interest.
I do not want to pester those happy folks.
As an old tinkerer SPS, HMI, graphic industry retiree in electronics and mechanics since 1970, we tried the time, cost efficient avenues first.

What forum category would be the correct one to post?

20 Arduino Uno R3 controls 8 IR sensors 5v NO, 0V NC detect inputs, 4 turnout 5v control coil relay outputs, 4 signal LED outputs.
That is for a 36”, 1.50 m track section, with 2 turnouts for the bypass track.

Arduino Mega for multiple yard turnouts and signals.

All communicate to the central operator console Arduino Mega to display switch , signal status LED in track layout.
Operator toggle switch signals to Arduino Mega communicate back to the track block Arduino Unos operating the outputs.

External I2C 24ls256 update turnout, signal LED status and reads back at first power up to show last status.

I Am fully aware that different yards will need their own operator console Ardu Mega.

I did not find multi Ardu R3, Mega layouts of this kind.

Many thanks for any replies.

It's a bit of a complicated way to go about it. So you probably won't find something exactly like that.

I would keep the processing on one unit and let it control everything. Trying to tie together multiple processors all doing part of the job can add unnecessary complication. A single mega should be able to keep up with trains coming and going. You can use SPI (or if the runs are short enough I2C) expanders to put the pins where you need them instead of adding a bunch of extra Arduinos.

But that's just how I would tackle it. If you want to keep with this route, start with the classic Serial Input Basics thread and learn how to make Arduinos talk to one another.

As @Delta_G indicates, you want to keep the tasks small if you can. I buy Arduino Nano Everys by the six pack and for more complicated builds, have each one handle a specific task and pass along control as needed to a central MCU, Mega being a good choice.

One key is to keep the logic levels consistent. Don't involve level shifting, it just makes things harder.

Same goes for buttons. pinMode (myButton, INPUT_PULLUP); saves time, parts and headaches.

Also as @Delta_G indicates, the tutorial by @Robin2 is a great way to go for multi serial comms. I just send single chars as in example #1 and read them in on a central Mega. It really does make complex systems come alive since one MCU is essentially just directing traffic. And that doesn't even touch using interrupts or simple digitalRead(myArduinoTurnpike); to look to pass through routines from Nano Every B say, through Mega A to Nano Every C!

Lastly, don't forget that when you need to lock in certain routines on an Arduino, you're probably looking to build a finite state machine. So you have at least one variable (serial input, or maybe an ultrasonic sensor, maybe a five-way guitar pick up switch) that dictates the state that drives the machine. Sorry if this is old hat to you, but anyways, here's a couple quick sketches that illustrate the point that may be useful to you. These are based on a solution I offered up to a fellow who wanted to control different devices in his pet lizard's vivarium. Did you know that a lizard aquarium is called a vivarium? Neither did I, but here's the sketches:
sketch one - use alone with the Serial monitor to type stuff in or use in conjuction with sketch two:

/* May also be used with companion sketch "charDriverUltrasonicSender"
   or just used as is by typing in the chars to Serial Monitor  */

char mode;
const int light = 3;
const int pump = 4;
const int fan = 5;

void setup() {
  Serial.begin(115200);
  pinMode(light, OUTPUT);
  pinMode(pump, OUTPUT);
  pinMode(fan, OUTPUT);
  Serial.println(F("charDrivenThreeDeviceStateMachine"));
  Serial.println();
  Serial.println(F("Type 0-7 to change functions"));
  Serial.println();
  mode = '0'; // start state variable at mode 0
  modeZero(); // let us know and init devices to off
}

void loop() {
  if (Serial.available() > 0) {
    mode = Serial.read(); // could be any switch or sensor driving this
    switch (mode) {
      case '0':
        modeZero();
        break;
      case '1':
        modeOne();
        break;
      case '2':
        modeTwo();
        break;
      case '3':
        modeThree();
        break;
      case '4':
        modeFour();
        break;
      case '5':
        modeFive();
        break;
      case '6':
        modeSix();
        break;
      case '7':
        modeSeven();
        break;
      default: // optional, but leave in even if you don't use, some say
        break;
    }
  }
}

void modeZero() {
  Serial.println(F("mode 0: light off, pump off, fan off"));
  Serial.println("");
  allOff();
}
void modeOne() {
  Serial.println(F("mode 1: light on, pump on, fan on"));
  Serial.println("");
  allOn();
}
void modeTwo() {
  Serial.println(F("mode 2: light on, pump on, fan off"));
  Serial.println("");
  lightAndPump();
}
void modeThree() {
  Serial.println(F("mode 3: light off, pump on, fan on"));
  Serial.println("");
  fanAndPump();
}
void modeFour() {
  Serial.println(F("mode 4: light on, pump off, fan on"));
  Serial.println("");
  lightAndFan();
}
void modeFive() {
  Serial.println(F("mode 5: light on, pump off, fan off"));
  Serial.println("");
  justLight();
}
void modeSix() {
  Serial.println(F("mode 6: light off, pump on, fan off"));
  Serial.println("");
  justPump();
}
void modeSeven() {
  Serial.println(F("mode 7: light off, pump off, fan on"));
  Serial.println("");
  justFan();
}
void allOff() {
  digitalWrite(light, LOW);
  digitalWrite(pump, LOW);
  digitalWrite(fan, LOW);
}
void allOn() {
  digitalWrite(light, HIGH);
  digitalWrite(pump, HIGH);
  digitalWrite(fan, HIGH);
}
void lightAndPump() {
  digitalWrite(light, HIGH);
  digitalWrite(pump, HIGH);
  digitalWrite(fan, LOW);
}
void fanAndPump() {
  digitalWrite(light, LOW);
  digitalWrite(pump, HIGH);
  digitalWrite(fan, HIGH);
}
void lightAndFan() {
  digitalWrite(light, HIGH);
  digitalWrite(pump, LOW);
  digitalWrite(fan, HIGH);
}
void justLight() {
  digitalWrite(light, HIGH);
  digitalWrite(pump, LOW);
  digitalWrite(fan, LOW);
}
void justPump() {
  digitalWrite(light, LOW);
  digitalWrite(pump, HIGH);
  digitalWrite(fan, LOW);
}
void justFan() {
  digitalWrite(light, LOW);
  digitalWrite(pump, LOW);
  digitalWrite(fan, HIGH);
}

sketch two:

/*
  Companion sketch: charDrivenThreeDeviceStateMachine
  Read and act on 3 ultrasonic sensors, based on Tim Eckel's
  example NewPing library sketch that pings 3 sensors 20 times a second.
  Receiving sketch is set up to handle 8 states (0-7) to act on three devices
  (a light, a pump and a fan if so configured in such a circuit)
*/

#include <NewPing.h>

#define SONAR_NUM 3       // Number of sensors.
#define MAX_DISTANCE 200  // Maximum distance (in cm) to ping.

NewPing sonar[SONAR_NUM] = {
  // Sensor object array.
  NewPing(4, 5, MAX_DISTANCE),  // sensor 0 trigger pin, echo pin, and max distance.
  NewPing(6, 7, MAX_DISTANCE),  // sensor 1 trigger pin, echo pin, and max distance.
  NewPing(8, 9, MAX_DISTANCE)   // sensor 2 trigger pin, echo pin, and max distance.
};
int mode = -1;
int lastMode = -2;

void setup() {
  Serial.begin(115200);  // Open serial monitor at 115200 baud to see ping results.
  Serial.println(F("charDriverUltrasonicSender"));
  Serial.println();
}

void loop() {
  /* uncomment this function to just read and set up sensors */
  // justReadSensors();
  /* comment out everything else in loop() if just using above function */
  checkSensorPings();
  switch (mode) {
    case 0:
      allOff();
      break;
    case 1:
      allOn();
      break;
    case 2:
      lightAndPump();
      break;
    case 3:
      fanAndPump();
      break;
    case 4:
      lightAndFan();
      break;
    case 5:
      justLight();
      break;
    case 6:
      justPump();
      break;
    case 7:
      justFan();
      break;
    default:
      // do nothing
      break;
  }
  lastMode = mode;
}

void checkSensorPings() {
  if (sonar[0].ping_cm() == 0 && sonar[1].ping_cm() == 0 && sonar[2].ping_cm() == 0) {
    mode = 0;
  } else if ((sonar[0].ping_cm() > 50 && sonar[0].ping_cm() < 100) && (sonar[1].ping_cm() > 50 && sonar[1].ping_cm() < 100) && (sonar[2].ping_cm() > 50 && sonar[2].ping_cm() < 100)) {
    mode = 1;
  } else if ((sonar[0].ping_cm() > 50 && sonar[0].ping_cm() < 100) && (sonar[1].ping_cm() > 50 && sonar[1].ping_cm() < 100) && (sonar[2].ping_cm() == 0)) {
    mode = 2;
  } else if ((sonar[0].ping_cm() == 0) && (sonar[1].ping_cm() > 50 && sonar[1].ping_cm() < 100) && (sonar[2].ping_cm() > 50 && sonar[2].ping_cm() < 100)) {
    mode = 3;
  } else if ((sonar[0].ping_cm() > 50 && sonar[0].ping_cm() < 100) && (sonar[1].ping_cm() == 0) && (sonar[2].ping_cm() > 50 && sonar[2].ping_cm() < 100)) {
    mode = 4;
  } else if ((sonar[0].ping_cm() > 5 && sonar[0].ping_cm() < 15) && (sonar[1].ping_cm() == 0) && (sonar[2].ping_cm() == 0)) {
    mode = 5;
  } else if ((sonar[0].ping_cm() == 0) && (sonar[1].ping_cm() > 50 && sonar[1].ping_cm() < 100) && (sonar[2].ping_cm() == 0)) {
    mode = 6;
  } else if ((sonar[0].ping_cm() == 0) && (sonar[1].ping_cm() == 0) && (sonar[2].ping_cm() > 50 && sonar[2].ping_cm() < 100)) {
    mode = 7;
  }
}

void allOff() {
  if (lastMode != mode) {
    Serial.print('0');  // allOff(); to companion sketch
  }
}
void allOn() {
  if (lastMode != mode) {
    Serial.print('1');  // allOn(); to companion sketch
  }
}
void lightAndPump() {
  if (lastMode != mode) {
    Serial.print('2');  // lightAndPump(); to companion sketch
  }
}
void fanAndPump() {
  if (lastMode != mode) {
    Serial.print('3');  // fanAndPump(); to companion sketch
  }
}
void lightAndFan() {
  if (lastMode != mode) {
    Serial.print('4');  // lightAndFan(); to companion sketch
  }
}
void justLight() {
  if (lastMode != mode) {
    Serial.print('5');  // justLight(); to companion sketch
  }
}
void justPump() {
  if (lastMode != mode) {
    Serial.print('6');  // justPump(); to companion sketch
  }
}
void justFan() {
  if (lastMode != mode) {
    Serial.print('7');  // justFan(); to companion sketch
  }
}

void justReadSensors() {
  for (uint8_t i = 0; i < SONAR_NUM; i++) {  // Loop through each sensor and display results.
    delay(50);                               // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
    Serial.print(i);
    Serial.print("=");
    Serial.print(sonar[i].ping_cm());
    Serial.print("cm ");
    Serial.println();
  }
}

1 Like

8/10/24

Some more details and revisions:

Great advice.
I may have not explaint enough my large 12m x 20m main line layout.
This 2 track main DC analog line has 1.50 - 3m long freight trains and shorter passenger ones. Every 50 cm is a IR Infrared sensor installed. High 5V no train, 0V train present.
Like with my old shift register photocell detection switching timed relay one, six IR sensors to each dual track block Arduino Uno R3 controlled as a standalone.

Four Outputs for two signals Red/Green . Red = next 1.50 m is occupied, Green= next 1.50 track meter is clear.
Automatic track block monitoring, so several trains on the main-lines do not collide.

If the central console operator of the four yard areas wants to route a main line train into the yard, his yard section Arduino Mega operates the yard switches and turnouts.

He also sees at his track console layout train locations reported back by Arduino serial, or Ethernet (to be tested if even needed since my serial wire length is under 15 m).

Yard management based on Ross and others ( Moba, Stummi examples).
The main line runs through as explained above.

The yard is not automated. All kids, like in my old flip-flop design, want to have fun.

Toggle switches, LEDs, yard derailments, wrecker crane use, you name it!

Arduino Mosfet DC control or PWM if those vintage loko motors can handle it from the 5V PC old power supplies.

Old PC 3.5V, 5V 12V DC power bus.

My Swiss friend Roland has a visual display tested vintage 80s HP 1k system in use.

The German company I worked for over two decades, used a Rs232 and later 422 network Motorola 6800 CPU external controller.

To unite several printing unit status to the central operator console for remote operation, beside the PB press unit panel one, the network had a hub / router. All custom build OEM HW.

The HP has RS 232 interface ports.

Thanks again for any advise.

1 Like

Two replies.
First post contains one question:

To which I say, it depends what question you haven't asked yet.
Your second post seems to be laying out the case for communications, but you never really ask a question. So I will. Are you asking us "What communication strategy/hardware would be suitable?" If that is the question, more info is needed.

  • what do you envisage displaying on the computer?
  • what do you envisage controlling from the computer?
  • do you foresee automating some or all of the trains?
1 Like

You have a video of this layout? Would love to just see it running, all the work that went into such an epic train set.

Agreed. Lots of description of a railroad layout that assumes Arduino helpers have any idea what all this stuff does. I'm not a model railroader; I had to look up what a turnout is. I found the general description and a specific use case of a crossing loop.

None of this helps me visualize what OP is trying to accomplish or if this is a show-and tell (which is great, too).

  • Pictures are worth a thousand words.

  • Schematics are worth 10,000 words.

  • Code you post using code tags is worth its weight in gold.

  • If you have questions, please post them directly and to the point. Something like:

    "How would I connect a Pololu 38KHz IR proximity module to an Arduino Uno R3 and
    have it send a status message to an Arduino Mega over Serial when a train passes
    by it to both print the message on the Serial Monitor and also inform the Mega to
    switch a servo-powered turnout 45 degrees to allow another train to pass?

    Here is my code:

 /*  Uno R3 IR proximity module code to Mega central controller */

// your libraries
// your definitions

void setup(){
// your setup code
}

void loop(){
// your loop code
}
   /*  Mega central train controller code to Arduino Uno */

// your libraries
// your definitions

void setup(){
// your setup code
}

void loop(){
// your loop code
}

And here's a video to illustrate what I am trying to simulate: "

1 Like

By the way, I'm a model railroader with a basement full of railroad. Although I'm in DCC, many of the problems I've faced, and which I suspect you're getting around to asking about, are dependent on strategy, performance requirements, and sometimes just plain "I'd druther do this than that". But I can't help you much until I know what it is you are asking. Nuts-and-bolts about a solution you've thought up, is a lot different from answering "Should I do A, B, or C?"
FWIW, this might be a data point.

  • I have two 35 meter loops, each has/will have block detection, signalling, and mainline turnout control from a supervisory computer. Remote controlled turnouts on the visible layout - about 20; detection blocks - around 40(includes each turnout); about 100 LEDs across about 45 masts/dwarfs for the signaling
  • The above is controlled/monitored by 9 Nano nodes, and all data is passed to JMRI via an RS485 network implementing the CMRI protocol
  • I also have a 200 meter main line which is unsignalled, undetected - what we call "dark" territory - which I'm presently developing localized turnout control for. This mainline will have 16(or so) train order masts at 8 locations for controlling the low-volume traffic; these train order locations will also be nodes on the CMRI network.
  • The above is supported by 2 staging decks in a separate room, each has 12 tracks for staging trains and a 4-track yard for building/dismantling trains
  • Three yards exist/will exist for that main line - one at each end, and one in the middle.
    (These will likely be a mix of staging yards and actual scenic'd yards, depending upon how it all works out.) The dark territory turnouts are/will be controlled by servos with local panels(Nano based) as needed, including the three yards.

That's where I'm at these days. What are you really trying to do, @jdh-avl77?

Any chance you have a video? I like seeing folks' epic layouts, if you have a video you don't mind sharing.

1 Like

Bingo.

I see lots of words, but drawing up a schematic or some kind of model/representation of (1) the entire system and (2) the key building blocks will make it lots easier to help explore what the options are.

For instance:

This should be fairly easy to describe in some kind of graphical model. I understand it's also a module/building block that is repeated a number of times. So there's the bigger picture/system that this is part of, which can also be modeled in terms of its (a) building blocks and (b) the interfaces between these blocks.

Adding to the static model, think about flowcharts or other types of process models that describe the behavior of the system (i.e. the entire system and its individual building blocks).

@jdh-avl77 you'll find that if you adopt this structured way of modeling your system, it'll both be easier to engage people in helping you out, and you'll find that a number of design problems will 'solve itself' because of the structured approach towards modeling it.

I'd add to this that I'd be cautious to hang on too much to legacy solutions that others may still use. How it was done in the 6800 days is not necessarily how it's most easily approached today, although some concepts are virtually timeless. I'd also defer specific component choices (e.g. Uno R3) to a later stage once you've clearly formulated functional requirements. In general, try to separate functional design and actual implementation. They'll get mixed up sooner or later anyway; the further you can push back that moment, the better off you are, in general.

I'll leave it to the railroaders among us to comment on specific solutions that are already available for model railroads. All I know is that it's a big ecosystem with a thriving DIY & microcontroller subcommunity, as well as a number of firms and ventures that have devised all manner of solutions and control systems that may (or may not) be suitable. One of the key questions in this regard is whether it's valuable to reinvent the wheel - and if so, which wheels exactly, and for which reasons.

Good luck and have fun!

PS: re: "Too many opinions" - the number of opinions you'll have to contend with will always outstrip the number of people you consult. Try to get used to it. In the end, only one set of opinions counts - yours.

1 Like

Exactly.

Thing is, while there's lots of overlap in this community, I for one need the requirements spelled out because I don't know jack about model railroading. I'm relying on the overlap to offer solutions, such as the coding piece after the circuit is already working. If I know the voltages involved and the goal of the code, controlling them with Arduino actually becomes pretty easy to me (and so many betters than I here) and I don't mind dropping a code (since I lost interest in crossword puzzles).

2 Likes

No idea if I reply to all kind suggestions or not the correct FORUM RULE WAY.

Many thanks to everybody.

As a 1970 Radio TV apprentice we had many manufacturer brands. All were following set schematic , transmission and other principles. Later I worked with residential, commercial and industrial SW, HW, applications. Wherever CPUs appeared, I was exploring.

Since 1986 my focus has been PLC, HMI, Motor controls, IT NW, IPC in the graphic industry.

All very structured, trusted and as Arduino keeps evolving.

The 1 step forward, 3 steps backward upgrade experience is no surprise.

Since 1983 HP1k computer RTE OS, C and Fortran have been my companions. Even in retirement, we are a global HP boomer network.

Call us sentimental, HP1k can handle a multitude of real time tasks. Plenty of RS 232 ports, serial, parallel and NW options to be the master HMI controller of the Ardu Minion world. (Joking)

Arduinos are Santa HP little helpers since the bulky Motorola 6800 I/O industrial controller won’t fit on a model RR.

Yes there are plenty of ready made DCC and PC solutions and products to buy.

80% planning, 20% execution is still my credo.

Yes flow charts after notepad and pencil use.

Here my bench HW:

Ardu Uno R3 (2019) RR 1.50 m track section control

RR 1.50 m track block all 50 cm IR sensors (as pullup 5V HIGH, detect 0V LOW)

SIgnal red, green LED outputs 5V

A0 current sensor input.

Mosfet output PWM to regulate train DC power. (NO DCC engines)

1 Output to right track block in charge Arduino

1 Output to left track block in charge Arduino

1 Input from left track block in charge Arduino

1 Input from right track block in charge Arduino

Ardu Uno R3 (2019) RR turnout control for main line train and bypass track IR function:

TU1 straight output

TU1 turnLeft output

TU2 straight output

TU2 turn right output

RR 1.50 m bypass track block all 50 cm IR sensors (as pullup 5V HIGH, detect 0V LOW)

SIgnal red, green LED outputs 5V

A0 current sensor input.

Mosfet output PWM to regulate train DC power. (NO DCC engines)

So with these modules you can build like Legos whatever you want.

Great, looking forward to what you come up with - have fun with your project!

Thank you your input. My Swiss friend has not given me any details at this time how he controlled his Marklin layout with the HP HMI at this moment.
As I wrote before my 555 timer / flip flop chips stored the momentary toggle switch left / right turnout action on an old fashion operator console.

I saw in the forum Arduino MEGA console controls. Again it is a browsing phase at the moment to have more inside view on the existing train layout controls in the Ardu and other train Forums.