Go Down

Topic: rfid compare tag code (Read 5087 times) previous topic - next topic

Loic

Aug 27, 2007, 07:46 pm Last Edit: Aug 27, 2007, 10:38 pm by Loic Reason: 1
Hello everybody,

After weeks of intense testing I succeeded in reading tag codes from the 13.56Mhz APSX RW-210 rfid reader! This is the code: http://www.technicum.net/rfid/rfid_read.pde

It sends the read command via software serial to the rfid reader. Next it reads in the Tag code via hardware serial. Finally it prints a nice tag code to the computer!

Now the problematic part;
As a next step I wanted to compare the tag code to a list of known tags and then do a certain action (for example blink a led). I've been struggling with this for a week now so I decided to ask for some help. This is one of my numerous attempts  :-[
Code: [Select]
#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
int serIn;             // var that will hold the bytes-in read from the serialBuffer
byte serInString[12]; // array that will hold the different bytes
int serInIndx  = 0;    // index of serInString[] in which to inser the next incoming byte
int serOutIndx = 0;    // index of the outgoing serInString[] array;
int ledPin = 13;                 // LED connected to digital pin 13
char Tag1[] = "001B4EC1D014E0D57B"; //known tag code, should become a list of 50+ tags

void setup()  {
 // define pin modes for tx, rx, led pins:
 pinMode(rxPin, INPUT);
 pinMode(txPin, OUTPUT);
 pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 mySerial.begin(19200); // set the data rate for the SoftwareSerial port
 Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
 
 
 mySerial.print(0xfa, BYTE); // request tag code
 
 // only if there are bytes in the serial buffer execute the following code
 if(serialAvailable()) {    
   
   //keep reading from serial untill there are bytes in the serial buffer
    while (serialAvailable()){        
       serIn = serialRead();              //read Serial        
       serInString[serInIndx] = serIn; //insert the byte you just read into the array at the specified index
       serInIndx++;                    //update the new index
    }
   
    //feedback that something was received
    Serial.println ("Processing Tag");
 }
 
 //do somenthing else perhaps wait for other data.
 Serial.println ("NO TAG ");
 
 //print out later in the loop the sentence only if it has actually been collected;
 if( serInIndx > 0) {
     Serial.print("Tag ID=");      
     
     //loop through all bytes in the array and print them out
     for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++) {
         Serial.print((serInString[serOutIndx]), HEX );    //print out the byte at the specified index
           if((serInString[12], HEX) == Tag1[19]) { //compare received tag code to known tag code
           digitalWrite(ledPin, HIGH); // if true blink led
           delay(500);
           digitalWrite(ledPin, LOW);
           delay(500);
           digitalWrite(ledPin, HIGH);
           delay(500);
           digitalWrite(ledPin, LOW);
           delay(500);
         }
         //serInString[serOutIndx] = "";            //optional: flush out the content
     }
       
     //reset all the functions to be able to fill the string back with content
     Serial.flush(); //flush serial buffer
     serOutIndx = 0;
     serInIndx = 0;
 }
   
 //slows down the visualization in the terminal
 Serial.println();
 delay(200);
}


The tag code "001B4EC1D014E0D57B" is the code that I have copied from serial monitor after reading a tag. All my attempts won't make the led blink :( Can someone please help me, I would like to put 50+ tags in the memory that trigger a certain action.

Kind Regards,
Loïc

kg4wsv

Quote
The tag code "001B4EC1D014E0D57B" is the code that I have copied from serial monitor after reading a tag.


This is probably  the hex representation of a binary number, not really a string.  try initializing your target array like this:
Code: [Select]
char target[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b };

Also, I just  glanced at it but your loop function doesn't look right.  You are asking for a new tag every time you run loop and apparently assuming that the data will be returned immediately.  This is not necessarily the case.  You are also assuming that the data is made available in a single uninterupted stream, and this is almost certainly wrong.  Look at the part of the code where you are reading the data; that section probably needs a re-write.

Quote
I would like to put 50+ tags in the memory that trigger a certain action.  

Hmm, the ATmega8 only has 1k of RAM, and your target strings are about 10 bytes long, so that's half the available memory just to store the strings you are matching against.  It'll probably work, as long as the rest of your code isn't too memory intensive, but you should be aware you are approching the limits of the device and method you're using.

Of course,  the 168 has twice the RAM and there are methods for storing data in program space (flash), but they're not as straightforward as the methods you use now.

-j

Loic

#2
Aug 29, 2007, 04:10 pm Last Edit: Aug 29, 2007, 04:12 pm by Loic Reason: 1
Thank you kg4wsv,

I've been trying your suggestions for the last 24hours but with no success. The code that prints the tag code back to the serial monitor was modified from code I found on the web, I'm not such good coder to be able to rewrite it with a new approach to getting the tag codes reported. But as far as printing nice unique tag codes to the serial monitor this code works perfectly, so I'm not sure the "compare tag code to list" problem I'm having is to find in the way this original code works. But being a "C" noob I could be totally wrong.
Next thing I tried was using the <string.h> library, trying memcmp and strcmp. No succes  :( , but again could be my semi-noobness :)

The last weeks I've been looking at this basic stamp code that does exactly what I want to do http://www.digitaldawgpound.org/wp-content/uploads/2007/03/rw210_rfid_reader.bse  (from this project http://www.digitaldawgpound.org/nick84/post=189) trying to understand the data types and sizes to work with (bytes vs chars etc).
Could someone who understands the basic stamp code please help me on the right way? I really appreciate your help.

Regards, Loïc

kg4wsv

String functions are not appropriate, as you are working with chinks of binary data, not strings.  Specifically, C strings are null terminated arrays, which means a byte containgin 0x00 will occur after the contents of the string.  In the example you are playing with, there is a null in the first array element, which means that is a zero length string as far as strcmp() and friends are concerned.  memcmp may be better, but I haven't checked the docs on that one myself.

Your look function needs to look something like this:

Code: [Select]
#define TAG_LEN 8
char target_tag[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b };
void loop()
{
   byte bytes_read=0;
   char tag_read[TAG_LEN];
  // code to request tag data goes here

 // loop here until we get the required number of bytes back from the reader
 // this code will fail unpredicably in the event of communication errors
  while (bytes_read < TAG_LEN)
     while (Serial.available() > 0)
         tag_read[bytes_read++] = Serial.read();

  // compare the tag we read to see if it matches
  if (memcmp(tag_read, target_tag, TAG_LEN))
      do_something();
}


This is off the cuff, so there may be errors, especially at the boundary conditions...

-j

John_Ryan

Quote
Thank you kg4wsv,
I've been trying your suggestions for the last 24hours but with no success.


Ouch, I think most of us know that all too well.

Have you perhaps tried hacking this code:-

http://www.arduino.cc/playground/Learning/PRFID

It's for a parallax, but there might be something in it you could use.

brianbr

Quote
String functions are not appropriate, as you are working with chinks of binary data, not strings.  


The Parallax RFID Reader from Grand Designs sends a start byte of 0x0A, then ten hexadecimal digits in ASCII, then a stop byte 0x0D. Its all 'printable ASCII' so string functions are appropriate. Tie off the ID string by replacing the stop byte with 0x00, then use strcmp() to match to your array of valid IDs.


cheers ... BBR

Loic

#6
Aug 30, 2007, 07:18 pm Last Edit: Aug 30, 2007, 07:19 pm by Loic Reason: 1
@John Ryan: In the past I've tried to modify the parallax rfid code for weeks in a row without any succes (see my other forum post: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1186246253/15).
After this I finally succeeded in printing the the tag codes to serial monitor by modifying some other code I found on the web. But with this last code (the code I posted at the beginning of this topic) I noticed that by changing the variable "serInString" from char to byte the output was always smaller and more equal in length rather than being always different from tag to tag. This is the output for 3 tags using a "char" variable:
00FFFFFFDDFFFFFF8EFFFFFF96E014FFFFFFE010FFFFFFC8
00FFFFFF989FFFFFF96E014FFFFFFE0FFFFFF857B
001B4EFFFFFFC1D014FFFFFFE0FFFFFFD57B
This is the output for the same 3 tags using a "byte" variable:
00DD8E96E014E010C8
0098996E014E0857B
001B4EC1D014E0D57B
These are all printed with the command "Serial.print((serInString[serOutIndx]), HEX );"
I mention all this because maybe the whole problem of comparing the tags to a list is related to this. I've also spotted in the basic stamp code that the tags are in this format
Code: [Select]
'Valid tags

Tag1         DATA     $00, $00, $7B, $7D, $90, $F2, $36, $07, $07, $F2, $03, $7D

Tag2         DATA     $00, $00, $7D, $7D, $1E, $1F, $E0, $E6, $EF, $6E, $04, $04
Thus being 12 hex numbers while I only have 9 in two tags and even one tag (0098996E014E0857B) with 17 character that  I even can't split into HEX (if you know what I mean)

@brianbr: I've tried the "strcmp" command but with no succes, the led flashes, but only when wrong tags a presented. Maybe it's related to the problems described above.

Does anyone see any light in this mess? :-/ Any help is really appreciated.

Kind Regards, Loic

John_Ryan

I've got the same problem, in a round about kind of way. While, my tag checking will be handled outside Arduino, I'd still like a more portable version checking tags inside Arduino.

But, converting char to string I haven't found a means to do that yet, and have spent the better part of two days searching.

Loic

@John Ryan: I would be happy to work together to solve this!

I've reworked my previous code based on the all suggestions. Still no luck :(
This is it:

Code: [Select]
#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

#define TAG_LEN 12

// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

int ledPin = 13;
int serIn;
byte code[TAG_LEN];             // var that will hold the bytes-in read from the serialBuffer
byte bytes_read = 0;
char target_tag[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b };

void setup()  {
 // define pin modes for tx, rx, led pins:
 pinMode(rxPin, INPUT);
 pinMode(txPin, OUTPUT);
 pinMode(ledPin, OUTPUT);
 mySerial.begin(19200); // set the data rate for the SoftwareSerial port
 Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
 
 
 mySerial.print(0xfa, BYTE); //request Tag code
 
 // only if there are bytes in the serial buffer execute the following code
 if(serialAvailable()) {    
   
   //keep reading from serial untill there are bytes in the serial buffer
    while (serialAvailable() && bytes_read < TAG_LEN){                //read Serial        
       code[bytes_read] = serialRead(); //insert the byte you just read into the array at the specified index
       bytes_read++;                    //update the new index
    }
   
    //feedback that something was received
    Serial.println ("Processing Tag");
 }
 
 //do somenthing else perhaps wait for other data.
 Serial.println ("NO TAG ");
 
 //print out later in the loop the sentence only if it has actually been collected;
 if( bytes_read >= TAG_LEN) {
     Serial.print("Tag ID= ");      
     
     //loop through all bytes in the array and print them out
     for(bytes_read=0; bytes_read < TAG_LEN; bytes_read++) {
         Serial.print((code[bytes_read]), HEX);    //print out the byte at the specified index
         //serInString[serOutIndx] = "";            //optional: flush out the content
     }
   if (memcmp(code, target_tag, TAG_LEN) > 0) { //if received tag code == to listed tag code
         digitalWrite(ledPin, HIGH); //do something (blink a led)
         delay(500);
         digitalWrite(ledPin, LOW);
         delay(500);
       }
     //reset all the functions to be able to fill the string back with content
     bytes_read = 0;
 }
   
 //slows down the visualization in the terminal
 Serial.flush(); //flush serial buffer
 Serial.println();
 delay(200);
}


I really can't think of anything else to do. Any help is appreciated.


Regards, Loïc

John_Ryan

That would be good. I need to compare the char variable that the tag is stored, against literals eg. "3300960185". It's not mission critical in my case, but the problems become a nag that I'd like to solve, and it would be nice to have a portable version.

My latest discoveries:-

http://www.arduino.cc/en/Tutorial/TextString

So I'll take a look at it this evening and see what it does.

Someone here also got 3 tags individually recognized, the english is broken, and I couldn't find any code.

http://www.sarades.no/index.php?paged=2

John_Ryan

ok, so that solved my problem.

Here's the revised code including the TextString library:-

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1185507207/30

I'm reading from 8 input switches, if one is pressed, then a reading is taken from the Parallax RFID. If a tag is recognized, all 8 LED's in the 3rd array of 8 LED's flashes. Otherwise, a LED corresponding to the switch pressed, is flashed.

So that's handy for when I need to demo a standalone version. Otherwise, the intent is to check valid tags against a database of tag's stored in a web based .txt file. That parts handled by processing/php so a connection is needed for it to operate (till I buy an Arduino BT).

Loic

Nice!  :)

I'll try it with my reader code first thing tomorrow. It's 2pm now (Belgium), so I better start off fresh tomorrow morning. I'll keep you updated. Thanx again for helping me out.

Cheers, Loïc  

John_Ryan

You should be able to use comma's to separate the tags:-

TextString myTags = TextString(5500); // enough for about 500 with comma's

myTags.setArray("1010101010,1010101011,1010101012,");

Then add a comma after the tag is scanned, and use:-

if (myTags.contains("1010101010,")) {
  // checks if myString contains the subString "1010101010,"
}

The 168 should hold over a thousand unique tags, not bad considering the readers ex China off eBay store 500 and cost about the same as an Arduino, but don't do all the cool stuff Arduino's can do.

Loic

#13
Sep 07, 2007, 11:10 pm Last Edit: Sep 07, 2007, 11:14 pm by Loic Reason: 1
Finally it works!!! This code reads the tag and compares it to a multidimensional array of known tags. If the tag matches to one in the array then an action is executed (blinking a led).
Here's the code:

Code: [Select]
#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

#define TAG_LEN 12
#define ARR_LEN 2
// set up a new serial
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

int ledPin = 13;
int serIn;
byte code[TAG_LEN];             // var that will hold the bytes-in read from the serialBuffer
int bytes_read = 0;
char target_tag[ARR_LEN][TAG_LEN] =
{{0x00, 0x00, 0xdd, 0x8e, 0x96, 0x0e, 0x00, 0x01, 0x04, 0xe0, 0x10, 0xc8 },
{0x00,  0x00, 0x1b, 0x4e, 0xc1, 0x0d, 0x00, 0x01, 0x04, 0xe0, 0xd5, 0x7b}};

void setup()  {
 // define pin modes for tx, rx, led pins:
 pinMode(rxPin, INPUT);
 pinMode(txPin, OUTPUT);
 pinMode(ledPin, OUTPUT);
 mySerial.begin(19200); // set the data rate for the SoftwareSerial port
 Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
 
 mySerial.print(0xfa, BYTE); //request Tag code
     
 if(serialAvailable()){
    //keep reading from serial untill there are bytes in the serial buffer
    while (serialAvailable() && bytes_read < TAG_LEN){                //read Serial        
    code[bytes_read] = Serial.read();
    bytes_read++;  // ready to read next digit
    }
 }
 //do somenthing else perhaps wait for other data.
 Serial.println ("NO TAG ");
 
 //print out later in the loop the sentence only if it has actually been collected;
 if( bytes_read >= TAG_LEN){
   for(int i=0; i<bytes_read; i++){
         Serial.print(code[i], HEX);    //print out the byte at the specified index
           Serial.print(",");
   }
   for(int i = 0; i < ARR_LEN; i++)
   {
     if(memcmp(code, target_tag[i], TAG_LEN) == 0 )
     {
         digitalWrite(ledPin, HIGH);
         delay(500);
         digitalWrite(ledPin, LOW);
         delay(500);
     }
   
   }
   Serial.flush(); //flush serial buffer
}

 Serial.println();
 delay(100);
 bytes_read = 0;
 
 }



Now I'll start cleaning up the code and post a tutorial at the Arduino Playground.
Thank you everybody for the support!
Kind Regards, Loïc

John_Ryan


Go Up