I got tired of my standard paper business cards and despite the fact that I've yet to have a reason to hand out the 50 that I originally ordered, I decided to try to upgrade to something a little cooler.
There are a number of really clever hi-tech business cards out there. One of my favorites is Kevin Mitnick's card which actually doubles as a lock pick set:
I thought it would be fun to try to make some kind of business card for my site that really expresses what I'm all about. A few months back, I found a really neat idea for a USB business card:
When connected to a USB port, the card acts like a keyboard with a pre-programmed message. The card is activated by tapping the Caps-Lock key on the user's normal keyboard, and the Caps-Lock LED indicator signal (which is sent to all keyboards attached to the PC) activates it. When activated, the card types out all of its information into whatever text editor the user has open.
There are a number of different USB business cards out there, but all of those are simply USB flash drives. I really liked the idea of a business card that was a pre-programmed user input device with a hidden message that the user gets to watch unfold.
So I wanted a card like that for myself, but I wasn't about to blanket copy Frank's design. My idea was to do the same thing but with a mouse instead of a keyboard. When inserted, I wanted to make the card draw out some information. This way my card could include both text and graphics.
The user needs only to open a copy of MSPaint, point the mouse cursor at the canvas, insert the card, and stand back.
This proved more difficult that I thought.
There are a number of ways to make a device USB compatible. Atmel sells a number of AVR devices with built in USB controllers such as this guy, but most of them are made for more permanent applications instead of disposable business cards. This places their typical price in the $5-10 range which is way too steep for my purposes.
As an alternative, there is an open source package called V-USB. V-USB is a collection of code that when compiled allows a number of low-cost Atmel devices to communicate over USB. There isn't really a whole lot that's special about USB from a hardware standpoint. Unlike RS-232, USB operates over a more normal range of voltages that can easily interact with standard GPIO pins. The more challenging bit of USB communication is keeping up with the protocol. A device with a built in USB controller will have some specialized registers that allow it to do some of the USB communication in the background similar to how the serial UART functions on a number of low-end Atmel devices. If you are willing to sacrifice some processing power though, this can all be managed in software.
Getting a device working with V-USB is pretty easy. The standard download package comes with a number of sample projects including a standard mouse and keyboard, and it even includes schematics for recommended designs.
This project was really just testing the waters of what is possible, and considering how simple the design is, I decided to try it with a breadboard before jumping into making a PCB:
The design is stolen directly from the "circuits" folder of the download package:
USB data is transferred over two wires (D+ and D-) as a differential pair, and there are certain rules regarding circuit layout with USB. Because it's a differential signal, the signal paths must be kept very close so that anything induced on one line will also be induced on the other. Also, its high speed nature requires the lines to have minimal capacitance which makes a breadboard non-deal for a USB circuit. Regardless, I wired it up to a breadboard and it appeared to work, but I wouldn't suggest it for any substantially complex projects.
The ATTiny45/85 is a part that I haven't worked with before. It contains a PLL which allows the user to set the clock speed rather than being limited to a standard clock speed. As such, it's the only part compatible with the V-USB package that doesn't require some kind of external clock signal to keep time with the USB data. I ran mine at 16.5MHz. The lack of external crystal makes this part ideal for a low-cost USB business card.
The package took a little while to configure. I started with the hid-mouse code listed in the examples. I had to configure the Makefile to match my programming method as well as my part type. The Makefile includes fuse settings for a number of compatible devices, but the ATTiny48/85 is not listed. Using Frank's project as reference, I configured the fuses to use the PLL clock source.
I also had to configure the usbconf.h file which simply tells the software which pins the USB D+ and D- lines are connected to. You are only limited by the fact that both D+ and D- must exist on the same port (A, B, C...), and D+ must connect to INT0.
When compiled and run, the hid-mouse example shows up as a standard mouse and simply moves the mouse cursor around in a circle.
Every time the USB host polls the mouse, a function is called that calculates the x and y movement to continue this circle. I replaced this with my own code that reads values off a table. These values go into reportBuffer.dx, reportBuffer.dy, and reportBuffer.buttonMask. The first two indicate the distance the mouse should be moved in the x and y dimensions. After some tests, I jotted down the orientation of these axes on...a business card:
I think the dx and dy numbers are signed bytes, so you're limited to -128 to +127. I never tested this fact, but I noticed erratic behavior if I passed values that got much larger than 100, so I ended up writing my code to chop up large numbers into smaller numbers and passed those over multiple cycles rather than all at once.
ButtonMask configures which mouse buttons are being depressed. The LSB of this value is mouse button one (left click), and I didn't bother testing what the others do.
To assist in programming my designs into my business card, I made a simple script in Python that displays an image and then translates clicks on that image to coordinates that are compatible with the mouse code (after some manipulation). I ran into a few issues because the progmem command built into the GCC compiler that allows you to store large arrays in program memory only allows you to store single byte values. I was too lazy to hand-code a method for storing larger values (especially one that kept sign information intact), so I just had to be careful while clicking around not to space my clicks too far apart.
This program had some flaws though. The granularity was a little too high, so two clicks intended to draw a horizontal line might actually draw a slightly diagonal line due to imprecise mouse clicks.
Although this could be solved by rounding coordinates to the nearest 5 or 10, I still had the problem of lack of reference. If I wanted to tweak part of my design, I had no way of determining which set of coordinates corresponded to a particular point without meticulously stepping through all of the coordinates in my head. I ended up falling back on a pen and paper method:
If you couldn't guess by the image at the top of this post, I ran into some problems with this design. I was anticipating some difficulty as this project is a feed-forward system meaning that the mouse has no idea where the cursor actually is. If something were to move the mouse unexpectedly, the card would continue to scribble down its pattern which would look nothing like the intended design.
Another anticipated issue along this line was the mouse running off the canvas. If the user's drawing window was too small, or the mouse cursor was placed too close to the edges before activating the card, it would start clicking and dragging all over other windows. I figured that this one could be prevented with some very clear instructions printed on the card itself.
Unfortunately, I didn't anticipate that the computer, not the user, would be the one to ruin the concept.
See, a mouse doesn't tell the computer how to move the cursor; it only tells the computer how it's moving across its mousepad. The computer takes this into account along with the user's personal settings and some algorithms to actually decide how to move the mouse cursor. For example, most modern computers have "mouse acceleration" meaning that the speed of the mouse determines how far the cursor moves for every inch of mouse movement. This allows the user to move the cursor long distances without sliding the mouse all the way across his or her desk simply by flicking his or her wrist rapidly.
These are great features for mouse users. I'm sure that computers would be much harder to use if mouse movement shared a one to one relationship with cursor movement.
Unfortunately, these features make my design unfeasible. I found that my logo design was mutilated by these settings. Each of the mouse movements were coded relative to the previous mouse position, and minor differences between the anticipated position and real position due to things like mouse acceleration added up over time making the design drift. Even attempting to adjust the design to compensate for this drift, there was no way to guarantee that the design would work on everyone's computer.
For example, here's the design drawn in Photoshop Elements for OSX:
And here's the same input into Paint for Windows 7:
As you can see, the bounding box is a different size, and its shape even changed slightly.
I probably could continue to poke at this for a while, but I doubt I'll ever get it perfect, and if it's going to make a sloppy doodle, it doesn't really instill confidence in whoever receives this card from me.
Here's a brief demo of my card doing its thing on my Mac.
Well, it didn't work out how I was hoping. I still learned a little about the capabilities of V-USB though, and I might be utilizing it in some of my future projects.
In the meantime, I need to think of a cooler idea for a business card...
Continue the story here.
Project files can be found here: Business Card v1.0