As noted in earlier posts, I am building a model railroad crossing gate signal, complete with gate arms, flashers and sound. Although I haven't settled on exactly how I am going to implement detection of the train entering the zone, determining when its completely passed the entry sensor, tripped the exit sensor and completely passed the exit sensor to re-open the gate, I am researching using RFID for this now.
My thought is to have an RFID card in every car of all my rolling stock. Therefore, I want to read all the ID's of the cars as they go buy and for this particular need, always store the latest ID in a variable so that once the whole train has passed by, the last ID in the variable SHOULD be the ID of the last car in the train. I would also have a counter incrementing for each unique ID read so I can use that as a secondary check for the exit routine (check that the exit RFID reader gets the same car count as the entry reader). The exit reader would also match its exitTag to the entryTag from the entry reader.
I am implementing a state machine to control all this functionality but the problem lies in the RFID reading, I need a way to determine when the reader has read all the train cars tags. I thought the easiest way to do this was to use the elapsedMillis library and monitor for some interval where no card was read (two seconds? that would be way more than the time between two train cars) and once met, change state.
That is proving more problematic than I thought. Here is my latest attempt. I also think it might be better if the tag reading method only returned the last tag ID AFTER ITS DETERMINED NO MORE TAGS TO BE READ so that the code in the case statement is not the code that's running continuously.
Note: I am using the Adafruit RFID shield and Mifare Classic 1k S50 IC 13.56MHz RFID cards.
Any thoughts appreciated
case CrossingZoneState::CROSSINGZONE_RFIDDETECTED:
if (crossingZoneEntered == true)
{
// only thing we do here is monitor and identify the RFID tags of each car to determine last cars tag id
//well, this doesnt work
if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
{
//do all the tag reading in here
tag = IndentifyTag(entryRFIDReader);
readCount += 1;
if (tag != priorTag)
{
tagCount += 1;
}
priorTag = tag;
timeElapsedBetweenCardReads = 0; // reset the counter to 0 so the counting starts over...
}
// need to figure out how to determine no more cards are being read and change state and crossingZoneEntered back to false
}
if (crossingZoneExited == true)
{
}
break;
IdentifyTags method:
uint32_t IndentifyTag(Adafruit_PN532 rfidReader)
{
uint8_t tagID[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t tagIDLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
uint32_t rfidCardID = tagID[0];
boolean success = rfidReader.readPassiveTargetID(PN532_MIFARE_ISO14443A, &tagID[0], &tagIDLength);
if (success) {
// Display some basic information about the card for testing
Serial.println("Found an ISO14443A card");
Serial.print(" UID Length: "); Serial.print(tagIDLength, DEC); Serial.println(" bytes");
Serial.print(" UID Value: "); rfidReader.PrintHex(tagID, tagIDLength);
if (tagIDLength == 4)
{
// Mifare Classic card
rfidCardID <<= 8;
rfidCardID |= tagID[1];
rfidCardID <<= 8;
rfidCardID |= tagID[2];
rfidCardID <<= 8;
rfidCardID |= tagID[3];
Serial.print("Mifare Classic card #");
Serial.println(rfidCardID);
}
Serial.println("");
}
return rfidCardID;
}
Full switch statement:
switch (state)
{
case CrossingZoneState::CROSSINGZONE_CLEAR:
// only thing we do here is monitor the zone entry sensor
if (digitalRead(entrySensorPin) == HIGH) {
crossingZoneEntered = true;
state = CrossingZoneState::CROSSINGZONE_ACTIVATEGATES;
}
break;
case CrossingZoneState::CROSSINGZONE_ACTIVATEGATES:
// Do these once: turn on the flashers, put down the arms and turn on the crossing gate bells
if (didOnce = false)
{
// turn on flashers
// turn on sound
// lower gate arms
didOnce = true;
state = CrossingZoneState::CROSSINGZONE_READENTRYRFID;
}
break;
case CrossingZoneState::CROSSINGZONE_READENTRYRFID:
// only thing we do here is monitor and identify the rfid tags of each car to determine last cars tag id
// need to figure out how to determine no more cards are being read and change state
if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
{
//do all the tag reading in here
entryTag = IndentifyTag(entryRFIDReader);
readCount += 1;
if (entryTag != priorTag)
{
entryTagCount += 1;
}
priorTag = entryTag;
timeElapsedBetweenCardReads = 0; // reset the counter to 0 so the counting starts over...
}
else {
//change state now that entry rfid tag reader is finished
state = CrossingZoneState::CROSSINGZONE_OCCUPIED;
}
break;
case CrossingZoneState::CROSSINGZONE_OCCUPIED:
// only thing we do here is monitor the zone exit sensor
if (digitalRead(exitSensorPin) == HIGH) {
state = CrossingZoneState::CROSSINGZONE_READEXITRFID;
}
break;
case CrossingZoneState::CROSSINGZONE_READEXITRFID:
if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
{
//do all the tag reading in here
exitTag = IndentifyTag(entryRFIDReader);
readCount += 1;
if (exitTag != priorTag)
{
exitTagCount += 1;
}
priorTag = exitTag;
timeElapsedBetweenCardReads = 0; // reset the counter to 0 so the counting starts over...
}
else {//check tags and count now that entry rfid tag reader is finished
if (entryTagCount == exitTagCount && entryTag == exitTag)
{
state = CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES;
}
}
break;
case CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES:
// Do these once: turn off the flashers, raise the arms and turn off the crossing gate bells
if (didOnce = true)
{
// turn off flashers
// turn off sound
// raise gate arms
didOnce = false;
}
break;
case CrossingZoneState::CROSSINGZONE_ERROR:
boolean success = writeToFileOnSD(modelRRErrorLogFile, "ModelRRXingErrorLog.txt", "error string");
break;
}
crossingZoneEntered
andcrossingZoneExited
? What do they represent in terms of your train's movements? Is this code for the entry reader or the exit reader? – SoreDakeNoKoto May 5 '16 at 1:20