[Documentation] [TitleIndex] [WordIndex

Only released in EOL distros:  

Package Summary

UHF RFID (Ultra-High Frequency Radio Frequency Identification) reader based on ThingMagic Mercury5e (M5e) and Mercury5e-Compact (M5e-C) modules. ThingMagic's highly-capable Gen2 UHF RFID modules interact with low-cost "smart labels" (tags) at distances up to 6 meters depending on choice of antennas (distances over 100 meters possible using highly-directive antennas!) even without line-of-sight visibility, as RF penetrates most non-conducting materials. The reader can simultaneously query for hundreds of tags in the environment at once or query for presence / absence of a individual tag among a sea of others. A stand-alone Python library is provided as well as ROS wrappers.

  • Author: Travis Deyle, Advisor: Prof. Charlie Kemp (Healthcare Robotics Lab at Georgia Tech) and Prof. Matt Reynolds (Duke University)
  • License: new BSD
  • Source: git https://code.google.com/p/gt-ros-pkg.hrl/ (branch: master)

If you decide to use UHF RFID in your project, we kindly suggest taking a look at our lab's RFID in Robotics project page or the Pervasive Computing article: "RFID-Guided Robots for Pervasive Automation" (registration-free pdf).

Hardware Overview:

My UHF RFID reader of choice is the ThingMagic Mercury5e (M5e) and/or Mercury5e-Compact (M5e-C), pictured below left. I have personally verified these readers' operation with over 32 different UHF RFID tag variants, pictured below right (not to scale). Generally, I prefer Alien Squiggle tags; they are available for roughly $0.29-0.59 ea. in quantities of 500-1000 from places like BuyRFID or AtlasRFIDstore. Other tags, such as specialty tags designed to operate on / near metal, are more expensive; AtlasRFIDstore as a nice set of sample packs that give you the opportunity to explore different variants.

ThingMagic Mercury5e:

ThingMagic Mercury5e-Compact:

Generally speaking, I prefer the extra RF output power afforded by the M5e (full), as it translates into greater read ranges; the added antenna port is particularly useful for servoing applications. The M5e-C is also useful, as it can be powered solely off of USB (a hardware design I might elaborate on at a later date). Anyway, ThingMagic has dev-kits available for ~$1,500 that include the cabling, power regulation, an antenna, and some tags -- not a bad deal if you're starting fresh. However, for roughly $60, you can build your own carrier board with TTL RS232→USB (FTDI) already built in. My PCB design (Eagle CAD) can be found her (Design.zip); it can be fabricated by Advanced Circuits for $33 each.

One of the most important considerations when designing your UHF RFID system is the selection of reader antennas (the same considerations apply to tag antennas, but specifications are generally unpublished). This topic is too deep to fully explore here; most critically, you'll want to pay attention to:

Over the last several years, I have experimented with numerous antennas, both purchased and constructed: whips, dipoles, patches, loaded-microstrips, etc. Ultimately, I've settled on these two patch antennas (articulated using Robotis Dynamixel servos); generally choosing the largest antenna possible given robot integration size constraints (see EL-E photos above):

Software Overview:

The communication / software API for ThingMagic's module is obtained upon purchase; I do not believe I am at liberty to distribute my personal copy. However, my open source Python library (depending only on Pyserial) implements a sufficiently rich subset of the API and functions on Windows, Linux, and Mac OS. The stand-alone M5e library is contained in lib_M5e.py. Now for a demonstration, assuming a Linux machine and a M5e (full) reader operating at 30dBm (1Watt) output power:

import lib_M5e as M5e

r = M5e.M5e( '/dev/ttyUSB0', readPwr = 3000 )
r.ChangeAntennaPorts( 1, 1 )
r.QueryEnvironment()

r.TrackSingleTag( 'test_tag_id_' )
r.ChangeTagID( 'test_tag_id_' )
r.QueryEnvironment()
r.TrackSingleTag( 'test_tag_id_' )

r.ChangeAntennaPorts( 2, 2 )
r.QueryEnvironment()

Basically, this code sets up the reader, selects antenna port 1 for both transmit and receive, and queries for all tags in the environment for 50 ms (returns a list of tuples: [(ID, RSSI), ... ] ). Subsequently, the reader checks for the presence of a specific 96-bit tag ID (returns RSSI if read was successful, -1 otherwise). Then the ChangeTagID function changes the ID of the nearest tag (the one read first), and then queries the environment and tracks the tag again. Finally, the last two statements query the environment using the other antenna port.

There is also a M5e_Poller class that can run in a thread and continuously either query the environment or track a tag -- issuing callbacks with argument [antenna_name, ID, RSSI] after each read / read attempt:

import lib_M5e as M5e

def P1(r):
    r.ChangeAntennaPorts(1,1)
    return 'AntPort1'

def P2(r):
    r.ChangeAntennaPorts(2,2)
    return 'AntPort2'

def PrintDatum(data):
    ant, ids, rssi = data
    print data

r = M5e.M5e( '/dev/ttyUSB0', readPwr = 3000 )
q = M5e.M5e_Poller(r, antfuncs=[P1, P2], callbacks=[PrintDatum])
q.query_mode()

t0 = time.time()
while time.time() - t0 < 3.0:
    time.sleep( 0.1 )

q.track_mode( 'test_tag_id_' )

t0 = time.time()
while time.time() - t0 < 3.0:
    time.sleep( 0.1 )

q.stop()

That sums up the stand-alone library. The Robot Operating System (ROS) wrappers act in pretty much the same fashion as the M5e_Poller and can be found in ros_M5e.py (server node) and ros_M5e_client.py (client nodes). Only one server node can connect to the M5e module's serial port at once due to strict device handshaking protocols; any number of client nodes can control / query the server. The server code looks like this:

import ros_M5e as rm

def P1(r):
    r.ChangeAntennaPorts(1,1)
    return 'AntPort1'

def P2(r):
    r.ChangeAntennaPorts(2,2)
    return 'AntPort2'

ros_rfid = rm.ROS_M5e( name = 'my_rfid_server',
                       readPwr = 3000,
                       portStr = '/dev/ttyUSB0',
                       antFuncs = [P1, P2],
                       callbacks = [] )

rospy.spin()
ros_rfid.stop()

By default, the server does nothing (standby to save power). A client node must put the server into either QUERY_MODE or TRACK_MODE. This can be accomplished using any client. For example, using rosservice:

>  rosservice call /rfid/my_rfid_server_mode "['query']"
>  rostopic echo  -c /rfid/my_rfid_server_reader
[OUTPUT HERE]
>  rosservice call /rfid/my_rfid_server_mode "['track', 'test_tag_id_']"
>  rostopic echo  -c /rfid/my_rfid_server_reader
[OUTPUT HERE]
>  rosservice call /rfid/my_rfid_server_mode "['stop']"

The last call puts the reader back into standby mode (any argument other than 'query' or 'track'). The ros_M5e_client.py file implements a rudimentary RFID client that can perform the same operations.

import ros_M5e_client as rmc

r = rmc.ROS_M5e_Client( name = 'my_rfid_client' )
r.query_mode()
r.read( antenna = 'AntPort1' )

r.track_mode( 'test_tag_id' )
r.read( antenna = 'AntPort1' )

r.stop()

The read method for ROS_M5e_Client returns the latest RFID read on the desired antenna as a ROS RFIDread message.


2022-05-28 12:38