I've been working as an intern on the Apple Watch hardware team for the last six months, so I've been pretty busy with work and enjoying my time in California. However, I've also been thinking really hard about the next stages of the business card project. Working on the Watch has been a pretty humbling experience due to the scale of the hardware inside the watch. The components used and the parts that come together inside the watch are ridiculously tiny, which has been motivating me to make the card as thin and sleek as possible.

This is a long one. -- This is a post-mortem of more than six months of tedious deliberation, tough design, and dumb mistakes covered here.

jumping the gun

A few months ago, after I had returned from Baltimore, I made the mistake of trying to rush into the revised design without revisiting my initial design vision. I figured that all I needed to do was re-layout the board, figure out where I was going to place the components to make the most aesthetically pleasing card as possible, and I would be done. I started by creating a mockup of the card in illustrator. I don't have any screenshots from this point in time, so forgive me for these pictures of my screen.


I was playing a lot with the locations of the tab-mounted batteries. The plan was still to make two PCBs, one with the components and one with holes routed out for the components to sick up through, the top PCB having my information on its silkscreen. After reviewing the costs for the thinner PCBs I would need, I realized that it would be prohibitively expensive to require two PCBs per card. As the top board would have no traces (just silkscreen and routed holes), I figured there was no reason to make it a PCB, and began looking for other materials it could be built from. I settled on black anodized aluminum, which was available cheaply in 1mm thick sheets. This would require the PCB to be 0.6mm thick to have a final thickness of ~1.6mm, which was no problem. I picked the anodized aluminum for it's cosmetic appeal when laser engraved. Engraving the anodized surface removes the top layer of material which leaves a silver colored surface finish. This makes for a gorgeous contrast with the surrounding black anodized material.

Since the two layers would no longer be soldered together, I found some tiny screws on McMaster-Carr that I thought would work and chugged ahead with the board design without too much thought. I did purchase the screws and a tiny little tap to make sure that I could successfully tap the aluminum. The screws were of a minuscule pitch, and I was admittedly a little worried about only having one or two complete threads embedded in the metal. I figured most of the force on the screws would be in shear anyway

Here's another picture of my screen showing some work I did to re-layout out the board at this point.


The career fair was fast approaching and I was becoming sloppy with the design in a last-ditch effort to finish the second revision. I decided to hold off work until I had time to do things the right way. The first version of the card recieved great reactions at the fair. I can't really determine how much it influenced getting invited to interview, but I think it helped break the ice a considerable amount and I ended up getting an offer from Apple, so, things didn't go too badly I suppose. -- My life got a little busy with classwork at this point, and after the great reactions the work kind of trailed off for a while.

rethinking the design goals

During this project, I've done a lot of thinking about what the final version of the card should actually look like. My initial idea (as discussed in previous entries) was a stackup of two thin PCBs that were soldered or joined together in some way. When I started thinking about how I could get my personal information on the top PCB silkscreen (as shown before) I couldn't find a design that I was happy with. I tried a multitude of different arrangements of my name and information on the top board. It was difficult to find something that was aesthetically pleasing with the holes that were required in the top PCB for the components and the batteries.

Other than the appearance of the card, I was also very concerned with was the battery life of the CR2016 cells that would be soldered into the board. I wanted it to have a reasonable run time, otherwise the card would be somewhat disposable. After playing with the first revision for an extended amount of time and noting the battery life I was getting with CR2032 cells (which are double in size than the eventual CR2016 cells), I was becoming more concerned that having permanently mounted batteries may be a bad idea.

I wrote some code for the first version of the card which had the microcontroller act as if the card was being shaken at a regular rate. This would emulate the strobing of the LEDs (as they're not constantly on) to simulate the average current consumption. I tested the runtime using two fresh coin cells by monitoring the voltage across the cells until the card stopped functioning. I averaged about thirty to forty-five minutes of shake-time. I considered this fairly good, but not great. I could probably save some power by putting the microcontroller to sleep during dead-times of the shake period, but the largest consumer of power by far is the LEDs at around 5mA a piece.

Unfortunately, the LED power consumption is quite difficult to lower. Pulse width modulating (PWM) the LEDs would decrease the power consumption, but unless the PWM frequency was high enough, shaking the card could reveal the LEDs turning on and off. Additionally, the effect actually relies on the LEDs being as bright as possible, if they are not very bright, the persistence of vision effect fails. The only way to decrease the LED current without compromise would be to use a constant-current LED driving scheme and do away with the current limiting resistors. However, the power dissipation in the current limiting resistors is minimal compared to the power dissipated in the LEDs.

Additionally, since I wanted the card to be hackable, having such a short battery life doesn't encourage the hacking of the card. Who wants to put work into creating a new application of a device that only has thirty minutes of total use time? I can't expect the recipients of the card to be soldering in new tab-mounted coin cells that can only be found on Digi-Key.

After all of this, I started to become obsessed with having a clean card front and user-replaceable batteries, and began to think about ways I could accomplish both.


My first thought was some sort of metal cap or disc that would solder across a hole in the top and bottom PCBs, which would encapsulate the battery inside the PCBs themselves. The discs would have to be attached to the PCB somehow, and be relatively thin, and the only way I could think of doing this was soldering the discs on. This approach was slightly better than the tab-mounted coin cells, as it would use regular CR2016s cells that would be purchasable at most department stores, but it still would require the user to have access to soldering equipment.

I then thought I could make the method that the PCBs attached to another non-permanent (instead of soldering the PCBs together). I looked into tiny micro-screws intended for watchmaking, but the cheapest screws I could find that would be short enough (~1.6mm in length, including the pan or countersunk head) were something like forty dollars a piece on a specialty watch hardware website. I suppose this would work, but it would be outrageously expensive to have even four screws per card. Additionally, I'm not sure that PCB substrate takes well to being tapped or countersunk.

A friend then recommended magnets, an idea I instantly fell in love with. I started searching for thin magnets, and found my answer at K&J magnetics. They have cylindrical magnets that are 1/32nd of an inch thick, which is about 0.8mm, or about half the target thickness of the card. I started to think about how I would get the magnets to be attracted to the PCB itself.

problems with magnets

After some thought, I realized the card would likely be in close proximity with other items in a wallet that may be sensitive to magnetic fields, such as credit cards with magnetic stripes. Credit cards are usually of the high-coercivity variety, which require a stronger magnetic field to erase than low-coercivity stripes, which are usually found on hotel room keys and such. I wanted to make sure that the business card wouldn't erase either card, especially because recruiters at career fairs are likely staying in hotels! I wouldn't want to erase their room key on purpose. K&J magnetics actually has a great webpage about this exact topic that I learned a lot from.

At first, this issues seemed to make the magnetic solution a nonviable one. However, if a magnet is captivated between two magnetically permeable materials, the magnetic field on the other side of the material is of a much smaller magnitude. I haven't taken electromagnetics yet, and I'm a little rusty from my physics course, but from what I understand magnetically permeable materials have an field induced inside them by the permanent magnet, which counteracts the field of the magnet. How much field is induced is a function of a few different material properties.

For the solution to work, the materials on each side of the magnet need to have the right properties and dimensions to counteract as much of the field of the permanent magnet as possible. This should be fine to put inside a wallet as long as the field on the other side of the piece of metal is small enough to not affect any magstripes.

putting it back together

Since I wanted metal on either side of the magnet, I figured why not make the top half of the card out of metal? The bottom part of the card would still be a PCB, and the magnets would be attached to the PCB with little caps of metal behind the magnet so that the magnet was captivated on both sides by metal.

Using a piece of metal for the top also elegantly solves my other two issues. The batteries can sit up inside the piece of metal, and the metal itself can act as half of the battery holder, making electrical contact with batteries and the PCB. Also, I can use a slightly thicker piece of metal and cut slots up into the metal to hide away the electronic components. This means the top of the card will be one continuous, clean slate that I can place my information onto.

other considerations

Here are some other sketches from when I was thinking about this new arrangement. I briefly considered making only the "rim" of the card out of steel, and then somehow affixing a piece of aluminum inside the steel rim. Also shown is the idea to mask the back of the card using a piece of steel foil and vinyl sheet. The steel would be attached using some sort of double sided adhesive film, something like the 3M adhesive that Apple uses extensively in their products.


Here's another view from the front.


magnetic simulations

Before I became too invested in idea I picked, I wanted to be sure that these magnets wouldn't erase hotel keys. The first step I took was learning how to use this open source magnetic simulation software, FEMM. It has a small graphical interface to place points in 2D space, which are then connected with lines (or arcs) to create regions. You then define the properties of all of the regions before running a simulation. The most powerful feature of the software is being able to script all of these actions with Lua.

I figured stainless steel would be a classy material for the front of the card, however only some varieties are magnetic. I settled on one that I could get from McMaster-Carr in a good thickness. The metal needed to be a little more than 1mm thick, in order to have thickness left to mill out cavities for the 1mm tall components that are on the PCB. There could be some potential problems with this, but more on that later. I chose 410 stainless for it's magnetic properties and price.

From here, I created a Lua script that allowed me to modify the thickness of the magnet, the thickness of the stainless steel, the diameter of the magnet, the magnet grade (K&J sells a few different varieties), the thickness of the piece of metal on the backside of the magnet, and the diameter of this piece of metal.

I didn't do a great job of versioning this script, but below is the state of the script as I left it. I started by defining the physical parameters of the stackup, this way I could adjust the dimensions and see how they affected the result without having to hardcode the dimensions into the functions that create the nodes or the segments.

The last bit of code generates a plot of the magnetic field magnitude over the surface of the metal top, which is what I'm actually interested in. The geometry of the assembly leads to different field strengths along the surface of the card, so the peak strength in the plot is of the most interest. This let me quickly try a few different configurations and run the simulations to investigate the field strength. Obviously, the results are to be taken with a grain of salt, but initial experimentation leads me to believe that I should be in the clear.


-- properties
-- magnet dimensions
magnet_diameter = 3/16
magnet_thickness = 1/32

-- pcb properties
pcb_thickness = 0.0236220472 -- (0.6mm)

-- steel steel properties
steel_thickness = 0.040 -- (~1.0mm)

-- location of magnet
left_border_size = 0.070 -- (1.524mm)
right_border_size = 0.070 -- (1.524mm)

-- steel cap properties
steel_cap_oversize = 0.025
steel_cap_thickness = ((steel_thickness + pcb_thickness) - magnet_thickness) / 2

-- insulation properties
insulation_thickness = 0.005

-- boundary raduis
boundary_radius = 0.75

-- float distance (credit cards will be ~1 mil from the surface)
float_distance = 0.001

-- zoom parameters
zoom_distance = 0.1

-- draw things

-- magnet points
magnet_tl = {x = -(magnet_diameter / 2), y =  (magnet_thickness / 2) + steel_cap_thickness/2}
magnet_tr = {x =  (magnet_diameter / 2), y =  (magnet_thickness / 2) + steel_cap_thickness/2}
magnet_bl = {x = -(magnet_diameter / 2), y = -(magnet_thickness / 2) + steel_cap_thickness/2}
magnet_br = {x =  (magnet_diameter / 2), y = -(magnet_thickness / 2) + steel_cap_thickness/2}

-- steel top points
steel_tl = {x = -((magnet_diameter / 2) + left_border_size), y = steel_thickness}
steel_tr = {x =  ((magnet_diameter / 2) + right_border_size), y = steel_thickness}

-- midpoints
midpoint_fl = {x = -((magnet_diameter / 2) + left_border_size), y = 0}
midpoint_fr = {x =  ((magnet_diameter / 2) + right_border_size), y = 0}
midpoint_ml = {x = -(magnet_diameter / 2), y = 0}
midpoint_mr = {x =  (magnet_diameter / 2), y = 0}

-- steel cap points
cap_tl = {x = -((magnet_diameter / 2) + steel_cap_oversize), y = magnet_bl.y}
cap_tr = {x =  ((magnet_diameter / 2) + steel_cap_oversize), y = magnet_bl.y}
cap_bl = {x = -((magnet_diameter / 2) + steel_cap_oversize), y = magnet_bl.y - steel_cap_thickness}
cap_br = {x =  ((magnet_diameter / 2) + steel_cap_oversize), y = magnet_bl.y - steel_cap_thickness}

-- fr4 bottom points
pcb_bl = {x = -((magnet_diameter / 2) + left_border_size), y = -pcb_thickness}
pcb_br = {x =  ((magnet_diameter / 2) + left_border_size), y = -pcb_thickness}

-- add all the points

mi_addnode(magnet_tl.x, magnet_tl.y)
mi_addnode(magnet_tr.x, magnet_tr.y)
mi_addnode(magnet_bl.x, magnet_bl.y)
mi_addnode(magnet_br.x, magnet_br.y)

mi_addnode(steel_tl.x, steel_tl.y)
mi_addnode(steel_tr.x, steel_tr.y)

mi_addnode(midpoint_fl.x, midpoint_fl.y)
mi_addnode(midpoint_fr.x, midpoint_fr.y)
mi_addnode(midpoint_ml.x, midpoint_ml.y)
mi_addnode(midpoint_mr.x, midpoint_mr.y)

mi_addnode(cap_tl.x, cap_tl.y)
mi_addnode(cap_tr.x, cap_tr.y)
mi_addnode(cap_bl.x, cap_bl.y)
mi_addnode(cap_br.x, cap_br.y)

mi_addnode(pcb_bl.x, pcb_bl.y)
mi_addnode(pcb_br.x, pcb_br.y)

-- draw the segments

-- magnet
mi_addsegment(magnet_tl.x, magnet_tl.y, magnet_tr.x, magnet_tr.y)
mi_addsegment(magnet_tr.x, magnet_tr.y, magnet_br.x, magnet_br.y)
mi_addsegment(magnet_br.x, magnet_br.y, magnet_bl.x, magnet_bl.y)
mi_addsegment(magnet_bl.x, magnet_bl.y, magnet_tl.x, magnet_tl.y)

-- steel top
mi_addsegment(steel_tl.x, steel_tl.y, steel_tr.x, steel_tr.y)
mi_addsegment(steel_tr.x, steel_tr.y, midpoint_fr.x, midpoint_fr.y)
mi_addsegment(midpoint_fr.x, midpoint_fr.y, midpoint_mr.x, midpoint_mr.y)
mi_addsegment(steel_tl.x, steel_tl.y, midpoint_fl.x, midpoint_fl.y)
mi_addsegment(midpoint_fl.x, midpoint_fl.y, midpoint_ml.x, midpoint_ml.y)

-- pdb left
mi_addsegment(midpoint_fl.x, midpoint_fl.y, pcb_bl.x, pcb_bl.y)
mi_addsegment(pcb_bl.x, pcb_bl.y, cap_bl.x, cap_bl.y)
mi_addsegment(cap_bl.x, cap_bl.y, cap_tl.x, cap_tl.y)
mi_addsegment(cap_tl.x, cap_tl.y, magnet_bl.x, magnet_bl.y)

-- pdb right
mi_addsegment(midpoint_fr.x, midpoint_fr.y, pcb_br.x, pcb_br.y)
mi_addsegment(pcb_br.x, pcb_br.y, cap_br.x, cap_br.y)
mi_addsegment(cap_br.x, cap_br.y, cap_tr.x, cap_tr.y)
mi_addsegment(cap_tr.x, cap_tr.y, magnet_br.x, magnet_br.y)

-- steel cap
mi_addsegment(cap_bl.x, cap_bl.y, cap_br.x, cap_br.y)

-- add materials
air = mi_getmaterial("Air")
steel = mi_getmaterial("1010 Steel")
N42 = mi_addmaterial("N42", 1.05, 1.05, 155319  * sqrt(42))

-- create material points
magnet_point = {x = 0, y = (magnet_tl.y + magnet_bl.y) / 2}
steel_top_point = {x = 0, y = (steel_tl.y + magnet_tl.y) / 2}
pcb_left_point = {x = (pcb_bl.x + cap_bl.x) / 2, y = (pcb_bl.y + midpoint_fl.y) / 2}
pcb_right_point = {x = (pcb_br.x + cap_br.x) / 2, y = (pcb_br.y + midpoint_fr.y) / 2}
steel_cap_point = {x = 0, y = (cap_tr.y + cap_br.y) / 2}
air_point = {x = 0, y = steel_tl.y + 0.25}

-- add block labels
mi_addblocklabel(magnet_point.x, magnet_point.y)
mi_addblocklabel(steel_top_point.x, steel_top_point.y)
mi_addblocklabel(pcb_left_point.x, pcb_left_point.y)
mi_addblocklabel(pcb_right_point.x, pcb_right_point.y)
mi_addblocklabel(steel_cap_point.x, steel_cap_point.y)
mi_addblocklabel(air_point.x, air_point.y)

-- assign properties
mi_selectlabel(magnet_point.x, magnet_point.y)
mi_setblockprop("N42", 1, 0, "", 90)

mi_selectlabel(steel_top_point.x, steel_top_point.y)
mi_selectlabel(steel_cap_point.x, steel_cap_point.y)
mi_setblockprop("1010 Steel")

mi_selectlabel(pcb_left_point.x, pcb_left_point.y)
mi_selectlabel(pcb_right_point.x, pcb_right_point.y)
mi_selectlabel(air_point.x, air_point.y)

-- create the boundary
mi_addnode(boundary_radius, 0)
mi_addnode(-boundary_radius, 0)
mi_addarc(boundary_radius, 0, -boundary_radius, 0, 180, 1)
mi_addarc(-boundary_radius, 0, boundary_radius, 0, 180, 1)

-- create the boundary property
mi_addboundprop("ABC", 0, 0, 0, 0, 0, 0, 1/(uo*boundary_radius*in), 0, 2)
mi_selectarcsegment(0, boundary_radius)
mi_selectarcsegment(0, -boundary_radius)
mi_setarcsegmentprop(1, "ABC")

-- generate the mesh, run the simulation

-- adjust the view
mo_zoom(pcb_bl.x - zoom_distance, pcb_bl.y - zoom_distance, steel_tr.x + zoom_distance, steel_tr.y + zoom_distance)
mo_showdensityplot(1, 0, 1, 1e-3, "bmag")

-- create the path
mo_addcontour(steel_tl.x - float_distance, steel_tl.y + float_distance)
mo_addcontour(steel_tr.x + float_distance, steel_tr.y + float_distance)
mo_addcontour(pcb_br.x + float_distance, pcb_br.y - float_distance)
mo_addcontour(pcb_bl.x - float_distance, pcb_bl.y - float_distance)
mo_addcontour(steel_tl.x - float_distance, steel_tl.y + float_distance)

-- plot!

Here's the configuration that the script sets up for the simulation.


Here's a shaded plot of the magnetic field magnitude around the magnet.


Here's a plot showing the magnetic field strength on a path around the surfaces of the card.


Unfortunately the plot shows a field strength of about 0.3 Tesla, which is 3000 Gauss. This shouldn't be strong enough to erase the high-coercivity cards, but may pose a real problem for the low-coercivity variety. The high field strength occurs in only a very small region, so there is a possibility that the stackup may work.

magnetic reality

Not wanting to rely on the simulations alone, I purchased a variety of the smallest magnetics I've ever seen in my life. I also bought a magstripe reader/writer. This let me write data to some low-coercivity cards, torture them with magnets, and ensure the data was still present after experimentation.

When the magnets were placed directly on the magstripe, the cards were no match even for the weakest strength magnets, which wasn't a surprising result. The field strength on the surface of the magnets (even in the weakest locations) is about an order of magnitude larger than the field strength required to erase a low-coercivity card. However, placing the magnet between two thin sheets of steel (about 0.02" thick) seemed to make the cards completely immune to the magnets. At this point, even though the simulation results were a bit scary, I was confident enough to carry on with the design. Further testing will need to be done with the card fully assembled.

refining the circuit design

On the hardware end of things, I've only made small changes. Here's the revised schematic for this version.


The slide switches that were on the first version were awful. The tab that was used to switch them broke off easily, and I had problems with pads lifting when too much mechanical stress was placed on the switch. The latter issue could likely be fixed with a different landing pad design, but I can't fix the former.

In addition, I didn't want to rely only on the user being responsible enough to turn the on/off switch into the off position after every use. This could be fixed by using a software timer to put the card to sleep after a timeout, but if this is done, then the slide switch becomes redundant. I decided to replace the slide switch with a momentary pushbutton that would awake the card from sleep, making the microcontroller responsible for putting itself and the card into a low power state.

The only use for the boost converter is to provide a uniform voltage to the LEDs for all loads and at all charge states of the battery. As the microcontroller and accelerometer will function down to around 1.8V, the boost converter doesn't need to be running if the LEDs aren't on. I chose a different variant of the MCP1640 that features an "input to output bypass" mode. The slide switch was previously enabling or disabling the boost converter completely, now the microcontroller is responsible for "waking up" the boost converter if any LEDs will be turned on. Shutting down the boost converter further reduces the sleep current of the card.

I also removed the programming slide switch. A long-press of the new pushbutton (or some combination of pressing and shaking) will now activate the programming mode. -- In fact, the pushbutton might have been unneeded if re-programming wasn't a feature. The interrupt output of the accelerometer is wired to a pin of the microcontroller that supports wake-on-interrupt, so the accelerometer could potentially be responsible for waking the microcontroller up after a high acceleration event. I plan to implement this feature, such that the card can be woken up by shaking or by pressing the pushbutton.

I added a second ambient light sensor. I wrote some code a while ago to test the data transmission over light functionality (shown in the video below) and had some issues with achieving reliable transmissions. These problems could potentially be fixed in software, but I thought the more elegant solution would be to add a second ambient light sensor, using one to receive a data signal and one to receive a clock signal.

The programming header and debug outputs were changed from the through-hole type to a small surface mount pads, which reduces the physical footprint of both features, while still enabling the card to be inspected and modified.

Lastly, I had to make some changes to how the battery is connected in the schematic. These are consequences of the physical design changes that were made, which will be shown later.

refining the layout

With the new stackup, the board layout was now less critical, as no holes would have to be made in the top layer of the card. While this gave me a lot more freedom, I still needed to group the components so the stainless steel would have a minimum number of cuts made in it. The first step was determining the new location of the batteries. Without having to account for the long tabs that came out of the batteries, I could fit them all on one end of the card. I chose to put them on the right side of the card, furthest away from the LEDs, almost in the same place as the prototype design. I figured this would position the center of mass closest to the axis of rotation when shaking it, making it marginally easier to shake quickly.

I kept the LEDs in the same location as they were before, but moved them ever so slightly closer together to improve the readability of the text that appears in midair. I placed the two ambient light sensors on either side of the column of LEDs. I wanted the sensors to be as far apart from one another as possible to reduce the chance of "crosstalk" between the two sensor readings. It was a tough decision to move the sensors from the bottom of the card to the top (the same side of the LEDs), as I really wanted to use the LEDs to create a "loading bar" feature as the data was being transmitted to the card. However, I didn't want to have the components exposed on the bottom of the board.

The battery holder design proved to be a challenge. I put a ring of exposed copper on the bottom side of the card to attach a metal cover plate to. I'm still a bit unsure of how easy this will be to affix, but I think it should be relatively easy to reflow with a hefty amount of solder paste. As the metal front of the card is half of the battery holder, the PCB ground must be electrically connected to the metal plate. While it was tempting to expose some pads on the top of the PCB and cross my fingers that they would be connected, I was worried that small relative movements between the two layers would lead to intermittent battery connection. I remembered seeing little spring-loaded contacts used in the iPhone 4 to connect to the removable back cover, and managed to find something similar after a long afternoon of surfing Digi-Key.


These fingers are intended to be contacts for RF shields. I placed two of them on the board. I did some back-of-the-napkin calculations to ensure that the spring force was small enough to be compressed by the magnets holding the assembly together. I did try and place the fingers close to the corners with the magnets. I didn't want the springs pushing the board away from the metal in the middle of the board where there is no magnets.

Before finishing the board layout, I needed to make sure that everything would fit together mechanically. Specifically, I was interested in the location of the pushbutton switch and how I would make it press while not protruding from the edge of the card. I also needed to figure out the positioning of the magnets.

Keep in mind that both board layout and the mechanical designs were occurring in parallel, which is difficult to write in a linear manner. This might also explain why some pictures don't match up with one another or follow strict chronological order. In reality, I was constantly switching back and forth between the layout of the PCB and the mechanical layout.

mecahnical (re)design

I got really carried away here. I started by exporting the current layout of the board to a DXF format, so that I could place the reliefs in the metal cover in the appropriate positions. Until I finalized the board layout, I modeled the board as a thin rectangle. I divided I needed to keep the layer of kapton tape between the board and the metal cover to reduce the potential for shorts. This also bought me a little bit of thickness.

I made extensive use of Solidworks' variables feature. I kept almost every design aspect of the design as a variable, which made it easy to make sure that the file for the kapton layer and the metal layer were kept in sync. A slight annoyance was Solidworks' inability to share variables between files. Each time I changed a variable I had to export the variables as a text file, and then open each part that used the variables and import the text file. This ended up being quite time consuming. If I were to start from scratch, I would probably start the models inside an assembly and construct them from a single sketch.

Here's an early rendering of the card stackup. You can see the little metal discs to back the magnets, as well as the cutout that is needed in the metal cover for the LEDs to be seen through. I made some simple models of coin cells, as well as the discs that would be soldered to the back of the PCB.


Work here was very slow. I didn't have access to a machine shop while in California to test any of the designs or prototype anything, I was left to doing research to determine if any design choices were unattainable. (I did look into getting a TechShop membership, but the costs were overwhelming, and I didn't have a car to get me there and back)

Even though at this point the design is "done" I'm still having doubts as to if some of facets of the mechanical design are achievable. One concern is the rigidity of the stainless steel part. I am worried that with so many cuts into such a thin piece of metal that the cover piece will be flimsy and easily bent. I did the following simulation in Solidworks to gain a small level of confidence. I don't remember how much force I applied to the edges of the card but I remember it being quite a few pounds. The metal deflects, but not a large amount.

Another concern is the depth to which I am trying to mill into a thin piece of metal. To achieve my goal thickness I need to mill about 0.043 inches into an 0.048 inch thick piece of metal, which leaves a wall thickness of roughly 5 thousandths of an inch. I've contacted a few prototyping services in the Bay Area asking if they would be capable of manufacturing the part, but all refused, which isn't a good sign. I'm not worried about this being a deal breaker, as if I can't manage to make it work, I can always use a slightly thicker piece of metal which would leave more wall thickness.

Although I would like to mill the piece, another approach I considered (and haven't ruled out) was using two pieces of metal, one thicker and one thinner. The thicker piece would have holes all the way through the piece, and then the thinner piece (with only holes for the LEDs to shine through) would be affixed to the thicker piece. To attach the pieces, I considered brazing, using a conductive adhesive, or using blind rivets.


(I should briefly mention Dan Gelbart's excellent video series available here on YouTube. He has an 18 part series on prototyping techniques. Be warned, they will make you jealous of his somewhat ridiculously well equipped machine shop.)

I don't have a ton of photos along the way of this process, as a lot of it was iterative and uninteresting. Here's what I decided to do to recess the pushbutton inside of the metal top. Also shown are the holes for the LEDs and ambient light sensors.


I also modeled the batteries, magnets, steel magnet caps, and the battery backing plates for the PCB. Also included in the model was a thin piece of kapton insulating tape that will go between the PCB and the front plate to prevent the steel plate from inadvertently shorting any exposed pads or traces on the PCB.

finishing the routing

Once I was happy with the mechanical placement of everything I went back and finished the layout of the board. I was able to really increase the density and cleanliness of the routing compared to the prototype. Here's a photo from when I was nearly done.


I wanted to add a bit of flair to the card itself so it would stand out if it never saw completion or became lost from the front piece. To this end, I created a little logo for card to expose as gold plated copper in order to set it apart from the silkscreen. The first version (shown above) was created by making a grid of circles in Adobe Illustrator, warping them using one of the transform tools, and then removing all but the circles needed to create the characters. I then exported the document as a DXF and used one of the DXF import scripts available in Eagle. This was a terrible approach.

I wanted the logo to be exposed copper, so the logo needed to adhere to the design rules for minimum trace spacing. This was difficult to estimate in Illustrator, so it was left up to trial and error. It also created a lot of unnecessary geometry, making Eagle very unresponsive. Fed up with this approach, I took a quick detour and developed this tool. It allowed me to control the geometry of the logo with some sliders and immediately see the result on screen. Here's a short video of me messing with the parameters.

I then wrote the following script (in Node.js) that takes the parameters and generates a Eagle script filled with commands that would recreate the logo inside Eagle. It's essentially the same script that runs in the webpage, except the draw functions are replaced with functions that append text into a buffer. The functions abstract away some of eagle commands and made things a bit easier. I created the circles by creating polygons with two arcs. I used polar "clicks" in Eagle to simplify some of the math.
var fs = require('fs')

var clickCmd = function(x, y) {
    return '(' + x + ' ' + y + ')'

var polarClickCmd = function(r, deg) {
    return '(P ' + r + ' ' + deg + ')'

var changeLayerCmd = function(nameOrNumber) {
    return 'LAYER ' + nameOrNumber + ';\n'

var changeGridCmd = function(units, scale) {
    return 'GRID ' + units + ' ' + scale + ';\n'

var circleCmd = function(x, y, radius) {
    return 'CIRCLE ' + clickCmd(x, y) + clickCmd(x, y + radius) + ';\n'

var dtr = function(deg) {
    return (deg / 180.0) * Math.PI

var rtd = function(rad) {
    return (rad / Math.PI) * 180

var polycircleCmd = function(x, y, radius, width, signal) {
    //poly gnd 1 (P 10 0) +180 (P 10 180) +180 (P 10 0);
    output = ''
    //set the reference point as the middle of the circle
    output += 'MARK ' + clickCmd(x, y) + ';\n'
    //use polar coordinates to make the circle
    output += 'POLY ' + signal + ' ' + width + ' '
    output += polarClickCmd(radius - (width / 2), 0) + ' '
    output += '+180 '
    output += polarClickCmd(radius - (width / 2), 180) + ' '
    output += '+180 '
    output += polarClickCmd(radius - (width / 2), 0) + ';\n'
    return output;

var generate = function() {

    //all units in degrees and millimeters
    var config = {
        angleOffset: 23.1981981981982,
        xOrigin: 4.43125,
        yOrigin: 4.43125,
        outerRadius: 34.36716716716716,
        circleWidth: 0.2,
        // circleRadius: 0.16597597597597596,
        circleRadius: 0.17597597597597596,
        gridSpacing: 0.5114414414414414,
        squeeze: 2.7927927927927927,
        originOffset: -15.365365365365363,
        layer: 1,
        net: 'LOGO'

    //super hacky but whatever
    var logo = [
        '                   xxxx                 x',
        '                  x                     x',
        ' xxxx  xxx  x   x x      xxx  x xx      x',
        'x   x x   x x   x x     x   x xx  x  xxxx',
        'x   x x   x  x x  x     x   x x     x   x',
        'x   x x   x  x x  x     x  xx x     x   x',
        'xxxx   xxx    x    xxxx  xx x x      xxxx',
        'x                                        ',
        'x                                        ',
        'x                                        ',

    var output = '';

    for(var yLoc = 0; yLoc < logo.length; yLoc++) {
        var startAngle = 90 - config.squeeze
        var angle = startAngle - config.angleOffset
        var angleIncrement = (startAngle - 2.0 * config.angleOffset) / logo[yLoc].length
        var radius = config.outerRadius - yLoc * config.gridSpacing
        for(var xLoc = 0; xLoc < logo[yLoc].length; xLoc++) {
            if(logo[yLoc][xLoc] == 'x') {
                var x = radius * Math.cos(dtr(angle)) + config.xOrigin + config.originOffset
                var y = radius * Math.sin(dtr(angle)) + config.yOrigin + config.originOffset
                var net = config.net + xLoc + '_' + yLoc
                output += changeLayerCmd(config.layer)
                output += polycircleCmd(x, y, config.circleRadius, config.circleWidth, net)
                output += changeLayerCmd(29) // tstop layer
                output += polycircleCmd(x, y, config.circleRadius, config.circleWidth, '')

            angle -= angleIncrement

    return output

var output = generate()
fs.writeFileSync('logo-gen.scr', output)

This outputs a long file filled a few hundred lines of the following:

MARK (13.32610058209206 13.408113400274502);
POLY LOGO19_0 0.2 (P 0.07597597597597597 0) +180 (P 0.07597597597597597 180) +180 (P 0.07597597597597597 0);
MARK (13.32610058209206 13.408113400274502);
POLY  0.2 (P 0.07597597597597597 0) +180 (P 0.07597597597597597 180) +180 (P 0.07597597597597597 0);

It places each pad on a different net in the document so that the design rule check system treats them as separate copper areas that must be separated by the minimum spacing rules. It creates the same geometry on the copper layer and the soldermask stop layer so that the PCB manufacturer does not place soldermask over the pads.

Here's the two layers that are created by the script when run in Eagle.


Lastly, I thought it would look neat if the copper groundplane pour was absent underneath the "swipe" that was created by the logo. I figured this would create a subtle contrast from the rest of the card (soldermask has a slightly different color and texture when it's over copper as opposed to bare board substrate) and emphasize the "shaking" motion that the logo was making.

I wrote the following snippet (which uses the same functions from the above script to abstract the Eagle commands) which generates the two ground plane polygons on the top layer. This only generates a few lines of Eagle script, but it was still useful to not have to do the math by hand.

output = ''
var x = (config.xOrigin + config.originOffset)
var y = (config.yOrigin + config.originOffset)

var r = config.outerRadius + config.gridSpacing
var height = Math.sqrt(r * r + Math.abs(x * x))
var startAngle = Math.atan2(Math.abs(y), height)
var endAngle = Math.atan2(height, Math.abs(y))
var arcDegrees = rtd(endAngle - startAngle)
var loc = r * Math.cos(startAngle) + x
//draw the top right ground plane
output += changeLayerCmd(config.layer)
output += 'MARK ' + clickCmd(x, y) + ';\n'
output += 'POLY GND 0.3 '
output += clickCmd(0, loc) + ' -' + arcDegrees + ' ' + clickCmd(loc, 0) + ' '
output += clickCmd(78, 0) + ' ' + clickCmd(78, 50) + ' ' + clickCmd(0, 50) + ' ' + clickCmd(0, loc) + ';\n'

var r = config.outerRadius - (config.gridSpacing * 12)
var height = Math.sqrt(r * r + Math.abs(x * x))
var startAngle = Math.atan2(Math.abs(y), height)
var endAngle = Math.atan2(height, Math.abs(y))
var arcDegrees = rtd(endAngle - startAngle)
var loc = r * Math.cos(startAngle) + x
//draw the bottom left ground plane
output += changeLayerCmd(config.layer)
output += 'MARK ' + clickCmd(x, y) + ';\n'
output += 'POLY GND 0.3 '
output += clickCmd(0, loc) + ' -' + arcDegrees + ' ' + clickCmd(loc, 0) + ' '
output += clickCmd(0, 0) + ' ' + clickCmd(0, loc) + ';\n

Here's what this script produces in Eagle, with the previous script already having been run. I'm pretty proud of the result.


After a bit more tweaking, here is the final layout of the card.


creating a mockup

I felt that a nice rendering of the card would be appropriate just in case none of my ideas come to fruition. The renderings needed two things: models of the components and a decal to apply to the PCB.

OSH Park has gorgeous board previews that are created when you upload gerbers or board files. However, I want to eventually get the card made in black silkscreen, so I had to create a rendering myself. To do this, I used Eagle's EXPORT IMAGE command to export a monochrome image of a few individual layers. I exported the copper, silkscreen, soldermask stop layers.


I colored the copper layer with a gold-ish color, and then masked it in Photoshop using the soldermask stop layer. I inverted the stop layer and placed it on top (to simulate the soldermask), and placed the silkscreen on top in white. This resulted in the following image.


Next, I fiddled with Solidworks' Circuitworks package to import component position information into Solidworks and create an automatic model of the board. This replaced the existing model I had previously made of the shape of the PCB. The first step is exporting a .emn file from Eagle, which can be done using the EagleIDFExporter.ulp user language program which is included with Eagle. This file contains board outline geometry, drill sizes and locations, as well as component names and locations.

I wasn't satisfied with any of the included components I found in Circuitworks, and I wanted more detail than simple extruded rectangles. Instead, I created a model of each component by hand (except for a few which had models on the manufacturer's website). Circuitworks tries to infer a reference axis that corresponds to the Eagle part (the origin, and X and Y directions). It usually gets it wrong, leaving parts going through the board and in the wrong location. Circuitworks has a library import process that has an option to select an axis to use as a reference, so I created one for each part.


With this done, I could go through the Circuitworks import process, and then add the generated assembly back into my main assembly.


Some renderings are below.




That about wraps things up for now. The next steps are to get the PCB fabricated and mill the metal front plate, which will have to wait until I have access to the Georgia Tech machine shop.