close-circle
Close
0%
0%

Voight-Kampff Machine

Distinguishing Humans from Replicant's

Similar projects worth following
close
The Voight-Kampff is a machine that uses biometric sensors to measure a subjects emotional response. Voight-Kampff machines are used by Blade Runners to determine whether an individual is a real human or a replicant (which are not legally allowed on earth). Since replicant's exhibit lower emotional responses than humans it is a simpler and more cost effective method than performing a complete genetic analysis of every suspected individual.

At the present time, this project is divided into 2 parts:

  1. Voight-Kampff machine (this project) - functional replica of the movie prop
  2. viEwMotion (View Emotion) - wearable Voight Kampff - which houses the sensors used fort measuring emotional response (in the form of a wrist band).

This section of the overall project will address the building and fabrication of the machine used in Bladerunner. This includes working out a complete 3D model of the machine, building the moving parts (arm, "eye", and bellows), interfacing the 3 separate monitors, LED bargraphs, and all software and hardware including schematics.

The viEwMotion section will focus on the sensors used (with full schematics, etc.), software algorithm development and fabrication of the wrist band housing the sensors.

RedGreenBargraph Drawing 1.pdf

Mounting jig for Red and Green bargraph

Adobe Portable Document Format - 546.80 kB - 10/14/2017 at 19:07

eye
Preview
download-circle
Download

RedBargraph Drawing 1.pdf

Mounting jig for Red bargraph

Adobe Portable Document Format - 509.37 kB - 10/14/2017 at 19:07

eye
Preview
download-circle
Download

  • 1 × Continuous Rotation Servo (standard size) FeeTech FS5103R (Adafruit product number 154)
  • 1 × Continuous Rotation Micro Servo FeeTech FS90R (Adafruit product number 2442)
  • 1 × NEMA17 Stepper Motor with Planetary Gearbox 5:1 planetary gearbox
  • 1 × Standard Servo
  • 8 × Rectangular LED's green over main monitor

View all 12 components

  • Bellow's Mechanism Functioning!

    Tom Meehan07/03/2017 at 00:25 0 comments

    After a much experimentation, much of it making overly complicated mechanisms, I finally went back to basics and tried using a normal regular servo to move the bellows. I'm not sure why i didn't try it first but I think it was because of difficulties in getting the "arm" to raise - nothing I tried had enough torque until I found a geared stepper.

    Anyway, here's the video of my test run:

    The code is super basic, just using the standard Arduino Servo library to control the motion. I want to smooth out the motion if I can. If possible, I hope to find a servo library that allows steps less than 1 degree (or, if I have to, write my own).

  • Progress on the infamous Voight-Kampff arm

    Tom Meehan06/09/2017 at 04:33 0 comments

    I've been trying to get a video of my functioning Voight-Kampff “arm” filmed and posted for more than a week now, finally I recorded it and now I can post it and here it is:

    After re-writing my control code multiple times I finally realized what I was doing wrong – I simply needed to change my conditional statements from “if” to “while”. An embarrassing mistake but all to easy to miss when I haven't had anyone else look at my code (to easy to read “into” your own writing – if I'd had someone else look at it they would have caught it immediately – “palm to forehead” moment).

    Here's the functioning code:

    /*VK arm - lift, extend, rotate 
    *  Serial communication used in initial debugging
    *  Goal - use signal from RPi to trigger the arm raise, extend and
    *  rotate sequence
    *   - endstops for safety and to signal extension and rotation limits
     */
    
    //Arm Raise motor -Stepper motor driven by Pololu A4988 driver
      int RaiseDir = 8; //dir pin - arduino pin to direction pin on Stepper Driver
      int RaiseStep = 9; //step pin - arduino pin to step pin on Stepper Driver
      
    #include <Servo.h>
    //Servo's
    // Arm Extension servo
    Servo ExtServo;    //Extends and retracts upper arm
      int ExtStop = 3;
      boolean ExtVal = true;
      int ExtFor = 100;  //adjust according to speed and weight
      int ExtBack = 0;
      int ExtHold = 90;
    //  "Eye" Rotation servo
    Servo RotServo;     //Rotates eye Up (forward) or Down (back)
      int RotStop = 6;
      boolean RotVal = true;
      int RotUp = 100;  //adjust according to speed and weight
      int RotDown = 86;
      int RotHold = 90;
      
    void setup() {
      ExtServo.attach(2);  //470uF electrolytic cap- for motor start
      ExtServo.write(ExtHold);
      RotServo.attach(5);  //470uF electrolytic cap- for motor start
      RotServo.write(RotHold);
      pinMode(RaiseDir, OUTPUT);
      pinMode(RaiseStep, OUTPUT);
      pinMode(ExtStop, INPUT_PULLUP);
      pinMode(RotStop, INPUT_PULLUP);
      Serial.begin(9600);
    }
    
    void loop() {
      delay(1000);    //Pause
      Raise();        //Raise the arm
      delay(1000);    //Pause
      Extend();       //Extend the arm
      delay(1000);    //Pause
      Rotate();       //Rotate "Eye" forward
      while(1);
     }
    
    void Raise() {
      Serial.println("Raising Arm...");
      digitalWrite(RaiseDir,LOW); // Set Dir high
        for(int x = 0; x < 125; x++)   {
          digitalWrite(RaiseStep,HIGH); // Output high
          delay(10); // Wait
          digitalWrite(RaiseStep,LOW); // Output low
          delay(10); // Wait
            }
      Serial.println("Arm Raised...");
      return;
    }
    
    void Extend() {
      ExtVal=digitalRead(ExtStop);
      while  (ExtVal == true)  {     
        //Serial.println("Extending Arm..  ");
        ExtServo.write(ExtFor);
        ExtVal = digitalRead(ExtStop);
        //Serial.print(ExtVal);
      }
       //Serial.println("Arm Extended..");
       ExtServo.write(ExtHold);
       return;
    }
    
    void Rotate()  {
       RotVal=digitalRead(RotStop);
       while (RotVal == true) {
        //Serial.println("Rotating Up..");
        RotServo.write(RotUp);
        RotVal = digitalRead(RotStop);
        }
        RotServo.write(RotHold);
       //Serial.println("Eye In Position...");
        return;
    }
    Well anyway, it's fixed and working correctly now. I do still need to add a “retract and store” sequence but that is fairly simple now and will depend on the types of end-stops I use to detect the positions of the different moving parts.

    I'm continuing to work on modeling, what I refer to as, the “eye” servo box. I haven't added all the details yet since I'm still trying to finalize the scale (in reference to the “shaver”). One attempt is visible in the current video (3D-printed the front half, filled lines with “Bondo Glazing and Spot Putty”, sanded, primed and painted black).

    The screens on the VK are continuing to give me headaches – I made cutouts of the different available LCD screen sizes (that support “component input” and 4:3 aspect ratio) just so that I could check out how they might work.

    I've also been attempting to use some old CRT viewfinder's (salvaged from VHS Video Camera's) and trying to project the image onto a mini screen. So far this has been unsuccessful, I... Read more »

  • VK - LED Bar Graphs

    Tom Meehan04/24/2017 at 00:16 0 comments

    Light Bar Above Main Screen

    For this bar graph I'm currently using 12 - 2x5mm rectangular LED's (I used Red/Green LED's that have 3 leads - common cathode, 2 anodes 1 for each color). I was thinking to make a more graded display (2 levels for each LED – green then red so 24 levels) but realized that wouldn't really match the display in movie. The movie display looks like a 8 Red then 4 Green array, so I'm only using 2 leads for each LED – 8 with Red anode and 4 with Green anode (final design will use single color LED's).

    I'm currently using two SN74HC595 - 8 bit serial to parallel out shift registers to control the LED's. This means that 16 bits of information (0 or 1 / on or off) are sent out (4 bits are unused since there are only 12 LED's). A great tutorial on using these shift registers with LED's and Arduino's is at Adafuit - Arduino Lesson 4.

    Light Bar Below Small Screens

    The 10 bar LED below the 2 smaller screens, on the left side (from the examiners point of view).

    These LED bar-graphs seem to fit, they are come in a 20 DIL package with a 2.54mm pin spacing (they fit perfectly on a solder-less breadboard, bridging the middle of the board). My initial idea was to use shift registers (74HC595's) for this bar-graph also but remembered a circuit I built following a tutorial a few years ago that used a single Johnson Decade Counter (CD4017BE) to control all 10 LED's and at that time I adapted it to work with an Attiny85 using an analog input (voltage divider made of a resistor and a 10K thermistor – for basic temperature biofeedback). This tutorial is a good on on using the Johnson Decade Counter.

    The Johnson Decade Counter decreases the pins used to control the LED array from 3 to 2 and eliminates the need for current limiting resistors (though still likely a good idea) since it can only output 10mA per pin. Unlike the 595 shift registers used for the main screen LED Bar the 4017 requires us to use rapid switching for persistence of vision – only one LED can be lit at a time.


  • CAD work update

    Tom Meehan04/12/2017 at 18:41 0 comments

    Quick update on CAD work on workup for 3D model of Voight Kampff.

    Still refining this but all files are up on OnShape (may need to create a free account to view or work files).

  • AD8232 ECG Breakout Testing

    Tom Meehan04/12/2017 at 04:08 0 comments

      The AD8232 is a great chip, from Analog Devices, for reading bio-electrical signals (mainly muscle and heart - but may be good for EEG). The chip only comes in a 4 mm × 4 mm, 20-lead LFCSP package but thankfully SparkFun carries a breakout for it SparkFun Single Lead Heart Rate Monitor – AD8232 ,SEN-12650.

      SparkFun even has a hookup guide and a repository on Github for code examples. The code on Github hasn't been updated for a few years but I've tested the Arduino code and it works fine (the Processing code does not seem to work on the newest release of Processsing - 3.3). To visualize the heart data I just used the Arduino code and the Serial Plotter in the Arduino IDE (located in the “Tools” tab). Here's an example:

      I'll go into further detail later.

      But, for now I built up a VK model using card stock (the front is fairly accurate but the top is missing a lot of details):

      In the foreground are some of the sensors and screens I've been testing.

      I mainly put this model together to:

      1. See if my measurements and scale were correct.
      2. To use as a physical comparison for parts (to see if screens, etc actually fit correctly).

      Thankfully, it seems that I'm on the right track!

  • Non-contact IR Thermometer Updates

    Tom Meehan04/07/2017 at 06:59 0 comments

    Testing Harbour Freight non-contact IR temp sensor. Drawing from DIY Thermal Camera for information on connecting to Arduino for sending serial information to laptop.

    I adapted and simplified some code to read and send the temperature data:

    /*Harbour Freight Non-Contact IR Temp Sensor
    adapted from https://dorkbotpdx.org/blog/scott_d/inexpensive_ir_based_temperature_sensor_for_microprocessors
      changed to use serial monitor instead of a 16x2 LCD and function order re-organized
        setup -> loop -> readBit  with indentations added to make reading easier
    */
    
    #define CLK 3
    #define DATA 4
    
    volatile int nbits = 0;
    volatile byte hexbyte = 0;
    volatile byte read_byte;
    volatile int byte_ready = 0;
    
    volatile unsigned char message[4];
    volatile int nbytes = 0;
    volatile int message_waiting = 0;
    
    unsigned long last_time = 0;
    
    float temp;
    float ambient;
    
    void setup() {
      delay(2000);
      Serial.begin(9600);
    
      pinMode(CLK, INPUT);
      pinMode(DATA, INPUT);
      attachInterrupt(1, readBit, FALLING);
    }
    
    void loop() {
      if (message_waiting == 1) {
        last_time = millis();
      if (message[0] == 0x4c) {
        int t = message[1]<<8 | message[2];
        temp = t/16.0 -273.15;
        Serial.print(millis()/1000.0);Serial.print(" ");
        Serial.println(temp);
        } 
          else if (message[0] == 0x66) {
            int t = message[1]<<8 | message[2];
            ambient = t/16.0 -273.15;
          }
       message_waiting = 0;
      }
    
      if (millis() - last_time > 1000) {
        nbits = 0;
        nbytes = 0;
        hexbyte = 0;
        message_waiting = 0;
        byte_ready = 0;
        last_time = millis();
        }
    }
    
    void readBit() {
      int val = digitalRead(DATA);
      nbits++;
      int bit = (val == HIGH) ? 1 : 0;
      hexbyte = (hexbyte << 1) | bit;
      if (nbits == 8) {
        if (byte_ready == 0) {
          read_byte = hexbyte;
          byte_ready = 1;
          }
        if (hexbyte == 0xd) {
          nbytes = 0;
          message_waiting = 1;
          } 
        else if (message_waiting == 0) {
          if (nbytes < 4) {
            message[nbytes] = hexbyte;
          }
          nbytes++;
        }
      hexbyte = 0;
      nbits = 0;
      }
    }
    Finally have a better understanding of the S:D ratio that is given on commercial non-contact temperature sensor units. The Harbour Freight one that I purchased states that it 6:1 spot to distance ratio, this means that at 6 inches the spot size (area read) is 1 inch and at 12 inches the spot size is 2 inches.

    A good illustration (from Grainger, shows a 12:1 ratio):

  • Non-contact IR Thermometer / Sensor for Blush Response

    Tom Meehan04/06/2017 at 02:55 0 comments

    Initially I tested the Melexis 90614 sensor (I chose this sensor due to it's smaller field of view compared to other sensors I looked at). While the sensor worked perfectly, it was only good for short range (under 10cm) – I expected this might be the case which is why I detailed the method of narrowing the field of view in my last post. I tried that method by using a 1mm hole (in polished steel sheet metal) and placing it 1mm from sensor. Well, no luck. This only resulted in cutting the total IR getting to sensor (limited view by cutting everything else out – not by focusing field of view to smaller area, which would utilize the whole sensor).

    This led me to dropping the whole idea of measuring changes in temperature of the “cheek” area due to not being able to focus a sensor on a small area from any reasonable distance. Well, that is, until I met Michael Shaub at the Hackaday Un-Conference in Chicago. Talking to him about his IR Imaging project DIY Thermal Camera , as well as his presentation of the project, gave me the motivation to look further into how these sensors can be focused on a small area at a greater distance from the sensor.

    Presently testing out ideas using: Infrared Laser Thermometer Pittsburgh® - Harbour Freight item#93984 ($18.99) (which I think is the one Micheal is using). Basic specs for this are below:

    • 6:1 spot size to distance ratio
    • Non-contact IR thermometer pin-out
      • Data (pin D on module) to pin 12
      • Clock (pin C on module) to pin 2
      • Power (pin V on module) to diode from 3.3V supply
      • Ground (pin G on module) to ground

    Test results coming soon!

  • Issues and Solutions

    Tom Meehan03/13/2017 at 17:30 0 comments

    Mechanical issues encountered and solved (mostly):

    Biggest mechanical issue has been with my 3D Printer – one of the nuts on my Z-axis lead screws became stripped out. It took awhile to determine this was the issue (initially looked like a failure in the coupling of the lead screw to the stepper motor) and once I did figure it out I had to find a replacement nut, disassemble and re-assemble the printer, and then re-level and re-calibrate the whole thing. This obviously held me up in prototyping test parts but it is fixed and working better than ever now.

    Extension arm – currently testing 1/4” aluminum cylindrical extrusion (sounds technical but I got it off the shelf at Menards). Have found that it is “nominally” 1/4”, but is actually a bit larger than that. Came into play when testing a 1/4” I.D. nylon bushing – by itself it worked, but when inserted into a wood block it was to tight for the rod, even after running a 1/4” drill bit through it. So, switched to some Delrin – drilled a 1/4” hole through a 3/4”x3/4”x3/4” cube – better but still tight. Sanded down the lower section of the 1/4” aluminum rod with 400-600 grit sand paper – now it slides in and out smoothly.

    Servo motors – primarily the motor to extend the arm, needed more torque and metal gears – solved (SG-90 servo's from TowerPro). Encountered one new issue with the servo for arm extension – I incorrectly thought that the servo would rotate more than 180 degrees. I was able to fix this by converting the servo motor into a continuous rotation gear motor ( Adafruit guide to modifying servo for continuous rotation ). I will need to add limit switches to mark the endpoints of the travel of the arm.

    Raising the arm - continuing to test motors for raising the arm on the VK. None of the Servo's I have on hand are strong enough (high enough torque) and they stall under the tests I've tried. The same goes for all but the largest of the geared motors that I have on hand. I finally put together a test rig for my largest geared motor only to find that it had insufficient torque at lower speeds (controlling with PWM and a L293 H-Bridge). I ended up having to order a NEMA 17 stepper motor with a planetary gearbox (5:1 reduction), torque ratings look more than sufficient. I should receive it by Wednesday this week.

    Sensor Issues solved and working on:

    PulseOx sensor (MAX30100) – surface mount pads are just too small for me (since I'm just a beginner with surface mount components). I've etched multiple breakout boards (pics below) but have been unsuccessful at making an actual working board, the pads on the surface mount package are just to small for me (I've only just started using SMD components). I decided it would just be easier to buy a commercial module, the MAXREFDES117 (it uses the MAX30102 PulseOx sensor and comes with sample code for the Arduino).

    After receiving the MAXREFDES117 I soldered some header pins on to connect it up. Downloaded the code from Maxim Integrated, opened it up in my Arduino IDE and tried compiling it... a no go, it threw a bunch of errors and would not compile. Looking through all the header files I found that I needed to change the pin and port assignments the the I2C interface to work correctly. I did all that but still it wouldn't compile. Then I figured I might need to update my IDE – turns out it was a bit old (I was using 1.6.4 while the newest is 1.8.1). After updating everything I opened the new IDE, loaded up the example sketch and tried again to compile – it still failed. After some online searching and watching some videos by Maxim Integrated I could not find any comments by anyone using this module with an Arduino.

    Finally I decided to reach out to Maxim Integrated Support and emailed them about my problems with getting the module to work with their sample code. I did receive a reply back stating that they tested the sample code and experienced the same...

    Read more »

  • Blush Sensor

    Tom Meehan02/21/2017 at 05:53 0 comments

    Currently I'm using the GY-906 (off eBay) MLX90614 - non-contact IR temperature sensor breakout board. I chose this sensor mainly because it had a smaller field of view than Texas Instruments TMP006 sensor. Adafruit has tutorial's and libraries for both of these sensors (here's the link for the MLX90614 Adafruit Tutorial and Arduino Libraries).

    My initial tests for this sensor worked flawlessly - no issues with communication through an Arduino and sensor reacted as anticipated to different temperature gradients.

    While I can't find my bookmark for it, TI has a tutorial on limiting the field of view of their TMP006 sensor and I'm using that information to attempt to do the same with the MLX90614. Their approach is fairly simple and straight forward though it does require simple measurements and a little bit of trigonometry.

    Below is an illustration of the basic concept:

    To make it a bit easier to understand (conceptually) I rotated the view 90 degrees:

    The field of view is circular with a radius of "r1" for my purposes I'm using a radius, for the field of view, of 5cm (so a circle with a diameter of 10cm - basically want to view the cheeks on the face of the subject). As a starting point I'm using 50cm as the distance from the sensor to the subjects face. This gives us:

    Once we know the required angle we just need to figure the size of the hole for the aperture and how far away it needs to be from the sensor:

    The needed angle (5.7 degrees) was calculated above now we only have to plug in the distance from the aperture that we want, then we'll have the radius hole we need (just double that to get the diameter).

    For the aperture I plan to use some thin aluminum sheet and polish the side facing the sensor. I'll start testing this part tomorrow to see if it works in the way I'm hoping it will.

  • Arm Extension

    Tom Meehan02/10/2017 at 21:43 0 comments

    This is a short video I shot demonstrating the arm extension mechanism on the Voight-Kampff.

    The 2 pulley wheels and the coupling attaching the rods together I designed and 3D printed for this test, the thicker metal rod is a 7mm guide rod salvaged from an old scanner auicnd the thinner rod was taken from a pants hanger (it ran through the 2 clips on the hanger). For a quick and easy bushing for the rod to slide through I used HDPE (from kitchen cutting board).

    Still picture of test:

View all 12 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates