Tristan RobertYves Gabriel
Published © GPL3+

Visual Input System for Object Recognition (V.I.S.O.R.)

An interactive robotic eyeball that detects nearby people, looks around realistically, and displays "I see you. "

IntermediateShowcase (no instructions)7 days52
Visual Input System for Object Recognition (V.I.S.O.R.)

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
SG90 Micro-servo motor
SG90 Micro-servo motor
×3
Standard LCD - 16x2 White on Blue
Adafruit Standard LCD - 16x2 White on Blue
×1
Breadboard (generic)
Breadboard (generic)
×1
Machine Screw, M2.5
Machine Screw, M2.5
×1
Machine Screw, M3
Machine Screw, M3
×2

Software apps and online services

Arduino IDE
Arduino IDE
Tinkercad
Autodesk Tinkercad

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

VISOR components

Eyeball, Eyelid Top, Eyelid Stand, Rectangular Lever

VISOR platform

Platform

Code

VISOR code

C/C++
Arduino IDE, C++
#include <Servo.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);
Servo detectSRVO;
Servo heyeSRVO;
Servo blinkSRVO;
    
bool objectdetected = false; //variable for motion detection
bool eyeactive = false; //status of eye
bool open = false; //should eye be opened or closed

int dCounter = 5; //checks for motion, 0 = motion present
int dVal = 0; //detect servo rotation variable

void setup() {
  closeEyelid();
  detectSRVO.attach(4);
  heyeSRVO.attach(7);
  blinkSRVO.attach(9);
  pinMode(5, OUTPUT); //trig for ultrasonic rangefinder
  pinMode(6, INPUT); //echo for ultrasonic rangefinder
  Serial.begin(9600);
  lcd.init();
  lcd.clear();
  lcd.backlight();
}

void loop() {
  rotateSensor();
  if(objectdetected == true){
    Serial.println("motion detected");
    dCounter = 0; //motion present, reset counter
  }
  else{
    Serial.println("motion not found");
    dCounter = dCounter + 1; //no motion present, add to counter
  }
  Serial.println(dCounter);
  activateEYE();
  
}

void rotateSensor(){
  for(int i = dVal; i < 90; i++){
    detectSRVO.write(i); //rotate eye
    delay(30);
    dVal = i; //variable memory for servo rotation
    search(); //search while rotating
    if(objectdetected == true){
      return; } //report detection
  }
  for(int i = dVal; i > 0; i--){
    detectSRVO.write(i); //rotate eye
    delay(30);
    dVal = i; //variable memory for servo rotation
    search(); //search while rotating
    if(objectdetected == true){
      return; } //report detection
  }
}

void search(){
  digitalWrite(5, LOW); //ultrasonic rangefinder function 
  delayMicroseconds(2);
  digitalWrite(5, HIGH);
  delayMicroseconds(10);
  digitalWrite(5, LOW);
  int duration = pulseIn(6, HIGH);
  int distance = (duration / 2) * 0.0344;
  if(distance <= 30){
    objectdetected = true; //if distance to nearest object is less than 30 cm, report object detected as true
  }
  else{
    objectdetected = false; //otherwise report object detected as false
  }

}

void activateEYE(){
  if(dCounter < 5){ //counter allows eye to stay on briefly, even if no motion is directly present
    openEyelid(); //open eyelid
    eyeactive = true; //active status is true

  }
  else{
    closeEyelid(); //close eyelid, counter has reached max
    eyeactive = false; //eye status should be inactive
    heyeSRVO.write(90); //return horizontal eye servo to normal position
    lcd.clear(); //clear I see you message from the LCD
  }
  if(eyeactive == true){ //procedues if eye is active
    int tMove = random(20,1000); //randomize horizontal servo movement for eye
    int d = random(78, 112); //randomize pauses between movement
    heyeSRVO.write(d); //move eye
    delay(tMove);
    lcd.setCursor(2, 0);
    lcd.print("I see you.."); //write I see you on the LCD
    int tBlink = random(100, 2500); //randomize blink servo movement for eye
    delay(tBlink);
    Serial.println("blinking");
    blinkEye(); //blink eye
    
  }

}

void openEyelid(){
  if(open == false){
    open = true;
    for(int j = 0; j < 175; j++){ //slowly open eye
      blinkSRVO.write(j);
      delay(10);
    }
  }
}
void closeEyelid(){
  if(open == true){ 
    open = false;
    for(int j = 175; j > 0; j--){ //slowly close eye
      blinkSRVO.write(j);
      delay(10);
    }
  }
}

void blinkEye(){
  for(int j = 175; j > 0; j--){
    blinkSRVO.write(j);
    delay(5); //close eyelid quickly
  }
  delay(10); //pause
  for(int j = 0; j < 175; j++){
    blinkSRVO.write(j);
    delay(5); //open eyelid quickly
  }
  
}

// Tristan Robert and Yves Gabriel, 2026

Credits

Tristan Robert
1 project • 0 followers
Yves Gabriel
1 project • 0 followers

Comments