Final Project: RekasBot

Concept:

The idea was to create a bot that can be controlled with hand movement using machine learning with the P5.ml library. The P5 sketch has an in-car design with the steering wheel and the Arduino comprises 4dc motors, two ultrasonic sensors, and some LEDs.

Interactive Design:

For user interactivity, I decided to use the P5.js. The computer video webcam helps the machine learning library to detect the movement of the user’s hand and map these movements to the size of the canvas. This information is used to control the steering wheel, which controls the Arduino.

Arduino Code:

For the Arduino aspect, the motors are controlled using switch cases. The Arduino receives cases from the P5 sketch and based on those cases, the Arduino knows how to control the 4 DC motors. The Arduino uses the ultrasonic sensors to detect obstacles and sends this information to the P5 sketch to be viewed by the user.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <Servo.h>//include the Servo library/
#include <time.h>//include the time library for seeding random number
Servo myservo;//creating servo object
const int ain1Pin = 3;//setting pins for motor for left side which is connected in parallel
const int ain2Pin = 4;
const int pwmAPin = 5;
const int bin1Pin = 8;//setting pinf for motor for right side
const int bin2Pin = 7;
const int pwmBPin = 6;
const int trigPin1 = 11;//setting pins for front ultrasonic sensor
const int echoPin1= A0;//I used A0 pin cause I didnt have space...Please pardon me
const int trigPin2 = 10;//setting pins for back ultrasonic sensor
const int echoPin2 = A1;//here too
const int warningbuzzer=12;//setting the buzzer to 12
//servo motor
const int headmovePin=9;//setting the servo motor pin to 9
int wallstop=0;//initializing the obstacle detection
unsigned long previousMillis = 0;//setting millis to 0
const long interval = 5000;//setting interval for the millis
void setup() {
myservo.attach(headmovePin);//pass the servo pin to the servo library
randomSeed(time(NULL));//seed random number using the current time
pinMode(ain1Pin, OUTPUT);//setting the pins as output and input
pinMode(2, OUTPUT);//light checker
pinMode(ain2Pin, OUTPUT);//motor pin
pinMode(pwmAPin, OUTPUT); // not needed really
pinMode(bin1Pin, OUTPUT);
pinMode(bin2Pin, OUTPUT);
pinMode(pwmBPin, OUTPUT); // not needed really
// Start serial communication so we can send data
// over the USB connection to our p5js sketch
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
pinMode(warningbuzzer, OUTPUT);
Serial.begin(9600);//setting the serial band
while (!Serial.available()) {
digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
Serial.println("0,0"); // send a starting message
delay(300); // wait 1/3 second
digitalWrite(LED_BUILTIN, LOW);
delay(1000);//delay for a second
}
}
void loop() {
wallstop=crushstop();
//When the serial is detected do this
while (Serial.available()) {//while the serial connection exists
digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data
wallstop=crushstop();//update the wallstop from the crush function
unsigned long currentMillis = millis();//set current millis
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
movehead();//if the interval is reached, move the head
}
int movement = Serial.parseInt();//get the movement case from p5
if (Serial.read() == '\n') {//when we read a new line,
switch(movement){//execute the following commmands based on the case
case 0://no movement
analogWrite(pwmAPin, 0);
digitalWrite(ain1Pin, HIGH);
digitalWrite(ain2Pin, LOW);
analogWrite(pwmBPin, 0);
digitalWrite(bin1Pin, LOW);
digitalWrite(bin2Pin, HIGH);
break;
case 1://forward
analogWrite(pwmAPin, 255);
digitalWrite(ain1Pin, LOW);
digitalWrite(ain2Pin, HIGH);
analogWrite(pwmBPin, 255);
digitalWrite(bin1Pin, HIGH);
digitalWrite(bin2Pin, LOW);
break;
case 2://reverse
analogWrite(pwmAPin, 255);
digitalWrite(ain1Pin, HIGH);
digitalWrite(ain2Pin, LOW);
analogWrite(pwmBPin, 255);
digitalWrite(bin1Pin, LOW);
digitalWrite(bin2Pin, HIGH);
break;
case 3://right front
analogWrite(pwmBPin, 255);
digitalWrite(bin1Pin, HIGH);
digitalWrite(bin2Pin, LOW);
break;
case 4://left front
analogWrite(pwmAPin, 255);
digitalWrite(ain1Pin, LOW);
digitalWrite(ain2Pin, HIGH);
break;
case 5://right back
analogWrite(pwmBPin, 255);
digitalWrite(bin1Pin, LOW);
digitalWrite(bin2Pin, HIGH);
break;
case 6://left back
analogWrite(pwmAPin, 255);
digitalWrite(ain1Pin, HIGH);
digitalWrite(ain2Pin, LOW);
break;
default://if not case is gotten within our expected range, stop
analogWrite(pwmAPin, 0);
digitalWrite(ain1Pin, HIGH);
digitalWrite(ain2Pin, LOW);
analogWrite(pwmBPin, 0);
digitalWrite(bin1Pin, LOW);
digitalWrite(bin2Pin, HIGH);
break;
}
delay(5);
Serial.println(wallstop);//send the detection to p5
}
}
}
int crushstop(){//this function returns 1 when an obstacle is ahead and 2 when an obstacle is behind
int wallstop=0;//initialize wallstop
digitalWrite(trigPin1, LOW);
delayMicroseconds(2); //basically shooting beems and using the time it takes to bounce back to calculate distance
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
// Time it takes for the pulse to travel back from the object long
int duration1 = pulseIn(echoPin1, HIGH);
// Universal conversion of time into distance in cm
int distance1 = duration1 * 0.034 / 2;//divided by two beause its a two way thing
digitalWrite(trigPin2, LOW);
delayMicroseconds(2);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);
// Time it takes for the pulse to travel back from the object long
int duration2 = pulseIn(echoPin2, HIGH);
// Universal conversion of time into distance in cm
int distance2 = duration2 * 0.034 / 2;
if(distance1<5){//if collision is detected behind, send 2
wallstop=2;
tone(warningbuzzer,2000);//play the tone
delay(5);
}
else if(distance2<5){
wallstop=1;//if collision is detected infront, send 1
tone(warningbuzzer,2000);//play the tone
delay(5);
}
else{
wallstop=0;
noTone(warningbuzzer);//if nothing is detected dont play a tone
}
return wallstop;//return this info
}
void movehead(){
myservo.write(random(0, 180));//move the head to a random number between 0 and 180
delay(15);
}
#include <Servo.h>//include the Servo library/ #include <time.h>//include the time library for seeding random number Servo myservo;//creating servo object const int ain1Pin = 3;//setting pins for motor for left side which is connected in parallel const int ain2Pin = 4; const int pwmAPin = 5; const int bin1Pin = 8;//setting pinf for motor for right side const int bin2Pin = 7; const int pwmBPin = 6; const int trigPin1 = 11;//setting pins for front ultrasonic sensor const int echoPin1= A0;//I used A0 pin cause I didnt have space...Please pardon me const int trigPin2 = 10;//setting pins for back ultrasonic sensor const int echoPin2 = A1;//here too const int warningbuzzer=12;//setting the buzzer to 12 //servo motor const int headmovePin=9;//setting the servo motor pin to 9 int wallstop=0;//initializing the obstacle detection unsigned long previousMillis = 0;//setting millis to 0 const long interval = 5000;//setting interval for the millis void setup() { myservo.attach(headmovePin);//pass the servo pin to the servo library randomSeed(time(NULL));//seed random number using the current time pinMode(ain1Pin, OUTPUT);//setting the pins as output and input pinMode(2, OUTPUT);//light checker pinMode(ain2Pin, OUTPUT);//motor pin pinMode(pwmAPin, OUTPUT); // not needed really pinMode(bin1Pin, OUTPUT); pinMode(bin2Pin, OUTPUT); pinMode(pwmBPin, OUTPUT); // not needed really // Start serial communication so we can send data // over the USB connection to our p5js sketch pinMode(trigPin1, OUTPUT); pinMode(echoPin1, INPUT); pinMode(trigPin2, OUTPUT); pinMode(echoPin2, INPUT); pinMode(warningbuzzer, OUTPUT); Serial.begin(9600);//setting the serial band while (!Serial.available()) { digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data Serial.println("0,0"); // send a starting message delay(300); // wait 1/3 second digitalWrite(LED_BUILTIN, LOW); delay(1000);//delay for a second } } void loop() { wallstop=crushstop(); //When the serial is detected do this while (Serial.available()) {//while the serial connection exists digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data wallstop=crushstop();//update the wallstop from the crush function unsigned long currentMillis = millis();//set current millis if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; movehead();//if the interval is reached, move the head } int movement = Serial.parseInt();//get the movement case from p5 if (Serial.read() == '\n') {//when we read a new line, switch(movement){//execute the following commmands based on the case case 0://no movement analogWrite(pwmAPin, 0); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, 0); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); break; case 1://forward analogWrite(pwmAPin, 255); digitalWrite(ain1Pin, LOW); digitalWrite(ain2Pin, HIGH); analogWrite(pwmBPin, 255); digitalWrite(bin1Pin, HIGH); digitalWrite(bin2Pin, LOW); break; case 2://reverse analogWrite(pwmAPin, 255); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, 255); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); break; case 3://right front analogWrite(pwmBPin, 255); digitalWrite(bin1Pin, HIGH); digitalWrite(bin2Pin, LOW); break; case 4://left front analogWrite(pwmAPin, 255); digitalWrite(ain1Pin, LOW); digitalWrite(ain2Pin, HIGH); break; case 5://right back analogWrite(pwmBPin, 255); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); break; case 6://left back analogWrite(pwmAPin, 255); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); break; default://if not case is gotten within our expected range, stop analogWrite(pwmAPin, 0); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, 0); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); break; } delay(5); Serial.println(wallstop);//send the detection to p5 } } } int crushstop(){//this function returns 1 when an obstacle is ahead and 2 when an obstacle is behind int wallstop=0;//initialize wallstop digitalWrite(trigPin1, LOW); delayMicroseconds(2); //basically shooting beems and using the time it takes to bounce back to calculate distance digitalWrite(trigPin1, HIGH); delayMicroseconds(10); digitalWrite(trigPin1, LOW); // Time it takes for the pulse to travel back from the object long int duration1 = pulseIn(echoPin1, HIGH); // Universal conversion of time into distance in cm int distance1 = duration1 * 0.034 / 2;//divided by two beause its a two way thing digitalWrite(trigPin2, LOW); delayMicroseconds(2); digitalWrite(trigPin2, HIGH); delayMicroseconds(10); digitalWrite(trigPin2, LOW); // Time it takes for the pulse to travel back from the object long int duration2 = pulseIn(echoPin2, HIGH); // Universal conversion of time into distance in cm int distance2 = duration2 * 0.034 / 2; if(distance1<5){//if collision is detected behind, send 2 wallstop=2; tone(warningbuzzer,2000);//play the tone delay(5); } else if(distance2<5){ wallstop=1;//if collision is detected infront, send 1 tone(warningbuzzer,2000);//play the tone delay(5); } else{ wallstop=0; noTone(warningbuzzer);//if nothing is detected dont play a tone } return wallstop;//return this info } void movehead(){ myservo.write(random(0, 180));//move the head to a random number between 0 and 180 delay(15); }
#include <Servo.h>//include the Servo library/
#include <time.h>//include the time library for seeding random number

Servo myservo;//creating servo object

const int ain1Pin = 3;//setting pins for motor for left side which is connected in parallel
const int ain2Pin = 4;
const int pwmAPin = 5;

const int bin1Pin = 8;//setting pinf for motor for right side 
const int bin2Pin = 7;
const int pwmBPin = 6;

const int trigPin1 = 11;//setting pins for front ultrasonic sensor
const int echoPin1= A0;//I used A0 pin cause I didnt have space...Please pardon me
const int trigPin2 = 10;//setting pins for back ultrasonic sensor
const int echoPin2 = A1;//here too

const int warningbuzzer=12;//setting the buzzer to 12
//servo motor
const int headmovePin=9;//setting the servo motor pin to 9

int wallstop=0;//initializing the obstacle detection

unsigned long previousMillis = 0;//setting millis to 0
const long interval = 5000;//setting interval for the millis


void setup() {
  myservo.attach(headmovePin);//pass the servo pin to the servo library
  
  randomSeed(time(NULL));//seed random number using the current time 

  pinMode(ain1Pin, OUTPUT);//setting the pins as output and input
  pinMode(2, OUTPUT);//light checker
  pinMode(ain2Pin, OUTPUT);//motor pin
  pinMode(pwmAPin, OUTPUT); // not needed really
  pinMode(bin1Pin, OUTPUT);
  pinMode(bin2Pin, OUTPUT);
  pinMode(pwmBPin, OUTPUT); // not needed really
  // Start serial communication so we can send data
  // over the USB connection to our p5js sketch
  pinMode(trigPin1, OUTPUT);
  pinMode(echoPin1, INPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);
  pinMode(warningbuzzer, OUTPUT);

  Serial.begin(9600);//setting the serial band

  while (!Serial.available()) {
    digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
    Serial.println("0,0"); // send a starting message
    delay(300);            // wait 1/3 second
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);//delay for a second
  }
}

void loop() {
  wallstop=crushstop();
  //When the serial is detected do this
  while (Serial.available()) {//while the serial connection exists
    digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data
    wallstop=crushstop();//update the wallstop from the crush function
    unsigned long currentMillis = millis();//set current millis

    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
      movehead();//if the interval is reached, move the head
    }
    int movement = Serial.parseInt();//get the movement case from p5
   if (Serial.read() == '\n') {//when we read a new line,
     switch(movement){//execute the following commmands based on the case
      case 0://no movement
        analogWrite(pwmAPin, 0);
        digitalWrite(ain1Pin, HIGH);
        digitalWrite(ain2Pin, LOW);
        analogWrite(pwmBPin, 0);
        digitalWrite(bin1Pin, LOW);
        digitalWrite(bin2Pin, HIGH);
      break;
      case 1://forward
        analogWrite(pwmAPin, 255);
        digitalWrite(ain1Pin, LOW);
        digitalWrite(ain2Pin, HIGH);
        analogWrite(pwmBPin, 255);
        digitalWrite(bin1Pin, HIGH);
        digitalWrite(bin2Pin, LOW);
      break;
      case 2://reverse
        analogWrite(pwmAPin, 255);
        digitalWrite(ain1Pin, HIGH);
        digitalWrite(ain2Pin, LOW);
        analogWrite(pwmBPin, 255);
        digitalWrite(bin1Pin, LOW);
        digitalWrite(bin2Pin, HIGH);
      break;
      case 3://right front
        analogWrite(pwmBPin, 255);
        digitalWrite(bin1Pin, HIGH);
        digitalWrite(bin2Pin, LOW);
      break;
      case 4://left front
        analogWrite(pwmAPin, 255);
        digitalWrite(ain1Pin, LOW);
        digitalWrite(ain2Pin, HIGH);
      break;
      case 5://right back
       analogWrite(pwmBPin, 255);
        digitalWrite(bin1Pin, LOW);
        digitalWrite(bin2Pin, HIGH);
      break;
      case 6://left back
        analogWrite(pwmAPin, 255);
        digitalWrite(ain1Pin, HIGH);
        digitalWrite(ain2Pin, LOW);
      break;
      default://if not case is gotten within our expected range, stop
        analogWrite(pwmAPin, 0);
        digitalWrite(ain1Pin, HIGH);
        digitalWrite(ain2Pin, LOW);
        analogWrite(pwmBPin, 0);
        digitalWrite(bin1Pin, LOW);
        digitalWrite(bin2Pin, HIGH);
      break;
     }
      delay(5);
      Serial.println(wallstop);//send the detection to p5
      
    }
  }
  
}

int crushstop(){//this function returns 1 when an obstacle is ahead and 2 when an obstacle is behind
  int wallstop=0;//initialize wallstop
  digitalWrite(trigPin1, LOW); 
  delayMicroseconds(2); //basically shooting beems and using the time it takes to bounce back to calculate distance
  digitalWrite(trigPin1, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trigPin1, LOW); 
  // Time it takes for the pulse to travel back from the object long 
  int duration1 = pulseIn(echoPin1, HIGH); 
  // Universal conversion of time into distance in cm 
  int distance1 = duration1 * 0.034 / 2;//divided by two beause its a two way thing

  digitalWrite(trigPin2, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin2, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trigPin2, LOW); 
  // Time it takes for the pulse to travel back from the object long 
  int duration2 = pulseIn(echoPin2, HIGH); 
  // Universal conversion of time into distance in cm 
  int distance2 = duration2 * 0.034 / 2;
  if(distance1<5){//if collision is detected behind, send 2
    wallstop=2;
    tone(warningbuzzer,2000);//play the tone
    delay(5);
  }
  else if(distance2<5){
    wallstop=1;//if collision is detected infront, send 1
    tone(warningbuzzer,2000);//play the tone
    delay(5);
  }
  else{
    wallstop=0;
    noTone(warningbuzzer);//if nothing is detected dont play a tone
  }
  return wallstop;//return this info
}

void movehead(){
  myservo.write(random(0, 180));//move the head to a random number between 0 and 180
  delay(15);
}

 

P5.js:

For this part, the P5.js sketch receives the user hand positions info from the P5.ml library and maps it to get its corresponding points on the canvas. After, these values are averaged and the average-X value is used to control the steer’s left or right turn. The average-Y value is used to control the forward and backward movement. Based on this cases are developed and sent to the Arduino for execution of tasks.

The P5 sketch is divided into five parts

Serial connection:

This part is responsible for connecting the Arduino to the P5 sketch and since its not my code I will not post it

Intro Page:

The next part is the intro page. Is welcomes the user into the project and also gives some info to the user about how to use the vehicle. I made the background picture myself using photoshop and then I added some buttons and sounds

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class ipage{
constructor(IB,S1,S2,F1,F2){//receive all needed variables as in images and sound
this.BG=IB;//the background
this.S1=S1;//sound
this.playbool=false;//boolean to start game
this.helpbool=false;//boolean to open help page
this.F2=F2//font
}
show(){//this shows the designs in the page
this.BG.resize(windowWidth,windowHeight);//resize the introimage
image(this.BG,0,0);//displaying background
textAlign(CENTER);
this.createhelp();//calling the help function for the help page
this.playbox();//calling the playbox button function
if(this.helpbool){//if the helpbool is true display the help page
this.helppage();
}
return this.playbool;//this returns true if the play button is pressed
}
playbox(){//this function displays the start button
rectMode(CORNER);
fill(150,180,40);
if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150){
fill(150,0,0);//creating the hover effect
}
if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150&&mouseIsPressed&&!this.helpbool){
S2.pause();// the play is pressed, play pause the background music
this.S1.play();//playing the start button pressed sound
this.playbool=true;//sets the playboolean to true
}
rect(windowWidth*0.1,windowHeight*0.8,350,150,60);//drawing the start button
fill(0);
textFont(F1);
textSize(90);
textAlign(CENTER);
text("Start",windowWidth*0.1+180,windowHeight*0.8+110);
}
createhelp(){
fill(100);
if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30){
fill(60);//create hover effect
}
if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30&&mouseIsPressed){
this.helpbool=true;//set boolean to open help page
}
circle(windowWidth*0.9,windowHeight*0.1,60);//these following code just creates the help button
fill(255,255,0);
textSize(30);
textFont(NORMAL);
text("?",windowWidth*0.9,windowHeight*0.1+10);
}
helppage(){
fill(100);
rect(50,50,windowWidth*0.95,windowHeight*0.9,50);
textFont(this.F2);
fill(255);
textSize(80);
text('WELCOME',windowWidth*0.5,windowHeight*0.25);
textSize(30);
text('Move your Hand Up and Down while pressing the mouse to control the gear',windowWidth*0.5,windowHeight*0.4);
text('Move your Hand left and right to control the steer',windowWidth*0.5,windowHeight*0.5);
text('Click on the Q key to go to the Homepage',windowWidth*0.5,windowHeight*0.6);
text('Press the space bar to connect to Arduino',windowWidth*0.5,windowHeight*0.7);
text('GOOD LUCK!',windowWidth*0.5,windowHeight*0.8);
fill(100);
if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30){
fill(60);//create hover effect
}
if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30&&mouseIsPressed){
this.helpbool=false;//set boolean to close help page
}
circle(windowWidth*0.5,windowHeight*0.9,60);//these following code just creates the ok button
fill(255,255,0);
textSize(30);
textFont(NORMAL);
text("OK",windowWidth*0.5,windowHeight*0.9+10);
}
}
class ipage{ constructor(IB,S1,S2,F1,F2){//receive all needed variables as in images and sound this.BG=IB;//the background this.S1=S1;//sound this.playbool=false;//boolean to start game this.helpbool=false;//boolean to open help page this.F2=F2//font } show(){//this shows the designs in the page this.BG.resize(windowWidth,windowHeight);//resize the introimage image(this.BG,0,0);//displaying background textAlign(CENTER); this.createhelp();//calling the help function for the help page this.playbox();//calling the playbox button function if(this.helpbool){//if the helpbool is true display the help page this.helppage(); } return this.playbool;//this returns true if the play button is pressed } playbox(){//this function displays the start button rectMode(CORNER); fill(150,180,40); if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150){ fill(150,0,0);//creating the hover effect } if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150&&mouseIsPressed&&!this.helpbool){ S2.pause();// the play is pressed, play pause the background music this.S1.play();//playing the start button pressed sound this.playbool=true;//sets the playboolean to true } rect(windowWidth*0.1,windowHeight*0.8,350,150,60);//drawing the start button fill(0); textFont(F1); textSize(90); textAlign(CENTER); text("Start",windowWidth*0.1+180,windowHeight*0.8+110); } createhelp(){ fill(100); if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30){ fill(60);//create hover effect } if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30&&mouseIsPressed){ this.helpbool=true;//set boolean to open help page } circle(windowWidth*0.9,windowHeight*0.1,60);//these following code just creates the help button fill(255,255,0); textSize(30); textFont(NORMAL); text("?",windowWidth*0.9,windowHeight*0.1+10); } helppage(){ fill(100); rect(50,50,windowWidth*0.95,windowHeight*0.9,50); textFont(this.F2); fill(255); textSize(80); text('WELCOME',windowWidth*0.5,windowHeight*0.25); textSize(30); text('Move your Hand Up and Down while pressing the mouse to control the gear',windowWidth*0.5,windowHeight*0.4); text('Move your Hand left and right to control the steer',windowWidth*0.5,windowHeight*0.5); text('Click on the Q key to go to the Homepage',windowWidth*0.5,windowHeight*0.6); text('Press the space bar to connect to Arduino',windowWidth*0.5,windowHeight*0.7); text('GOOD LUCK!',windowWidth*0.5,windowHeight*0.8); fill(100); if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30){ fill(60);//create hover effect } if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30&&mouseIsPressed){ this.helpbool=false;//set boolean to close help page } circle(windowWidth*0.5,windowHeight*0.9,60);//these following code just creates the ok button fill(255,255,0); textSize(30); textFont(NORMAL); text("OK",windowWidth*0.5,windowHeight*0.9+10); } }
class ipage{
  constructor(IB,S1,S2,F1,F2){//receive all needed variables as in images and sound
    this.BG=IB;//the background
    this.S1=S1;//sound
    this.playbool=false;//boolean to start game
    this.helpbool=false;//boolean to open help page
    this.F2=F2//font
  }
  show(){//this shows the designs in the page
    this.BG.resize(windowWidth,windowHeight);//resize the introimage
    image(this.BG,0,0);//displaying background
    textAlign(CENTER);
    this.createhelp();//calling the help function for the help page
    this.playbox();//calling the playbox button function
    if(this.helpbool){//if the helpbool is true display the help page
      this.helppage();
    }
    return this.playbool;//this returns true if the play button is pressed
  }
  
  playbox(){//this function displays the start button
    rectMode(CORNER);
    fill(150,180,40);
      if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150){
      fill(150,0,0);//creating the hover effect
    }
    if(mouseX>windowWidth*0.1&&mouseX<(windowWidth*0.1)+350&&mouseY>windowHeight*0.8&&mouseY<(windowHeight*0.8)+150&&mouseIsPressed&&!this.helpbool){
      S2.pause();// the play is pressed, play pause the background music
      this.S1.play();//playing the start button pressed sound
      this.playbool=true;//sets the playboolean to true 
    }
    rect(windowWidth*0.1,windowHeight*0.8,350,150,60);//drawing the start button
    fill(0);
    textFont(F1);
    textSize(90);
    textAlign(CENTER);
    text("Start",windowWidth*0.1+180,windowHeight*0.8+110);
  }
  createhelp(){
    fill(100);
    if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30){
      fill(60);//create hover effect
    }
    if(dist(mouseX,mouseY,windowWidth*0.9,windowHeight*0.1)<=30&&mouseIsPressed){
      this.helpbool=true;//set boolean to open help page
    }
    circle(windowWidth*0.9,windowHeight*0.1,60);//these following code just creates the help button
    fill(255,255,0);
    textSize(30);
    textFont(NORMAL);
    text("?",windowWidth*0.9,windowHeight*0.1+10);
  }
  helppage(){
    fill(100);
    rect(50,50,windowWidth*0.95,windowHeight*0.9,50);
    textFont(this.F2);
    fill(255);
    textSize(80);
    text('WELCOME',windowWidth*0.5,windowHeight*0.25);
    textSize(30);
    text('Move your Hand Up and Down while pressing the mouse to control the gear',windowWidth*0.5,windowHeight*0.4);
    text('Move your Hand left and right to control the steer',windowWidth*0.5,windowHeight*0.5);
    text('Click on the Q key to go to the Homepage',windowWidth*0.5,windowHeight*0.6);
    text('Press the space bar to connect to Arduino',windowWidth*0.5,windowHeight*0.7);
    text('GOOD LUCK!',windowWidth*0.5,windowHeight*0.8);
    fill(100);
    if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30){
      fill(60);//create hover effect
    }
    if(dist(mouseX,mouseY,windowWidth*0.5,windowHeight*0.9)<=30&&mouseIsPressed){
      this.helpbool=false;//set boolean to close help page
    }
    circle(windowWidth*0.5,windowHeight*0.9,60);//these following code just creates the ok button
    fill(255,255,0);
    textSize(30);
    textFont(NORMAL);
    text("OK",windowWidth*0.5,windowHeight*0.9+10);
    
  }
}

Help Page:

This page is just to give the user info about the game and wish them luck as they embark on the Journey.

the code is found in the intro class and the page is controlled with the use of Boolean variables.

Dashboard:

Coming into the main page, the Dashboard shows the gearbox and the collision screen that alerts the user when the user is close to an obstacle.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class dash{//this class prints the dashboard, the gear and the detection screen
constructor(dashY){
this.Y=dashY;//the Y coordinate to which the dashboard is drawn
this.movementFB=0;//the front and back movement counter
this.gearY=0;//this controls the gearmovement
}
showdash(){
push();//creating the dashboard
strokeWeight(5)//set stroke weight to 5
fill(193, 154, 107);//fill with brown
beginShape();//we draw the dashboard
curveVertex(0,this.Y);
curveVertex(0,this.Y);
curveVertex(windowWidth/2,this.Y-50);//creating the curve look
curveVertex(windowWidth,this.Y);
curveVertex(windowWidth,windowHeight);
curveVertex(0,windowHeight);
curveVertex(0,this.Y);
curveVertex(0,this.Y);
endShape();
pop();
}
showgear(gearY){//this function shows the gear
this.gearY=gearY;//capies value of the gearY from handpose
rectMode(CENTER);//set rectange mode
textSize(50);
fill(0);//fill with black
rect(windowWidth*0.5,this.Y+110,150,300,50);
if(mouseIsPressed){//if the mouse is pressed means gear is being controlled
if(this.gearY<windowHeight*0.35){
this.movementFB=1;//set gear to drive
}
else if(this.gearY>windowHeight*0.5){
this.movementFB=2;//set gear to reverse
}
else{
this.movementFB=0;//set gear to P
}
}
textAlign(CENTER);//align text to center
textSize(50);
fill(0,128,0);//fill with green
switch(this.movementFB){
case 0:
text('P',windowWidth*0.5,this.Y+110);//p for parking
break;
case 1:
text('D',windowWidth*0.5,this.Y+110);//D for drive
break;
case 2:
text('R',windowWidth*0.5,this.Y+110);//R for reverse
break;
}
textAlign(LEFT);
textSize(12);
return this.movementFB;//return the gear movement info
}
showScreen(wallstop){//this shows the detection
rectMode(CENTER);
textSize(50);
textAlign(CENTER);
fill(0);
rect(windowWidth*0.75,this.Y+110,500,300,50);//create screen
fill(128,0,0);//fill the text with red
if(wallstop==1){//if the front ultrasonic sensor is the one sensing
text('OBJECT',windowWidth*0.75,this.Y+50);
text('DETECTED',windowWidth*0.75,this.Y+130);
text('AHEAD',windowWidth*0.75,this.Y+210);
}
else if(wallstop==2){//if the back ultrasonic is the one sensing
text('OBJECT',windowWidth*0.75,this.Y+50);
text('DETECTED',windowWidth*0.75,this.Y+130);
text('BEHIND',windowWidth*0.75,this.Y+210);
}
else{
fill(0,128,0);//fill the text with green
text('No',windowWidth*0.75,this.Y+50);
text('OBJECT',windowWidth*0.75,this.Y+130);
text('DETECTED',windowWidth*0.75,this.Y+210);
}
textAlign(LEFT);
textSize(12);
}
}
class dash{//this class prints the dashboard, the gear and the detection screen constructor(dashY){ this.Y=dashY;//the Y coordinate to which the dashboard is drawn this.movementFB=0;//the front and back movement counter this.gearY=0;//this controls the gearmovement } showdash(){ push();//creating the dashboard strokeWeight(5)//set stroke weight to 5 fill(193, 154, 107);//fill with brown beginShape();//we draw the dashboard curveVertex(0,this.Y); curveVertex(0,this.Y); curveVertex(windowWidth/2,this.Y-50);//creating the curve look curveVertex(windowWidth,this.Y); curveVertex(windowWidth,windowHeight); curveVertex(0,windowHeight); curveVertex(0,this.Y); curveVertex(0,this.Y); endShape(); pop(); } showgear(gearY){//this function shows the gear this.gearY=gearY;//capies value of the gearY from handpose rectMode(CENTER);//set rectange mode textSize(50); fill(0);//fill with black rect(windowWidth*0.5,this.Y+110,150,300,50); if(mouseIsPressed){//if the mouse is pressed means gear is being controlled if(this.gearY<windowHeight*0.35){ this.movementFB=1;//set gear to drive } else if(this.gearY>windowHeight*0.5){ this.movementFB=2;//set gear to reverse } else{ this.movementFB=0;//set gear to P } } textAlign(CENTER);//align text to center textSize(50); fill(0,128,0);//fill with green switch(this.movementFB){ case 0: text('P',windowWidth*0.5,this.Y+110);//p for parking break; case 1: text('D',windowWidth*0.5,this.Y+110);//D for drive break; case 2: text('R',windowWidth*0.5,this.Y+110);//R for reverse break; } textAlign(LEFT); textSize(12); return this.movementFB;//return the gear movement info } showScreen(wallstop){//this shows the detection rectMode(CENTER); textSize(50); textAlign(CENTER); fill(0); rect(windowWidth*0.75,this.Y+110,500,300,50);//create screen fill(128,0,0);//fill the text with red if(wallstop==1){//if the front ultrasonic sensor is the one sensing text('OBJECT',windowWidth*0.75,this.Y+50); text('DETECTED',windowWidth*0.75,this.Y+130); text('AHEAD',windowWidth*0.75,this.Y+210); } else if(wallstop==2){//if the back ultrasonic is the one sensing text('OBJECT',windowWidth*0.75,this.Y+50); text('DETECTED',windowWidth*0.75,this.Y+130); text('BEHIND',windowWidth*0.75,this.Y+210); } else{ fill(0,128,0);//fill the text with green text('No',windowWidth*0.75,this.Y+50); text('OBJECT',windowWidth*0.75,this.Y+130); text('DETECTED',windowWidth*0.75,this.Y+210); } textAlign(LEFT); textSize(12); } }
class dash{//this class prints the dashboard, the gear and the detection screen
  constructor(dashY){
    this.Y=dashY;//the Y coordinate to which the dashboard is drawn
    this.movementFB=0;//the front and back movement counter
    this.gearY=0;//this controls the gearmovement
  }
  showdash(){
    push();//creating the dashboard
    strokeWeight(5)//set stroke weight to 5
    fill(193, 154, 107);//fill with brown
    beginShape();//we draw the dashboard
    curveVertex(0,this.Y);
    curveVertex(0,this.Y);
    curveVertex(windowWidth/2,this.Y-50);//creating the curve look
    curveVertex(windowWidth,this.Y);
    curveVertex(windowWidth,windowHeight);
    curveVertex(0,windowHeight);
    curveVertex(0,this.Y);
    curveVertex(0,this.Y);
    endShape();
    pop();
  }
  showgear(gearY){//this function shows the gear
    this.gearY=gearY;//capies value of the gearY from handpose
    rectMode(CENTER);//set rectange mode
    textSize(50);
    fill(0);//fill with black
    rect(windowWidth*0.5,this.Y+110,150,300,50);
    if(mouseIsPressed){//if the mouse is pressed means gear is being controlled
      if(this.gearY<windowHeight*0.35){
        this.movementFB=1;//set gear to drive
      }
      else if(this.gearY>windowHeight*0.5){
        this.movementFB=2;//set gear to reverse
      }
      else{
        this.movementFB=0;//set gear to P
      }
    }
    textAlign(CENTER);//align text to center
    textSize(50);
    fill(0,128,0);//fill with green
    switch(this.movementFB){
      case 0:
        text('P',windowWidth*0.5,this.Y+110);//p for parking
        break;
      case 1:
        text('D',windowWidth*0.5,this.Y+110);//D for drive
        break;
      case 2:
        text('R',windowWidth*0.5,this.Y+110);//R for reverse
        break;
    }
    textAlign(LEFT);
    textSize(12);
    return this.movementFB;//return the gear movement info 
  }
  showScreen(wallstop){//this shows the detection
    rectMode(CENTER);
    textSize(50);
    textAlign(CENTER);
    fill(0);
    rect(windowWidth*0.75,this.Y+110,500,300,50);//create screen
    fill(128,0,0);//fill the text with red
    if(wallstop==1){//if the front ultrasonic sensor is the one sensing
      text('OBJECT',windowWidth*0.75,this.Y+50);
      text('DETECTED',windowWidth*0.75,this.Y+130);
      text('AHEAD',windowWidth*0.75,this.Y+210);
    }
    else if(wallstop==2){//if the back ultrasonic is the one sensing
      text('OBJECT',windowWidth*0.75,this.Y+50);
      text('DETECTED',windowWidth*0.75,this.Y+130);
      text('BEHIND',windowWidth*0.75,this.Y+210);
    }
    else{
      fill(0,128,0);//fill the text with green
      text('No',windowWidth*0.75,this.Y+50);
      text('OBJECT',windowWidth*0.75,this.Y+130);
      text('DETECTED',windowWidth*0.75,this.Y+210);
    }
    textAlign(LEFT);
    textSize(12);
  }
}

In order to show the gear box info it gets info from the poseNet calculations done in the sketch and for the collision screen it uses info from the ultrasonic sensors.

The Steering wheel:

Though also part of the Dashboard, this is a separate class because it  controls the left and right movement using info from the other parts. That is, is uses info from the gear box and collision screen. It is not a picture downloaded from somewhere but a hand coded diagram.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Steer{//this class creates the steer and controls the car movement front and back
constructor(ctr,F2,X=windowWidth/3,Y=windowHeight/2){//takes the steerX,the font and the position for the steer to be placed
this.angle=0;//equate the angle to 0
this.X=X;//set the X and Y for the placement of the steering wheel
this.Y=Y;
this.ctr=ctr;
this.movementLR=0;//create this Left right variable to store the movement
this.F2=F2;
}
show(ctr){//takes steer x
this.ctr=ctr;//update the ctr with steerX
push();//designing the steering using stack so that it can be rotated entirely at once
translate(this.X,this.Y);//making the orijin these
rotate(this.angle);//causes the rotation
noFill(0);
strokeWeight(80);
rectMode(CENTER);
circle(0,0,500);
fill(0);
stroke(0);
strokeWeight(12);
beginShape();
curveVertex(-230,-80);
curveVertex(-230,-80);
curveVertex(0,-120);
curveVertex(230,-80);
curveVertex(230,0);
curveVertex(80,70);
curveVertex(40,230);
curveVertex(-40,230);
curveVertex(-80,70);
curveVertex(-230,0);
curveVertex(-230,-80);
curveVertex(-230,-80);
fill(0);
endShape();
fill(100);
noStroke()
textSize(50)
textAlign(CENTER);
textFont(this.F2);
text('REKAS',0,0);//steering wheel/car brand
pop();
if(this.ctr>0&&this.ctr<windowWidth){//while the value is within our range
this.angle=map(this.ctr,0,windowWidth,-PI/2,PI/2);//update angle based on this
}
}
steerTurn(movementFB,wallstop){//this function controls the turning of the steer
if(this.angle<-PI/7.5&&movementFB==1&&wallstop!=1){
this.movementLR=4;//front left
}
else if(this.angle<-PI/7.5&&movementFB==2&&wallstop!=2){
this.movementLR=6;//back left
}
else if(this.angle>=-PI/7.5&&this.angle<-PI/8){
this.movementLR=0;//to prevent bugs
}
else if(this.angle>=-PI/7&&this.angle<PI/8&&movementFB==1&&wallstop!=1){
this.movementLR=1;//move straight ahead
}
else if(this.angle>=-PI/7&&this.angle<PI/7&&movementFB==2&&wallstop!=2){
this.movementLR=2;//reverse
}
else if(this.angle>=PI/7&&this.angle<PI/5){
this.movementLR=0;//yeah
}
else if(this.angle>=PI/5&&movementFB==1&&wallstop!=1){
this.movementLR=3;//front right
}
else if(this.angle>=PI/5&&movementFB==2&&wallstop!=2){
this.movementLR=5;//back right
}
else{
this.movementLR=0;//dont move
}
return this.movementLR;
}
}
class Steer{//this class creates the steer and controls the car movement front and back constructor(ctr,F2,X=windowWidth/3,Y=windowHeight/2){//takes the steerX,the font and the position for the steer to be placed this.angle=0;//equate the angle to 0 this.X=X;//set the X and Y for the placement of the steering wheel this.Y=Y; this.ctr=ctr; this.movementLR=0;//create this Left right variable to store the movement this.F2=F2; } show(ctr){//takes steer x this.ctr=ctr;//update the ctr with steerX push();//designing the steering using stack so that it can be rotated entirely at once translate(this.X,this.Y);//making the orijin these rotate(this.angle);//causes the rotation noFill(0); strokeWeight(80); rectMode(CENTER); circle(0,0,500); fill(0); stroke(0); strokeWeight(12); beginShape(); curveVertex(-230,-80); curveVertex(-230,-80); curveVertex(0,-120); curveVertex(230,-80); curveVertex(230,0); curveVertex(80,70); curveVertex(40,230); curveVertex(-40,230); curveVertex(-80,70); curveVertex(-230,0); curveVertex(-230,-80); curveVertex(-230,-80); fill(0); endShape(); fill(100); noStroke() textSize(50) textAlign(CENTER); textFont(this.F2); text('REKAS',0,0);//steering wheel/car brand pop(); if(this.ctr>0&&this.ctr<windowWidth){//while the value is within our range this.angle=map(this.ctr,0,windowWidth,-PI/2,PI/2);//update angle based on this } } steerTurn(movementFB,wallstop){//this function controls the turning of the steer if(this.angle<-PI/7.5&&movementFB==1&&wallstop!=1){ this.movementLR=4;//front left } else if(this.angle<-PI/7.5&&movementFB==2&&wallstop!=2){ this.movementLR=6;//back left } else if(this.angle>=-PI/7.5&&this.angle<-PI/8){ this.movementLR=0;//to prevent bugs } else if(this.angle>=-PI/7&&this.angle<PI/8&&movementFB==1&&wallstop!=1){ this.movementLR=1;//move straight ahead } else if(this.angle>=-PI/7&&this.angle<PI/7&&movementFB==2&&wallstop!=2){ this.movementLR=2;//reverse } else if(this.angle>=PI/7&&this.angle<PI/5){ this.movementLR=0;//yeah } else if(this.angle>=PI/5&&movementFB==1&&wallstop!=1){ this.movementLR=3;//front right } else if(this.angle>=PI/5&&movementFB==2&&wallstop!=2){ this.movementLR=5;//back right } else{ this.movementLR=0;//dont move } return this.movementLR; } }
class Steer{//this class creates the steer and controls the car movement front and back
  constructor(ctr,F2,X=windowWidth/3,Y=windowHeight/2){//takes the steerX,the font and the position for the steer to be placed
    this.angle=0;//equate the angle to 0
    this.X=X;//set the X and Y for the placement of the steering wheel
    this.Y=Y;
    this.ctr=ctr;
    this.movementLR=0;//create this Left right variable to store the movement
    this.F2=F2;
  }
  show(ctr){//takes steer x
    this.ctr=ctr;//update the ctr with steerX
  push();//designing the steering using stack so that it can be rotated entirely at once
  translate(this.X,this.Y);//making the orijin these
  rotate(this.angle);//causes the rotation
  noFill(0);
  strokeWeight(80);
  rectMode(CENTER);
  circle(0,0,500);
  fill(0);
  stroke(0);
  strokeWeight(12);
  beginShape();
  curveVertex(-230,-80);
  curveVertex(-230,-80);
  curveVertex(0,-120);
  curveVertex(230,-80);
  curveVertex(230,0);
  curveVertex(80,70);
  curveVertex(40,230);
  curveVertex(-40,230);
  curveVertex(-80,70);
  curveVertex(-230,0);
  curveVertex(-230,-80);
  curveVertex(-230,-80);
  fill(0);
  endShape();
  fill(100);
    noStroke()
  textSize(50)
    textAlign(CENTER);
  textFont(this.F2);
  text('REKAS',0,0);//steering wheel/car brand
  pop();
    if(this.ctr>0&&this.ctr<windowWidth){//while the value is within our range
  this.angle=map(this.ctr,0,windowWidth,-PI/2,PI/2);//update angle based on this
  }
  }
  steerTurn(movementFB,wallstop){//this function controls the turning of the steer
    if(this.angle<-PI/7.5&&movementFB==1&&wallstop!=1){
        this.movementLR=4;//front left
      }
      else if(this.angle<-PI/7.5&&movementFB==2&&wallstop!=2){
        this.movementLR=6;//back left
      }
      else if(this.angle>=-PI/7.5&&this.angle<-PI/8){
        this.movementLR=0;//to prevent bugs 
      }
      else if(this.angle>=-PI/7&&this.angle<PI/8&&movementFB==1&&wallstop!=1){
        this.movementLR=1;//move straight ahead
      }
      else if(this.angle>=-PI/7&&this.angle<PI/7&&movementFB==2&&wallstop!=2){
        this.movementLR=2;//reverse
      }
      else if(this.angle>=PI/7&&this.angle<PI/5){
        this.movementLR=0;//yeah
      }
      else if(this.angle>=PI/5&&movementFB==1&&wallstop!=1){
        this.movementLR=3;//front right
      }
      else if(this.angle>=PI/5&&movementFB==2&&wallstop!=2){
        this.movementLR=5;//back right
      }
      else{
        this.movementLR=0;//dont move
      }
    return this.movementLR;
  }
}

Sketch:

This is the last part that kind of sums everything up. This is where all the other components come together to produce this artwork. This is also where the poseNet functions and full screen Functions are declared.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let mySteer;//variable going to store steer object
let myDash;//gonna store the dashboard object
let handpose;//gonna store posenet object
let video;//gonna store video object
let predictions = [];//gonna store set of predictions from posenet
let steerX=300;//gonna store the average x coordinate of the hand
let gearY=250;//gonna store the average y coordinate of the hand
let movementLR=0;//gonnna store the left and right movement
let movementFB=0;//gonna store the front and back movement
let wallstop=0;//gonna store the obstacle detection
let steercontrol=0;//gonna control steer to make it feel smooth
let IntroBackground;//intropage background
let S1;//sound 1(button)
let S2;//sound 2
let F1;
let F2;
let introp;//gonna store intropage object
let introbool=true;//going to control the intropage display
let gamebool=false;//going to control the mainpage display
function preload(){
//in this preload function we will load all the uploads we need before we even start the game.
IntroBackground=loadImage("intro1.jpg");//this is for the background
S1=loadSound("button.mp3");//these sets are for the sounds
S2=loadSound("msound.mp3");
F1=loadFont("font1.ttf");//these sets are for the fonts
F2=loadFont("font2.ttf");
}
function setup() {
createCanvas(windowWidth, windowHeight);
video = createCapture(VIDEO);//capture video using camera
video.size(width, height);//set the size of the video to that of the screen
steercontrol=windowWidth/2//set the steercontrol for smoothness
handpose = ml5.handpose(video);//get posenet from the video feed using the ml library
// This sets up an event that fills the global variable "predictions"
// with an array every time new hand poses are detected
handpose.on("predict", results => {
predictions = results;
});
// Hide the video element, and just show the canvas
video.hide();
introp=new ipage(IntroBackground,S1,S2,F1,F2);//create intropage object
mySteer=new Steer(steerX,F2,windowWidth*0.5,windowHeight*0.85);//create steer object
myDash=new dash(windowHeight*0.85);//create dashboard object
S2.loop();//start playing the sound but with loop property
}
function draw() {
if(introbool){//if the introbool is true show intropage
gamebool=introp.show();//update gamebool from intro.show function
if(gamebool){introbool=false;}//if the gamebool is true,set intro to false
}
else{
background(50,150,255);
myDash.showdash()//show the dash
drawKeypoints();//call this function for geting info from the video hand detection
movementFB=myDash.showgear(gearY);//update the front back movement from the showgear function
movementLR=mySteer.steerTurn(movementFB,wallstop);//update the leftright movement from the steerturn function
if(steerX>0&&steerX<windowWidth){//if the steerX is within the range we want
mySteer.show(steerX);//show the steer with this value
steercontrol=steerX;//update the steercontrol incase we stop getting data
}
else{//if the steerX is not in our range,
if(steercontrol<windowWidth/2-5){steercontrol+=10;}//using our steercontrol,slowly move the steer to the center
else if(steercontrol>windowWidth/2+5){steercontrol-=10;}
mySteer.show(steercontrol);
}
myDash.showScreen(wallstop);//show the screen with the wallstop getten form the Arduino
}
}
function keyPressed() {//if spaebar is pressed connect to arduino
if (key == " ") {
// important to have in order to start the serial connection!!
setUpSerial();//connect to arduino
}
}
function readSerial(data) {
if (data!=null){//if the data is not null
//////////////////////////////////
//READ FROM ARDUINO HERE (handshake)
//////////////////////////////////
wallstop= int(trim(data));
//////////////////////////////////
//SEND TO ARDUINO HERE (handshake)
//////////////////////////////////
let sendToArduino = movementLR + "\n";
writeSerial(sendToArduino);
}
}
function drawKeypoints() {
let totalX=0;//set variable to store the sum of the x coordinates of all the predictions
let totalY=0;//same for y
let avgctr=0;//set a counter to count the predictions
let len=0;//I dont use len here but i was experimenting somthing
for (let i = 0; i < predictions.length; i += 1) {
const prediction = predictions[i];
len=predictions.lenght*prediction.landmarks.length;
for (let j = 0; j < prediction.landmarks.length; j += 1) {
const keypoint = prediction.landmarks[j];
totalX+=windowWidth-map(keypoint[0],0,video.width,0,windowWidth);//map the points to our window size and sum it
totalY+=map(keypoint[1],0,video.height,0,windowHeight);
avgctr++;//increase this too
}
}
steerX=totalX/avgctr;//update steerX with the average of X
gearY=totalY/avgctr;//same for Y but with average of Y
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);//resize the canvas to go to fullpage
}
function keyTyped() {
// $$$ For some reason on Chrome/Mac you may have to press f twice to toggle. Works correctly on Firefox/Mac
if (key === 'f') {
toggleFullscreen();//if f is pressed, show fullpage
}
if(key==='q'){//if q is pressed go to h=intro page
if(introbool==false){
introbool=true;
introp.playbool=false;
S2.play();
}
}
// uncomment to prevent any default behavior
// return false;
}
// Toggle fullscreen state. Must be called in response
// to a user event (i.e. keyboard, mouse click)
function toggleFullscreen() {
let fs = fullscreen(); // Get the current state
fullscreen(!fs); // Flip it!
}
let mySteer;//variable going to store steer object let myDash;//gonna store the dashboard object let handpose;//gonna store posenet object let video;//gonna store video object let predictions = [];//gonna store set of predictions from posenet let steerX=300;//gonna store the average x coordinate of the hand let gearY=250;//gonna store the average y coordinate of the hand let movementLR=0;//gonnna store the left and right movement let movementFB=0;//gonna store the front and back movement let wallstop=0;//gonna store the obstacle detection let steercontrol=0;//gonna control steer to make it feel smooth let IntroBackground;//intropage background let S1;//sound 1(button) let S2;//sound 2 let F1; let F2; let introp;//gonna store intropage object let introbool=true;//going to control the intropage display let gamebool=false;//going to control the mainpage display function preload(){ //in this preload function we will load all the uploads we need before we even start the game. IntroBackground=loadImage("intro1.jpg");//this is for the background S1=loadSound("button.mp3");//these sets are for the sounds S2=loadSound("msound.mp3"); F1=loadFont("font1.ttf");//these sets are for the fonts F2=loadFont("font2.ttf"); } function setup() { createCanvas(windowWidth, windowHeight); video = createCapture(VIDEO);//capture video using camera video.size(width, height);//set the size of the video to that of the screen steercontrol=windowWidth/2//set the steercontrol for smoothness handpose = ml5.handpose(video);//get posenet from the video feed using the ml library // This sets up an event that fills the global variable "predictions" // with an array every time new hand poses are detected handpose.on("predict", results => { predictions = results; }); // Hide the video element, and just show the canvas video.hide(); introp=new ipage(IntroBackground,S1,S2,F1,F2);//create intropage object mySteer=new Steer(steerX,F2,windowWidth*0.5,windowHeight*0.85);//create steer object myDash=new dash(windowHeight*0.85);//create dashboard object S2.loop();//start playing the sound but with loop property } function draw() { if(introbool){//if the introbool is true show intropage gamebool=introp.show();//update gamebool from intro.show function if(gamebool){introbool=false;}//if the gamebool is true,set intro to false } else{ background(50,150,255); myDash.showdash()//show the dash drawKeypoints();//call this function for geting info from the video hand detection movementFB=myDash.showgear(gearY);//update the front back movement from the showgear function movementLR=mySteer.steerTurn(movementFB,wallstop);//update the leftright movement from the steerturn function if(steerX>0&&steerX<windowWidth){//if the steerX is within the range we want mySteer.show(steerX);//show the steer with this value steercontrol=steerX;//update the steercontrol incase we stop getting data } else{//if the steerX is not in our range, if(steercontrol<windowWidth/2-5){steercontrol+=10;}//using our steercontrol,slowly move the steer to the center else if(steercontrol>windowWidth/2+5){steercontrol-=10;} mySteer.show(steercontrol); } myDash.showScreen(wallstop);//show the screen with the wallstop getten form the Arduino } } function keyPressed() {//if spaebar is pressed connect to arduino if (key == " ") { // important to have in order to start the serial connection!! setUpSerial();//connect to arduino } } function readSerial(data) { if (data!=null){//if the data is not null ////////////////////////////////// //READ FROM ARDUINO HERE (handshake) ////////////////////////////////// wallstop= int(trim(data)); ////////////////////////////////// //SEND TO ARDUINO HERE (handshake) ////////////////////////////////// let sendToArduino = movementLR + "\n"; writeSerial(sendToArduino); } } function drawKeypoints() { let totalX=0;//set variable to store the sum of the x coordinates of all the predictions let totalY=0;//same for y let avgctr=0;//set a counter to count the predictions let len=0;//I dont use len here but i was experimenting somthing for (let i = 0; i < predictions.length; i += 1) { const prediction = predictions[i]; len=predictions.lenght*prediction.landmarks.length; for (let j = 0; j < prediction.landmarks.length; j += 1) { const keypoint = prediction.landmarks[j]; totalX+=windowWidth-map(keypoint[0],0,video.width,0,windowWidth);//map the points to our window size and sum it totalY+=map(keypoint[1],0,video.height,0,windowHeight); avgctr++;//increase this too } } steerX=totalX/avgctr;//update steerX with the average of X gearY=totalY/avgctr;//same for Y but with average of Y } function windowResized() { resizeCanvas(windowWidth, windowHeight);//resize the canvas to go to fullpage } function keyTyped() { // $$$ For some reason on Chrome/Mac you may have to press f twice to toggle. Works correctly on Firefox/Mac if (key === 'f') { toggleFullscreen();//if f is pressed, show fullpage } if(key==='q'){//if q is pressed go to h=intro page if(introbool==false){ introbool=true; introp.playbool=false; S2.play(); } } // uncomment to prevent any default behavior // return false; } // Toggle fullscreen state. Must be called in response // to a user event (i.e. keyboard, mouse click) function toggleFullscreen() { let fs = fullscreen(); // Get the current state fullscreen(!fs); // Flip it! }
let mySteer;//variable going to store steer object
let myDash;//gonna store the dashboard object
let handpose;//gonna store posenet object
let video;//gonna store video object
let predictions = [];//gonna store set of predictions from posenet
let steerX=300;//gonna store the average x coordinate of the hand
let gearY=250;//gonna store the average y coordinate of the hand
let movementLR=0;//gonnna store the left and right movement
let movementFB=0;//gonna store the front and back movement

let wallstop=0;//gonna store the obstacle detection
let steercontrol=0;//gonna control steer to make it feel smooth

let IntroBackground;//intropage background
let S1;//sound 1(button)
let S2;//sound 2
let F1;
let F2;
let introp;//gonna store intropage object
let introbool=true;//going to control the intropage display
let gamebool=false;//going to control the mainpage display

function preload(){
  //in this preload function we will load all the uploads we need before we even start the game.
  IntroBackground=loadImage("intro1.jpg");//this is for the background
  S1=loadSound("button.mp3");//these sets are for the sounds
  S2=loadSound("msound.mp3");
  F1=loadFont("font1.ttf");//these sets are for the fonts 
  F2=loadFont("font2.ttf");
  
}

function setup() {
  createCanvas(windowWidth, windowHeight);
  video = createCapture(VIDEO);//capture video using camera
  video.size(width, height);//set the size of the video to that of the screen
   steercontrol=windowWidth/2//set the steercontrol for smoothness
  handpose = ml5.handpose(video);//get posenet from the video feed using the ml library

  // This sets up an event that fills the global variable "predictions"
  // with an array every time new hand poses are detected
  handpose.on("predict", results => {
    predictions = results;
  });

  // Hide the video element, and just show the canvas
  video.hide();
  introp=new ipage(IntroBackground,S1,S2,F1,F2);//create intropage object
  mySteer=new Steer(steerX,F2,windowWidth*0.5,windowHeight*0.85);//create steer object
  myDash=new dash(windowHeight*0.85);//create dashboard object
  S2.loop();//start playing the sound but with loop property
}

function draw() {
  if(introbool){//if the introbool is true show intropage
    gamebool=introp.show();//update gamebool from intro.show function
    if(gamebool){introbool=false;}//if the gamebool is true,set intro to false
  }
  else{
    background(50,150,255);
  myDash.showdash()//show the dash
  drawKeypoints();//call this function for geting info from the video hand detection
  movementFB=myDash.showgear(gearY);//update the front back movement from the showgear function
  movementLR=mySteer.steerTurn(movementFB,wallstop);//update the leftright movement from the steerturn function
  if(steerX>0&&steerX<windowWidth){//if the steerX is within the range we want
    mySteer.show(steerX);//show the steer with this value
    steercontrol=steerX;//update the steercontrol incase we stop getting data
  }
  else{//if the steerX is not in our range,
    if(steercontrol<windowWidth/2-5){steercontrol+=10;}//using our steercontrol,slowly move the steer to the center
    else if(steercontrol>windowWidth/2+5){steercontrol-=10;}
    mySteer.show(steercontrol);
  }
  myDash.showScreen(wallstop);//show the screen with the wallstop getten form the Arduino
  }
}
function keyPressed() {//if spaebar is pressed connect to arduino
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();//connect to arduino
  }
}
function readSerial(data) {
  

  if (data!=null){//if the data is not null
    //////////////////////////////////
    //READ FROM ARDUINO HERE (handshake)
    //////////////////////////////////
    wallstop= int(trim(data));
    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    let sendToArduino = movementLR + "\n";
    writeSerial(sendToArduino);
  }
    
}
function drawKeypoints() {
  let totalX=0;//set variable to store the sum of the x coordinates of all the predictions
  let totalY=0;//same for y
  let avgctr=0;//set a counter to count the predictions
  let len=0;//I dont use len here but i was experimenting somthing
  for (let i = 0; i < predictions.length; i += 1) {
    const prediction = predictions[i];
    len=predictions.lenght*prediction.landmarks.length;
    for (let j = 0; j < prediction.landmarks.length; j += 1) {
      const keypoint = prediction.landmarks[j];
       totalX+=windowWidth-map(keypoint[0],0,video.width,0,windowWidth);//map the points to our window size and sum it
      totalY+=map(keypoint[1],0,video.height,0,windowHeight);
      avgctr++;//increase this too
    }
  }
  steerX=totalX/avgctr;//update steerX with the average of X
  gearY=totalY/avgctr;//same for Y but with average of Y
}
function windowResized() {
  resizeCanvas(windowWidth, windowHeight);//resize the canvas to go to fullpage
}

function keyTyped() {
  // $$$ For some reason on Chrome/Mac you may have to press f twice to toggle. Works correctly on Firefox/Mac
  if (key === 'f') {
    toggleFullscreen();//if f is pressed, show fullpage
  }
  if(key==='q'){//if q is pressed go to h=intro page
    if(introbool==false){
      introbool=true;
      introp.playbool=false;
      S2.play();
    }
  }
  // uncomment to prevent any default behavior
  // return false;
}

// Toggle fullscreen state. Must be called in response
// to a user event (i.e. keyboard, mouse click)
function toggleFullscreen() {
  let fs = fullscreen(); // Get the current state
  fullscreen(!fs); // Flip it!
}

Rekas Bot:

My inspiration for this project comes from my zeal to use the ml library in p5 and I had fun developing this.

Model:

Test Video:

Arduino Circuit Diagram:

Schematic Diagram:

Clarification on the Schematic motor drawing:

By Aya Riad

Future Improvements:

I Tried to implement Bluetooth but I was not able to because it kept on failing even though I had connected and set up everything right so I wish to be able to find a way to make this connection more reliable and also I plan to make the machine learning more reliable in future.

 

IM Showcase:

So just before the showcase started, I added one line of code which made the bot move randomly as though it had life.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
if(introbool){//if the introbool is true show intropage
gamebool=introp.show();//update gamebool from intro.show function
movementLR=int(random(0,6));//do random stuff
if(gamebool){introbool=false;}//if the gamebool is true,set intro to false
}
if(introbool){//if the introbool is true show intropage gamebool=introp.show();//update gamebool from intro.show function movementLR=int(random(0,6));//do random stuff if(gamebool){introbool=false;}//if the gamebool is true,set intro to false }
if(introbool){//if the introbool is true show intropage
    gamebool=introp.show();//update gamebool from intro.show function
    movementLR=int(random(0,6));//do random stuff
    if(gamebool){introbool=false;}//if the gamebool is true,set intro to false
  }

I am really proud of this last decision.

and when you  want to drive it, it stops the random movements.

For more videos

Thank you.

Leave a Reply