Skip to main content

I want to use an Arduino to send TMCC commands to my various TMCC engines, just like I can with my TMCC handheld controller.  Emulate my TMCC controller with an Arduino.  How do I get the TMCC RF parts to do this?  Cannibalize an existing TMCC controller?  Anyone tried to do this?

Original Post

Replies sorted oldest to newest

Both these ideas can be realized by connecting an Arduino to the DB9 serial port of a Base-1, Base-1L or Legacy Base. The TMCC and Legacy command specification is freely available. Note that to work with the full Legacy command set, an LCS SRE2 module is required. The SER2 is compatible with the Legacy and Base-1L, but not the original Trainmaster/Base-1 command base.

get the spec here: http://www.lionel.com/lcs/LCSP...er/styled/index.html

I thought that the DB9 port only allowed the TMCC base unit to talk to the TMCC controllers (ASC, BPC, etc.) but not to the engines via RF.  I want to be able to communicate with the engines via the Arduino.  Maybe I need to use the third wire that the Action Recorder uses.  Can you send me a link to a TMCC spec that might explain all this?

Hi Don - it's pretty easy to read and write TMCC or Legacy commands to and from the command base serial ports.  As Rudy mentioned, a SER2 is the most convenient way to go. Do keep in mind that the earth ground (ground for the command base) is supposed to be isolated from layout common (outside rail).

If you take a look at this link, you can find some of my Arduino projects. "Train Control" is a very complex system that automates train control, controls switches, signals, and accessories, and communicates with JMRI running on a computer.  But you will find examples of how to send TMCC, Legacy, and DCS commands over the Arduino serial port.

"Uncoupler Monitor" is a much simpler program that listens to the serial stream from the command base, and activates a relay module in response to commands directed to ACC 1-8.  Essentially a cheap and customizable version of the ASC.

For layout control I like the Arduino Mega, because it has four hardware serial ports. For accessories like the uncoupler monitor I like the Arduino Pro Mini, which is very small and costs less than $10. I am fiddling with transmitting commands from the Legacy base to HC-12 radio modules, with Arduino Minis in rolling stock picking up the radio commands (like a cheap and customizable Mini Commander).

 

I've been working on an Arduino-based project that controls my trains via Legacy, very much as Professor Chaos has done.  As Rudy says, you'll need an SER2 but the programming is pretty easy and Prof Chaos has been kind enough to share what he has done to help you get started. 

To send Legacy commands, you'll need the Legacy spec which requires (or used to require?) becoming an LCS Partner -- which is simple enough but you'll need to sign an NDA.

Here are the videos that Professor Chaos made that really inspired me on this project: https://www.youtube.com/channe...1UcTotGFTEih-nNVzL_w

I'm using 7 Arduino Megas, and my software monitors the location of all trains, throws turnouts, reserves and releases sections of track, blows the whistle, makes announcements, control accessories, and slowly accelerates and decelerates each train as it departs and arrives.  I've provided more detail in other posts, so if you're interested you might search my older posts.

Attachments

Images (6)
  • IMG_2118: Relays connect to track occupancy sensors
  • IMG_2239: Relays throw turnouts.  The "Train Control" Arduino connects via serial cable to the Legacy base.
  • IMG_2241
  • IMG_6405: Four of the seven Arduino Megas
  • IMG_6409: Shift registers used on control panel buttons and LEDs
  • IMG_7846: Control panel LEDs show what the Arduinos see: turnout position, train locations, and block occupancy.

You do not need to be a LCS Partner to get the Legacy Spec.  The TMCC and Legacy Specs are available in one document on Lionel's LCS page.  Now to get the the specs for all of the LCS modules and the format of the commands on the LCS bus, you will need to be an LCS Partner.  But if you just want to send Legacy commands you do not need to know anything about LCS, but you will need a SER2.  The SER2 is the only thing that will accept Legacy formated commands.  If you want to send them over wifi and use the LCS Wi-Fi module, then you will need to become an LCS Partner, like myself. 

If you are only going to use TMCC commands and not Legacy, then you don't even need a SER2.  You can connect directly to the Base-1's DB9 serial port.  In fact, I don't think it would work if you went through a SER2.  If you did I don't think the Base-1 would be able to recognize the commands.  As far as I know the Base-1 can only recognize native TMCC commands, and that would not be what it would be receiving if you went through a SER2.  I don't think any LCS module would work with the Base-1.  Rudy can confirn that.

If you have a hard copy of the TMCC manual,  then you have everything you need.  If you prefer an online copy you can search for it on Lionel's site under "Support".  I don't think the manual has ever changed though.

Harvy posted:

If you are only going to use TMCC commands and not Legacy, then you don't even need a SER2.  You can connect directly to the Base-1's DB9 serial port.  In fact, I don't think it would work if you went through a SER2.  If you did I don't think the Base-1 would be able to recognize the commands.  As far as I know the Base-1 can only recognize native TMCC commands, and that would not be what it would be receiving if you went through a SER2..  I don't think any LCS module would work with the Base-1.  Rudy can confirn that.

Correct, the original Base1 aka Trainmaster Command System is not compatible with and of the Layout Control System/LCS modules. Base1L and Base2 aka 990 Legacy Control System will both work with all LCS modules.

Based on the original poster's needs, no SER2 required.

Don Furgerson posted:

Thanks Harvy for the link to the TMCC Manual.  It has the general TMCC info that I already know.  Now I need to know the protocol for talking from the Arduino to the DB9 port on the TMCC Base Unit.  Where can I get that additional level of detail?

All of the information is in the attachment starting on page 36.  Let me know if you need help deciphering  it.

Don, the documentation for the protocol is here.

If you look in my Train Control program under the _interface tab, you will see routines for transmitting TMCC and the various kinds of Legacy commands.

I find it useful to have all the routines deposit commands in a circular buffer; another routine called from loop() sends commands out the serial port if at least 30 milliseconds have elapsed since the last command sent.

After looking at a number of Arduino tutorials last night I think I want an Arduino Mega 2560 with an RFID shield.  Our train club has a 12-block O-Gauge main line controlled with one TMCC base unit.  I want to run 4 trains on that loop with automatic speed reductions to avoid rear end collisions.  I've automated our 16-block (non DCC) HO main loop that way with current sensors and slowdown resistors, and have implemented that strategy on 3 of our O-Gauge block pairs, with limited success.  Works fine for engines running in conventional mode but for TMCC not so much.  The TMCC engine boards don't like the reduced voltage technique.  They slow down some but if you get it too low they will stop and flash their headlight.  Then a engine reset is needed <AUX1><0>.  I want to put an RFID sensor between the tracks at the beginning of each block (we run only one direction) and have the Arduino read the TMCC engine number from an RFID chip fastened under each TMCC/Legacy engine (we have 18).  The engine number will be stored in an array of blocks for later reference.  So I will know the engine number of all running engines.  When a train enters block "n" the Arduino will check if there is an engine in block "n+1".  If there is (engine number in the array) it will issue a TMCC command thru the DB9 port to slow the engine in block "n", and so on.  How long do you think it will take me to do this, and has anyone else attempted this?

Don, this would be a fun and relatively simple project -- assuming you've overcome the initial challenge of learning how to use an Arduino.  Both the TMCC control and the RFID communication can be done via serial ports, so the interface is really easy.  Back in 2015, I played with the ID-20 RFID reader.  It has a good range, so you can put it in a trackside structure and still be able to register RFID tags that have been placed in motive power as it passes by.  There may be something even better out now, but I was very pleased with the ID-20 and I believe it's what Professor Chaos uses on his layout. 

 Note that this isn't, and probably shouldn't be a "shield", because it will be simpler to keep the RFID readers trackside and keep your Arduino in a more convenient location.  You'll just need a few wires for power and the serial signal.

The challenge I see is that you propose placing RFID readers at every block -- which presumably means a bunch of them.  This was my original idea as well, with my autonomously-controlled layout.  However I soon realized that if I can just determine where each train is initially (perhaps using a single RFID reader, or by typing in a starting position for each train), I can use any sort of occupancy detection (such as an isolated rail section) and "know" which train is tripping it -- by virtue of where it was before and which direction it was heading.  On my own layout, I "register" trains at the beginning of a session (using an A/N display and rotary encoder) -- defaulting to the last-known position so it's usually trivial -- and then let my software track them using about 50 isolated track sections from that point forward.  I wound up not needing the RFID reader at all.  Another approach would have been to register trains by driving each of them past the RFID reader -- but that would have been a lot more effort for the operator than the solution I ultimately chose.

If you decide you still want to use multiple RFID readers, you'll need to figure out how to get them all to talk to your Arduino.  Serial readers might be possible using Software Serial and a Mega, or you could try to find readers that used a different communication protocol such as I2C or SPI.

Please keep us posted on your progress!

Last edited by Randy P.

Thanks for your input Randy.  You are right, if I input the engine numbers of the running trains in the correct order then my software can track them.  I like that plan.  Any suggestions on how to format the data needed to be sent to the TMCC base unit?  Just make up some interesting arrays?  Be nice to find an Arduino sketch that talks to a TMCC base via the serial port!

I'm sorry to be such a neophyte but I need a bit of additional hand-holding.  I am using the web-based Arduino IDE and have tailored my own "Blink" program to run on my new Arduino Uno last night.  And I have the link to Dr. Chaos's public dropbox (Thanks!) but don't know how to use it.  Don't know yet what an ".ino" file is or how to open it.  I could use a bit more help to find the specific Arduino code I need to send TMCC commands to the TMCC Base Unit (i.e. electronically "Turn the Red Knob").  Thanks for the help you have given so far.  Thanks again for helping.

Don, I learned everything I know about Arduino by watching YouTube videos, reading tutorial websites, and reading *numerous* Arduino books -- repeatedly.  Then I learned how to send commands from an Arduino to a TMCC loco by studying Professor Chaos's code and writing very small proof-of-concept sketches.  Just getting an engine to toot its whistle was a huge milestone, and extremely satisfying.

I started by watching this series of tutorials (several times) by Jeremy Blum: https://www.youtube.com/watch?v=fCxzA9_kg6s  I strongly suggest you start there.  He also has a book which covers pretty much the same material.

From your last post, I can say this is likely going to take you a lot of time.  I personally spent hundreds of hours learning and experimenting, and I enjoyed every minute of it.  But if you're really only interested in getting to the goal, the reward is not going to be worth the effort.  To an experienced Arduino programmer, especially someone who is already up to speed with the TMCC and Legacy protocols etc., what you are trying to do is a relatively trivial project -- probably less than a hundred lines of code (versus thousands of lines of code for my Legacy control project, so far.)  But for a novice, it's a long haul and only makes sense if the joy is in the journey.

For beginner books, I recommend Programming Arduino by Simon Monk.  It covers basic programming concepts as well as how to interface with various devices such as LEDs, sensors, motors, etc.  There is a second "advanced" volume that contains more good information for beginners.

After you understand the basics, for more of a deep dive into Arduino programming (with little emphasis on electronics), I highly recommend Beginning C for Arduino by Jack Purdum.

Good luck, and keep us posted on your progress!

Thanks again for helping me with this project.  I'm a retired EE & SW engineer and wrote a lot of code back in the day, but mainly in assembler and FORTRAN (sigh).  Have done a fair amount of C but never migrated to C++.  But I found the C++ libraries for TMCC train control, just hope that I can figure out how to use them.  But I'm retired now and since my wife is gone I have plenty of time to run the train room at my retirement community, especially the electrical part.  So I'm fully dedicated to the journey as well as the goal.  Now can I toot the whistle on my N&W 611 engine from my Arduino in under 100 days?  Then I must interface to an RFID reader and a small LCD display to complete my project.  Let the fun begin! [Should I put the first curly brace on a separate line or on the same line with the function call? (-: ] 

Don: I did a recent post called Arduino Lesson: How to Create a Library that may be helpful to you. I have not used the Web based IDE so I'm not sure what that is like. I would encourage you to go ahead and download the IDE software if that is a possibility. It's very easy.

TMCC is not on my resume but I think the idea is to send data through a serial port to the base unit over RS232. That should be fairly simple; see the Serial librarypage.

Great project! Good luck!

  -- Leo

Randy P,

I followed your project when you were posting about it and you made it look (or sound) easy. I feel much better knowing that it took you quite a while to get it all mastered. I am still struggling off and on with Arduinos, but other projects keep popping up and sidetracking me. Grandson has me helping with RC vehicles right now (another subject I knew nothing about until a few weeks ago). Your project looks like it turned out very nicely, pictures look great!! Also, thanks for the Jeremy Blum links and recommended books. I have watched a couple of Jeremy's videos, very sharp young fellow! Thanks for all the extra info here.

Don,

I have also been trying to follow Leo's thread (above), it's a very good one! But, the sidetracking has me once again for now.

Last edited by rtr12

One thing that came to mind immediately when I saw the TMCC command specification was how to express binary literals in C++ and the Arduino. The newer standards allow the form:

variable = 0B011010;
alternate = 0b10010;

The prefix 0B (zero, B) in either case indicates a binary literal. This is consistent with the octal and hexadecimal versions; leading 0 for octal, and leading 0x for hex. I wasn't sure about the binary version until I looked it up. Then I ran a quick check on the Arduino IDE and it compiled without complaining.

Thanks Leo for the info.  I'm ready to dive into the Arduino - TMCC communications serial interface with gusto the week.  For religious purposes that are beyond the scope of this post my major C programming efforts predate C++ and while I intellectually understand it's somewhat convoluted elegance I just refuse to get immersed in it.  Subsequently I'm poring over Prof Chaos TMCC class libraries and I will write a conventional C function this week called "outputToTMCC" which will be a bool function returning "true" if successful, providing that the TMCC Base Unit can provide that.  This should be educational and fun.  Looks looks I'm going to need a Mega, not a Uno since I need multiple serial ports.  One for the TMCC base unit, one for the RFID reader (engine identification) and my programming laptop and a mul-line LCD readout display. 

Wish I knew more about the TMCC Action Controller which has a 3-wire connection to the TMCC Base, I assume TX, RX and GND!  I don't use the Action Recorder but I do have the 3-wire cables. All the other TMCC controllers  use only TX from the base (the controllers RX) and ground, hence two wires, ("Data" and "Comm") as they are "simplex" devices which only send data to the TMCC controllers (I use 18 ASCs and 6 BPCs, and 6 TPCs) but get no dialog back except maybe an ACK of NAK.  The Action Recorder seems to be the exception.  I want to ( and am determined to) build my own virtual Action Recorder that I can command with the Arduino.  It would be neat to have complete specs on the Action Recorder.

Can I just connect the TMCC Base Unit to the Tx and Rx and ground pins on the Ardrino and avoid taking up DB9 serial connector?  Can I just create (assimilate/concatenate) the HEX command string to the TMCC base unit and just send it out?  I see the the raw commands on page 36 of the original TMCC manual  but it doesn't tell me timing quirks.  Just what packets need to be sent out and what timing anomalies will I incur.  Any hints would be helpful.

Now time to decipher Professor Chaos TMCC classes and write me C function to do successful TMCC output without the entanglements associated with his specific train control philosophy.  I will devise my own train control philosophy to suit our specific layout needs - as I know exactly how I want to run it but just don't have the software yet.  That's the fun part.  So creating the operating paradigm is as fun (sometimes more) than watching the finished product drive trains around out layout.  I want to savor both!

Please wish me luck and send me any TMCC quirks that I may get trapped with along the way.  I'll keep you posted on my project and publicly share my code when I'm done.  I'll prototype on the Uno and move to the Mega for final integration.  Remember that I must also interface with the RFID reader and small LCD display, plus other assorted digital I/O, such as current-sensing track occupancy detectors, which are all ready in place.  Should be fun!

And I agree with Randy, the journey is as much fun as the goal!

 

I'm using the Web-based Arduino IDE and it is visually different from the downloaded native Windows IDE and all the examples show the physical appearance of the native IDE, not the Web IDE.  I also didn't see how to import an existing .ido file from my computer into my Web-based sketch book.  What am I missing here? 

Would it be better to switch to the Windows-based native IDE and stop using the Web IDE?  For example I'd like to print my modified Blink sketch but I see no "Print" function in the Web-based IDE.  And there's no handy menu bar at the top of the Web-based IDE.  Which IDE do you use and recommend?  Whit print program can print the sketch exactly as it appears on my screen, colors and all?

Randy P. posted:

Don, I learned everything I know about Arduino by watching YouTube videos, reading tutorial websites, and reading *numerous* Arduino books -- repeatedly.  Then I learned how to send commands from an Arduino to a TMCC loco by studying Professor Chaos's code and writing very small proof-of-concept sketches.  Just getting an engine to toot its whistle was a huge milestone, and extremely satisfying.

I started by watching this series of tutorials (several times) by Jeremy Blum: https://www.youtube.com/watch?v=fCxzA9_kg6s  I strongly suggest you start there.  He also has a book which covers pretty much the same material.

From your last post, I can say this is likely going to take you a lot of time.  I personally spent hundreds of hours learning and experimenting, and I enjoyed every minute of it.  But if you're really only interested in getting to the goal, the reward is not going to be worth the effort.  To an experienced Arduino programmer, especially someone who is already up to speed with the TMCC and Legacy protocols etc., what you are trying to do is a relatively trivial project -- probably less than a hundred lines of code (versus thousands of lines of code for my Legacy control project, so far.)  But for a novice, it's a long haul and only makes sense if the joy is in the journey.

For beginner books, I recommend Programming Arduino by Simon Monk.  It covers basic programming concepts as well as how to interface with various devices such as LEDs, sensors, motors, etc.  There is a second "advanced" volume that contains more good information for beginners.

After you understand the basics, for more of a deep dive into Arduino programming (with little emphasis on electronics), I highly recommend Beginning C for Arduino by Jack Purdum.

Good luck, and keep us posted on your progress!

Can I get a copy of your code to blow the whistle?  It might jump-start me.  And I do have the Arduino Uno starter kit and Simon Monk's book.  Very informative so far.

Please recommend a good trackside RFID reader, I've now decided that I need only one reader.  Once my 4 trains pass the reader (in the middle of Block 2 of 12) just one time I can gather enough data to build my own train registration array and the automation will sync up with that so I can easily know which train (TMCC ENG #) is in each occupied block and sequence them around the layout.  The registration array will be indexed by the TMCC engine number - 2, so our Engine 2 (PRR 0-4-0) will be array row 0.  So I need a static trackside reader with USB (or some interface) back to the Arduino plus some small RFID transmitters to mount on/in each engine.  That's 22 engines needing RFID transmitters so I would appreciate low cost.  Any suggestions?

I just thought of another glitch in my plans.  Currently I only want to talk to my TMCC (and Legacy) engines but I might want to talk to some of my TMCC controllers as well. I currently use 3 base units to control 3 separate groups of controllers (ASC, BPC, etc.) and only one of them connects the RF to the outside rail (to avoid interference).  That all works fine.  So if I want to communicate with engines I must communicate with the one base unit that is connected to the track.  But a serial connector is already connected to that base unit.  So do I just use my 3-wire serial connector and use all 3 wires (TX, RX, GND) to the Arduino first, then daisy-chain TX and GND (just two wires) to the other local controllers?  I can (have to) live with that limitation that I can control all engines but only the ancillary controllers daisy-chained to the one base unit that the Arduino is connected to.  The other controllers cannot be controlled from the Arduino, only by my CAB-1 controllers.  Small inconvenience.  Could use 3 Arduinos somehow connected together, but that adds complications I don't want to deal with right now.  Any ideas?

Don, that's a lot of questions ;-) 

* I agree, you'll be fine just writing your code in C, no need for C++.  C++ is another steep curve for an old-school programmer (I go back to FORTRAN and punch cards as well) but became necessary due to the complexity of my project.

* I wasn't even aware that there was a web-based IDE for Arduino.  But it sounds like you need to install the traditional Windows-based IDE to help answer your questions about Prof. Chaos's code.  I personally use Microsoft Visual Studio with a plug-in called Visual Micro -- it makes editing and debugging Arduino code significantly easier, but again there is a steep learning curve.  Definitely not necessary for the straightforward project you're describing.

* I've never interfaced directly to TMCC, only to Legacy.  But I doubt you can just connect wires directly between an Arduino and a TMCC base because the Arduino works on 5v signals, and some RS232 signals are higher voltage.  You can buy an "RS232 to TTL Converter Module" on eBay for $5, which allows you to use a regular 9-pin serial cable.  I've attached a photo of the adapter I use to connect to Legacy -- you should be able to plug a 9-pin serial cable directly into your TMCC base unit (you don't need an SER2 unless yo're connecting to Legacy) -- but I'm just guessing.  Note that I needed a couple of in-line adapters to get the right wires talking (the mini adapter swaps RX and TX if I recall correctly? - it's been a long time since I hooked this up and it was just trial and error until I got it working.)

* I don't know what it means to talk to a TMCC controller?  I'm only sending commands to engines via the base unit, and there is no feedback from the base unit.  If you look at the signals that the base unit is sending out, you'll see that it sends everything three times, for good measure I guess.  So if you connect to any base unit that's connected to your track -- I'm not sure what more you would need?  Unless you've got different base units programmed for different trains -- i.e. if only certain base units are able to send commands to certain trains?  My knowledge here is a little fuzzy.  I've got a couple of controllers but only one primary base unit.

* As I mentioned previously, I recommended the ID-20 RFID reader, which will connect directly to your Arduino's serial port (and yes, you should be using a Mega so you'll have four hardware serial ports.)  That was the best unit I could find in 2015 -- there may be something better now.

* I no longer have my proof-of-concept code to blow the whistle, but it was less than 10 lines.  My real code is more complex than what you'll need, as I'm talking to Legacy, and (like Prof. Chaos), I dump my outgoing commands into a circular buffer.  Then I poll the buffer and keep track of the time, to send commands at least 25ms apart, and send each command three times.  These numbers and more are all pre-defined CONSTants.  But here is some info that may help -- with the caveat that it's very hard to read without any formatting!

I start by setting up byte variables to hold each of the up-to-9 bytes of an outgoing command.  For TMCC there are only three outgoing bytes, but Legacy can have up to 9 bytes.  This is done at the top of the code, in setup():

// First define global bytes for each of the 9 possible used in Legacy commands.
// Most commands only use simple 3-byte Legacy (or TMCC) commands.
// Nine-byte commands are for Dialogue, Fx, and Control "extended" commands.
byte legacy11 = 0x00; // F8 for Engine, or F9 for Train (or FE for emergency stop all or TMCC)
byte legacy12 = 0x00;
byte legacy13 = 0x00;
byte legacy21 = 0xFB; // Always FB for 2nd and 3rd "words", when used
byte legacy22 = 0x00;
byte legacy23 = 0x00;
byte legacy31 = 0xFB; // Always FB for 2nd and 3rd "words", when used
byte legacy32 = 0x00;
byte legacy33 = 0x00; // This will hold checksum for "multi-word" commands

Then I populate the bytes as needed for whatever command I want to send.  For example, to send an "Absolute Speed" command here is the code -- please note that it won't make a lot of sense because I'm using a structure with pre-defined values, adding a checksum for Legacy, and other features too deep to go into here:

case 'A': // Set absolute speed
if (actionElement.deviceType == 'E') {  // This is an engine
legacy11 = 0xF8;
} else {  // This is a train
legacy11 = 0xF9;
}
legacy12 = actionElement.deviceNum * 2; // Shift left one bit, fill with zero (deviceNum is train or engine ID)
legacy13 = actionElement.parm1;  // parm1 will be the desired speed i.e. 50
legacyCmdBufEnqueue(legacy11);  // This puts the three-byte command into my outgoing buffer
legacyCmdBufEnqueue(legacy12);
legacyCmdBufEnqueue(legacy13);
legacyCmdBufTransmit(); // attempt immediate execution
break;

Here are the guts of the function that actually sends the data out the serial port.  I only write in bursts of three bytes, even if it's a longer (9-byte) Legacy command:

static unsigned long legacyLastTransmit = millis();
byte b;
if (!legacyCmdBufIsEmpty()) {
if ((millis() - legacyLastTransmit) > LEGACY_MIN_INTERVAL_MS) { // Enough time since last transmit, so okay to transmit again
b = legacyCmdBufDequeue(); // Get first byte of the command
if (b==0xF8 || b==0xF9 || b==0xFB) { // It's a Legacy command
} else if (b == 0xFE) { // It's a TMCC command
} else {
Serial.print("FATAL ERROR. Unexpected data in Legacy buffer: ");
Serial.println(b, HEX);
endWithFlashingLED(7); // Should never hit this!
}
Serial3.write(b); // Write 1st of 3 bytes
b = legacyCmdBufDequeue(); // Get the 2nd byte of 3
Serial3.write(b); // Write 2nd of 3 bytes
b = legacyCmdBufDequeue(); // Get the 3rd byte of 3
Serial3.write(b); // Write 3rd of 3 bytes
legacyLastTransmit = millis();
shortChirp(); // Do a little chirp just so I can hear when a command is sent to Legacy, i.e. in relation to when I see a train hit a sensor, to assess latency.
}
return;
}

At the end of the day, you can see that all you do is put the data in three 1-byte variables, and execute "Serial.write(data);" three times in your code.  So you could accomplish the above in six lines -- three to define the contents of each byte to be broadcast, and three Serial.writes.  Or just three lines if you put the data in the Serial.write() parameter ;-)

Okay Don, there is a lot to get you thinking.  Now I need to get back on track (ha ha) with my own project ;-)

Attachments

Images (1)
  • Arduino Legacy RS232

Hi Don - the daisy chain might work, but unless you are reading data from the Base with the Arduino, I think you can just connect the Base RX to the Arduino, and the Base TX to the controllers. (Obviously everyone gets GND). You can also use Legacy SER2 modules to get as many serial ports as you need.

Remember that the Base/SER2/controllers use RS-232 voltages, and the Arduino serial port is TTL. So you will need an RS-232-TTL converter between them. You can make your own with a MAX232 chip, or buy a pre-made one.

For an RFID reader, I've used ID-20 readers. Each one can connect to a TTL serial port on the Arduino, and you can get 125khz tags in all sorts of shapes and sizes.

This thread reminded me to publish some old code to read the serial output of the Command Base and dump it to the console with human read-able text appended to the three hex byte command.  The human read-able part - lots of #defines and text strings - was the grunt work.  The last time I compiled this was on Visual Studio 6 many years ago.  The current Visual Studio doesn't play nicely with old and "untrustworthy" C/C++ code (and life is too short to fuss with it) so building the executable is left to you.  See the README for a link to the multi-threaded TTY I/O code for the files you'll need to build a Windows EXE.  Of course, the Arduino folks will have to adapt the code appropriately for their platform, compilers, and I/O.  The source is .cpp files, the code style is mostly C, so devolving classes to C should not be difficult. 

GitHub project: CmdBaseReader

Command Base Reader example code

I'm currently using C# for development of Legacy tools so I cannot provide a Legacy version of CmdBaseReader using a C/C++ codebase.  I'll publish a Legacy command monitor once I'm satisfied with the code.

Regarding the Command Base serial channel, there is no problem multi-dropping multiple devices that read the output (which is the environment of multiple ICControls devices).  Don't know about potential chaos when transmitting to the Command Base from multiple sources.  I only have one Action Recorder so I haven't stressed writing to the port.

With the LCS devices, each device connects to its neighbors via the PDI cable which is NOT multi-dropped, and I assume that the LCS firmware deals with serial line contention issues.  Accordingly, I would recommend using the SER2 to transmit serial commands into the Legacy Base rather than connecting directly to the Legacy base.

Cheers,

John

 

I noticed the last few post keep mentioning Legacy.  From what I have read, Don is using TMCC only.  Therefore, all of the F8, F9 and FB stuff will not work for him.  He can only use FE.  Also, he cannot use a SER2 with a TMCC base.  They cannot talk to each other.  He has to go directly to the TMCC base.

Thanks Harvy.  Yes I must go directly to the TMCC base from my Arduino, no Legacy involved.  How do I convert the serial signals from TTL to RS-232?  I think that I only have to send commands to the TMCC base not receive and interpret any inputs.  Do I still need a Tx and Rx line?  I'm just acting like a smart Action Recorder.  Where can I buy a pre-built TTL to RS-232 converter and is that just for the Tx line?  Sounds like the ID-20 is the choice as an RFID reader.  Where do I get the reader and the transmitter chips?

Thanks Randy for your long response.  Guess I'll dig in and just proceed a byte at a time.  Going to be an adventure, but a fun one.  Would love just to have a graphic time-line graph (no code) of what a complete packet would look like, data,spaces,data,spaces,etc. for a complete transaction.  Someone of those old engineers has one lying around somewhere! Probably ought to draw one out just to get my head straight.

I don't think I can answer any of those questions, sorry.

One thing I want to bring to your attention.  I believe you said your main purpose is to receive train locations from various sensors and send out TMCC speed commands to the base unit to adjust their speed.  In my opinion Speed commands are the hardest of all TMCC commands to get working and the logic around them.  The TMCC spec gives you two options for speed commands, Relative and Absolute.  Not all engines respond to both.  Some engines will only respond to one or the other.  You may have to experiment.  My software gives users both options, but I believe in your case, since you want it all automated, you might also have to store which speed method each engine needs in your engine array.

Last edited by Harvy

Don, you should get an RS232 shield (or similar) to convert the serial comms and voltages to bytes that you read/write to the shield's serial port using an Arduino lib.  Once you are comfortable reading and writing bytes to the shield, then connect it to the Command Base and watch what you receive at 9600 baud 8 bits, no stop bits.  (the cable needs Tx, Rx, and Gnd wired).  You'll receive sets of three bytes beginning with 0xFE.  Then construct and write a 3-byte set to the shield.

I'm working on defining the data structures for my train project first then drop in the code.  I will run up to 4 (out of 20) trains on out 12 block main O-Gauge line, controlled by only TMCC, no Legacy (but we do have some LC+ engines).  I will detect each engine via RFID at only one point on the layout and automatically register the running trains after they all run past the ID-20 a couple of times.  So I need say 25 cheap RFID transmitters that don't look like key fobs and can go in the tenders of steam engines and inside the shells of the diesels and electrics.  Once everything is registered I will identify all trains passing the ID-20 on an LCD screen (Can you recommend a good 4-line LCD with a 12C interface?) with train info, scale speed and number of loops.  After that all works, I'll slow the train in the following block if a train is in the current block by sending TMCC commands to the following engine (already registered and tracked) using the RS-232 serial port on the TMCC base unit, while also using that port to control several other TMCC controllers (TPC,ASC,BPC, etc.) hopefully using one of the additional RS-232 serial ports on the Arduino Mega, so no RS-232 shield needed.  Will start out with sending Engine ID and relative speed commands to TMCC but later more bells and whistles (no pun intended, of course!).  That's enough of a plan to start the data structures and define some common functions (like "readRFID"). 

Since I'm re-learning C right now and never used C++ can I do all this in a year?  I think so with your help.  Thanks for helping so far.  I'll update progress and ask for more help as time goes on.  No back to the Arduino IDE.  I bought a small cheap laptop yesterday so I have a "portable Arduino IDE" now.  I loaded the native Arduino IDE on the laptop but I was using a web-based IDE on my desktop.  I gather that most of you use the native (downloaded) IDE as opposed to the web-based IDE, as the look and feel is different.

 

Don, just a couple of comments:

* Correct, you don't need a RS232 shield; with a Mega you have four on-board serial ports.

* I use "2004" i.e. 20 chars by 4 lines, LCD displays, which are available on eBay for less than $10.  They are available in I2C, SPI, and UART versions.  I've used several brands and they are all the same - just pick your interface and color.  They're also available on Amazon.

* You might want to do a little research on RFID readers, because the ID-20 is out of stock at Sparkfun.  I don't know if that's because it's discontinued or just out of stock.  There might be a better alternative by now.

* I always use absolute speed, never relative speed, because it's easier (and critical) to have certainty about how fast your train is moving (and I have lookup tables so I know that "medium" speed on one loco is often a different absolute speed number than it would be on another loco.)  I just don't see why you would ever use relative speed, because you need to keep track of how fast everything is moving -- if someone inadvertently adjusted the speed of a train, or if there was a bug in your software, then everything would be thrown off.  Also you can set momentum before setting a new absolute speed so the adjustment is more or less gradual.  That said, I know another poster said he'd had trouble with absolute and relative speed with TMCC, depending on the loco -- so something to be confirming as early in this project as possible - what works for your hardware.

* Before you start coding, you should think strategically about how you are going to start each operating session - in terms of how you will run trains past the RFID reader to get them registered into your system, and what happens when you see occupancy for a train that hasn't yet been registered.  And how do you bring things to a controlled stop.  One thing that i do is keep a short block of non-volatile memory updated with the last-known position of each train.  Then, when I start a new operating session I default to that setup.  In my case, I prompt the operator for the identification of each unknown occupied block (before any train starts moving) and default to the last-known train that was in that block -- so startup is typically just a matter of clicking "ok" six times (if there are six trains) for instance -- unless trains have been moved manually since the last automated session or if there was an emergency stop.

I'm sure you can finish this in less than a year.  The fun part is testing every aspect with a small "proof of concept" Arduino sketch and minimal hardware - it's very satisfying to see success of those small steps.  Then you assemble all those parts to get a working whole (not trivial in itself.)  And absolutely no need to use C++ other than to glean useful information from existing code that others have shared.

Thanks Randy for your comments.  I'll look into an alternate to the ID-20.  Where can I buy transmitter "buttons" cheaply as I better get 30?  All engines (Legacy, TMCC, LC+, conventional) will have RFID "buttons".  An array in the Arduino will have static info on each engine and when an new engine is given an RFID I'll add that RFID to an array that maps RFID to engine array index.  So there should never be the case that a unknown engine is encountered. 

All trains have their own siding so there are no trains on our long main line loop at startup.  To start up a session you power up an engine (full train) siding and pull it out on the main line at a random medium speed.  Once that one has cleared you bring out train number two, with enough space to avoid collision until they sync up.  Then start train #3 and so on.  Once train 1 passes the RFID sensor it is identified (RFID sensor in block 2) it's placed in a 12 position "block occupancy" array".  Occupancy is detected in all 12 blocks by detecting current with Hall-Effect current sensors, hence no voltage drop, and an occupancy map is updated in the Arduino.  So when block 3 shows "occupied" the engine index for the train in block 2 is sequenced into block 3, etc. 

So at any given time the Arduino knows which blocks are occupied and by which train.  Any "unidentified" train means a mess-up on my part and a fault is thrown and the TMCC HALT button is thrown by the Arduino.  These are the data structures I'm building up now.  I'll also measure scale speed of each train in block 2 and display it.  If I detect that the train behind the current train in block 2 (hence block 1) is gaining on it and is getting arbitrarily "too close" I want to send the following train (if its TMCC or Legacy) a relative "slow down" command, the duration of which is determined empirically, unique to each engine, and stored in the engine array.  If the next time around it still not slow enough I'll hit it again with a slowdown sequence.  What do you think of this paradigm?

AmeenTrainGuy posted:

I have a cab1 but I am planning to get a legacy command base if I write my program for the cab1 will it be transferable to legacy?

Legacy engines can understand both Legacy and TMCC commands and we run several Legacy engines with our TMCC command base, but we can't use all Legacy features (like quilling horn).  TMCC engines, on the other hand, cannot be operated from a Legacy command base.  TMCC command bases take commands from the Cab-1 via RF or from the RS-232 port on the base.  Legacy command bases take commands from the Cab-2 controller also via RF  but the signals are not comparable.  They also take wired commands but from a different LCS data link, not RS-232.  If you want to talk RS-232 to a Legacy command base you need a serial board LCS SER-2, but the commands must be in Legacy format, not TMCC format.  Hope that this helps.

Don, one of the approaches that I considered for registering trains into the system is similar to what you're describing.  I would manually drive an engine past the RFID sensor, at which time the computer would take over all control of that train -- adjusting the (absolute) speed and directing it on whatever route my algorithm assigned.  The operator (me) would then select a different engine or train on the CAB, and drive that train past the RFID sensor.  And so on.

I'm not sure how your hall effect sensors work -- do they show "occupied" whenever an engine is anywhere inside an electrically isolated block?  How do you do this?  Remember that a long train can extend into a block on either side...  I'd like to see exactly what sensors you are using and how they are connected to the track and an Arduino.  If you could post specific information about your hall effect occupancy sensors,  I'd very much appreciate it.

I'm using old-school isolated rail sections connected to time-delay relays (to avoid bounce/chatter), and have a sensor at each end of every block.  The length of the sections is adjustable as I'm using kapton tape with copper foil tape on top of the rails, rather than cutting the rail to create the electrical isolation.  So I keep a accurate accounting of when trains enter *and completely exit* each block.  Regardless of how long at train is, I know when a block has been completely cleared, and (because I use absolute rather than relative speed adjustments) I know when it is likely to reach the next sensor.  I like that certainty.

I know how many inches per second each train is moving at each speed step (I have four pre-defined for each loco - crawl, slow, medium, and fast.)  Using relative speed adjustments is just too arbitrary for my taste ;-)  This is beyond what you'll require, but I've also got tables that indicate rates of deceleration -- so I can calculate when to start slowing a train after hitting a destination siding entry sensor, and attempt to be at crawl speed the moment the train trips the destination siding exit sensor -- giving the software an opportunity to stop the train before it overshoots and fouls the mainline.  Note that entry/exit sensors are identical -- it just depends which direction the train is moving.  I also use these sensors to trip accessories such as crossing gates etc.

I buy virtually all of my parts on eBay, Amazon, and Sparkfun.

Ameentrainguy, I agree with Don's reply to you, but I'm not sure he was clear about one thing: You can write your software to send exclusively TMCC commands out the serial port, and if you upgrade to Legacy hardware and optionally also Legacy locos -- your software will still work fine.  All of the Legacy hardware and all Legacy locos will respond to TMCC commands -- whether from a Lionel TMCC control system or from serial data being spit out of an Arduino serial port.  As Don pointed out, the hardware interface will need to be upgraded for Legacy (to include an SER2), but your software will continue to work exactly as before.

My exclusively-Legacy project would work just fine if all I used were TMCC commands -- and my software would be simpler because the TMCC protocol is simpler.  The incentive to go with the Legacy protocol is that Legacy equipment offers more control -- more speeds, more control over triggering announcements, controlling smoke, etc.  If you look at the plain-English description of the commands in the TMCC protocol versus the Legacy protocol, you'll see what the differences are.

Randy P. posted:

Ameentrainguy, I agree with Don's reply to you, but I'm not sure he was clear about one thing: You can write your software to send exclusively TMCC commands out the serial port, and if you upgrade to Legacy hardware and optionally also Legacy locos -- your software will still work fine.  All of the Legacy hardware and all Legacy locos will respond to TMCC commands -- whether from a Lionel TMCC control system or from serial data being spit out of an Arduino serial port.  As Don pointed out, the hardware interface will need to be upgraded for Legacy (to include an SER2), but your software will continue to work exactly as before.

My exclusively-Legacy project would work just fine if all I used were TMCC commands -- and my software would be simpler because the TMCC protocol is simpler.  The incentive to go with the Legacy protocol is that Legacy equipment offers more control -- more speeds, more control over triggering announcements, controlling smoke, etc.  If you look at the plain-English description of the commands in the TMCC protocol versus the Legacy protocol, you'll see what the differences are.

Randy P. posted:

Don, one of the approaches that I considered for registering trains into the system is similar to what you're describing.  I would manually drive an engine past the RFID sensor, at which time the computer would take over all control of that train -- adjusting the (absolute) speed and directing it on whatever route my algorithm assigned.  The operator (me) would then select a different engine or train on the CAB, and drive that train past the RFID sensor.  And so on.

I'm not sure how your hall effect sensors work -- do they show "occupied" whenever an engine is anywhere inside an electrically isolated block?  How do you do this?  Remember that a long train can extend into a block on either side...  I'd like to see exactly what sensors you are using and how they are connected to the track and an Arduino.  If you could post specific information about your hall effect occupancy sensors,  I'd very much appreciate it.

I'm using old-school isolated rail sections connected to time-delay relays (to avoid bounce/chatter), and have a sensor at each end of every block.  The length of the sections is adjustable as I'm using kapton tape with copper foil tape on top of the rails, rather than cutting the rail to create the electrical isolation.  So I keep a accurate accounting of when trains enter *and completely exit* each block.  Regardless of how long at train is, I know when a block has been completely cleared, and (because I use absolute rather than relative speed adjustments) I know when it is likely to reach the next sensor.  I like that certainty.

I know how many inches per second each train is moving at each speed step (I have four pre-defined for each loco - crawl, slow, medium, and fast.)  Using relative speed adjustments is just too arbitrary for my taste ;-)  This is beyond what you'll require, but I've also got tables that indicate rates of deceleration -- so I can calculate when to start slowing a train after hitting a destination siding entry sensor, and attempt to be at crawl speed the moment the train trips the destination siding exit sensor -- giving the software an opportunity to stop the train before it overshoots and fouls the mainline.  Note that entry/exit sensors are identical -- it just depends which direction the train is moving.  I also use these sensors to trip accessories such as crossing gates etc.

I buy virtually all of my parts on eBay, Amazon, and Sparkfun.

 

Here's the Hall-Effect boards I used from eBay.

https://www.ebay.com/itm/Curre...?hash=item283e9b6153

You are right that this detection, while simple, does well on block entry but not on block exit.  On exit it may drop out after the engine leaves the block unless you are hauling passenger cars with incandescent lights.  I don't worry about the "overhang" right now as our blocks are long so I concern myself with just entry, not exit.  Time is calculated from entry to entry and I put in a delay before declaring "unoccupied" just to be safe.  A potentiometer allows you to adjust the pickup current but it won't detect cabooses with LED lights very well.  You could drop in a low ohm resistor in each caboose or around each EOT to suck enough current to declare occupancy.  Board outputs are dry 10a SPDT relay contacts to be used any way you choose.  No isolated track sections or overlays.  I detect all current at its source on our control panel so no wires to remote locations, a big plus.

I'm not sure what I'd do with absolute speed as I'd have to determine the sweet spot separately for each engine.  I'd rather set a nominal target speed for the first engine out and let the others queue up behind that one by adjusting their speed incrementally.  Obviously all speculation for now, we'll see how all this works out in a few months.  I'm sure that my scale MPH calculations will not be very precise but good enough for me, I hope.

Don, thanks for the info on your hall-effect board.  So do you just place the coil near the rail, and a train located anywhere on that isolated block of track shows current anywhere along that track?  If so, how do you isolate the block yet use a single power supply over multiple blocks?  Or is it detecting the train passing past the coil?  Dumb questions, I know! ;-)

If you don't want to connect all those relays directly to Arduino inputs, you can use a shift register.  I use a product called Centipede Shield from Macetech (though I don't use it as a shield; I mount it adjacent to my Arduino): http://macetech.com/store/inde...o&products_id=23  Great product and great support from those guys.

Either way, don't forget that relay contacts "bounce" and will register as multiple closures if you poll them too frequently.  Contacts can even "bounce" when released.  It's easily addressed with a bit of code, though some people prefer to debounce using hardware.  Just something to be aware of if your testing shows multiple entries into a block in a matter of a few milliseconds.

Randy P. posted:

Don, thanks for the info on your hall-effect board.  So do you just place the coil near the rail, and a train located anywhere on that isolated block of track shows current anywhere along that track?  If so, how do you isolate the block yet use a single power supply over multiple blocks?  Or is it detecting the train passing past the coil?  Dumb questions, I know! ;-)

If you don't want to connect all those relays directly to Arduino inputs, you can use a shift register.  I use a product called Centipede Shield from Macetech (though I don't use it as a shield; I mount it adjacent to my Arduino): http://macetech.com/store/inde...o&products_id=23  Great product and great support from those guys.

Either way, don't forget that relay contacts "bounce" and will register as multiple closures if you poll them too frequently.  Contacts can even "bounce" when released.  It's easily addressed with a bit of code, though some people prefer to debounce using hardware.  Just something to be aware of if your testing shows multiple entries into a block in a matter of a few milliseconds.

Here's what the current detectors look like on our control panel.  For each block you want to detect, you feed the center rail feed wire two or three times through the Hall-effect coil before connecting it on out to the track.  Each loop results in better current detection.  If the wire is big enough there is no voltage drop with this method of current detection.  Since I don't have my Arduino solution yet the on-board relay switches the center rail voltage of the block you are trying to slow down from 18v to 12v (adjustable), which TMCC boards can tolerate without resetting, and the resulting slowdown is enough to generate the required separation.  Some of the Legacy engines with Odessey Speed Control sluff off this drop and refuse to slow down very much, just doing what they are designed to do, not what I want them to do.  Hence my desire to slow all of them down more legitimately by keeping the voltage at 18v and use TMCC commands to slow the engines.  In that case the relay pulling in would cause an Arduino digital input to go high, causing me to output the slowdown commands to the engine needing slowdown.  I would use software to handle any relay "bounce" as I'm not looking for great accuracy here.  The red LEDs on the right indicate slowdown - unfortunately ON is no slowdown and OFF is slowdown.  Now back to choosing RFID and LCD components!

 

Attachments

Images (1)
  • blobid0: AC Current Detection Boards

Very interesting, Don -- thanks for the education!

I suggest you consider using your relays as SPST to connect *ground* (low) to an Arduino input when a block is occupied, rather than pulling input high to indicate occupied.  That's because the Arduino has a built-in pull-up resistor on each digital input, and thus it's often easier (and more typical) to trigger an event when a pin gets pulled low.  Then, with the pullup resistor feature turned on, a disconnected pin will read high rather than floating. 

If you use high (+5v) to indicate an event, then you'll need something to pull the inputs low when they are not being tripped, because a disconnected input can "float" and be unpredictable -- it's not necessarily going to be seen as "low" when not connected.  Forgive me if you already know all this -- because if not, it's an important thing to watch out for.

So after playing around with mt Arduino Uno and associated IDE this weekend building a super "Blink" program and re-learning C syntax I'm ready for more challenges.  Want to blow the horn on one of my TMCC engines.  Thanks for the code samples, so I have a head start.  All the other TMCC modules use only the Tx and Gnd wires from the base daisy-chained to Rx and Gnd  on each control module, except the Action Recorder which sends its Tx line back to the TMCC base Rx pin.  I don't have an Action Recorder so can't I just connect the Tx and Gnd from an extra RS-232port on my Arduino Mega to the Rx and Gnd on the TMCC base unit.  Do I even need to connect  the Tx from the base to Rx on the Mega?  That would just add on to the current Rx daisy chain.  I have extra 3-wire RS-232 TMCC cables, can't I just connect one to the Mega and use one out of the TMCC base and cross-connect them appropriately?  Let me know if I have this close to being correct.  Sounds deceptively too easy.  What baud rate do I need to assign?  Thanks again for helping.

I wanted to thank all of you on your help, and report on my progress.  Thanks to your suggestions and code snippets I can successfully control all my Legacy and TMCC engines from my Arduino Mega 2560.  I just use the 3-byte so I can olny do the commands coimmon to both TMCC and legagy, but that's fine for my needs right now.  The latest version of my train control sketch is attached in case you are interested.  My main loop function is a mini task scheduler and as such no subordinate functions are allowed to use the infamous "delay" function, as that defeats the purpose of multitasking.

I'm now ready to code the sub-function dealing with RFID.  Please suggest a suitable RFID reader and preferred serial interface.  Also I need to buy some RFID tags to mount in the first car of each train so I can properly identify and register it.  Can you suggest some suitable, reasonably priced,  tags for this purpose?

Thanks for all your help.

Don

PS: As I look back thru the posts I see that I previously asked about RFID.  Now, however I'm actually ready to go and do it, so I could use your latest suggestions before I start.

Attachments

Files (1)
LATEST TRAIN CONTROL SKETCH for TMCC

Hi Don,

When I was experimenting with RFID, I was using the ID-20: https://www.sparkfun.com/products/11828.  This unit has a very good range and is easy to use with an Arduino.  Here is the Sparkfun hookup guide: https://learn.sparkfun.com/tut...882562561.1510038480

See below for more notes and sample code.  Good luck!

Randy

Here are some raw notes I'll copy and paste from my testing in 2015/2016 which may be helpful:

Only need 3 wires coming off of ID-20LA RFID reader.
Pin 1 (GND) and Pin 7 (FORM) to Ground
Pin 2 (RES) and Pin 11 (VCC) to +5v
Pin 9 (D0) to Arduino serial port Rx. I.e. pin 15 for Serial3 RX
Pin 10 (READ) sets to +5v on RFID read, so good for LED via resistor to ground

TESTING 1/21/16: Connected the RFID reader to an Arduino using just three wires: +5v, ground, and signal (RFID reader pin 9.) It is important to power the RFID reader from the same power as the Arduino for the signal to work reliably. Also connected RFID reader pin 10 to the POSITIVE side of an LED, with a resistor then to ground. LED lights when code is read.

CABLE LENGTH 1/21/16: Tested the RFID reader connected to Arduino via a 62-foot-long 4-conductor 22awg cable (I have 1000' of this, very inexpensive.) looked at signal quality at each end of the cable and it was excellent both ways. So standard serial connection (one wire) even over such a long distance works no problem! No need for RS-485 due to length of wire between RFID reader and Arduino.

Important: 1/21/16: If the power does not have a common ground and common +5v between the RFID reader and the Arduino, the RFID reader may APPEAR to work correctly, however each reading for a given tag is likely to be wrong and possibly different each time. A power reset must be done to correct this.
FOR THIS REASON, because it can spit out random incorrect IDs, we should probably track more than three digits of each code -- to minimize the possibility of a random (bad) code matching an actual code. We can at least do four digits with an integer value.

Finally, here is some test code I wrote a few years ago -- it might help you get started:

// Rev 06-29-2015 by RDP

#define RFIDBUFSIZE 16 // Size of data sent by RFID reader
#define RFIDSTX 2
#define RFIDCR 13
#define RFIDLF 10
#define RFIDETX 3

void setup() { // Set up code called once on start-up
Serial.begin(9600); // Serial monitor
Serial.println("RFID Card Reader Test");

Serial3.begin(9600); // RFID reader will connect to Serial3
while (Serial3.read() > 0) { // Clear out any incoming RFID junk
delay(1);
}
}

void loop() { // Main code, to run repeatedly

if (Serial3.available()) {
byte rfidCode = getRFID();
Serial.print("Scanned RFID: ");
Serial.println(rfidCode);
// check to see if we already have registered this code, etc.

}

Serial.print(".");
delay(2000); // kill some time

}

////////////////////////////////
/// Define various functions ///
////////////////////////////////

byte getRFID() {
/* Gets called if there is at least a byte of data waiting in the incoming
serial buffer for the RFID reader. This routine reads the entire RFID,
does some basic confirming that it's a good read, and returns a byte 0..255
based on the last two hex digits of the scanned RFID code.
We could use all 10 hex digits, but totally unnecessary. We simply need
to be sure that we don't use two RFID tags that share the same last two
digits. There are 256 possible values, so not much chance of dup tags.
Assumes using the ID-20LA RFID reader.

Connect RFID reader pins as follows:
Pin 1 and Pin 7 to Ground
Pin 2 and Pin 11 to +5v
Pin 9 to Arduino serial port Rx. I.e. pin 15 for Serial3 RX

RFID reader sends 16 bytes each time it is activated:
Byte 1 = STX (0x02)
Byte 2..11 = 10 bytes of data, the unique ID. ASCII '0'..'9', 'A'..'F'
Byte 12..13 = 2 bytes of checksum
Byte 14..15 = CR + LF (decimal 13 and 10)
Byte 16 = ETX (0x03)
A typical string coming from the serial interface, in decimal, might be:
2, 54, 56, 48, 48, 57, 51, 55, 53, 67, 55, 52, 57, 13, 10, 3
We would look at 67, 55 -- which is 'C' '7' in ASCII read as hex, which is 199 decimal.
This is calculated as (12 * 16) + 7 = 199.
*/

byte rfidData[RFIDBUFSIZE]; // Buffer for incoming data

// Wait for all 16 bytes to be reading in serial buffer
do {} while (Serial3.available() < RFIDBUFSIZE);

for (int RFIDByte = 0; RFIDByte < RFIDBUFSIZE; RFIDByte++) {
rfidData[RFIDByte] = Serial3.read();
// Serial.println(rfidData[RFIDByte]);
}

if ((rfidData[0] != RFIDSTX) || (rfidData[13] != RFIDCR) || (rfidData[14] != RFIDLF) || (rfidData[15] != RFIDETX)) {
Serial.println("Houston, we have a problem!");
} else {
// Serial.println("All internal bytes look okay!");
}

// We will take the last two digits of the RFID code.
// ASCII '0'..'9' is 48..57. Subtract 48 from ASCII value to get value 0..9.
// ASCII 'A'..'F' is 65..70. Subtract 55 from ASCII value to get value 10..15.
// Then multiply by 1 or 16, depending on the position.

byte rfidCode = 0; // 00..FF = 0..255
if (rfidData[9] <= 57) { // Must be ASCII '0'..'9'
rfidCode = (rfidData[9] - 48) * 16;
} else { // Must be ASCII 'A'..'F'
rfidCode = (rfidData[9] - 55) * 16;
}
if (rfidData[10] <= 57) {
rfidCode = rfidCode + (rfidData[10] - 48);
} else {
rfidCode = rfidCode + (rfidData[10] - 55);
}

return rfidCode;
}

 

Hi Randy,

Thanks again for your help.  I copied your code and "Furgersonized" it (as my matching braces must line up vertically - a nit) and have ordered the RFID reader (and a breakout board) that you suggested.  I'll use it as a test and then integrate it into my overall project.

I was going to read all 16 characters and compare them but I'm only using 30 tags so hopefully the two characters you chose will be unique.  And makes comparison faster.  I'll let you know how I make out in a few weeks.

Then to connect a 4-line LCD panel via I2C to output results and I'll be pretty much done.  A fun project.  When my project is done what is the best way to share it in the public domain, as everyone seems to do?

Thanks again,

Don

Hi Don,

I always format my code -- the tabs were stripped when I pasted into the post ;-)  Since I opted not to use RFID to identify my locos (my Arduino prompts the operator for loco starting locations, defaulting to last-known, so it's a lot faster) I didn't have an .ino file to post -- just some clipped text saved in my OneNote notebook where I keep track of test results and such.

If you'd like to share your code, in my experience the most typical way would be to post it on GitHub.  A bit of a learning curve to set up an account and learn how to check in projects, but well worth it for the version control it provides.  It's free as long as your code is public, so that's a win-win.  Of course, you'll need to post a link to it where people will see it, such as here.

Randy

I am new to Lionel Legacy Trains and have been reading through this post and quite frankly, anything I can find regarding Legacy and Arduino for controlling Legacy trains. I have a customer who has a Legacy system set up in their business. They have a 22 foot oval with 36 inch curves at either end. Fairly basic setup, but running a train 16 hours per day constantly produces quite a bit of wear, mostly on the engine. I proposed that we replace the handheld(wireless) with an arduino mega and program it to run for a period of time, stop for example, one half hour, then repeat, until closing. I have basic understanding of programming, having written in Lisp, AutoLisp, Basic, Visual Basic, and dabbled in C, C++, and Visual C++. I started studying Arduino about 2 years back, on and off, when I started designing and building an Underwater ROV. We have purchased the SER2 unit and cables, as well as the RS232 shield, and various IR transmitters and receivers. My understanding is that the Legacy Engines utilize an IR transceiver to communicate with the base via a Fastrack ir sensor. I have purchased TSOP38238 IR receiver to see if this multi-spectrum receiver will sense the ir signal from the engine. If it does, I wish to use this signal to trigger a count to instruct the base unit to send various commands to the engine, such as speed, whistle, horn and light control. After the forth count, I would have the train pause for a period of one half hour, then repeat the sequence, until the closing, at which time it will be switched off for the night. As for installation of the ir receiver, I plan to drill a small hole in the track and lay it horizontal so as not to interfere with train operations. I had previously thought of ir or led laser transmitter and receiver on either side of the track to count the trains passing, but realized that the gaps between engine and subsequent cars would each trigger and event. That could be accounted for in the programming, but if they were to add or subtract cars in the future, additional programming would be required. Simplicity ,reliability and low cost are my three main goals here. Any advice would be appreciated as I really don't want to reinvent the wheel in this case. Sincerely, Charlie.

 

My software can do that.  Meaning record a scenario and play it back.  You can even repeat the scenario automatically.  You can also edit the scenario so you don't have to sit there recording while the train is stopped for 30 minutes.  Please click on the links in my signature below for more information.  Feel free to contact me directly as well.

Harvey, come to find out that my partner already purchased your software. The issue is that the customer has one computer in the convenience store and does not allow his employees access to it.  The store opens at five a.m. so the train control must be independent of a computer so which ever employee opens, they are able to start the train by simply turning on specific equipment. That is also a reason why the remote handheld is locked away as well, because not all employees are adept at operating said unit. Some have a tendency just to push buttons willy-nilly and we get called in to reset, a lot. Hence why I suggested Arduino for control. Some folks, when given many options, choose them all! I would prefer that a single power switch will control power to everything, and at most, simply pressing the reset button on the arduino will start the train operation for the day. We have toyed with using the remote to program the sequences in, but several issues arise from that. The first being that the complete circuit of the train once around the track varies in time according to friction in the curves. By using an IR receiver, we can let the program "adjust" the command timing. The train is mounted 8 foot up on a wall that separates the main store from the deli/kitchen. So half of the track is in the main store, the back half is in the kitchen and is covered in an eight inch accordion style tunnel. The track is mounted to  expanded metal mesh which is cut and bolted in place. It took us a good month to get the track leveled and mounted. We did this by cutting 1/8th inch plywood veneer to the exact shape and width of the assembled track, then used this to mount the track to. The veneer was assembled in four separate pieces in order to give as much stability to the track as possible. We actually mounted the veneer to the expanded metal mesh and leveled it as we assembled, then attached the track to the veneer, thus making repairs on the track much easier. As the train passes in to the kitchen area, we want all train noises to stop, then start again once in enters back into the main store. I believe we can accomplish this with a simple IR receiver which will trigger as the engine passes, given the multi spectrum receiver can "sense" the IR signal from the engine. This trigger event will be read by the arduino for each pass and used to by the program to perform different commands for each lap. After the fourth lap, the train will stop, every so often do a whistle, or make some locomotive sounds. After a half hour or so, it starts the lap sequence again, and so on, until closing time when the employee simply turns off the master power switch. If I had a dedicated laptop or computer, we could probably make your software work just fine, as long as we can idiot proof it from employees. The office is located some 30 to 40 feet from where the train is mounted, so any wiring will need to be pulled through the attic. This in itself is a non issue as I have spent many hours pulling cat6 communications wire, power, and video security cable through the attic in the past.

Hi Charlie,

If I was doing this, I'd forget about the Legacy IR sensors, and just use a few isolated rail sections (or something similar) to allow your Arduino to keep track of where the train is (be sure to account for "bounce" in your software or hardware.)  You can count laps, turn off the sound when the train enters one area and turn it back on when it exits, accelerate, slow to a smooth stop, make announcements, use the bell and horn, pause (or even power off the train) for any length of time, etc.  All in a big loop that could just run indefinitely -- no need for a computer, or the Legacy remote (I even power up my track and locos with my Arduino so I don't need my Legacy remote at all, when running in autonomous mode.)  You could have a button that started/stopped the whole thing to be used in the morning and afternoon (or anytime you wanted to stop and re-start the process.)  Or put it on an automatic timeclock and not even have to think about turning it on and off.

To keep things simpler, you might also consider just using TMCC commands (issued from the Arduino serial port to the Legacy base -- you don't even need an SER2 for this).  They are easier to understand/program, and they work fine on Legacy engines.  You just don't have quite as much control -- but you can easily do everything you've discussed.

The parts necessary to do this will be few and cheap, and the programming is pretty trivial once you get past the learning curve.  I would just write it in straight procedural C, a big loop.  (Guys, please don't jump on me, I have a degree in CS and ran a software company for 20 years -- but for a single-purpose trivial program like this, I'd just write it as one big loop with maybe a few functions for sending TMCC commands etc.)  Unless you want to use OOP for the fun of it ;-)

Since Prof. Chaos has already done what you want to do (though more sophisticated, and programmed in C++), I'd look at his code on Github and you'll see how to send TMCC commands and everything else you're trying to do.  He also uses RFID readers, which is another option for train detection -- but with only one train, it's overkill in my opinion.

Keep us posted, and let us know if you have any specific questions.

Randy

With Randy's guidance and some Hall-effect current detectors (one per block) and RFID train identification and registration I can easily run 4 Legacy/TMCC trains around a single 140' curvy loop using just the Arduino Mega talking RS-232 to the TMCC base (but could talk to Legacy as well).  They also can start and stop automatically, as desired.  I can measure the speed and gap for each train and send commands to each engine to keep the gap constant.  Operators have hand-held controllers but just for emergencies and some hands-on fun, usually the controllers are not needed.  As Randy said, I send only the 3-byte TMCC commands and I can control the basic functions on both Legacy and TMCC engines.

Charlie Rounds posted:

Harvey, come to find out that my partner already purchased your software. The issue is that the customer has one computer in the convenience store and does not allow his employees access to it.  The store opens at five a.m. so the train control must be independent of a computer so which ever employee opens, they are able to start the train by simply turning on specific equipment. That is also a reason why the remote handheld is locked away as well, because not all employees are adept at operating said unit. Some have a tendency just to push buttons willy-nilly and we get called in to reset, a lot. Hence why I suggested Arduino for control. Some folks, when given many options, choose them all! I would prefer that a single power switch will control power to everything, and at most, simply pressing the reset button on the arduino will start the train operation for the day. We have toyed with using the remote to program the sequences in, but several issues arise from that. The first being that the complete circuit of the train once around the track varies in time according to friction in the curves. By using an IR receiver, we can let the program "adjust" the command timing. The train is mounted 8 foot up on a wall that separates the main store from the deli/kitchen. So half of the track is in the main store, the back half is in the kitchen and is covered in an eight inch accordion style tunnel. The track is mounted to  expanded metal mesh which is cut and bolted in place. It took us a good month to get the track leveled and mounted. We did this by cutting 1/8th inch plywood veneer to the exact shape and width of the assembled track, then used this to mount the track to. The veneer was assembled in four separate pieces in order to give as much stability to the track as possible. We actually mounted the veneer to the expanded metal mesh and leveled it as we assembled, then attached the track to the veneer, thus making repairs on the track much easier. As the train passes in to the kitchen area, we want all train noises to stop, then start again once in enters back into the main store. I believe we can accomplish this with a simple IR receiver which will trigger as the engine passes, given the multi spectrum receiver can "sense" the IR signal from the engine. This trigger event will be read by the arduino for each pass and used to by the program to perform different commands for each lap. After the fourth lap, the train will stop, every so often do a whistle, or make some locomotive sounds. After a half hour or so, it starts the lap sequence again, and so on, until closing time when the employee simply turns off the master power switch. If I had a dedicated laptop or computer, we could probably make your software work just fine, as long as we can idiot proof it from employees. The office is located some 30 to 40 feet from where the train is mounted, so any wiring will need to be pulled through the attic. This in itself is a non issue as I have spent many hours pulling cat6 communications wire, power, and video security cable through the attic in the past.

That sounds pretty cool!  How about posting some pictures?

Have you thought about using the Lionel LCS IR SensorTrack?  You have to have an engine that it works with though.  It can trigger a recording.

I have just glossed through this topic, and maybe I missed something. My question to Don is:

Why are you trying to do this project the hard way, and reinvent the wheel?

All the software you need is already developed. It's called JMRI, which stands for Java Model Railroad Interface. It's free (no offense Harvy).

Why are you trying to detect off the center rail?

You have virtually free detection, as long as you are using a brand of track with the outside rails aren't electrically connected, think Gargraves, Atlas or MTH Scale Trax with a diode and a capacitor would do the job.

I'm sorry I didn't say all this at the beginning, six months ago. Probably would have saved you a lot of time and money.

Big_Boy_4005 posted:

I have just glossed through this topic, and maybe I missed something. My question to Don is:

Why are you trying to do this project the hard way, and reinvent the wheel?

All the software you need is already developed. It's called JMRI, which stands for Java Model Railroad Interface. It's free (no offense Harvy).

Why are you trying to detect off the center rail?

You have virtually free detection, as long as you are using a brand of track with the outside rails aren't electrically connected, think Gargraves, Atlas or MTH Scale Trax with a diode and a capacitor would do the job.

I'm sorry I didn't say all this at the beginning, six months ago. Probably would have saved you a lot of time and money.

Though you still need some hardware to interface your third-rail detection with JMRI, don't you?

I use an Arduino spoofing the C/MRI protocol, although I use it to pass all sorts of data to JMRI rather than occupancy itself.

Last edited by Professor Chaos
Big_Boy_4005 posted:

I have just glossed through this topic, and maybe I missed something. My question to Don is:

Why are you trying to do this project the hard way, and reinvent the wheel?

All the software you need is already developed. It's called JMRI, which stands for Java Model Railroad Interface. It's free (no offense Harvy).

Why are you trying to detect off the center rail?

You have virtually free detection, as long as you are using a brand of track with the outside rails aren't electrically connected, think Gargraves, Atlas or MTH Scale Trax with a diode and a capacitor would do the job.

I'm sorry I didn't say all this at the beginning, six months ago. Probably would have saved you a lot of time and money.

None taken, Big Boy.  I would jump at the chance to do something for free.

Big Boy, I like reinventing the wheel, being doing it for years.  As for JMRI it seems to have it's origin and lingo in the DCC and Linux world, not the Lionel TMCC and Legacy world - correct me if I'm wrong.  Can off-the-shelf JMRI talk directly to a Lionel TMCC controller via RS-232?  Anyway I wanted to use the Arduino, not a computer, to automate an existing layout with difficult track access for using isolated sections of outside rail to signal occupancy.  We are running Lionel TMCC which puts a control signal on the outer rails so both of our outer rails are continuous with no breaks.  The center "hot" feeds come back to a common control area and each wire takes a couple of loops through the Hall-effect detector before going to it's power source.  I think that's pretty neat technology.  It was very easy and relatively inexpensive to buy the detector modules which provides an SPDT relay to send a positive occupancy signal to the Arduino micro-controller.  I also want this control to run without any computer needed, just the Arduino Windows-based IDE for programming.  I'm fairly proficient in C programming so it was a hoot to program it, also for RFID train detection and registration, speed calculation and control, and output to an LCD panel, plus other custom goodies.  Sorry my method doesn't fit into your standard paradigm of computer-based, DCC type control - I'm happy with my new wheel!

Professor Chaos posted:
Big_Boy_4005 posted:

I have just glossed through this topic, and maybe I missed something. My question to Don is:

Why are you trying to do this project the hard way, and reinvent the wheel?

All the software you need is already developed. It's called JMRI, which stands for Java Model Railroad Interface. It's free (no offense Harvy).

Why are you trying to detect off the center rail?

You have virtually free detection, as long as you are using a brand of track with the outside rails aren't electrically connected, think Gargraves, Atlas or MTH Scale Trax with a diode and a capacitor would do the job.

I'm sorry I didn't say all this at the beginning, six months ago. Probably would have saved you a lot of time and money.

Though you still need some hardware to interface your third-rail detection with JMRI, don't you?

I use an Arduino spoofing the C/MRI protocol, although I use it to pass all sorts of data to JMRI rather than occupancy itself.

Yes Prof, but a C/MRI S-mini or two would more than cover his I/O needs as I understand them. They come with both inputs and outputs on a single board, no motherboard required as with C/MRI classic. I think the Arduino can run JMRI, but now I'm not exactly sure.

Thanks Harvy.

YES Don, that may indeed be its origin, but all the TMCC codes are built in. It was very nice of the guys who have been working on JMRI for years, to include Lionel TMCC as one of the many code sets. And it is for that reason I have chosen to use JMRI on my massive layout. I'm running 100% TMCC, as DCS codes are not published. If for some reason, I need to buy an MTH locomotive, I first convert it to TMCC. I do this because I eventually want to the computer to be able to run trains, stop, start and speed control.

I used all GarGraves flex track, and only use one outside rail for the ground on the mainline. The other outside rail is divided into segments. I had the advantage of having all the hardware I needed, and planned it this way since the beginning.

I'll admit that my way isn't for everyone, for a whole host of reasons. If your way works for you, that's all that really matters.

 

Big_Boy_4005 posted:

YES Don, that may indeed be its origin, but all the TMCC codes are built in. It was very nice of the guys who have been working on JMRI for years, to include Lionel TMCC as one of the many code sets. And it is for that reason I have chosen to use JMRI on my massive layout. I'm running 100% TMCC, as DCS codes are not published. If for some reason, I need to buy an MTH locomotive, I first convert it to TMCC. I do this because I eventually want to the computer to be able to run trains, stop, start and speed control.

I used all GarGraves flex track, and only use one outside rail for the ground on the mainline. The other outside rail is divided into segments. I had the advantage of having all the hardware I needed, and planned it this way since the beginning.

I'll admit that my way isn't for everyone, for a whole host of reasons. If your way works for you, that's all that really matters.

 

I went to the JMRI website and see no high-level tutorial.  And the control module is called "Decoder-Pro" and talks extensively about DCC, which I know nothing about and have no desire to learn.  Where is the documentation showing how TMCC trains are controlled using JMRI.  It seems like it would take me longer to get spun up on JMRI than to just open the Arduino IDE and start writing C code.  I've already written the Arduino function to talk to TMCC and I have what I consider a neat low-loss way to detect center-rail train occupancy so I'm pretty happy with the approach that I have taken.  Maybe even go public with my Arduino approach as DFRI!  Not sure if an Arduino Mega is capable of hosting the JMRI software or if that's even possible without a JMRI rewrite. Isn't it written in Java?

We use Atlas 21st Century track exclusively, which has insulated outer rails, but using outer-rail isolated sections for occupancy detection, which I have done on many previous layouts, requires long runs of control wires, interrupts the continuity of the TMCC outer-rail signal,  and the Hall-effect current detectors can all be put in one place which appealed to me.  Different folks, different strokes, I guess.

Sounds like you have a very impressive layout.  Where are you located?  Do you have a website?

Don

I have a vague memory of tmcc adapter for jmri but... details are fuzzy to non existent. You know I wrote a java base  lcs controller probably 2 yrs ago now. Well part of one. I could make the horn blow and the engine go and things like that. I never implemented all the commands, there are a lot. And I had this idea that I'd nibble away at it over time. Also not done that either. I even threatened to put it the pubic domain, not done. It is out at gitlab though in a currently private project. And so I encourage you to improve upon my poor example ... any interest in sharing?

I truly appreciate all the input so far. Some additional information on the current setup. All the fastrack sections are soldered and supplied power so as to eliminate(as much as possible) any power loss to distant track sections. I will include pictures of the setup as it stands so far. The original engine ran fine for a while, but broke as time went on. Turns out there were some design/manufacturing defects in that model which precluded using it for future use. We did some research and came up with an engine that was a bit more expensive, but fit the requirements the customer wanted and is compatible with the track and controls. I believe it is a Lionel Wabash locomotive.20180823_09041820180823_09044620180823_11144420180823_11162420180823_09073920180823_09054620180823_09041820180823_09044620180823_11144420180823_11162420180823_09073920180823_09053820180823_090538 

Attachments

Images (7)
  • 20180823_090418: Train and track as it enter the kitchen area
  • 20180823_090446: Track as it exits the kitchen area
  • 20180823_111444: New engine/locomotive
  • 20180823_111624: Controller with power wires to feed each track section
  • 20180823_090739: Track mounted to wall in main store area.
  • 20180823_090546
  • 20180823_090538: Track and train as in enters the kitchen showing mounting and support detail

The reason I thought of a simply IR receiver to sense when the locomotive passed are two fold. First, I believe I read somewhere or it was mentioned to me that the locomotives are built with an IR emitter/detector for use with the Sensortrack  unit. Second, if this is so, then by placing a small multiband IR receiver in the track I should be able to detect that signal as the locomotive passes over and pass that to the arduino mega to initiate commands at each passing. Simple trigger device requiring no modification of the train itself. This would be more than adequate for the layout they currently have. Because of the dimensions, we are unable to lengthen or shorten the track design without purchasing additional track segments and still have enough room for the scenery(trees, rocks, building, etc.). The IR receiver is small enough that a 1/8th inch hole in the track and under layment would suffice, without involving disassembling the current system. Wiring would be simple enough to conceal as 22 or 24 awg would work fine. The main issue is programming the arduino to send commands to the legacy controller as I have very little experience in this aspect with regards to legacy command structure. I have read up/downloaded as much as I could find in order to do so, but seem lost when it comes to understanding legacy. I have no experience in hexadecimal. 

Charlie Rounds posted:

The reason I thought of a simply IR receiver to sense when the locomotive passed are two fold. First, I believe I read somewhere or it was mentioned to me that the locomotives are built with an IR emitter/detector for use with the Sensortrack  unit. Second, if this is so, then by placing a small multiband IR receiver in the track I should be able to detect that signal as the locomotive passes over and pass that to the arduino mega to initiate commands at each passing. Simple trigger device requiring no modification of the train itself. This would be more than adequate for the layout they currently have. Because of the dimensions, we are unable to lengthen or shorten the track design without purchasing additional track segments and still have enough room for the scenery(trees, rocks, building, etc.). The IR receiver is small enough that a 1/8th inch hole in the track and under layment would suffice, without involving disassembling the current system. Wiring would be simple enough to conceal as 22 or 24 awg would work fine. The main issue is programming the arduino to send commands to the legacy controller as I have very little experience in this aspect with regards to legacy command structure. I have read up/downloaded as much as I could find in order to do so, but seem lost when it comes to understanding legacy. I have no experience in hexadecimal. 

Hi Charlie,

I am pretty much an expert when it comes to the TMCC and Legacy command structure since I am a Lionel LCS Partner who has been writing software for years.  I also have many years of Hex experience.  I can help you out if you want.

Harvey, I appreciated any help I can get. Our customer is also a friend, so we are trying to help them as cheap as possible yet give them something that will be pleasing to both them and their customers. It is a small village and where this building sits, long ago was a train depot, hence it is called "The Depot" now. The train tracks have been abandoned and are now a hiking, bicycle, seasonal trail. The train set is a hit with all the children that come in, so getting it up and operational has been an endeavor to say the least. If I were to post a scenario, step by step as to how we would like it to run, all I would need are the legacy commands needed to make the actions work with the base unit. I believe I can program that in to arduino as I have a little experience doing so. I am not so experienced in C, but I believe with the use of my Arduino programming books and examples I will be able to make it work. Again, I really appreciate any help we can get.

"Hi Charlie,

I am pretty much an expert when it comes to the TMCC and Legacy command structure since I am a Lionel LCS Partner who has been writing software for years.  I also have many years of Hex experience.  I can help you out if you want."

********************

Hi Harvey,

I'm glad for the chance to talk to a Legacy command expert.  I'd like to program my Arduino to send serial commands to the Legacy base to blow a diesel horn, or a steam whistle, in a prescribed pattern -- such as long, long, short, long for a grade crossing.  Yet the Legacy "blow horn" command (command 28) gives a very short toot and that's it.

The only solution I've been able to think of is to send a constant stream of "blow horn" commands, every n milliseconds.  However that timing, and the length of the blow, seems to be a little different for each loco.  I did a little testing and the whistle sounded choppy -- sometimes it sounded okay and other times it would stutter.

At worst, I could come up with the maximum delay between "blow" commands that sounds okay, and just spray out hundreds of commands.  But this is complicated by the fact that my Arduino is busy doing a lot of other things, including sending commands to several other locos concurrently, and abiding by a rule suggested by Prof Chaos that transmit bursts should be separated by at least 30ms (and sent in triplicate, which isn't a problem in this case.)

And if I have two or three engines that want to blow their horns at the same time...ugh.  There must be a better way, isn't there?

Have you figured out a way to do this, or does your software rely on the Legacy's built-in record option?

If you're using the brute-force method (per above) kindly share any details such as the delay between subsequent "blow" commands to keep it sounding, and the delay between subsequent any-kind-of commands.  Maybe I'm sending my "blow" commands too rapidly rather than too slowly...???  What is the minimum delay between serial bursts to the Legacy base, in your experience?

Thanks!

Randy

Hi Randy,

Horn commands should be repeated every 100 ms. That will give you a sustained blow as long as the commands keep coming.

If you have access to the LCS WiFi module, the free LCS WiFi Monitor Windows program would give you an easy way to see what commands the Lionel Remote is generating. TMCC commands may be enough for your application and these can be injected directly into the Lionel command base's serial port.

Sending Legacy commands requires an LCS SER2. But again, from reading your description of the desired operation, I think TMCC-style commands should be sufficient.

(http://www.lionel.com/lcs/LCSproducts/page/index.html)

Rudy

Railsounds posted:

Hi Randy,

Horn commands should be repeated every 100 ms. That will give you a sustained blow as long as the commands keep coming.

If you have access to the LCS WiFi module, the free LCS WiFi Monitor Windows program would give you an easy way to see what commands the Lionel Remote is generating. TMCC commands may be enough for your application and these can be injected directly into the Lionel command base's serial port.

Sending Legacy commands requires an LCS SER2. But again, from reading your description of the desired operation, I think TMCC-style commands should be sufficient.

(http://www.lionel.com/lcs/LCSproducts/page/index.html)

Rudy

Hi Rudy!

Thanks so much for this information!  Very helpful.  I do have all of the above products you mention (two of almost everything), and I have monitored the flood of commands in real-time on a laptop.  I was just hoping that Harvy (or anyone) might have knowledge of something I was overlooking -- aside from simulating pulling down on the horn control.

Great to have the 100ms number as a baseline gap.  Not too bad.

Since I have your attention - when sending a number of commands (i.e. several different commands stored in a buffer, such as set momentum, then set absolute speed, then turn on the bell, then trigger an announcement), my understanding is that I can send pairs (TMCC) or triplets (Legacy) of bytes together at the full 9600 baud rate -- but how long should I delay between subsequent commands?  Prof Chaos came up with the idea to leave a 30ms silence between contiguous commands -- whether addressed to the same or a different device.  Is there a standard you guys use?  Or is 9600 baud slow enough that any TMCC or Legacy device can swallow commands as quickly as they can be transmitted?

Thanks again -- your time is very much appreciated!

Randy

I don't know anything about Arduino (including how to pronounce it), but I can tell you that I pause 120ms between Horn commands while a user of my software holds down the Horn button.  This works 99.9% of the time.  You are correct that some engines seem to be pickier than others, but from my experience it is not the engine, it is the processor in whatever device is sending the commands.  It is not going to dedicate 100% of its CPU to sending out commands.  All you can hope for is to use trial and error to get it to work the best you can.  In your case you are lucky.  You are working with a finite number of engines.  For me, It is whatever engines my customers happen to have.

As far as wanting your Arduino to be doing other things while you are sending out Horn commands like there is no tomorrow, I use the "Application.DoEvents();" object in C#.  For my software, it allows it to detect the mouse up event so it can break out of the loop when the user releases the button of the mouse to stop sending horn commands.  It also allows you do anything else you want.

Another option for you, since there will be no user as such, is to create a separate thread to handle just the string of Horn commands.  That way your code can go on and do whatever you want.  If you don't understand the concept of threads, please let me know and I will explain it.

Here is my code for the Horn.  This does not include the Legacy variable horn.  That is separate code.

Let me know if you need me to explain this code more.  It is in C#.

 

I agree that a modest space between commands is prudent. Given the example you posted (set momentum, then set absolute speed, then turn on the bell, then trigger an announcement) I see no down-side to spacing out the commands somewhat. Using the monitor you can see how we handle timing from the remote, for example, when continuously spinning the throttle.

And as Harvy says, trial and error can be your friend!

Railsounds posted:

I agree that a modest space between commands is prudent. Given the example you posted (set momentum, then set absolute speed, then turn on the bell, then trigger an announcement) I see no down-side to spacing out the commands somewhat. Using the monitor you can see how we handle timing from the remote, for example, when continuously spinning the throttle.

And as Harvy says, trial and error can be your friend!

I am the developer behind High Rail for iPhone and iPad (https://highrailcompany.com). For those interested, I gave a talk earlier this year at the St. Louis CocoaHeads group on some techniques for building Lionel Legacy commands in Swift (https://swift.org). I did not, though, go into details on the Wi-Fi PDI protocols or the underlying async network connectivity. You can use the techniques I outline in the presentation and sample code to build type-safe multi-byte commands, too. It's cool stuff.

Here's the sample code: https://github.com/briancoyner/FiddleYard

Regarding the "spacing" (i.e. delay between commands): High Rail has the concept of a composite command that allows me to easily specify uniform delays between a group of homogeneous commands (e.g. dynamic whistle) or arbitrary grouping of heterogeneous commands. The default delay is 100ms, but can be changed as needed.

Lionel's PDI Wi-Fi tool is definitely helpful when debugging/ learning about the LCS/ Legacy/ PDI protocols. 

Perhaps this will be of interest to someone. 

 

 

Harvy posted:

I don't know anything about Arduino (including how to pronounce it), but I can tell you that I pause 120ms between Horn commands while a user of my software holds down the Horn button.  This works 99.9% of the time.  You are correct that some engines seem to be pickier than others, but from my experience it is not the engine, it is the processor in whatever device is sending the commands.  It is not going to dedicate 100% of its CPU to sending out commands.  All you can hope for is to use trial and error to get it to work the best you can.  In your case you are lucky.  You are working with a finite number of engines.  For me, It is whatever engines my customers happen to have.

As far as wanting your Arduino to be doing other things while you are sending out Horn commands like there is no tomorrow, I use the "Application.DoEvents();" object in C#.  For my software, it allows it to detect the mouse up event so it can break out of the loop when the user releases the button of the mouse to stop sending horn commands.  It also allows you do anything else you want.

Another option for you, since there will be no user as such, is to create a separate thread to handle just the string of Horn commands.  That way your code can go on and do whatever you want.  If you don't understand the concept of threads, please let me know and I will explain it.

Here is my code for the Horn.  This does not include the Legacy variable horn.  That is separate code.

Let me know if you need me to explain this code more.  It is in C#.

 

Harvy. thanks for the info. Unfortunately I can’t see the C# code you posted. I see the screen shot in your following post, but nothing for this one. Can anyone else see it?

Randy

Randy P. posted:
Harvy posted:

I don't know anything about Arduino (including how to pronounce it), but I can tell you that I pause 120ms between Horn commands while a user of my software holds down the Horn button.  This works 99.9% of the time.  You are correct that some engines seem to be pickier than others, but from my experience it is not the engine, it is the processor in whatever device is sending the commands.  It is not going to dedicate 100% of its CPU to sending out commands.  All you can hope for is to use trial and error to get it to work the best you can.  In your case you are lucky.  You are working with a finite number of engines.  For me, It is whatever engines my customers happen to have.

As far as wanting your Arduino to be doing other things while you are sending out Horn commands like there is no tomorrow, I use the "Application.DoEvents();" object in C#.  For my software, it allows it to detect the mouse up event so it can break out of the loop when the user releases the button of the mouse to stop sending horn commands.  It also allows you do anything else you want.

Another option for you, since there will be no user as such, is to create a separate thread to handle just the string of Horn commands.  That way your code can go on and do whatever you want.  If you don't understand the concept of threads, please let me know and I will explain it.

Here is my code for the Horn.  This does not include the Legacy variable horn.  That is separate code.

Let me know if you need me to explain this code more.  It is in C#.

 

Harvy. thanks for the info. Unfortunately I can’t see the C# code you posted. I see the screen shot in your following post, but nothing for this one. Can anyone else see it?

Randy

Sorry.  It was there before.  Hopefully you can see this:

Attachments

Images (1)
  • mceclip0
Last edited by Harvy

Well, it has been a bit since I posted, and I wanted to update on our progress to date. I had to wait for the IR receivers (tsop382) to arrive. In the meantime, we captured the various commands sent to the train from the legacy base unit to get an idea of what we were up against. The ir receivers arrived and I wired one up for testing to an arduino mega 2560, programmed it to flash an led signal when it received ir signal from a remote, then today we tested it on the tender behind the engine. The results are positive, it will receive a signal as the tender passes over. I wasn't quite sure if the ir signal from the tender was of the spectrum required, but the test removed all doubt. So we now have all the hardware required, and simply(or not so simply) need to write the software and upload it to the arduino to test. As I stated in previous post, the ir signal is simply a trigger to start a series of commands which will run in a loop, continuous all day until powered down, and will restart in the morning when powered up. Since we won't know the location of the train when power is turned on, it will slowly begin as a normal power up until it passes over the ir receiver at which point it will do certain commands, and repeat those commands for 3 more passes at which point it will slow to a stop, make certain noises intermittently for a period of 20 or 30 minutes, then start the loop over again. This pattern will continue throughout the day until powered down.

Hi Don - it's pretty easy to read and write TMCC or Legacy commands to and from the command base serial ports.  As Rudy mentioned, a SER2 is the most convenient way to go. Do keep in mind that the earth ground (ground for the command base) is supposed to be isolated from layout common (outside rail).

If you take a look at this link, you can find some of my Arduino projects. "Train Control" is a very complex system that automates train control, controls switches, signals, and accessories, and communicates with JMRI running on a computer.  But you will find examples of how to send TMCC, Legacy, and DCS commands over the Arduino serial port.

"Uncoupler Monitor" is a much simpler program that listens to the serial stream from the command base, and activates a relay module in response to commands directed to ACC 1-8.  Essentially a cheap and customizable version of the ASC.

For layout control I like the Arduino Mega, because it has four hardware serial ports. For accessories like the uncoupler monitor I like the Arduino Pro Mini, which is very small and costs less than $10. I am fiddling with transmitting commands from the Legacy base to HC-12 radio modules, with Arduino Minis in rolling stock picking up the radio commands (like a cheap and customizable Mini Commander).



Hi Professor

I have been studying the information you sent and sorry to report, I am confused (to say the least). First of all, when I try to open the files my Mac says I can't read the files and opens Arduino and then all the Arduino file names come up one after theater saying I can't open them. I need to force close Arduino after that. I tried to follow the short page you sent with the train codes, but I don't know what to type in as the parameter items in your function. Is it possible for you to send me (use my email if you wish (davidt@hotray.com) the library that I will need, plus the function calls to perform four actions: 1) Blow a horn of a selected engine (44, 81, 85);  2) Stop a selected engine; 3) Start a selected engine; and 4) operate a turnout. I assume that before the actual function calls I need to have code lines that specify which serial terminals to use. In this case that would be 0(Rx) and 1(Tx).

I thank you.

Add Reply

Post

OGR Publishing, Inc., 1310 Eastside Centre Ct, Suite 6, Mountain Home, AR 72653
800-980-OGRR (6477)
www.ogaugerr.com

×
×
×
×
Link copied to your clipboard.
×
×