Project Captivate

In this section, we describe our process in building the first full pairs of glasses. We also describe any issues we came across, how we addressed them, and how we updated the design files to mitigate them for future iterations.

A note about Production and Extensibility

We opted to manufacture our plastics using Nylon PA12 through a selective laser sintering (SLS) 3D printing process using an external vendor since Nylon is much more resilient and robust than other 3D printing materials while SLS printing offers a more uniform surface finish. However, we were also able to print all of our mechanical components with consumer-grade 3D printers (e.g., Formlabs Form 2, Prusa) so that is an avenue that is available for quick experimentation.

Our two rigid circuit boards were designed with specifications that fit most common circuit board manufacturers' capabilities (i.e., 4/4mil traces, 4 layers, 0.8mm board thickness, 0.2mm minimum hold sizes, and 1oz copper). The front flexible PCB is the only design feature which has a custom design feature, specifically having transition regions between 2-layers and 4-layers. We worked closely with a manufacturer in Shenzhen on producing the boards so it is possible other manufacturers may be able to support this feature. Otherwise, you can avoid the transition altogether and just make a 4-layer flexible PCB which would trade off robustness for added simplicity. For circuit board assembly, we were able to assemble a few sets by hand in our lab but many of the components are small and the front flexible PCB has 2 ball grid array (BGA) components so if lacking the soldering capabilities and expertise, an outside assembly service is recommended.

If wanting to add additional sensing modalities, we've added a few thru-hole connections on the PCB located on the right side that provides 3.3V power, ground, and connections to 3 general purpose input/output pins on the secondary MCU, equipped with access to the I2C communication and analog-to-digital conversion (ADC) peripherals. If some of the existing sensing subsystems are not needed for an application, those sensors can be removed and the existing connections can be re-purposed. One example would be to remove the blink sensor and use the existing power and the ADC lines to sample the signal of a different sensor. To make this easier, we've added various thru-hole regions on the front flexible circuit that wires can be soldered to. Another method that can be used is removing the PCB with the secondary processor and reusing our existing power circuit to design a new board with other sensing modalities.

ALRIGHT! Lets get started!

The first thing we did after receiving the PCBs from the manufacturer is inspected them to see if anything was broken or missing. What we noticed through some quick electrical tests was that the the assembler put on the wrong LEDs. The 2 LEDs that face toward the eyes and the 2 that illuminate the upper brows were not activating when a small current was passed through. We found out that the LEDs that were attached were common-anode but the ones in our design were supposed to be common-cathode (p/n: APFA3010SEKJ3ZGKQBKC). After contacting them, they informed us that they had received the wrong LEDs from the supplier and offered to replace them for us. However, due to logistical issues of sending them back and paying customs fees and tariffs, we decided to just replace them ourselves. What that means is that for each flexible circuit, we had to swap out 4 SMD LEDs. In addition, we also needed to swap out resistor R6 to 370k since the 453k resistor makes the blink detector too sensitive for real-world applications.

Placeholder
Flex Circuit Boards Fresh From Manufacturer
Placeholder
Replacing LEDs on Front Flex

We did have a bit of a bigger issue with the flex circuit that we learned after the circuit was already being manufactured. Through some iterative testing, we found that we needed to adjust the mechanical design to better position the nose sensors to increase the signal-to-noise ratio (SNR). This redesign also made it easier to insert the nose part of the flexible circuit into the mechanical housing. This meant that the two sections of the flexible PCB that are home to the on-nose sensors needed to be redesigned to conform to the new mechanical design. (Luckily for anyone working off of our latest design files, we’ve updated the final flex PCB layout to include these changes so you don't have to worry about this part). Unfortunately for us being on an academic budget, we didn’t have the funding to make a new batch of flexible PCBs and get them assembled so we had to think creatively. As a fix, we just manufactured the redesigned portions of the flexible circuit, snipped off the old nose sections of the original batch, and soldered on the new sections to the thru-hole pads we left there for future extensibility. This ended up working just fine but we did encounter a few issues related to the mechanical forces of snipping off the flexible circuit. Given that the whole board is flexible, including the copper layers and all intermediary layers, when you cut into the circuit, some of the copper layers can bridge and form shorts or partial connections. To mitigate this, we cut the board in a region where the copper traces in each layer don't overlap so that they wouldn't touch when cut into but it did take us a few hours to diagnose the issue.

Placeholder
Nose Pieces Snipped Off
Placeholder
Nose Piece Redesigns (To be Populated and Attached)

As for the 2 assembled side PCBs, everything looked good and the only thing we had to do is solder on the thru-hole thermopile on the secondary MCU PCB. We did this to save on assembly cost since it was the only thru-hole component on the board but would have dramatically increased assembly cost due to the manual labor required by the assembly house to solder the component.

Placeholder
Side PCBs
Placeholder
Thermopile Added to Seconday MCU PCB (Bottom is an Unpopulated Board)

Testing the Circuit Board Assembly

Note: if compiling our code via STM32CubeIDe, you'll likely get a few warnings about the code needing regeneration. This is because ST has a helpful utility called STM32Cube that allows you to setup the system through a GUI. However, this utility has a tendency of overwriting our custom code so we've deviated from relying on it and instead have setup peripherals manually using the same code structure that ST uses in their examples so its easy to follow. You can use the utility for your own application and we recommend doing so if new to embedded systems but it may overwrite some of our existing code so use it with caution.

At this point, we recommend testing the circuit electrical assembly prior to putting it in the plastics to ensure everything works. Hopefully with the latest board revisions, you shouldn't encounter an issue but given the uncertainty of the assembly process and the assembly service you use, its important to check a subset of your batch to ensure it all works as planned. For us right now, this step will guarantee all the LEDs light up as they should, the processors are successfully flashed, and all the sensor channels work.

The first thing we will do is flash the secondary MCU. For this, we won't need to connect all three circuit boards together since the core power circuitry is on the secondary MCU so as long as we provide 3.7-4.2V power into the battery input pins, the circuit will be live. To flash the secondary MCU, you need a Tag-Connect TC2030 cable connected to an ST-LINK programmer (ref schematic for pinout requirement). Once you power up the board via the battery connections, press the connector onto the progamming pins, and flash the binary using the STM32CubeProgrammer utility or compile the code and flash it using the STM32CubeIDE software (note: make sure the switch is in the ON position which is the position away from the connector to the flex circuit). If everything goes right, either utility should finish successfully. We won't be able to check the sensor channels until we get the remainder of the system connected and programmed.

Now we need to connect all three PCBs to be able to program the main MCU. Its recommended that you tape the flex down so that it doesn't get strained by any of the programming cables (flex circuits are fragile!). To flash the main MCU, the process is a bit easier since we were able to fit a USB Micro port. However, this will required you to make a custom USB cable where you can remap the pins so that you can connect it directly to an ST-LINK. We recommend going on Adafruit or a similar website and procuring a Micro USB connector shell that you can easily solder on wires to. Do not connect the 5V line between the programmer and the glasses circuit since the ST-LINKs aren’t designed to provide a lot of power and can be easily broken by attempting to sink too much power.

Placeholder
Circuit Board Assembly (already partially assembled in housing)

Since the main MCU is a dual-core STM32WB55 chip, we need to flash the network processor first and then the application processor. ST Microelectronics provides binaries to flash the network processor with but you need to choose the one that your application requires (e.g., Bluetooth and/or OpenThread or Bluetooth and/or ZigBee). The binaries we’ve successfully used with our glasses are the BLE stack and the OpenThread stack. We’ve also used the BLE & OpenThread concurrent stack and modified our latest revision for it but for reasons unknown to us, the OpenThread stack goes down after a few minutes of the system being active. In any case, we’re going to focus on the BLE-only binary for this tutorial.

Before flashing, make sure the two side PCBs are connected to the flex and as a reminder, the circuitry is secured so that you are not adding strain to the flexible circuit. Either with a power supply or a LiPo battery (3.7V), apply power to the system via one of the two battery connections (doesn't matter which one since they are OR'ed in hardware). To flash the network processor binary, you need to download the STM32CubeProgrammer application and connect the ST-Link to the main MCU via the custom USB cable you made. Follow the instructions on flashing the network binary found in the README in the STM32WB55 network binary folder.

Now that we have the network stack flashed, we are ready to flash our main MCU. For LED validation, we have a custom binary we made that you can flash that slowly cycles through all the LEDs so that you can tell if something needs to be resoldered — sometimes you might notice one color doesn't activate on an LED so you may need to add solder to a pin on the LED corresponding to that color. After that, you can grab the latest code for the main MCU on GitHub and open it with STM32CubeIDE (or your preferred development environment). To validate the sensor channels are all working, uncomment the line in captivate_config.h that’s titled TEST_RUN_ON_START which will automatically run the sensor channels when powered on. Then, in the MasterThreadTask function in master_thread.c, you can add a breakpoint after the packetizeData function call and check if sensorPacket is populated with proper data. This is also the thread you can modify with your own custom sensing architecture since this is the central point for the sensor subsystems. If something is wrong, check the electrical connections for that sensing subsystem. (note: we do not check if the VIVE position system is working in this tutorial since that requires the base stations to be setup. Since the circuitry for that is simple, we assume it works.)

Placeholder
LEDs Flashing (already partially assembled in housing)

Plastics Assembly

Alright, lets hide the electronics in some plastics! The first thing we’ll do is work on the temple arms. For the arm with the main MCU (i.e., the left one), we need to attach two pieces of copper tape for the pogo pins on the PCB to make contact with. This contact is for the capacitive touch feature of the glasses. In the plastic temple arm, you can see two square cavities for the pieces so just cut them to size and insert them with tweezers. It’s recommended to stake the copper (press the copper in at a few points with a pointy tweezers) to ensure its in there securely.

Placeholder
Placing Capacitive Touch Pads

For the batteries, we chose 150mAh batteries we found on AliExpress (401050) but feel free to choose whatever is appropriate for your application and modify the cavity size as you wish. We did have to replace the cables the batteries came with since they weren’t long enough but that may not be the case with the ones you order. Feed the battery wires through the internal channel and then solder on the ends to the respected PCB. We recommend soldering a longer length of wire than what is needed and then trimming it to the right length after feeding it through the internal channel, prior to soldering it to the PCBs. This internal channel is only made possible because we 3D printed these glasses so if pursuing injection molding, you will need to expose this channel and then cover it after. Also, if 3D printing it, the channel can get partially clogged with 3D printing material so you may need to run a solid core wire through it a few times to unclog it (we needed to do this for a subset of the plastics).

Placeholder
Batteries in Housing Cavity
Placeholder
Batteries Inserted into Plastics

Once the batteries are in, you can insert the side PCBs into their respected cavities and solder on the wires. Make sure they are oriented so that the flex connector is pointing inward. At this point, you can also attach the plastic slider attachment for the switch on the secondary MCU PCB.

Placeholder
Side PCBs and Batteries Inserted into Plastics Before Battery Wires are Clipped and Soldered

In addition, we need to cut some covers for the batteries so that they aren’t exposed. We chose neoprene foam covers because its comfortable against the skin but also allows the batteries some space in case they swell slightly during normal use. The form we used for the covers is located here.

Placeholder
Cutting of Battery Covers
Placeholder
Battery Covers Attached
Placeholder
Slider Added to Secondary MCU PCB

Now we can assemble the flex into the front housing. First, we need to prebend the flex slightly to make the process a bit easier. Specifically, you will need to gently bend the ends where the Front LED is in a stair-step pattern to conform to the inner surface of the front housing. Becareful not to apply any pressure on the LED Driver that is in that area since we’ve found that it cracks pretty easily because of it being in a chip-scale package (its raw silicon so its brittle).

Placeholder
Prebending Flex Circuit Board (GENTLY!)
Placeholder
Prebent Flex Circuit Board

Prior to putting the flex circuit in the front housing, we will insert the fresnel lenses into the plastics. These lenses are necessary since they guide the light from the concealed LED, allowing for a greater light transmittance and a wider field-of-view so that the LED can be seen at greater angles. We recommend placing them in gently through the front face and then using a flat surface to push them in all the way so that they are flush. These lenses deform easily since they are plastic so use a flat surface so that you don't distort the lens.

Placeholder
Inserting Fresnel Lenses

Now we are ready to insert the flexible circuit. Gently slide the nose pieces of the flex into their respected cavity and bend the circuit in real-time to conform to the mechanical housing. Then carefully push in the remaining sections of the flexible PCB so that they rest snuggly in the plastic. We recommend using soft tweezers so that you don't accidentally cut or rip the circuit. Once in, we can now start working on the fiber optics!

Placeholder
Placing Flex Circuit into Front Plastics
Flex Circuit in Front Housing

The fiber optics that we chose are designed to illuminate radially instead of just on the ends (i.e., side-glow). To be able to do this, the manufacturer wraps a standard fiber optic cable in a clear teflon tube that reduces the internal reflectivity of the cable and allows for light to dissipate radially across the length of the light pipe. For our design, we need to remove part of this teflon tubing so that the fiber can be inserted tightly into the top of the glasses, allowing for a more streamlined look. We only leave the teflon tubing on the fiber where it is exposed to increase the radial transmittance at those locations. Its important that the fiber being inserted makes contact with the LED that illuminates it to reduce internal light loss and maximize the light transfer from the LED into the fiber.

Placeholder
Cutting Fiber Optics
Placeholder
Fiber Optic Outer Layer Removed
Placeholder
Fiber Inserted into Frame and Touching Internal LED

We’re now ready to snap on the back cover for the front housing. Bend the two pieces of flex that are intended to run through the hinge so that they are outward facing and then insert the cover. The back cover will bend slightly when being inserted but should snap into place. The back cover also has 4 supporting No. 00 screws that self-tap into the plastic but we’ve found them to be unnecessary for our use but feel free to include them for added robustness.

Placeholder
Front Back Cover Inserted

Now that the back cover is on, we will attach the temple arms. For each temple arm, we have a screw for the top and the bottom that self-taps into the plastics. For the top screw, we have an additional spacer to reduce any movement due to torquing of the arms. Insert one arm into the front housing hinge, attach the flex cable to the rigid side PCB, insert back cover for that temple arm, and then insert the No. 2 screws. Repeat for the other arm.

Placeholder
Temple Arm Inserted into Front Housing Assembly and Flex Cable Connected
Placeholder
Back Cover for Temple Arm Inserted
Placeholder
Placed Spacer into Top Hole
Placeholder
Added Screw into Top
Placeholder
Added Second Screw into Bottom

Add the supporting No. 00 screws for the temple arm covers so that they don't open!

Placeholder
Supporting Screws for Temple Arm Covers

FINISHED!

Placeholder
Assembled Pair of Glasses (Front)
Placeholder
Assembled Pair of Glasses (Back)