Skip to main content

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

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.
×
×