Virtual reality through IR headtracking

Table of Contents

Note: This supercedes my previous project report.

Inspiration: https://youtu.be/Jd3-eiid-Uw?t=149

TED talk: https://youtu.be/QgKCrGvShZs?t=19

1 What is it?

I propose building a USB device that tracks the position and orientation of a single user's head, and uses that information to furnish a realistic view-dependent rendering of a 3D scene.

The device consists of a USB infrared camera rig (a webcam-sized component which clips to the top of a computer monitor and communicates with the computer over USB) and an infrared emitter device that affixes to the user's head (default option: safety glasses equipped with battery-powered infrared LEDs.)

The firmware on the camera rig detects and pinpoints the LED light sources using the infrared camera. It collects that information over

2 Who's done what beforehand?

The video shown above is the foundational example. Using the Wii remote and sensor bar from a Nintendo Wii, the author hacked together a device that performs head tracking in this way. Since this result, a community of other hackers have put together Wii-based hacks of various kinds.

An advantage of using Nintendo products is that they are easily attainable and cost potentially less than their individual parts due to various economic factors.

A primary defect, explored here, is that the parts are pre-assembled and blackboxed. We shouldn't have to buy the equipment from Nintendo itself. I also suspect they are also no longer as inexpensive as their constituent parts.

3 To-do list

  • [X]

    DONE Source materials.

    • [X] Infrared camera. The most special-purpose part is the infrared camera, which I have ordered from Digikey. https://www.digikey.com/catalog/en/partgroup/ir-positioning-camera-for-arduino/71049 It performs some on-board image processing, which is neat, but time permitting I intend to investigate the inner workings to build one myself if I can.
    • [X] Programming cables. It is useful to have a set of cables for connecting boards to computers and each other in various ways. I have obtained a male-female USB extender, an FTDI serial-to-usb cable, and I have built several 2x03 and 2x02 ribbon cable connectors.
  • [X]

    DONE Set up a server. Communication will be handled in Javascript using nodejs, so as to take advantage of both the 3D graphics capabilities and the serial communication.

    • [X] Install nodejs and npm.
    • [X] Design a simple nodejs+websockets demo. (Completed during interfaces week.)
    • [X] Communicate over serial using nodejs (Completed during interfaces week.)
    • [X] Install i2c for nodejs. As a result of experimentation during interfaces week, I have adopted a new approach: I will use nodejs to communicate with the board over serial, and the board itself will communicate over I2C. Node never needs to speak I2C.
    • [X] TODO Use nodejs to communicate with a basic I2C node board.
  • [X]

    Master I2C communication.

    • [X] Mill and stuff an I2C bus board. (Neil's example board will work). I broke the proverbial lance on this during network week, and will therefore instead try prototyping with an atmega with built-in I2C capabilities rather than bitbanging.
    • [X] Design and build a mega board for speaking I2C.
    • [X] Test the mega board.
    • [X] Install infrared lights on the mega board…
    • [X] …and verify that they work.
    • [X] Communicate over I2C. The infrared camera itself transmits its information over I2C.
  • [X]

    Set up a digital environment

    • [X] Render a digital scene
    • [X] Make a mockup of camera input, controlled by the mouse instead of by infrared light positioning.
  • [ ]

    Design and build an enclosure for the camera rig

    • [ ] Experiment with ways of combining the milling board with, e.g. a binder clip.
    • [ ] Try interference fit with an acrylic box enclosure.
    • [ ] Design the box, with a hole for serial cable and for the camera.
  • [-]

    Build an infrared emitter

    • [X] Place infrared LEDs on a regular board.
    • [X] Ensure that the ir camera can detect them. (Todo during networking week)
    • [ ] Try prototyping an acrylic bar or other simple-to-cut device that you can affix a battery to.
    • [X] Instead, first mill a PCB board that supports a battery
    • [ ] Design parametric glasses using SVG generation.
    • [ ] Design a cancellated visor that has holes for through-hole infrared leds.
    • [ ] Experiment with ways to attach arms to the visor (3d printed hinges? interference fit between acrylic–brittle?)
    • [ ] Experiment with ways of attaching circuitry to the glasses (copper tape, vinyl cutter, etc.) May need to sandwich electronics between two support structures for aesthetics.
    • [ ] Perform an initial draft test.
    • [ ] etc.
  • [-]

    Coordinate Projection

    • [X] Transform 2d infrared coordinates into 3D world coordinates.
    • [ ] Figure out a good user interface for calibrating the origin of the camera (simple reset switch on emitter? keyboard input?)
  • [ ]

    Design an enclosure tailor-made for the pcb board and camera

    • [ ] screws
  • [-]

    Integration

    • [X] Ensure that nodejs can communicate with a basic serial board. (Finished during interfaces week.)
    • [X] Ensure that position data can be transmitted over web sockets. (Finished synthetic data generation project during networking week: the nodejs server artifically generates position data and sends it over websockets, where it's interpreted and plotted client-side.)
    • [X] Understand the format being transmitted by the IR camera. (Read on the datasheet, but to be confirmed in practice.)
    • [ ] ! Experiment with possible speedups — to get best speed, should I convert highly compressed ir camera data in C before sending over serial, or server-side in javascript before sending it over websockets, or client-side in javascript in the browser?
    • [X] Translate the IR camera data into virtual-world viewpoint given the known rigid arrangement of the led array.
    • [ ] Decide what to do with bad data.
    • [ ] Unknown unknowns.
  • [ ]

    Stretch goals

    • [ ] Binocular ir cameras for additional dimensions of movement.
    • [ ] Experiment with more than two leds, including a tetrahedral arrangement for head rotation.
    • [ ] Keyboard controlled walking
    • [ ] Multiple user agents through shuttering.

4 Work log

  • Built a board for speaking TWI/I2C by bitbanging. Used Neil's serial bus board and adapted code from the accelerometer. Board failed in mysterious ways (see networking week); decided to revisit using native TWI.

  • Designed a board for natively speaking TWI (using atmega328p).

    • Board design 005-mega-first.jpg
    • Board had some manufacturing and design errors. 006-mega-first-copper.jpg
    • Manufacturing errors: some pins were subtly bridged (RESET and CLK).
    • Design errors: accidentally used pins that were not general-purpose I/O for some of the LEDs (most ADC pins are, but these weren't). Put placeholder 0 ohm resistors on the SCL and SDA lines, forgetting that if I needed pullup resistors, they'd need to be between the lines and Vcc, not on the lines themselves.
    • Mysteriously, serial i/o produces gibberish. Will need to use oscilloscope to determine
    • ! Emergent idea: Although I initially intended the LEDs to indicate status, I could also use one as an IR LED for testing the camera.
  • Programmed the board. 008-mega-programming.jpg

    • I used Neil's hello.arduino.328p.blink code to test whether the board was programmable at all.
    • I borrowed a TWI library to test whether I could communicate with the camera. I intend to define my own API functions instead.
    • Initiating TWI worked once I fixed the solder bridge between reset and clk (which caused the board to reset every time the register was activated).
    • Sending a hello command to the camera worked — after many hours of debugging, I discovered that it was necessary to wait around 1sec before sending the first TWI command. I suspect the camera needs time to load.
    • Sending a read request to the camera worked — after a great mystery (the camera itself has very sparse, contradictory, flawed documentation written by various hobbyists), I found that you have to write a specific byte to the camera each time you want to request bytes from it.
  • Fixed serial (Thursday)

    • I swapped which of TX and RX refered to in and out again. For reference, it's relative to the computer: Transmit is out, and Recieve is in. (To be absolutely sure, compare the board design and code for echo hello world and see which is which.)
    • Adapting the echo hello world code from attiny45 produced gibberish, suggesting timing errors.
    • I realized that the makefile for m328p.blink assumed a 20MHz crystal on the mega. So I changed F_CPU from 20000000 to 8000000, as 8MHz is the default clock speed for the m328p's internal clock.
    • Finally, the default echo hello world baud rate was too high. Given that there's no crystal, we need a lower baud rate.
  • LED daughter boards

    • Using inkscape, made a triangular array.
    • Then experimented with a simpler design. You can add one or two leds (so, for example, one infrared and one visible).
    • 022-led-daughter-on.jpg
  • Board 2.0

    • 016-mega-revised.jpg
    • Comparison: 020-mega-comparison.jpg
    • Relocated all four LEDs to general i/o pins.
    • Added a status LED between vcc and gnd.
    • Added a 5V regulator to regulate power to the peripherals. This required one additional 0.1uF capacitor, because the datasheet recommended adding smoothing capacitors to both sides. (I already had a smoothing 1uF capacitor between unregulated power and ground, because this design is a descendant of one of Neil's.)
    • Added a 20MHz resonator — I expect the camera might require fast timing. Will remove if unneeded.

Saturday 8/Dec/2018

  • Having milled four led daughter boards, stuffed them. 026-led-daughters.jpg 027-led-daughters-on.jpg

  • Used phone camera to check that the infrared leds were working. Turns out they work with 100Ω resistors rather than 500Ω resistors. 024-infrared.jpg

  • Finally found documentation for the commands to send to the camera to make it activate. It works! (Todo later: simplify the code using subroutines and fundamental register commands instead of library commands.)

  • By inserting appropriate delays, became able to request repeated reads from the camera without it blocking.

  • Used Interface week's nodejs code to read from the serial output

  • Wrote a bit-shifter to unpack the encoded data from the camera.

  • Modified my synthetic-data-generating code to decode serial input and send it over web sockets (modification of Interface week's nodejs code.)

  • ! Plotting of a single point works correctly. (Todo: test multiple points.)

  • Plotting of multiple points works correctly. Experimented with various ways to deal with the event-based serial data spurts. Optimization using slice instead of repeated shift.

  • Workflow:

    • Run node on ir-serial.js
    • Open a page like dxh.plot.infrared.html in the browser.
  • wooden glasses (all one piece with flextured hinges!)

https://www.youtube.com/watch?v=2Nj167idFkQ

Sunday 9/Dec/2018

  • Made a daughter board for converting 9V battery into regulated 5V using four pin connectors.
  • Worked out projection math successfully (field of view calculations; camera coordinates to real coordinates)

038-battery.jpg 040-battery-on.jpg 041-battery-assist.jpg

Monday 10/Dec/2018

  • Began designing enclosure for pcb board; sketched plan to print a back part and lasercut a viewing screen.
  • Brainstorming about ways to affix board to monitor like webcam.
  • Lasercut a mounting place for the pcb board

044-enclosure.jpg 045-enclosure.jpg 046-mounted.jpg 047-mounted.jpg

Tuesday 11/Dec/2018

  • Designed and lasercut draft version of visor; further iteration awaits.

049-visor.jpg 050-visor.jpg 051-visor.jpg

Author: Dylan Holmes

Created: 2018-12-12 Wed 12:47

Emacs 26.1 (Org mode 8.3beta)

Validate