nuralink

Lie Detector

A Wearable Dystopian Artifact

Project Overview

This is a portable, handheld lie detector device that analyzes a person’s sweat fluctuations (GSR) and heart beat (Pulse) to determine if they are telling the truth or lying. It displays the result on a TFT LED screen and uses NeoPixels for instant visual feedback. This device is conceptualized as an artifact within a dystopian setting.

Subterra: The Dystopian Context

In this dystopia, humanity is trapped underground, breathing recycled air in vast, sterile sanctuaries. The surface is uninhabitable, ravaged by a mutated chemical that wiped out all plant life and caused oxygen levels to plummet. The outside world is a toxic wasteland, and any exploration of it is strictly forbidden.

For individuals, life is one of survival, restriction, and disconnection. They are born into a world with no sun, no fresh air, and no connection to the natural world. Every day is a monotonous cycle of work in underground farms, producing oxygen and food to sustain a growing population. There are no opportunities for exploration, and dreams of the surface are nothing more than a forbidden fantasy.

Daily life is tightly controlled. Work is assigned based on necessity, and personal freedoms are nonexistent. Space is limited, and resources are precious—competition for both is fierce. Relationships are restricted, and the constant threat of punishment keeps the population in line. While some wonder about what lies beyond the underground sanctuaries, curiosity is dangerous, as any attempt to defy the laws or explore the surface leads to severe consequences. Humanity survives, but at the cost of their connection to nature, freedom, and hope.

Persona

Inspiration Board

Inspiration Board

Inspiration Board

Inspiration Board Collage Placeholder

Miro Link: View Board

Sketch

Conceptual Sketch

Circuit Diagram

Circuit Diagram

Wiring Diagram Placeholder

Bill of Materials

Name Qty Size Datasheet
Raspberry Pi Pico WH 1 51mm x 21mm x 2.1mm PDF
Neopixel 2 5mm x 5mm PDF
Resistor 2 4mm x 1.5mm x 1.5mm PDF
Button 2 8mm x 8mm x 9mm PDF
Pulse Sensor 1 5mm x 3.5mm PDF
TFT LED Screen 1 58mm x 33mm x 8mm PDF

Mechanical Drawing

Mechanical Drawing

Mechanical Drawing (Measurements in mm) Placeholder

Pseudo-Code

Initialize display and GPIO pins
    - Setup SPI pins for communication with the display
    - Release any previous display and setup display bus
    - Initialize the ST7735R display

Create a text label for dynamic messages on the display

Initialize pins for GSR sensor, pulse sensor, and buttons
    - Setup GSR sensor pin for analog input (for resistance- sweat)
    - Setup pulse sensor pin for analog input (for detecting heartbeat)
    - Setup power and calibration buttons for digital input

Initialize NeoPixels for visual feedback (Green for Truth, Red for Lie)

Define function `show_message(msg)`:
    - Update the displayed message with the given `msg`

Define function `read_gsr()`:
    - Collect multiple GSR readings (10 samples)
    - Return the average value of the readings

Define function `read_pulse()`:
    - Read pulse sensor data to calculate heart rate in beats per minute (bpm)
    - Use a simple algorithm to detect pulses (e.g., rising edges)
    - Return calculated bpm

Set initial variables:
    - Calibration step, truth and lie readings, thresholds for GSR and pulse, calibration flag, and device state

Start main loop:
    - Display "Press Power" message
    - If power button is pressed:
        - Toggle the device's on/off state
        - Show appropriate message and turn off NeoPixels when off
    - If device is off, wait and continue the loop

    If the device is on:
        - If the device is not calibrated:
            - Show calibration step message
            - If calibration button is pressed:
                - Read GSR and pulse data (both)
                - Append GSR and pulse readings to the appropriate list (truth or lie readings)
                - Increment calibration step
                - When calibration is complete, calculate and display the thresholds for both GSR and pulse rate, mark as calibrated
        - Else, in normal operation:
            - Read current GSR and pulse data (bpm)
            - If the GSR value is close to the truth threshold and the pulse rate is within normal range:
                - Indicate Truth with Green light and show "TRUTH" message
            - Else if the GSR value is close to the lie threshold and the pulse rate is elevated:
                - Indicate Lie with Red light and show "LIE" message
            - Else, indicate inconclusive result with no lights and show "INCONCLUSIVE" message
    - Wait for 0.2 seconds before the next loop iteration
        

Final Code (CircuitPython)

import time
import board
import digitalio
import analogio
import busio
import displayio
import terminalio
import neopixel
from adafruit_st7735r import ST7735R
from adafruit_display_text import label

# Display Setup
mosi_pin = board.GP11
clk_pin = board.GP10
reset_pin = board.GP17
cs_pin = board.GP18
dc_pin = board.GP16

displayio.release_displays()
spi = busio.SPI(clock=clk_pin, MOSI=mosi_pin)
display_bus = displayio.FourWire(spi, command=dc_pin, chip_select=cs_pin, reset=reset_pin)
display = ST7735R(display_bus, width=128, height=160, bgr=True)
main_group = displayio.Group()
display.root_group = main_group

text_area = label.Label(terminalio.FONT, text="Initializing...", color=0x000000, x=10, y=80)
main_group.append(text_area)

# GSR and Buttons Setup
gsr_pin = analogio.AnalogIn(board.GP27)
power_button = digitalio.DigitalInOut(board.GP12)
power_button.switch_to_input(pull=digitalio.Pull.DOWN)
calibration_button = digitalio.DigitalInOut(board.GP13)
calibration_button.switch_to_input(pull=digitalio.Pull.DOWN)

# NeoPixels
pixels1 = neopixel.NeoPixel(board.GP14, 1)  # Green (Truth)
pixels2 = neopixel.NeoPixel(board.GP15, 1)  # Red (Lie)

# Functions 
def show_message(msg):
    text_area.text = msg

def read_gsr():
    readings = []
    for _ in range(10):
        readings.append(gsr_pin.value)
        time.sleep(0.01)
    return sum(readings) // len(readings)

# Variables 
calibration_step = 0
truth_readings = []
lie_readings = []
truth_threshold = 0
lie_threshold = 0
calibrated = False
device_on = False

# Main Loop 
show_message("Press Power")

while True:
    if power_button.value:
        device_on = not device_on
        if device_on:
            show_message("Device ON")
        else:
            show_message("Device OFF")
            pixels1[0] = (0, 0, 0)
            pixels2[0] = (0, 0, 0)
        time.sleep(0.5)  # debounce

    if not device_on:
        time.sleep(0.1)
        continue

    if not calibrated:
        show_message(f"Cal Step {calibration_step+1}")
        if calibration_button.value:
            gsr = read_gsr()
            if calibration_step in (0, 1):
                truth_readings.append(gsr)
            elif calibration_step in (2, 3):
                lie_readings.append(gsr)

            calibration_step += 1
            time.sleep(0.5)  # debounce

            if calibration_step == 4:
                # Calculate thresholds
                truth_threshold = sum(truth_readings) // len(truth_readings)
                lie_threshold = sum(lie_readings) // len(lie_readings)
                calibrated = True
                show_message("Calibrated!")
                # In a real environment, prints go to serial console
                # print(f"Truth Threshold: {truth_threshold}") 
                # print(f"Lie Threshold: {lie_threshold}")
                time.sleep(1)

                # Show calibrated values briefly
                show_message(f"T:{truth_threshold}\nL:{lie_threshold}")
                time.sleep(2)
                show_message("Ready")
    else:
        # After calibration: normal operation
        gsr = read_gsr()
        # print("GSR:", gsr)

        margin = 1500  # Adjust sensitivity margin

        if gsr <= (truth_threshold + margin):
            # Lie detected (lower GSR often means less sweat/stress in this simple setup)
            # Reversing logic based on project description where Lie is red and Truth is green
            pixels1[0] = (0, 255, 0)  # Green
            pixels2[0] = (0, 0, 0)
            show_message("TRUTH")
        elif gsr >= (lie_threshold - margin):
            # Truth detected
            pixels1[0] = (0, 0, 0)
            pixels2[0] = (255, 0, 0)  # Red
            show_message("LIE")
        else:
            # Inconclusive
            pixels1[0] = (0, 0, 0)
            pixels2[0] = (0, 0, 0)
            show_message("INCONCLUSIVE")

        time.sleep(0.2)