Physical Computing: Wheredipuddit? RFID Inventory Boxes

For my final project in physical computing, I wanted to follow through with one of my pre-ITP goals to accomplish during the program, which I outlined in an older blog post.

Proposal

I wanted to build an inventory system which used RFID/wifi/whatever to check stuff in to boxes, so that when I needed to find something, I could pull it up on my phone or in a browser and ask it where it was, and the box it was in would glow with LED light.  At the same time, these boxes and things would become individuals and traits, respectively, that I could add to or subtract from to create objects with personalities.

Because I hate having to wait for the delivery, here are some videos showing it in action:

Pinging an object from the Wheredipuddit interface:

Pinging an object via QR code (I would show this via a cellphone but I didn’t have another camera):

YouTube Preview Image

Checking in emotions into a box:

YouTube Preview Image

Some Inspirations for This Project

This was an idea somewhat fleshed out in Cory Doctorow’s book “Makers”.  The book involves two hackers who work together in a junkyard to produce lots of low-tech but highly ingenious inventions and gadgets that end up making modestly large amounts of money.  Serial tinkerer-capitalists or something.  Some of the relevant text, from Cory Doctorow’s free (!) online version of “Makers”:

Tjan opened the door with a flourish and she stepped in and stopped short. When she’d left, the place had been a reflection of their jumbled lives: gizmos, dishes, parts, tools and clothes strewn everywhere in a kind of joyful, eye-watering hyper-mess, like an enormous kitchen junk-drawer.

Now the place was *spotless* — and what’s more, it was *minimalist*. The floor was not only clean, it was visible. Lining the walls were translucent white plastic tubs stacked to the ceiling.

“You like it?”

“It’s amazing,” she said. “Like Ikea meets *Barbarella*. What happened here?”

Tjan did a little two-step. “It was Lester’s idea. Have a look in the boxes.”

She pulled a couple of the tubs out. They were jam-packed with books, tools, cruft and crud — all the crap that had previously cluttered the shelves and the floor and the sofa and the coffee table.

“Watch this,” he said. He unvelcroed a wireless keyboard from the side of the TV and began to type: T-H-E C-O. . . The field autocompleted itself: THE COUNT OF MONTE CRISTO, and brought up a picture of a beaten-up paperback along with links to web-stores, reviews, and the full text. Tjan gestured with his chin and she saw that the front of one of the tubs was pulsing with a soft blue glow. Tjan went and pulled open the tub and fished for a second before producing the book.

“Try it,” he said, handing her the keyboard. She began to type experimentally: U-N and up came UNDERWEAR (14). “No way,” she said.

“Way,” Tjan said, and hit return, bringing up a thumbnail gallery of fourteen pairs of underwear. He tabbed over each, picked out a pair of Simpsons boxers, and hit return. A different tub started glowing.

“Lester finally found a socially beneficial use for RFIDs. We’re going to get rich!”

“I don’t think I understand,” she said.

“Come on,” he said. “Let’s get to the junkyard. Lester explains this really well.”

He did, too, losing all of the shyness she remembered, his eyes glowing, his sausage-thick fingers dancing.

“Have you ever alphabetized your hard drive? I mean, have you ever spent any time concerning yourself with where on your hard drive your files are stored, which sectors contain which files? Computers abstract away the tedious, physical properties of files and leave us with handles that we use to persistently refer to them, regardless of which part of the hard drive currently holds those particular bits. So I thought, with RFIDs, you could do this with the real world, just tag everything and have your furniture keep track of where it is.

“One of the big barriers to roommate harmony is the correct disposition of stuff. When you leave your book on the sofa, I have to move it before I can sit down and watch TV. Then you come after me and ask me where I put your book. Then we have a fight. There’s stuff that you don’t know where it goes, and stuff that you don’t know where it’s been put, and stuff that has nowhere to put it. But with tags and a smart chest of drawers, you can just put your stuff wherever there’s room and ask the physical space to keep track of what’s where from moment to moment.

“There’s still the problem of getting everything tagged and described, but that’s a service business opportunity, and where you’ve got other shared identifiers like ISBNs you could use a cameraphone to snap the bar-codes and look them up against public databases. The whole thing could be coordinated around ‘spring cleaning’ events where you go through your stuff and photograph it, tag it, describe it — good for your insurance and for forensics if you get robbed, too.”

He stopped and beamed, folding his fingers over his belly. “So, that’s it, basically.”

Perry slapped him on the shoulder and Tjan drummed his forefingers like a heavy-metal drummer on the side of the workbench they were gathered around.

They were all waiting for her. “Well, it’s very cool,” she said, at last. “But, the whole white-plastic-tub thing. It makes your apartment look like an Ikea showroom. Kind of inhumanly minimalist. We’re Americans, we like celebrating our stuff.”

“Well, OK, fair enough,” Lester said, nodding. “You don’t have to put everything away, of course. And you can still have all the decor you want. This is about clutter control.”

“Exactly,” Perry said. “Come check out Lester’s lab.”

“OK, this is pretty perfect,” Suzanne said. The clutter was gone, disappeared into the white tubs that were stacked high on every shelf, leaving the work-surfaces clear. But Lester’s works-in-progress, his keepsakes, his sculptures and triptychs were still out, looking like venerated museum pieces in the stark tidiness that prevailed otherwise.

Tjan took her through the spreadsheets. “There are ten teams that do closet-organizing in the network, and a bunch of shippers, packers, movers, and storage experts. A few furniture companies. We adopted the interface from some free software inventory-management apps that were built for illiterate service employees. Lots of big pictures and autocompletion. And we’ve bought a hundred RFID printers from a company that was so grateful for a new customer that they’re shipping us 150 of them, so we can print these things at about a million per hour. The plan is to start our sales through the consultants at the same time as we start showing at trade-shows for furniture companies. We’ve already got a huge order from a couple of local old-folks’ homes.”

I kind of read into the book a post-Apple world, where the production process has become so hyper and quick in order to account for gadgetphiles’ fickle tastes that smaller ideas are put into mass production, that grand visions are no longer marketable in a soon-enough timeframe.  What we’re seeing today is the democratization of hardware, following in the shadow of software’s reign, which has dominated the last 30 years or so.  With lots of small shops now selling microcontrollers, Radio Shack retooling its stores to sell circuitry components once again, and the advent of the internet of things and sensor-based objects that are learning how to sense the world around them, our world is going autonomous.  Think military drones, but on smaller scales and for more common-day applications.

Having boxes talk made me think of the TED Talk by the MIT student who built small toy blocks, Siftables, with screens on them which had accelerometers and sensors to detect tilting, proximity to other blocks, etc. and could be configured immediately to play games instructed by the nearby computer:

My classmate Mark Breneman was telling me to look into near-field communication, or NFC.  It’s included in the Nexus S phone for Android:

YouTube Preview Image

This will probably obsolete RFID, but right now it’s not quite cheap enough for usage in the same way that the ID-12 and other RFID readers are.  Its security is an improvement upon RFID though, so it will likely win for more complicated applications.  I’d love to continue doing projects related to presence, identification, and communication using these techs though.

Another classmate (and make: contributor) Matt Richardson sent me this project, “Doh”, which uses RFID and Arduino to help you remember your wallet and keys before heading out the door.

Planning and Ordering Stuff

Here is a sketch I drew for what I want to build, along with some of the components I already ordered to make it work.

“EL tape” in the top-right should read “digital RGB LED strip”.  I bought both but ended up just using the digital RGB LED strip.

I wanted the Indiana Jones-y guy at the bottom to be significantly jowly, as he is in the film, but I think I just ended up messing up his whole head.  I love that quote though.  “We have top men working on it right now.”  “Who?”  “TOP. MEN.”

YouTube Preview Image YouTube Preview Image

I’d love to have a tour of some of the tech behind Walmart’s and UPS’s logistics systems, which reportedly make use of RFID to help with real-time inventory.  The breadth of data and the information that they must be able to extract from it all is staggering to think about.

My system was only composed of two working boxes though, since it gets rather expensive quickly to get wifi-capable microcontrollers (I got Diamondbacks from cutedigi), RFID kits, some RFID stickers, digital RGB LED strips (to make the tupperware boxes I’ll get to glow), 4AA battery packs from Radio Shack to power the microcontrollers, and other assorted power connectors.  I also got some LED screens in case I wanted to do some interface stuff.  The tupperware I bought at KMart.  I had to order plastic PVC ID cards off Amazon.com, as they are surprisingly hard to find in town (Staples didn’t even have them).  Maybe they are a somewhat controlled item because people use them to make fake IDs?

Now, having never played with any of these things, and having never done a physical computing project of this magnitude, I was fully expecting that I would have pieces that wouldn’t work with each other (I’m worried about the cards/tags/stickers and RFID readers being compatible), and that I may have had to buy MORE stuff.  I chose this project because I thought it’d be doable, given my experience and the capability of the hardware.

What I wanted to do is just prototype a simple inventory system where each box has a scanner that lets me “check in/out” objects on an RFID reader, which then passes the data over wifi to my server, which then displays a nice PHP script showing where stuff is.  If I want to find something, the PHP script asks the box that contains it to light up.  That’s about it.  And maybe, if I had enough time, I could let the boxes talk to each other in some silly way.  If I had time.  And if things didn’t blow up in my face.

Well, things kind of blew up in my face.  I gave myself plenty of time, but I ran into tons of problems.  Here’s the process:

Documentation

Sparkfun RFID Starter Kit

I bought a couple RFID starter kits from Sparkfun, which include 2 ID-card sized 125KHz cards, an ID-12 RFID module, and an RFID reader breakout board.  I tested the RFID readers by just plugging in a mini-USB to USB cable I bought from cutedigi.  Those read fine, displaying the RFID card codes into the ZTerm modem comms app for OS X.  That working, I then tried to get the reader to work when connected to my Arduino Uno, using the code posted by Nick Gammon on the Arduino forum.  Soldered wires to the VCC (5V), GND (ground), and TX.  Made sure to not have the TX wire attached to the RX pin on the Arduino while uploading the above sketch.  Then, success!  Successful reading of RFID numbers to Arduino’s serial monitor!

RGB LED Strips

My next task was to get my LPD8806 digital RGB LED strips to work with my Arduino Uno.

YouTube Preview Image

Several other students had worked with the strips for their physical computing projects, so I got some good tips on what transistors, shields, etc. to use for EL tape and EL wire, and what pages to look at.  Lady Ada’s guide was invaluable.

It looked like the RGB LED strips have the potential to draw way too much power for a portable solution.  I was worried I might have to go with EL tape or wire as potential solutions, which provide less visual feedback to the user (the RGB LED strips have individually addressed LEDs that you could make any color and thus give the user visual cues).  At that point, I also started considering what other components could provide feedback.  I wasn’t too happy about using individual LEDs — I thought that might look sloppy.  And a wave shield for playing sounds has its own host of problems: you have to solder the kit yourself, the shield would be inside the box so the sound would be muffled, etc.

I had ordered 2 meters of the LPD8806.  I unsoldered the first meter from the second as instructed by Limor’s (Lady Ada) guide, by peeling the strips apart as I heated them up with a soldering iron.  Then I soldered wires onto the input connections on the strip.

Then I wired everything up according to this diagram, also on the guide:

I had a massive problem understanding the power requirements, as the product page said that you’d need a 2 amp power supply in order to run the strips at full white output.  Well, I tried 1 meter strips with a 4 AA battery pack (with wire-only connectors; bought at Radio Shack).  Those worked great with the strandtest sketch from the LPD’s library I downloaded off Lady Ada’s site.  Success!:

YouTube Preview Image

I was most nervous about getting the LED stuff to work, but they already came with a library with examples to command the LEDs how I wanted; the hard part was figuring out the power and wiring.  4 AA batteries worked fine, when connected with the Arduino and running whites on each LED (though I wouldn’t want to keep it that way, lest it burn out or  be underpowered).  Where I ran into trouble later was when I wanted to run the RFID reader as well; the power draw coming off the LEDs while also running the wifi and RFID code was too much — not enough juice?  I was excited about creating color moods for the containers to represent their feelings, and I was looking forward to a beautiful fade-in, fade-out cyan for when a box says it contains an object I want.

Networking

I bought two Diamondbacks, which are basically ATmega328 chips on Arduino Duemilanove boards with on-board wifi (supporting open networks, WPA, WPA2, and WEP…a key bonus for accessing the multitude of networks out there) on recommendation from my classmate Gavin and my prof, Scott Fitzgerald.

I was a little worried about getting this part working because wifi is still a little sketchy and undocumented in Arduino-land.  I spent hours upon hours downloading different peoples’ libraries and looking through the Arduino.cc and linksprite and asynclabs forums and docs.  I even looked through the Chinese linksprite files, which was painful.

But the example sketches I was trying wouldn’t compile!  I asked Gavin, a classmate, for help and he mentioned that he was using Arduino version 0022, whereas I was using the latest version, 0023 (RC beta 3).  I downloaded 0022 and the sketches started compiling!  Not too long later, I managed to connect my little Diamondback to my WPA2 router!

So here’s what I learned:

  • Get a git clone of the user-contributed WiShield Arduino library from asynclabs.  Install it to your Arduino sketch folder in “libraries/”.
  • Edit apps-conf.h so that only one “APP_” define is uncommented.  For the client-based example sketches (like SimpleClient), uncomment “#define APP_WEBCLIENT”.
  • If things don’t compile and you get weird errors, try a different Arduino version.  I had to install Arduino 0022 to get my Diamondback to work.
  • Opening .pde sketches in Arduino 0023 will cause them to be renamed to .ino, which 0022 won’t see.  So you’ll have to go back and rename the sketch and re-open Arduino 0022 to see it again.
  • I think I had to go track down wire.h on the interwebs and save it as wiring.h because it was missing for some reason, giving me a compiler error message.
  • Make sure you set a static IP on your router for the wifi device to connect to — it can’t handle DHCP.

 

What a headache to get all that working!  The forums were not very descriptive or helpful for getting this to work.

I had to combine that code (which lets me GET a string of variables to a PHP web page, which can then be passed into a MySQL database, with two other pieces of code: code to read in the RFID ID # via serial port (which I did above), and code to poll the web server to see if the server is instructing it to light up the LEDs or not.  I was really, really, really hoping this is a smooth process.

Front- and Back- Ends

I set up the database and front-end for the web server.  I set up a few tables, one for my list of things, one for my list of containers (I made things and containers separate because I’m thinking some things might also be containers), one for a log tracking what events have happened.

The front-end went smoother than I thought.  I used jQuery and jQueryUI to easily build in a working interface.  It took me the most time to figure out how to correctly encode the MySQL pull into JSON via PHP so that I could access it via JavaScript and jQuery for my autocomplete search functions.  But it helped me to better understand how to navigate the DOM and inter-operate between the different languages.

Now I’ve got a pretty slick interface, though I might need to restructure the MySQL pulls into PHP classes instead of one-offs.  I also might need to restructure the data so that not everything is given away in my source’s JSON.  There’s a ton of work I need to do adding functionality for things like having the web server tell the Arduino to turn on its LEDs, etc.  But the basic layout is done!

I even added quests and recipes.  The quests seen above: OCD is unlocked when you put all the objects of the same type in the same box.  Fort Knox is when you check in your wallet, your checkbook, and a small box into the same container.  Love at First Light was going to be the coup de grace of my demo: both boxes would have “love” checked into them, and then they’d face each other (both have a reader and an RFID attached to their fronts) to talk, and then the small box would be checked into Eve.  All these conditionals would give birth to a new container in my database, called “Caintainer”.  So I wanted to create life for my class demo.  It didn’t work. :/

You can try out the Wheredipuddit interface on my web server.  It’s not connected to anything though.

Problems

These pieces all worked fine on their own.  It came time to put them all together.  This is when I started running into issues.  First of all, I was wrestling with the code to send the GET request.  The sample Arduino code that connected to a weather database worked.  My PHP script to read an HTTP URL into a MySQL database worked.  But when I tried to modify the Arduino sketch so that it could insert a different RFID based on which one was scanned, and then requested through the Arduino, I’d often get Arduino resets.  My professor suggested that I stop trying to mess around with char pointers (char *) and arrays, and just hardcode in the URLs based on if..then checks for which RFID was scanned.

This worked with one example but for 20, it also reset the board.  I suspected I was filling up the memory on the Arduino or something.  I reduced the number of if..else if..then checks to just 3 different RFID tags, and that seemed to work okay.

I then added the digital RGB LED strips.  With the way I wired it up, everything was drawing from the same power, and I’d get the Arduino to work fine, but when I scanned the RFID reader, it would click (not enough power, or a short circuit), or the LEDs wouldn’t come on.  I ended up getting another 4 AA battery pack and connecting it to the Arduino + RFID, with the LEDs getting their own (but grounded with the Arduino).  I’m not sure if this circuit caused later problems — I don’t think it did since I didn’t get any more issues, power-wise.  Save for the flimsy battery pack wires.  If I had more time, I’d definitely solder the wires to header pins so they’d be more robust to being moved.  The wires popped out pretty easily without pins.

I added another GETrequest at the end of the loop, which checked to see if the server had changed the box’s mood.  The server would just output 1 integer on the ping.php page, which the Arduino would read and then display on the LEDs the corresponding color for the new mood.

I blew out an RFID reader after being frustrated and trying a different power setup.  I guess it didn’t like being hooked up along a connection tied to a 12V battery pack.  Oops.  First time I’ve blown out a component.

Maybe this was caused by the bug — or butterfly — in my Arduino.  I guess the butterfly was from a classmate’s butterfly project (she apparently had butterflies mailed to her).

I had some problems understanding the callback function that was coded into the example sketch.  It basically said, if you receive data in the serial buffer, then run this function to process it.  It had incoming variables already so they were my constraints.  I didn’t understand the underlying code enough to either scrap it or modify it.  I spent tons of time trying to figure out how to read my HTTP request’s response (which, in this sketch, shows the whole HTTP headers, which was a pain in the ass because that’s a lot of extra characters I have to deal with in my serial buffer).  I tried many examples and tried writing some failed C.  I ended up, though, with this:

// Function that prints data from the server
void printData(char* data, int len) {
  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and
  // includes the HTTP header.
  while (len-- > 0) {
    Serial.print(*(data++));
    if (*(data) == '*' ) { //'*' is our beginning character
      startRead = true; //Ready to start reading the part
    }
    if (startRead) {
      Serial.print(*(data++));
      if (*(data) == '0'){ // content
        dither(strip.Color(0,127,127), 20);
      }
    ...
    }
  ...
}

The reading of Serial.print(*(data++)) in the startRead conditional is crucial to read in the next character.  I did try to do a serial.flush() after this callback function but I think it was interfering with the other GETrequest so I removed it.  But I suspect more must be done here to make it a clean read…

I have a feeling having two GETrequests could have contributed to one of my major issues, which seemed to be flooding the serial buffer.  I’d often get the LED 13 light stuck on, as if it was being flooded with data.  I did try to serial.flush() my serial connections but that seemed to destroy communications — nothing was logged in my database as having been touched.  Other times, I would scan stuff in or try to ping them from my browser (pinging from browser would tell the Arduino on its next connection that it needed to light up to show the user that the requested object was inside), and nothing would happen!

This is actually exactly what happened during my class presentation.  Nothing worked.  I felt bad about it because I prepared for the project well, bought stuff early, put in early test work, and then did all-nighters for almost two weeks trying to figure the whole thing out.  I felt like I tried hard, picked a project I could accomplish, and put in the time.  And it still didn’t work during the demo, though I KNOW some parts of it work well…sometimes. Here’s a video clip of me giving my presentation (may have been edited for time):

Conclusion

So there you go.  It was a highly disappointing ending to a final project.  I wondered if working alone caused my problems, or not asking others for enough help.  My lessons learned:

  • When doing serial communications, make sure you try to understand EVERYTHING being passed across.  Make sure to always use the serial monitor, just to be sure you’re getting expected results.
  • When doing communications between client and server, always build tons of logging into your code, even at first when you’re just scaffolding the project.  You will need to do small unit testing on each case individually to make sure it works, before trying to put everything together.  The worst is when you can’t figure out where your problems are being caused, because there’s too much going on and too many points of failure.  Keep the network traffic thin so there’s more margin for error.  TEST EVERYTHING INDIVIDUALLY.
  • I would have bought an extra Arduino and the new WiShield 2.0 shields, or waited for the new Arduinos with built-in wifi.  The problem I had with the Diamondback was that I ended up using poorly documented code that didn’t do what I wanted it to and didn’t seem very configurable, and operated far less usefully than Arduino’s example code in the ethernet library.  The WiShield 2.0 code seemed far more user-friendly.

 

What interests me about this is the long-term application.  What will it be like when objects can tell you if they’re missing parts, or they can report to you on their health, or they can take out some of the daily logistics planning that we send to our brains’ subroutines every day while we try to get other stuff done?  What will the world be like when things start talking to each other outside of the internet?  Can I get my boxes to talk to each other while they’re near each other?  Can I build recipes, like scan a bunch of characteristics (honesty, humor, good looks) into the boxes so that, if the recipe is right for both, they “fall in love”?  In talking with another classmate, Tak, we realized that if there were, say, 50 boxes piled against a wall, you could turn them into interactive pixels, controllable via Processing sketches!  And as I talked to yet another classmate, Christie, I realized, what if there will be a job in the future for creative storytellers where their job is to imbue objects with personalities?  Think of just observing everyday objects talk to each other, all being coded by different people, all with unpredictable and surprising interactive behaviors, with companies competing to hire the most creative people to give their products signature anthropomorphized personalities.

I didn’t get my project to work.  I thought I’d be able to do it.  But I ended up encountering issues at almost every step of the way, with five obstacles popping up once I solved just one.

I definitely need a mental break from school now that the semester’s over.  I want this idea to work, but I’m going to have to accept that I need to move on from it because I’ll have other class projects to do.  But it’s very hard for me to leave a problem unsolved.  So it’s been gnawing at me.  But I’ll be using the break to forget about it, and try not to come back and try to figure out what’s wrong with it.  At least for a while, or until I can use the project for another class or application.  Sigh.

My Arduino code is below the jump:

/*
* Chopped together from various sources.
* Make sure to uncomment #define APP_WEBCLIENT in apps-conf.h
*/
#include "SPI.h"
#include <WiServer.h>
#include <LPD8806.h>
#include <NewSoftSerial.h>
#define rxPin 8
#define txPin 6

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

NewSoftSerial mySerial = NewSoftSerial(rxPin, txPin);
String rfidTag, rfidTagClean;

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {
x,x,x,x}; // IP address of WiShield
unsigned char gateway_ip[] = {
x,x,x,x}; // router or gateway IP address
unsigned char subnet_mask[] = {
255,255,255,0}; // subnet mask for the local network
char ssid[] = {
"ROUTERNAME"}; // max 32 bytes
unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {
"ROUTERPASSWORD"}; // max 64 characters

// WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};

// setup the wireless mode; infrastructure - connect to AP; adhoc - connect to another WiFi device
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;

uint8 ip[] = {
x,x,x,x};

// LPD8806-based strandtest code config
int dataPin = 2;
int clockPin = 3;

// Set the first variable to the NUMBER of pixels. 32 = 32 pixels in a row
// The LED strips are 32 LEDs per meter but you can extend/cut the strip
LPD8806 strip = LPD8806(32, dataPin, clockPin);

void setup() {
// Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
WiServer.init(NULL);

// Enable Serial output and ask WiServer to generate log messages (optional)
Serial.begin(57600);
mySerial.begin(9600);
Serial.flush();
mySerial.flush();

WiServer.enableVerboseMode(false);

// Start up the LED strip
strip.begin();

// Update the strip, to start they are all 'off'
strip.show();
colorChase(strip.Color(0,127,127), 10);
}

int count = 0;
boolean rfidSent;
void loop(){
rfidSent = false;
if (mySerial.available()) {
char incoming = (char)mySerial.read();
// Packet structure, see ID-12 datasheet.
// STX A B C D E F G H I J Y Z CR LF ETX
// 2 - - - - - - - - - - - - 13 10 3

// If the last character of the packet is 3, move on.
if(incoming == 3) {

// Skip the first character and take the next 12
rfidTagClean = rfidTag.substring(1, 13);
rfidTag = "";
rfidSent = true;

}
else {
rfidTag = String (rfidTag + incoming);
}
}

// 2900AE3D12A8
if (rfidSent == true) {
if (rfidTagClean == "4A00DE829E88") {
char * queryURL = "PATHTOFILE";
GETrequest getRFID(ip, 80, "HOSTNAME", queryURL);
getRFID.setReturnFunc(printData);
getRFID.submit();
}
else if (rfidTagClean == "4A00DE491FC2") {
char * queryURL = "PATHTOFILE";
GETrequest getRFID(ip, 80, "HOSTNAME", queryURL);
getRFID.setReturnFunc(printData);
getRFID.submit();
}
else if (rfidTagClean == "4A00DE2E4AF0") {
char * queryURL = "PATHTOFILE";
GETrequest getRFID(ip, 80, "HOSTNAME", queryURL);
getRFID.setReturnFunc(printData);
getRFID.submit();
}
else if (rfidTagClean == "4A00DE3750F3") {
char * queryURL = "PATHTOFILE";
GETrequest getRFID(ip, 80, "HOSTNAME", queryURL);
getRFID.setReturnFunc(printData);
getRFID.submit();
}
rfidTagClean = "";
}

if (count % 300 == 0) {
GETrequest getRFID2(ip, 80, "HOSTNAME", "PATHTOFILE");
getRFID2.setReturnFunc(printData2);
getRFID2.submit();
}

if (count > 15000) {
count = 0;
}
else {
count++;
}

for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0);
}
strip.show();

// Run WiServer
WiServer.server_task();
delay(10);

}

// Function that prints data from the server
void printData(char* data, int len) {
// Print the data returned by the server
// Note that the data is not null-terminated, may be broken up into smaller packets, and
// includes the HTTP header.
while (len-- > 0) {
Serial.print(*(data++));
if (*(data) == '*' ) { //'*' is our beginning character
startRead = true; //Ready to start reading the part
}
if (startRead) {
Serial.print(*(data++));
if (*(data) == '0'){ // content
dither(strip.Color(0,127,127), 20);
}
else if (*(data) == '1') { // angry
scanner(127,0,0, 10);
}
else if (*(data) == '2') { // happy
dither(strip.Color(127,127,0), 20);
}
else if (*(data) == '3') { // in love
dither(strip.Color(127,0,0), 20);
}
else if (*(data) == '4') { // jealous
colorChase(strip.Color(127,0,0), 10);
}
else if (*(data) == '5') { // preggers
rainbowCycle(0); // make it go through the cycle fairly fast
}
//len = 0;
startRead = false;
}
}

for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0);
}
strip.show();

}

// Function that prints data from the server
void printData2(char* data, int len) {
// Print the data returned by the server
// Note that the data is not null-terminated, may be broken up into smaller packets, and
// includes the HTTP header.
while (len-- > 0) {
Serial.print(*(data++));
if (*(data) == '*' ) { //'*' is our beginning character
startRead = true; //Ready to start reading the part
}
if (startRead) {
Serial.print(*(data++));
if (*(data) == '1'){
dither(strip.Color(0,127,127), 30);
}
//len = 0;
startRead = false;
}
}

for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0);
}
strip.show();

}

// An "ordered dither" fills every pixel in a sequence that looks
// sparkly and almost random, but actually follows a specific order.
void dither(uint32_t c, uint8_t wait) {

// Determine highest bit needed to represent pixel index
int hiBit = 0;
int n = strip.numPixels() - 1;
for(int bit=1; bit < 0x8000; bit <<= 1) {
if(n & bit) hiBit = bit;
}

int bit, reverse;
for(int i=0; i<(hiBit << 1); i++) {
// Reverse the bits in i to create ordered dither:
reverse = 0;
for(bit=1; bit <= hiBit; bit <<= 1) {
reverse <<= 1;
if(i & bit) reverse |= 1;
}
strip.setPixelColor(reverse, c);
strip.show();
delay(wait);
}
delay(250); // Hold image for 1/4 sec
}

// Chase a dot down the strip
// good for testing purposes
void colorChase(uint32_t c, uint8_t wait) {
int i;

for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0); // turn all pixels off
}

for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c); // set one pixel
strip.show(); // refresh strip display
delay(wait); // hold image for a moment
strip.setPixelColor(i, 0); // erase pixel (but don't refresh yet)
}
strip.show(); // for last erased pixel
}

// fill the dots one after the other with said color
// good for testing purposes
void colorWipe(uint32_t c, uint8_t wait) {
int i;

for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}

// Sine wave effect
#define PI 3.14159265
void wave(uint32_t c, int cycles, uint8_t wait) {
float y;
byte r, g, b, r2, g2, b2;

// Need to decompose color into its r, g, b elements
g = (c >> 16) & 0x7f;
r = (c >> 8) & 0x7f;
b = c & 0x7f;

for(int x=0; x<(strip.numPixels()*5); x++)
{
for(int i=0; i<strip.numPixels(); i++) {
y = sin(PI * (float)cycles * (float)(x + i) / (float)strip.numPixels());
if(y >= 0.0) {
// Peaks of sine wave are white
y = 1.0 - y; // Translate Y to 0.0 (top) to 1.0 (center)
r2 = 127 - (byte)((float)(127 - r) * y);
g2 = 127 - (byte)((float)(127 - g) * y);
b2 = 127 - (byte)((float)(127 - b) * y);
}
else {
// Troughs of sine wave are black
y += 1.0; // Translate Y to 0.0 (bottom) to 1.0 (center)
r2 = (byte)((float)r * y);
g2 = (byte)((float)g * y);
b2 = (byte)((float)b * y);
}
strip.setPixelColor(i, r2, g2, b2);
}
strip.show();
delay(wait);
}
}

// "Larson scanner" = Cylon/KITT bouncing light effect
void scanner(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
int i, j, pos, dir;

pos = 0;
dir = 1;

for(i=0; i<((strip.numPixels()-1) * 8); i++) {
// Draw 5 pixels centered on pos. setPixelColor() will clip
// any pixels off the ends of the strip, no worries there.
// we'll make the colors dimmer at the edges for a nice pulse
// look
strip.setPixelColor(pos - 2, strip.Color(r/4, g/4, b/4));
strip.setPixelColor(pos - 1, strip.Color(r/2, g/2, b/2));
strip.setPixelColor(pos, strip.Color(r, g, b));
strip.setPixelColor(pos + 1, strip.Color(r/2, g/2, b/2));
strip.setPixelColor(pos + 2, strip.Color(r/4, g/4, b/4));

strip.show();
delay(wait);
// If we wanted to be sneaky we could erase just the tail end
// pixel, but it's much easier just to erase the whole thing
// and draw a new one next time.
for(j=-2; j<= 2; j++)
strip.setPixelColor(pos+j, strip.Color(0,0,0));
// Bounce off ends of strip
pos += dir;
if(pos < 0) {
pos = 1;
dir = -dir;
}
else if(pos >= strip.numPixels()) {
pos = strip.numPixels() - 2;
dir = -dir;
}
}
}

// Cycle through the color wheel, equally spaced around the belt
void rainbowCycle(uint8_t wait) {
uint16_t i, j;

for (j=0; j < 384 * 5; j++) { // 5 cycles of all 384 colors in the wheel
for (i=0; i < strip.numPixels(); i++) {
// tricky math! we use each pixel as a fraction of the full 384-color
// wheel (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the wheel cycle around
strip.setPixelColor(i, Wheel(((i * 384 / strip.numPixels()) + j) % 384));
}
strip.show(); // write all the pixels out
delay(wait);
}
}

uint32_t Wheel(uint16_t WheelPos)
{
byte r, g, b;
switch(WheelPos / 128)
{
case 0:
r = 127 - WheelPos % 128; // red down
g = WheelPos % 128; // green up
b = 0; // blue off
break;
case 1:
g = 127 - WheelPos % 128; // green down
b = WheelPos % 128; // blue up
r = 0; // red off
break;
case 2:
b = 127 - WheelPos % 128; // blue down
r = WheelPos % 128; // red up
g = 0; // green off
break;
}
return(strip.Color(r,g,b));
}

  • Cathy

    Hey hey! Cathy from facebook here. Lover diagram; I never knew u had such artistic talent!
    So, this whole time I’m reading the story, and am on edge with one question:
    1. I was assuming the containers would automatically sense the physical spot the object was in and light up appropriately. So, I was curious how the setup could prevent one container from sensing an object in the other container, but still allow the user to be able to sense the object from any airspace. I see you avoided that problem by having a human manually scan it in.

    2. This makes for an awesome project, but im wondering what is the practicality and cost advantage over using a regular 2d printed barcode in place of the RFID?

    Or if I’m totally missing the point here since I’m not an EE, feel free to ignore me!

  • Ben Turner

    1) Yeah, the main limitation as well as as a benefit is that the tags need to be really close (like, almost touching) to be excited by the RFID reader.  I’m going to have to do some contingency testing on it once I put it together, to make sure parts don’t slide over and get picked up by the reader, or when two boxes are placed/stacked next to each other.  If I knew what I was doing more, I could probably put a switch onto the RFID reader so that it would only power on when you press a button to scan the tag.

    2) Yes, you’re right, it’s not the cheapest solution, although RFID tags are getting pretty cheap for hobbyists and for large scale (not so much for mid-scale).  Also, it’s easier to get components for RFID than for getting a barcode scanner and then having stickers made (and having to basically lay out the bar codes into images to have printed out).  It’s also something I just wanted to play with and demonstrates some usage for the Arduino. :)  So it’s not entirely cost effective, but it’s a definite learning experience!

    Glad you wrote, thank you. :)

  • Cathy Ben

    Good article. Your RFID Inventory Boxes are very creative. It’s a nice sharing.

    qr codes