A blog documenting projects and ideas

Automated readings of an RFID tag in a metal trolley

For a college project, I’m working on an automated product identification system for trolleys used in shops. As you can see from the above picture, this would involve mounting an antenna (attached to an RFID reader) on a trolley. All of the products in the shop would have small RFID tags on them and as soon as a customer takes one off the shelf and puts it in the trolley, it is detected and registered.This sounds simple enough but there are lots of problems with the idea. In this case the trolley is a metal grid and radio waves and metal don’t mix all that well. Reflections in the trolley can cause ‘blind spots’ due to destructive interference and things of that nature. Without doing experiments , there is no way to know how well it will work. In this case its best to do the experiment and then think about the theory afterwards. The proposed experiment is this:

1. Mount antenna on trolley ✓
2. Place and RFID tag in the trolley at certain positions
3. For each position the product is in, try to read it with less and less power to see how low it can go before being unreadable.
4.After that is done, move the antenna to a different part of the trolley to see how the results differ

Here are all the spots where I am going to place the product with a tag on it:

numbered_trolley

This is a picture of the empty box with said tag on it:

box with tag

Here are some places where I might put the antenna. First one is where it is at the moment, mounted on the handle. Or it could be mounted on the front of the trolley or even mounted under the trolley:

In my last blog, I wrote a Python script to decrease the reader antenna transmit power from 30dBm down to 0dBm whilst measuring the received tag signal strength. This is useful because you can quickly see what the lowest power that can be used is. Here is an example graph of that script, the tag was placed in the trolley and this is the output:

Plot of Transmit power vs tag signal strength

So now the experiment is slightly different so I modified the script to run 9 times, each time it runs a line is added to the graph. So at the end there are nine lines on the graph, with each line representing a different position in the trolley. After the program gets one set of readings ( at one position ) it waits for the user to press enter before it takes the next set of readings, this allows me time to move the product to a different position in the trolley.

Here is the Python Script:

# Program written by Shane Ormonde 19th March 2014
# Reader power level is reduced from 30dB to 0dB
# measurements every 1dB
# this repeats 9 times to get 9 sets of results
# plots transmit power vs received tag signal strength for each
# different position
import socket
import xml.etree.ElementTree as ET
import matplotlib.pyplot as plt
TCP_IP = '192.168.0.113'
TCP_PORT = 80
BUFFER_SIZE = 4028
#Variables
tags = []
r_power = []
t_power = []
T_power = []
epc = 0
tag_power = ''
new_power = ''
def send_xml_get_data():
f = open('find_tags.xml','r+') ## open xml file to send to reader
data = f.read() ## read it as a string into variable data
f.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set up socket connection
s.connect((TCP_IP,TCP_PORT))
s.send(data) ## send the xml file
rdata = s.recv(BUFFER_SIZE) # xml file returned by the reader
s.close()
f = open('tag_data.xml','w')
f.write(rdata)# write it to a file called tag_data.xml
f.close()
def parse_xml(): # this function opens the xml file from the reader and gets the data we want from it
tree = ET.parse('tag_data.xml')## load the received xml file for parsing
root = tree.getroot()
for tag in root.findall('tag'): # find the child called 'tag'
epc = tag.find('epc').text ## within that child get the epc number of the tag
tag_power = tag.find('dbm').text ## also ge the tag signal strength
print "tag signal strength = " + tag_power
if epc == 'e2003411b802011412255232': # this is just to ensure that no other tags are accidentaly read
r_power.append(tag_power)
def decrement_power(): #opens the xml file and overwrites the number in the 'power' tag
tree = ET.parse('find_tags.xml')
root = tree.getroot()
for roSpec in root.findall('roSpec'): # read back this new power level and print to screen
power = roSpec.find('power').text
print "transmit_power = " + power
t_power.append(power)
for power in root.iter('power'): ## set a new transmit power level
new_power = int(power.text) - 1 # decrease the power by one dB
power.text = str(new_power)
tree.write('find_tags.xml') # write the changes to the file
def set_power_max(): # opens the command xml file being send to the reader and sets the power to 30dB
tree = ET.parse('find_tags.xml')
root = tree.getroot()
for power in root.iter('power'): ## set a new transmit power level
new_power = 30
power.text = str(new_power)
tree.write('find_tags.xml')
def plot(): # plots transmitted power versus received tag power
g = len(r_power) # if the tag cannot be read, the r_power list will have less than 30 elements, this makes the both the same length
T_power = t_power[0:g]
plt.plot(T_power,r_power, colour , linewidth = 2)
plt.grid(True)
plt.axis([0, 30, -70, -35])
plt.gca().invert_xaxis() # this makes 30dB at the origin
plt.ylabel('Receive Power (dBm)')
plt.xlabel('Transmit Power(dBm)')
set_power_max() ## in case the last program failed whilst running and the power is not already at max
for h in range(9):
try:
var = input("Re-position the tag and press enter") ## wait for user to press enter
except SyntaxError:
pass
if h == 0: colour = 'g' ## at each pass, change the line colour
if h == 1: colour = 'b'
if h == 2: colour = 'r'
if h == 3: colour = 'c'
if h == 4: colour = 'm'
if h == 5: colour = 'y'
if h == 6: colour = 'k'
if h == 7: colour = 'r--'
if h == 8: colour = 'k--'
for i in range(30):
send_xml_get_data() # send the command xml, get readers response
parse_xml() # open the xml file and get the wanted data
decrement_power() # decrease the reader transmit power by 1
plot()
set_power_max()
for l in range(30): ## delete the lists so they are empty for the next set of data
try:
t_power.pop()
except IndexError:
pass
try:
r_power.pop()
except IndexError:
pass
plt.show()
set_power_max() ## reset reader power to max

Here is a reference for the graph. So each line can be matched to a position in the trolley:

Results:

Antenna mounted on handle:
(click on the picture to get a full view)

Notice that when the tag is underneath the antenna (solid black line) the received tag power is quite good, but on either side of that position the received power is not nearly as good. The red dotted line is missing because the tag could not be read at that position.

Antenna mounted on the front of the trolley:

Much better results this time. The the tag located opposite the antenna at the back of the trolley (dotted black line) can only be read with max power. Apart from that every other tag can be read down to quite a low transmit power.

Antenna mounted under the trolley:

Fairly terrible result. Note that when the antenna was mounted on the front and back of the trolley, the antenna was ‘peering in’ to the trolley. As in, it wasn’t actually transmitting through the metal grid of the trolley. The under-mounted antenna had to transmit through the metal grid. As can be seen from the graph, this severely attenuated the transmitted signal of the reader.

Conclusions:

Mounting the antenna so that it is ‘looking in’ to the trolley as opposed to trying to transmit through the metal grid of the trolley is definitely the way to go. When the antenna was mounted on the front, I could only mount it vertically due to the slightly awkward position. I will try to mount it horizontally next week and see if that improves results. Also I could try and increase the sensitivity of the reader. This would be at the expense of read speed but it would be interesting to see what affect that would have.