Mark DiVecchio's O-Gauge Train Layouts

1992 Layout Page

2006 Layout Page

2009 Layout Page

P&LE Postcards by Howard Fogg 

Plasticville Buildings

Portable Layout Page

Train Clubs

Bing Track

Remote Train Control Program

YouTube Channel

OOK Radio Support

Technical Videos

ADPCM - Playing clips from .mth sound files

P&LE McKees Rocks Locomotive Shop
3D Printer Project

White Tower Restaurant
3D Printer Project


Train Detection using PN532 RFID Modules

This Page last updated on .


On this page, I describe the work that I've doing to implement a method of train detection on my layout. My layout uses 3-rail tubular track so al of the work that I've done is with that kind of track. I expected to see (and I did) that the metal track would affect the operation of the tag reader.

This is based on the work that I did for the Remote Train Control (RTC) program and OOK Radio Support.

Prior Art

Two people that I've been working with have implement schemes to do train detection.

Mike Hewett

Mike has implemented a scheme where the tag reader is inside of a car. The tags are mounted below the track. The tag reader detects a tag and sends a response via a Zigbee radio to the control computer.

Ray Leiter

Ray's implementation uses a tag reader under the track (he uses FastTrack) with tags mounted under the engine.

Here is a video that Ray did showing his work:

Image loading....


Ray has an RFID tag reader under the track. It connects to an Arduino and an Elechouse CC1101 radio. He has the Arduino programmed to send out an SXS command each time a train is detected. He uses the UID on the tag to know which engine was detected so that SXS command addresses the right engine.

My Ideas

I'm looking at an implementation similar to Ray's. I envision a scheme where there are tag readers at strategic places around the layout. RFID tags are attached underneath every engine and car on the layout. Tags are programed with information about the engine/car to which they are attached. A control computer could then use that tag information to control the engines.

I would use the radio and commands that I developed for the RTC program using OOK transmission codes.

Needs to be cheap. I choose the 13.56 MHz tags.

I plan to put two tags on each engine, one on the front truck and one on the rear truck. Cabooses will have one tag on the rear truck. All other cars will have a tag in the middle of the body. I plan on each tag having information about its distance from the end of the car. I hope to be able to couple/uncouple, Pikov Andropov cars automatically via the control computer.

So what can we do with this. I envision a "smart" control program which gets the tag information and controls the trains. Say, for example, you are running one freight train, doing switching to drop off and pick up cars. Let a computer run another freight train in the other direction. The computer would know where your train is and control the other train to take sidings to keep out of your way.

Or maybe, the computer controls a first class train over the layout while you, controlling a peddler freight, have to figure out how to keep out of its way while still doing your work.

Hardware

Here is the hardware that I looked at and the hardware that I finally selected.

RFID Tag readers

I looked at three different RFID tag reader boards. They all operate at 5V.

Blue NFC Board

I bought this board on eBay (search for PN532). It has the antenna adjacent to the circuitry. I attached it beneath the track with the "NFC" logo under the tracks, facing up.



Red NFC board by Elechouse

This board is from Elechouse.  The antenna surrounds the circuitry. I attached it beneath the track with components facing downward. Be warned that there are many knockoffs of this board on eBay. I tested both the genuine board from Elechouse and a knockoff board from China. Be very careful not short the printed circuit board etches to the track. I did and burned out the NFC board and the attached Arduino.




NFC board with External Antenna by Elechouse

This board is from Elechouse.  I attached the antenna under the track with antenna side facing downward.


.

Tags

I selected several different tags to test. All of these tags could be programmed with up to 768 bytes of information. They all worked at 13.56 MHz.

Found on eBay, these transparent NFC tags were mounted on a 25 mm PVC disk.



Found on eBay, these white sticker style tags with adhesive. 25mm(diameter)




This tag, from Adafruit was really small and would be especially easy to mount underneath engines and cars. Size: 15.6mm x 6mm



Also from Adafruit, this sticker style tag. Size: 41mm x 24mm x 0.2mm / 1.6" x 1" x 0.008. Per the Adafruit web page : "Works about 2.5" away from reader". Wow - that would be great, but these tags were pretty large.



Arduino Uno with one Tag Reader Attached


I used an Arduino running at 5V because the RFID tag reader boards operate at 5V.



Connection to the Arduino


All of the RFID tag readers that I tested can connect to the Arduino three different ways. I used the SPI method. SPI uses a simple synchronous serial communications with a separate select line.

Using the SPI required small switches on the tag reader board to be changed (the boards default to RS232 style serial connection).

SPI uses four signal lines plus 5V power and ground. Three common control lines connect to all SPI devices attached to the Arduino. They are SCK, MISO and MOSI. The fourth signal line, SS/CS,  is a chip select line which is unique to each SPI device. I used the ICSP header for the three common control lines :



I connected the SS/CS pin of the tag reader to pin 10 on the Arduino. I conected the other three SPI pins to the ICSP header on the Arduino. Look at the drawing above for MISO (pin 1), SCK (pin 3) and MOSI (pin 4). I then used VCC (pin 2 - 5V) and ground (pin 6)

First Tests

Download and install the latest Arduino IDE.

The Arduino required libraries to interface with the RFID tag reader boards. There are several libraries floating around. The one I used can be downloaded from here. The downloaded file should be named PN532-PN532_HSU.zip.

Once you unzip the file, you should have five folders inside of a top level folder. Move these five folders into your Arduino Libraries folder (usually at : C:\Users\<username>\Documents\Arduino\libraries).

The five folders are:

NDEF
PN532
PN532_SPI
PN532_HSU    (not used but gets loaded with the whole library)
PN532_I2C    (not used but gets loaded with the whole library)

I wrote a simple test program based on the examples in the Arduino PN532 library. Using the Arduino IDE, I displayed each tag as it was detected. I mounted each tag reader underneath the track. I mounted the tag at the lowest spot on the engine that I used. Knowing that the metal of the engine would affect the operation, I mounted the tag with double sided foam tape so that as much of the tag as possible was in "free air" and not near metal.

Results

There were clear winners. First the really large tag worked the best. But it was too hard to mount inconspicuously under the engine or car. The smallest tag did not detect at all. The tag in the transparent PVC mounting was the best overall. It was solid enough to be able to extend into "free air" without distorting. The round white tags were too floppy and tended to get picked by the switch tracks on my layout.

For the boards, it was clear that the Elechouse version with the separate antenna was the best at detecting tags through the metal 3-rail tubular track.

I tried the tag reader boards running at both 5V and 3.3v. I found that 5V operation gave a few millimeters more detection range.

Arduino Uno with Multiple Tag Readers attached

One of my goals was to have multiple RFID tag readers attached to each Arduino. The three common control lines (SCK, MISO, and MOSI) are connected between the Arduino and all the tag readers. The fourth control line (SS) is unique to each tag reader. SS can be connected to digital pins 2-10 and analog pins 0-5 for a total of 15 tag readers attached to each Arduino. The most I have tested is 4 tag readers. I'm thinking that one Arduino would handle train detection for a passing siding. That would be 6 tag readers, 3 each surrounding each of the two switches that make up the passing siding. That way you can detect trains entering the leaving the siding on all tracks.

Elechouse PN532 & NDEF Libraries

I had to edit the PN532 library. The library allocates a 255 byte buffer for each tag reader. An Arduino with 15 readers would then require 3825 bytes of  RAM. Each Arduino Uno only has 2,048 bytes of RAM so we would have a problem.

Since each tag reader (in my code) is read sequentially, only one 255 byte buffer is actually needed. I made this change to the code:

    From the PN532.h in the PN532 folder, remove the definition of
      uint8_t pn532_packetbuffer[255];
    and add this line just after the #ifndef at the beginning of PN532.h
extern unsigned char pn532_packetbuffer[255]; 
    Here is what the beginning of PN532.h should look like:

/**************************************************************************/

/*!

@file PN532.h

@author Adafruit Industries & Seeed Studio

@license BSD

*/

/**************************************************************************/
#ifndef __PN532_H__

#define __PN532_H__

extern unsigned char pn532_packetbuffer[255]; // Add for Mark's Train Detection sketches

#include <stdint.h>


#include "PN532Interface.h"


    Here is what the end of the PN532.h should look like:

private:
    uint8_t _uid[7];  // ISO14443A uid
    uint8_t _uidLen;  // uid len
    uint8_t _key[6];  // Mifare Classic key
    uint8_t inListedTag; // Tg number of inlisted tag.
    uint8_t _felicaIDm[8]; // FeliCa IDm (NFCID2)
    uint8_t _felicaPMm[8]; // FeliCa PMm (PAD)
    //uint8_t pn532_packetbuffer[255];    // Remove for Mark's Train Detection sketches
    PN532Interface *_interface;
};   
#endif


Any sketch which uses this library must actually define the buffer by adding this global which must be in the calling sketch as
      unsigned char pn532_packetbuffer[255];
Once you make this change, the example NFC sketches in the downloaded library won't work any more unless you add the definition of the buffer in each sketch.

RTC Tag Defintion Header File

Next get a copy of the header file that I wrote that includes the defintion of the information loaded into the tag. The header file also includes the definition of the RS-232 packet sent by the Arduino back to the control computer over the serial connection.  You can download that file from here.

Create a folder inside your library folder (next to the NDEF and PN532 folders). Name it RTC_NFC and place my header file RTC_NFC.h into it.

Spend some time studying this header file as it defines all of the import tag and communication information. Here is a copy to look at. If you are going to actual do some programming, download the latest version of the file using the link above.

Here is a listing of the RTC_NFC.h header file
(this may not be as up to date as the zip file linked to above):

/*
* RTC_NFC.h
*
Remote Train Control Program for Windows

© Copyright 2018 by Mark DiVecchio <markd@silogic.com>

This file is part of Remote Train Control.

Remote Train Control is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Remote Train Control is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Remote Train Control. If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------
* Author: Mark DiVecchio
* Creation date: 1 Jan 2018
*/

//------------------------------------------------------------------------------------------
// Engine Data Structure

struct ED { // Engine Data in binary
uint8_t TagID; // 0 = tag not programmed, 0x88 = tag is programmed
#define TAG_PROGRAMMED 0x88
uint8_t EngineNo; // 0 = not an engine (look at CarType), otherwise Engine Number 1-99 (look at CarType)
#define NOT_AN_ENGINE 0
uint8_t TagLocation; // 0 = Tag not on a truck, 1 = Tag on Front truck, 2 = Tag on Rear truck (Engines and Cars)
#define NOT_ON_A_TRUCK 0
#define TAG_ON_FRONT_TRUCK 1
#define TAG_ON_REAR_TRUCK 2
uint8_t EngineType; // 0 = not an engine, 1 = Diesel, 2 = Steam (Engines Only)
#define NOT_AN_ENGINE 0
#define DIESEL_ENGINE 1
#define STEAM_ENGINE 2
uint8_t Coupler; // 0 = no coupler, 1 = rear coupler only, 2 = front coupler only, 3 = front and rear couplers
#define NO_COUPLER 0
#define REAR_COUPLER_ONLY 1
#define FRONT_COUPLER_ONLY 2
#define FRONT_AND_REAR_COUPLER 3
uint8_t SXS; // 0 = no SXS Sound, 1 = has SXS sound at clip 42 (Engines only)
#define NO_SXS_SOUND 0
#define HAS_SXS_SOUND 1
uint8_t CarType; // see list below
// if EngineNo == NOT_AN_ENGINE
#define UNKNOWN 0 // 0 = unknown
#define BOXCAR 1 // 1 = Boxcar
#define TANK_CAR 2 // 2 = Tank Car
#define FLAT_CAR 3 // 3 = Flat Car
#define CABOOSE 4 // 4 = Caboose
#define TENDER 5 // 5 = Tender
#define GONDOLA 6// 6 = Gondola
#define COAL_CAR 7 // 7 = Coal Car
#define ORE_CAR 8 // 8 = Ore Car
#define MOW_FLATCAR 9 // 9 = MOW Flatcar
#define MOW_CRANE_CAR 10 // 10 = MOW Crane Car
#define MOW 11 // 11 = MOW Misc
#define COACH 12 // 12 = Passenger Coach
#define OBSERVATION 13 // 13 = Passenger Observation
#define BAGGAGE 14 // 14 = Baggage
// xx-255 TBD
// if EngineNo != NOT_AN_ENGINE
#define UNKNOWN 0// 0 = unknown
#define GP38_2 1 // 1 = GP38-2
#define GP7 2 // 2 = GP7
#define GP9 3 // 3 = GP9
#define U28B 4 // 4 = U28B
#define BERKSHIRE 5 // 5 = Berkshire
#define DODDLEBUG 6 // 6 = Doddlebug
#define SW1200 7 // 7 = SW1200
#define SW1500 8 // 8 = SW1500
#define SWITCHER_0_4_0 9 // 9 = 0-4-0 Switcher
#define SWITCHER_0_8_0 10// 10 = 0-8-0 Switcher
#define H_9 11 // 11 = 2-8-0 H-9 Consolidation
#define SW_9 12 // 12 = SW-9
// xx-255 TBD
uint8_t Railroad; // 0 = unknown or other, 1 = P&LE, 2 = A&S, 3 = NYC, 4 = B&O, 5 = P&E
#define UNKNOWN_OR_OTHER 0
#define P_AND_LE 1
#define A_AND_S 2
#define NYC 3
#define B_AND_O
#define P_AND_E
#define LE_AND_E
uint8_t CarLength; // Length of car in centimeters, coupler face to coupler face (include Tender)
uint8_t TagOffset; // Distance from center of tag to coupler face in centimeters
// for engines/cars with two tags, the distance must be same for both tags
union {
struct {
uint8_t n1; // --
uint8_t n2; // --
uint8_t n3; // -- Up to 6 digit engine/car number in ASCII (w/leading zeros) "002808"
uint8_t n4; // --
uint8_t n5; // --
uint8_t n6; // --
};
uint8_t CarNumber[6]; // Up to 6 digit engine/car number in ASCII (w/leading zeros) "002808"
};
};
//
// Packet Format - TBD - under development
//
// offsets of certain fields in the ASCII data packet
#define SOPIDX 0
#define BOARDIDX 2
#define PORTIDX 4
#define TAGCOUNTIDX 6
#define PACKETTYPEIDX 8
#define BYTECOUNTIDX 10
#define DATAIDX 12
// then starting at DATIDX:
#define TAGIDIDX 0
#define ENGINENOIDX 2
#define TAGLOCATIONIDX 4
#define ENGINETYPEIDX 6
#define COUPLERIDX 8
#define SXSIDX 10
#define CARTYPEIDX 12
#define RAILROADIDX 14
#define CARLENGHTIDX 16
#define TAGOFFSETIDX 18
#define CARNUMBERIDX 20 // for the next 12 characters

struct CMD { // Packet in ASCII
union {
uint8_t StartOfPacket[2]; // SOP
unsigned char Packet[2];
};
uint8_t Board[2]; // Sending board nmber
uint8_t Port[2]; // used for target board # for type 5x commands
uint8_t TagCount[2];
uint8_t PacketType[2];
uint8_t ByteCount[2];
uint8_t Data[32 + 1 + 1]; // data (32 bytes) + checksum + EOP
};
struct Packet_Header { // Packet header in binary
uint8_t SOP; // SOP
uint8_t Board; // Sending board nmber
uint8_t Port; // used for target board # for type 5x commands
uint8_t TagCount;
uint8_t PacketType;
uint8_t ByteCount;
//uint8_t Data[32 + 1 + 1]; // data (32 bytes) + checksum + EOP
};
/*
* Message packet format
*
* character based packet. digits '0' to 'F'
* Start of Packet and End of Packet are special hex codes to help identify the
* packet boundaries.
-------------------------------
Start of packet character - 2 hex digits
Sending Board # - 2 hex digits - number starting at 1
Port # - 2 hex digits - number starting at 0
Tag Counter by board - 2 hex digits - modulo "FF" - 0-255
Packet type 2 hex digits : Error - Tag - Information/Status - Command
Byte Count - 2 hex digits - count all digits in the Data packet
<----> Data Packet
Checksum - 2 hex digits - 8 bit binary sum of all characters between Start of Packet and End of Packet
End of Packet character - 2 hex digits
-----------------------------------
*/
#define START_OF_PACKET 0xFF // Start of Packet Character
#define END_OF_PACKET 0xF0 // End of Packet Character
//Error:
//0x10 Didn't find PN53x board on port X
#define PN53xNOTFOUND 0x10
//0x11 Unable to read Block X
#define CANTREADBLOCK 0x11
//0x12 Tag not Programmed
#define TAGNOTPROG 0x12
//0x13 Unable to authenticate
#define AUTHERROR 0x13

//Tag:
//0x20 not used
//0x21 Block 4
#define TAGDATABLOCK4 0x21
//0x22 Block 5
#define TAGDATABLOCK5 0x22

//Information:
//0x01 Hello X RFID Readers Attached
#define HELLOPACKET 0x01
//0x03 Board Y Tag X Detected
#define TAGDETECTED 0x03
//0x04 Found chip PN5xx
#define PN53xFOUND 0x04
//0x05 Waiting for an ISO14443A tag detection
#define WAITING 0x05

//Command Packet Received (TagNo contains the target board number):
//0x50
//0x51
//0x52



Programming the RFID Tag reader

Using one of the examples supplied in the library, I wrote a sketch, which I called RTCNFC, to monitor up to 15 tag readers and when a tag is detected to send a packet of information out of the hardware serial port.

You can download the sketch from here. A few important sketch variables and #defines:

#define BOARDNUMBER 1   // Arduino board number 1-x must be unique
// Each arduino can can service up to 15 PN532 ports using both digital and analog pins for the select - SS/CS signal
// pins D10 D9 D8 D7 D6 D5 D4 D3 D2 - -   A5 A4 A3 A2 A1 A0  // 9 digital pins work as SS, 6 analog pins work as SS/CS
// typically pin D10 is used by the CC1101 radio if that is used in your implemetation.
// In this sketch, A0 is used for the LED.
#define PORTCNT 4      // number of NFC Readers attached - maximum 15
// Port Address pins for SS. Put these in the order you need based on your wiring of the PN532 reader boards
uint8_t PortAddress[15] = {A5, 2, A3, 3, A1, A4, A2, 4, 5, 6, 7, 8, 9, A0, 10}; // A0 (LED) and D10 (Elechouse CC1101 Radio) used by other interfaces
#define LED A0         // Non standard LED since pin 13 is used by the SPI interface
Each board must be given a unique board number using BOARDNUMBER. Tell the sketch how many tag readers are attached using PORTCNT. PortAddresses[15] should list, in order, the Arduino pins connected to the SS line. Only the first PORTCNT pins are actually used by the sketch. I picked this order randomly and you can use any order. My sketch uses A0 for the LED and 10 is reserved for a possible radio.


Example of an Arduino with one Tag reader

Image loading....
 

On this Arduino, I've connected up SCK, MISO and MOSI. SS/CS is connected to pin A5 (Any of 15 pins can be used, I picked this one). 5V and ground are connected. For an indicator, I used an LED on pin A0. This LED blinks whenever a tag is detected. Tag is mounted under the track with antenna side down so that there is no chance of shorting the antenna to the track. I'll explain about the white wires a later on this page.

Example of an Arduino with four Tag readers


Image loading....


On this Arduino, I've connected up SCK, MISO and MOSI to 4 tag readers. SS from each tag reader is connected to pins A5, 2, A3 and 3 (Any of 15 pins can be used, I picked these). 5V and ground are connected. For an indicator, I used an LED on pin A0. This LED blinks whenever a tag is detected. For my testing, I only used 3 of the readers which you can see placed underneath the track.

Programming the tags

The RTCNFC sketch can also write engine/car information to the tag. This information is sent out the hardware serial port when the tag is detected.

To write information to the tag, first, edit this line

// set to 1 to write a tag - Write only occurs with PORTIDX 0
#define WRITEON 0

to set WRITEON to 1

// set to 1 to write a tag - Write only occurs with PORTIDX 0
#define WRITEON 1

This will write tag data to the first tag detected on tag reader 0.

Setup the data to be written by editing the sketch (I know that this not a really good solution and I need something with a better user interface). So fill up the data structure Tag.CarData and Tag.CarName. The first of these will be written to block 4 of the tag and the second to block 5. The data written from Tag.CarData is read up when a tag is detected and sent out the hardware serial port of the Arduino.

Here is the section of the sketch RTCNFC.ino which writes the tag
(this may not be as up to date as the zip file linked to above):

//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------

if (PortIdx == 0) { // only write with first (zeroth) NFC Port
// If you want to write something to test with, the following
// few lines write data to blocks 4 and 5. This would not normally
// be done in a sketch that reads tags only
if (TagCount == 1) { // only write once
// Prepare block 4 data -----------------------------
Tag.CarData.TagID = TAG_PROGRAMMED; // Tag programmed code = 0x88
Tag.CarData.EngineNo = 15; // 0 = not an engine (look at CarType), otherwise Engine Number 1-99 (look at CarType)
Tag.CarData.TagLocation = TAG_ON_REAR_TRUCK;
// NOT_ON_A_TRUCK = Tag not on truck
// TAG_ON_FRONT_TRUCK = Tag on Front truck
// TAG_ON_REAR_TRUCK = Tag on Rear truck
Tag.CarData.EngineType = DIESEL_ENGINE;
// NOT_AN_ENGINE = not an engine, DIESEL_ENGINE = Diesel, STEAM_ENGINE = Steam
Tag.CarData.Coupler = FRONT_AND_REAR_COUPLER; // NO_COUPLER = no couplers
// REAR_COUPLER_ONLY = rear coupler only (might be on tender)
// FRONT_COUPLER_ONLY = front coupler only
// FRONT_AND_REAR_COUPLER = front and rear couplers
Tag.CarData.SXS = HAS_SXS_SOUND; // NO_SXS_SOUND = no SXS sound
// HAS_SXS_SOUND = has SXS sound at clip 42
Tag.CarData.CarType = GP38_2; // see list below
// if EngineNo == NOT_AN_ENGINE
#define UNKNOWN 0 // 0 = unknown
#define BOXCAR 1 // 1 = Boxcar
#define TANK_CAR 2 // 2 = Tank Car
#define FLAT_CAR 3 // 3 = Flat Car
#define CABOOSE 4 // 4 = Caboose
#define TENDER 5 // 5 = Tender
#define GONDOLA 6// 6 = Gondola
#define COAL_CAR 7 // 7 = Coal Car
#define ORE_CAR 8 // 8 = Ore Car
#define MOW_FLATCAR 9 // 9 = MOW Flatcar
#define MOW_CRANE_CAR 10 // 10 = MOW Crane Car
#define MOW 11 // 11 = MOW Misc
#define COACH 12 // 12 = Passenger Coach
#define OBSERVATION 13 // 13 = Passenger Observation
#define BAGGAGE 14 // 14 = Baggage
// xx-255 TBD
// if EngineNo != NOT_AN_ENGINE
#define UNKNOWN 0// 0 = unknown
#define GP38_2 1 // 1 = GP38-2
#define GP7 2 // 2 = GP7
#define BP9 3 // 3 = GP9
#define U28B 4 // 4 = U28B
#define BERKSHIRE 5 // 5 = Berkshire
#define DODDLEBUG 6 // 6 = Doddlebug
#define SW1200 7 // 7 = SW1200
#define SW1500 8 // 8 = SW1500
#define SWITCHER_0_4_0 9 // 9 = 0-4-0 Switcher
#define SWITCHER_0_8_0 10// 10 = 0-8-0 Switcher
#define H_9 11 // 11 = 2-8-0 H-9 Consolidation
#define SW_9 12 // 12 = SW-9
// xx-255 TBD

Tag.CarData.Railroad = P_AND_LE; // UNKNOWN_OR_OTHER = unknown or other
// P_AND_LE = P&LE
// A_AND_S = A&S
// A_AND_S = NYC
// B_AND_O = B&O
// P_AND_E = P&E
// LE_AND_E = Lake Erie & Eastern
Tag.CarData.CarLength = 15 * 2.54; // Length of car in centimeters, coupler face to coupler face (include Tender)
Tag.CarData.TagOffset = 1 * 2.54; // Distance from center of tag to coupler face in centimeters
// for engines/cars with two tags, the distance must be same for both tags

Serial.print(F("Tag Programming 0x")); Serial.println(Tag.CarData.TagID, HEX);
Serial.print(F("Engine Number ")); Serial.println(Tag.CarData.EngineNo);
Serial.print(F("Tag Location ")); Serial.println(Tag.CarData.TagLocation);
Serial.print(F("Engine Type ")); Serial.println(Tag.CarData.EngineType);
Serial.print(F("Coupler Type ")); Serial.println(Tag.CarData.Coupler);
Serial.print(F("SXS Equipped ")); Serial.println(Tag.CarData.SXS);
Serial.print(F("Car Type ")); Serial.println(Tag.CarData.CarType);Serial.print(F("RailRoad ")); Serial.println(Tag.CarData.Railroad);
Serial.print(F("Car Length ")); Serial.println(Tag.CarData.CarLength);
Serial.print(F("Tag Offset ")); Serial.println(Tag.CarData.TagOffset);

// -------------------------------------
// Up to 6 digit engine/car number in ASCII (numbers and letters w/leading spaces) " 2808"
memcpy_P(Tag.CarData.CarNumber, F(" 2061"), 6);
// prepare Block 5 data --------------------------
memset(Tag.CarName, 0, sizeof(Tag.CarName)); // zero out the block
memcpy_P( Tag.CarName, PSTR("P&LE GP38-2#2061"), sizeof(Tag.CarName));
{
char buf[17];
memcpy(buf, Tag.CarData.CarNumber, sizeof Tag.CarData.CarNumber);
buf[6] = '\0';
Serial.print(F("Car Number ")); Serial.println(buf);
memcpy(buf, Tag.CarName, sizeof Tag.CarName);
buf[16] = '\0';
Serial.print(F("Car Name ")); Serial.println(buf);
}
// ------------------------------------------------------------------------------
// Write Block 4
success = Port[PortIdx]->mifareclassic_WriteDataBlock (ENGINEDATABLOCK, (uint8_t *)&Tag.CarData); // write block 4 with Engine Data
if (!success) {
PrintBoardNumber(); Serial.println(F("Write Block 4 failed"));
return;
}

// Write Block 5
success = Port[PortIdx]->mifareclassic_WriteDataBlock (ENGINENAMEBLOCK, (uint8_t *) Tag.CarName); // write block 5 with Engine Name
if (!success) {
PrintBoardNumber(); Serial.println(F("Write block 5 failed"));
return;
}
PrintBoardNumber(); Serial.println(F("WriteDataBlocks 4 & 5 Complete"));
}
}
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------


I'll write more instructions about this.....

Arduino Mega 2560

Programming the Mega 2560 to be the control computer


Image loading....


I used an Arduino Mega2560 as the control computer. Its also possible to use a PC as the control computer. The Mega is powered by a 12V wall wart.

The Mega receives tag detection information from each Arduino over the hardware serial port #1 ("Serial1"). Almost any kind of program can written to act on tag detection by the Arduino. Command packets can be built and sent out the radio to a TIU to control engines and accessories. Now we can finally implement the functionality of the Lionel 132 Stop Station.

CC1101 Radio by Elechouse

The radio I use is a TI CC1101 based radio from Elechouse. Note that the image on their web page says RF1100SE but I received the correct version labeled RF1191SE-V3.1. This is a 3.3V device and no signal pin can be connected to a 5V Arduino output.


I connected a big (330uf) electrolyitc decoupling capacitor between VDD (pin 2) and GND (pin 10) on the radio board. I don't know if this is really doing any good or not. You can make it optional.




Be careful  when you connect up the radio. This is a TOP VIEW (or COMPONENT SIDE VIEW) of the board. The pins actually stick out the back side of the board.

Compiling a sketch which uses the CC1101 radio from Elechouse requires my library CC1101E. You can download it from here. In your local Arduino Library folder, create a folder named "CC1101E" and put the CC1101E_OOK library files in it.

Level shifters

Since the CC1101 radio can only handle 3.3v signals, I used a simple (and cheap) level convertor. I found these on eBay. These are bi-directional and can easily handle the SPI command interface to the radio and speed of data TX/RX to/from the radio (9600 baud).  I level shifted 4 signals: SCK, MOSI, SS/CS, and GDO0. Signals going from the radio to the Mega do not need to be level shifted, the Mega can correctly read them even as 3.3V signals.



Radio and Level Shifter Wiring


On the Mega, I connected pins from the ICSP connector to the radio.

ICSP 1 - MISO directly to the radio pin 5
ICSP 3 - SCK to a level shifter then to radio pin 4
ICSP 4 - MOSI to a level shifter then to radio pin 3

then

Mega Pin 53 - SS/CS to a level shifter then to radio pin 7
Mega Pin 11 - GDO0 to a level shifter then to radio pin 8
Mega Pin 3 - GDO2 directly to radio pin 6

then

3V3 directly to radio pin 1 and the level shifter LV pin
GND directly to radio pin 9 and the level shifter GND pin
5V directly to the level shifter HV pin


Interconnection

Image loading....


My goal is to have many Arduino around the layout all feeding tag detections back to a control computer (a Mega2560 or a PC). Each reader sends out a packet of information when a tag is detected. The hardware serial TX output of one Arduino is connect to the RX input of the next Arduino.  Each Arduino monitors its RX pin and when a packet is received, it is forwarded out the TX pin. Eventually the tag detection information all ends up at the control computer.

This photo shows the interconnection between the Arduinos and the Mega. Connecting them is a four wire "telephone" cable. Three wires are used : 12V raw power (VIN), ground  (GND), and serial data. The 12V raw power from a wall wart is plugged into the Mega. The VIN pin sends that voltage down to the string of Arduinos. Each Arduino uses its own voltage regulator to generate 5V for itself and its associated tag reader boards. The hardware serial TX pins are not really designed to send signals over telephone cable and I'm violating the RS-232 spec here but it seems to work. I've got about 10-15 feet of telephone cable between the RX and TX pins. I'm running the hardware serial lines at 38400 baud. I want to eventually raise that to 57600 baud.

Test run with bells and whistles

Image loading....


I wrote a sketch for the Mega. The sketch receives on  RX1, tag detection information from the two Arduinos. The sketch then uses the tag information to send commands over the radio to the TIU and engine.  This is a fairly simple sketch that  rings the bell, blows the whistle and adjusts the engine speed. I called the sketch RTCMegaMaster and you can download from here.

Each time a tag is detected, this sketch receives information about the engine/car attached to the tag, including:
 The video will describe what action is taken as the engine passes over each tag.

More complicated test run with direction changes and different sounds

Image loading....


I edited my sketch called RTCMegaMaster to make it a little more complicated. I added commands to change the engine direction and play a few different sounds. The program also is more random at issuing commands so that it is not just a repeating sequence.

Of course, this isn't doing anything real world-like.

Programming a PC to be the Control Computer

TBD

Unanswered Questions

Since this is a development project, there are still unanswered questions. Paul Reynolds sent me some questions about my questions and added my answers here (Paul's comments in Red).

1. How reliable will the tag detection be?

> You may need to employ redundant systems, e.g. RFID and video, or RFID and
> bar code scanning to get high reliability.

Right now, the tag is 5mm above the track and the track is about 10mm thick. So detection seems good at that 15mm distance from the antenna but I don't know the maximum detection distance. Since I plan to put a tag on every car, I will have to keep that tag as close to the track as possible.

2. Can an Arduino really handle 15 tag readers?

> Are you worried about current draw?  Too high a workload?

I don't know exactly how the tag readers work so it is probably possible that if two (or more) tag readers detect a tag at the same time that the Arduino may not get to the second tag reader before the tag leaves the antenna's field.

I don't know if the tag reader holds the information untill it is read out.

I'm not too worried about current draw. I can always add more 12V current and use separate 5V regulators for the tag readers (right now, I use the Arduino to make the 5V for the tag readers).

3. Can the hardware serial interconnection scheme handle the detection packet traffic?

> Arduinos can handle software serial as I suspect you know.  Why not use
> more than one serial on each Arduino and set up a crude hypercube
> topology?  For a few more ports you can reduce path length, and thus node
> visits, exponentially.

In my scheme, all of the Arduinos are "in series" with respect to the RS-232 lines. That means the most upstream Arduino is relaying the packets from other Arduinos while at the same time handling attached tag readers.

I am using the hardware serial port only and running it at a very high baud rate to try to reduce this problem.

4. Is a Mega powerful enough to work as a control computer or will a PC program be required?

> Never used a mega, but I'm not bothered by using a low end PC as the
> controller.  You could use the PC to do other tasks so its capability is
> not wasted.

I agree, it will probably require a PC.

That brings up the issue of writing a control program that is not deterministic. We would want a program that simulates an train engineer in each cab, making decisions on the fly about what to do rather than a rote step 1, step 2, etc. That is a whole 'nuther can 'o worms.

5. What happens if two tags are detected by two tag readers at the same time?

> Answer depends on whether this question pertains to one Arduino with near
> simultaneous inputs, or multiple Arduinos with near simultaneous inputs.
> The latter shouldn't be a problem.  If you're polling the readers from a
> single Arduino, couldn't you capture inputs in a time-switched manner?
> Reader output probably isn't all that fast..

As I mentioned earlier, I am worried about a tag reader never getting a chance to read out its detection to the Arduino. Right now I poll the readers one by one. I might be able to change this to a interrupt driven scheme.

6. What happens if the hardware serial connection is overloaded?

> Not sure what this question is addressing.  Overloaded by what?  Multiple
> concurrent reader inputs?  Multiple comms from other Arduinos?  Both?

The upstream Arduinos might have a lot of RS232 traffic to forward up to the next Arduino. The hardware serial port can handle fast RS232 but its buffer could still possibly overflow.

The Arduino Mega2560 has 4 hardware serial ports so I could  make four serial pipelines going into the Mega.




This site prepared and maintained by Mark DiVecchio

email :  markd@silogic.com

SD&A HOME
 
 Mark's Home Page

The DiVecchio genealogy home page
The Frazzini genealogy home page

This site will be under construction for a while.