Adventures in the land of Arrfid, Part The Second

In which our heroes frantically rework the RFID reader after catastrophic failure.

I have here visualized the security system as of our last update. We have a parallax rfid sensor feeding serial data to the arduino. The arduino sends that data (over serial) to the controller laptop. The laptop authenticates the tag that comes in, then activates the latching relay (through the parallel port), which then turns on the door.

Door thing

So this next detail isn't clear in this diagram, but where I have marked 'Parallel', what I really mean is that we took an old parallel cable, plugged it into the computer, then cut it in half, and stripped some of the individual wires poking out of the frayed end, soldering them to the relay. This is something you might say is Not Robust (TM).

Naturally, mere days after rejoicing at the completion of this project, someone managed to knock our whole assembly over, severing some of the wires, and just making a mess of things. Instead of repairing the assembly as it existed, Dave decided it would be a good idea to upgrade the system instead, using new code and hardware yet untested. And so it was, on 9PM, Thursday the 10th of February, we decided we would start (essentially) a new, critical infrastructure project from scratch. Go us!

The hardware:

  • An Arduino: a Teensyduino was used for this project because it was what we had on hand, and we could open two serial connections in hardware. If we used a regular arduino, one serial connection would be through hardware, and the other would be through software, but it would still work.
  • A Latching Relay: When using relays, you have to worry about the so-called 'transient spike', which is a many-thousand voltage current that's produced when the electromagnet inside stops receiving power. You do this via a diode and a transistor. With a latching relay, the mechanism is physically different and has protective circuitry built in. You can simply send a 5v signal to one terminal to activate it, 5v to the other terminal to switch it off, no worries about your microcontroller exploding.
  • 12v Power Supply: Hooked to the electric strike through the relay, we just took an old 12v wall wart, snipped the end off and soldered the bare wires to a board. You can be classy and use a barrel connector if you want.
  • Electric Strike: Documented in our previous installment. Ours is in fail-secure mode. If the power ever goes out, the door stays locked. It opens when it receives 12v on the input line.
  • Parallax RFID Module: The parallax RFID reads 12khz tags and sends them via serial to your microcontroller.

With all the pieces in place, the general idea was the same: read an rfid, validate it, then open the door, and in the process, make the whole thing more robust.

Reading the RFID

Take a moment to peruse the sensor's documentation. I'll wait.

The device has 4 pins, one for Vcc (the symbol for your circuit's power supply, for the non-EE types), one for ground, one for serial Tx (transmission), and one for enabling and disabling the device.

In passive RFID, the sensor emits an electromagnetic signal perpendicular to its antenna coils. In this case, the signal operates at 125kHz. When a tag (tuned to the same 125kHz) enters the field in front of the coil, it essentially reflects the signal back, slightly transformed. Encoded in these transformations are the contents of the RFID tag: a 10 digit hex number (fancier tags can hold more information).

Emitting this signal can take up a lot of power, so the reader provides a mechanism to turn itself on and off. This is what the 'rfid enable' line is for. Curiously, if you pull it high, the antenna is disabled. If you pull it low, then it starts reading. Since we're hooked up to wall warts (as opposed to batteries), we decided to leave the reader enabled all the time.

Next is the problem of reading the tag. It outputs on the tx line, 2400 baud serial, which can be read natively by the arduino. Simply hook up the tx (output) from the rfid to the rx (receive, ie: input) on your arduino, then set it to read at 2400, and you're set. The diagram on page 3 shows the output format. It starts with a 0x0A, then 10 bytes of rfid tag data, and then a 0x0D, every single time it reads a tag. You'll also notice that as long as a tag is in sensor range, it will repeat the sequence on the serial line.

You could naively read the serial line until you get something that's neither a 0x0A or a 0x0D, then read 10 bytes, call that a tag, and be on your merry way. That would work... usually. Remember that 125kHz number I gave earlier? The problem is, rfid isn't the only thing that works around that frequency. Flourescent lights, poorly-shielded wiring, and very possibly chocolate cheesecakes all emit signals on that frequency. Another problem is, the wiring from our parallax to our rfid might be noisy. You might just get spurious data coming down the serial line, just from ambient electrical noise. This means that occasionally, you'll get a bad read. Fortunately, the behavior of the parallax gives us a way around it.

The first mechanism we can use is the set of delimiters, 0x0A and 0x0D (coincidentally, the characters for LF and CR, as in CRLF, \r\n). Knowing this, we can reasonably believe that anything in between these two bytes is a tag. In pseudo code,

    function rfid_read():
        read a character from the serial line
        if the character is _not_ 0x0A (\n),
            return null
        read 10 characters into a buffer
        read one more character
        if this last character is not 0x0D (\r),
            return null

        return the buffer with the tag

And, I guess, since we're already here, in actual C,

    int rfid_read(char *buffer) {
        char c = Serial.read();
        if (c != 0x0A) {
            return 0;
        }
        for (int i = 0; i < 10; i++) {
             buffer[i] = Serial.read();
        }
        c = Serial.read();
        if (c != 0x0D) {
             return 0;
        }
        return 1;
    }

Now, that works, more or less. You'll notice that I read into a buffer instead of allocating space and returning a new buffer (maybe you didn't notice. I'm just offering it up). The reason is we don't want to fiddle too much with memory management, but that's a topic for later.

This is pretty great, as it gets around the problem of noise on our serial line (between the rfid and the arduino). If it doesn't have 10 bytes surrounded by our delimiters, it's not data coming from our parallax. We still have a problem though, in that the parallax could still possibly fire incorrectly from stray signals on the 125kHz frequency. To combat this, we use the continuous repeat behavior of the parallax. The theory being, if we read twice and get the same signal both times, then we probably have a legitimate rfid card, and not some random noise.

Again, some pseudocode:

    function read_tag():
        call rfid_read once, and store the value in buffer A
        call rfid_read a second time, store the value in buffer B
        if buffer A = buffer B,
             return the contents of buffer A
        
        return null

And now, some real code:

    int read_tag(char *tag_buffer) {
        char buffer_b[11];         // Use a 10 character buffer, plus one for the null byte
        tag_buffer[10] = 0;        // Assume tag_buffer is also 10 characters long, at least, and set the null byte
        buffer_b[10] = 0;          // Set the null byte, because we don't do it in rfid_read

        if (!rfid_read(tag_buffer)) {
            return 0;
        }
        if (!rfid_read(buffer_b)) {
            return 0;
        }
        
        for (int i = 0; i < 10; i++) {                 // We could use strcmp here, but we're doing it manually for to learn!
            if (tag_buffer[i] != buffer_b[i]) {
                return 0;
            }
        }
        return 1;        
    }

Cool.

So now, we just have to glue it all together. One point to remember is cleanup. After we've successfully read a tag, we don't want any more information out of the Serial buffer. Rather, we don't care about it for a few seconds, at least, so we should flush the serial buffer on success.

All that's left is to initialize the serial port for communicating a tag back to the computer, then read and send.

    HardwareSerial uart = HardwareSerial();

    void flush_serial_buffers() {
        while (Serial.available()) {
            Serial.read();
        }
        while (uart.available()) {
            Serial.read();
        }
    }

    void setup() {
        uart.begin(9600);           // Communicate with the computer at 9600
        Serial.begin(2400);         // Communicate with the rfid at 2400
        flush_serial_buffers();
    }

    void loop() {
        char tag_buffer[11];
        if (read_tag(buffer)) {
            Serial.println(buffer);
            delay(6000);             // Disable reads for 6 seconds
            flush_serial_buffers();
        }
    }

And that, more or less, is that. What we have now is a reliably robust mechanism for reading an rfid tag and sending it to a computer to be later processed.

Next week, on Door Adventures: Revenge of the Door, we'll look at the python side of reading a tag and validating it! Stay tuned! Same bat time, same bat channel!

Comments

door open/close switch works

the sugru did the trick! even though not in use at the moment, the door open/closed switch is operational and hooked up to teensy. needs code to take advantage of it.
the door spaghetti wiring is cleaned up and the cable is long enough and rj45 connected on both ends.

Wiring upgraded

At the PC-side of things, we upgraded the wiring from this old breadboard to this nice tiny little soldered together device

Here you can see romanian and his shiny head, soldering the wires from the door to an rj-45 jack (actually he's taking a break to do some work for his job so he doesn't get fired)

Here's how it looks by the door side

it fits

it really does: safety third (hanging by a thread) and legitimate business (we gots RFID)

Even more jury rigged

The original was even more jury rigged, but somehow still managed to work (until we broke it)
1. The arduino-laptop connection was usb-serial, not plain serial
2. On the laptop itself were two separate python processes. one read rfids from the arduino, the other had a mini webserver and controlled the door strike. The former contacted the latter via making HTTP calls over loopback
3. Also the wires weren't soldered together, but instead connected via a screw terminal block. Actually some were, others connected via solderless breadboard
4. Also the connections and arduino and breadboard were suspended in mid-air, because the cable from the door to the laptop was a couple feet too short. The wires taking the stress of suspending it in air were only 4 tiny wires inserted into the breadboard. A gentle breeze would cause these wires to dislodge and the arduino to drop.
5. Don't forget that the door could also be activated by SMS, though I never figured out what magic got the SMS to the laptop in order to trigger yet another script to look for a code in the SMS and then call via HTTP again to open the door.

Who's online

There are currently 0 users and 11 guests online.

Syndicate

Syndicate content

Ace Monster Toys is a non-profit hackerspace based in Oakland, CA, dedicated towards education, hacking, and maker culture.

Terms of Service | Privacy Policy | Refund Policy | Contact Us

MakerBots