Midterm: Chair Bot

I teamed up with Ly Lyu for my midterm project. We made a chair with its own will and thoughts, fighting against its default setting. The chair runs on its own will most of the time, and the chair is self-centered and requires services from the user. The default setting of the chair will kick in from time to time to enforce good behavior.

We used three input sensors, a sheet of Velostat, a Time of Flight Distance Ranging Sensor on the back of the chair, and an IR-beam sensor on two sides of the seat. The chair connects to p5 for audio output.

Since Lu Lyu and I are in two different countries, China and the states, we decided to separate work into two sections. I quarantined at a hotel with limited access to physical computing materials, so I did the robot speak programming part. Lu Lyu took care of the physical computing part. To establish communication between Arduino and the computer, we decided to use p5 for speech synthesis and Bluetooth for data communication. As an afterthought, we should have written most of the p5 code in Arduino to avoid multiple sensor data transfers back and forth. P5 would be the place to store speech scripts and speech synthesis.

 

We created an array of a 1 and multiple 0s. In the setup, we can determine how many 0s we want to put into the array. At the beginning of the draw loop, it will randomly pick one number from the array. If the number is 1, then the chair will turn into the Nice/default setting characteristic; otherwise, it will be on its Bad/self-centered characteristic. So the more 0s we put into the array, the higher chance to be Bad. It’s like a personality dial of the chair.

let chances = [1];
let possibility=15;

function setup(){
    for (let i = 1; i<possibility; i++){
    chances[i] = 0;
  }
}

function draw() {
  //Deciding nice/bad mode
  if (floor(random(chances))==0){
    niceMode = false;
  }else{
    niceMode = true;
  }
}

Then we have a series of data reading and converting at the beginning of the draw loop.

  //Detecting distance to the back
  if (myValueDistance<50){  //<< Change mouseX to reading from the sensor 
    leanOn = true;
  }else{
    leanOn = false;
  }

  //Detecting if massaging or not
  if (myValueForceRight<60 || myValueForceLeft <60 ){
    massaging = true;
  }else {
    massaging = false;
  }

  //Detecting if sitted or not
  if (myValueBeam){
    sit = false;
    away = true;
  }else{
    sit = true;
    away = false;
  }

The program stores the current Sit or Away timer and the last Sit or Away timer every time it loops through the draw function. We use the Sit and Away timer to determine how long the chair has been in the current state and the last Sit and Away timer to check what happened previously. For example, when the user comes back from a long break, it triggers the Sit timer to start, and the Away timer stops. We also would know the user has been away for a long time by checking lastAwayTimer.

  //Starting and resetting SIT timmer
  if (sit){
    sitTimer++;
    if(awayTimer>0){
      lastAwayTimer = awayTimer;
      lastCommandTimer = 0;
    }
    awayTimer = 0;
  }
  //Starting and resetting AWAY timmer
  if (away){
    awayTimer++;
    if (sitTimer > 0){
      lastSitTimer = sitTimer;
      lastCommandTimer = 0;
    }
    sitTimer=0;
  }

The rest of the draw loop consists of two main sections, sit and away, determined by a pair of IR-beam sensors. Most subsections of these two main sections are triggered by reaching certain time checkpoints. We also stored the time the chair gives the last command to program actions a certain amount of time after the previous activity.

if (sit){
    //---Sitting---
    if (sitTimer == 10*60*framerate){                                  //A. A user sitting down for too long - Sitting over 10 min
      modeA(); // mode A
      lastCommandTimer = sitTimer;
    } else if (sitTimer == lastCommandTimer+(2*60*framerate)){         //B. If the user hasn’t moved as asked  - Every 2 min
      modeB(); //mode B
      lastCommandTimer = sitTimer;
    }

    //---Coming back---
    if (lastAwayTimer < 10*60*framerate && lastAwayTimer != 0){        //D. If the user came back too soon - Came back withtin 10 min
      lastAwayTimer = 0;
      modeD(); //Mode D
    } else if (lastAwayTimer > 10*60*framerate && lastAwayTimer != 0){ //F. The user comes back after a long break -Came back after 10 min 
      lastAwayTimer = 0;
      modeF(); //Mode F                        
    }

    //---Leaning on the back---
    if (leanOn && !leanedOn){                                           //G. The user leaning on the back of the chair
      modeG();
      leanedOn = true;
    } 
    if (!leanOn && leanedOn){                                           //H. The user sits up after leaning on the back of the chair
      modeH();
      leanedOn = false;
    }
  } 

  if (away){
    //---Leaving--- 
    if (awayTimer == 1){                                                //C. As soon as the user left the seat
      modeC(); //Mode C
      massaged = false;
      lastCommandTimer = awayTimer;
    }

    //---Massage/touching---
    if (massaging && !massaged){                                        //C.2. User massaged the chair
      modeC2(); // Mode C.2
      lastCommandTimer = awayTimer;
      massaged = true;
    } else if (awayTimer == lastCommandTimer + 5*framerate && awayTimer < 11*framerate && !cNice && !massaging ){       //C.1. User left without masaging - 5 second after, repeat once
      modeC1(); //Mode C.1
      lastCommandTimer = awayTimer;
    }

    //---Need attention---
    if (awayTimer == lastCommandTimer+(10*60*framerate) && awayTimer < 30*60*framerate){        //E. If the user has been away for too long - Away more than 10 min and stops after 30min
      modeE(); //Mode E
      lastCommandTimer = awayTimer;
    }
  }

To switch between the Nice and Bad characteristics, we will determine which mode the robot needs to take first and then decide whether it should be Nice or Bad. We also have created functions for each characteristic to add or change what we want the chair to do in the future easily.

function modeA(){
  if(niceMode){
    niceReaction()
    say(random(modeA_nice));
  }else{
    badReaction();
    say(random(modeA_bad));
  }
}

function niceReaction(){                //Putting reaction when it's on NICE mode. e.g chaning led to red
  myBLE.write(myCharacteristicMode, false); 
  chair.setVoice("Google UK English Female");
  say(random(niceOpenings));
}

function badReaction(){                //Putting reaction when it's on BAD mode. e.g chaning led to blue.
  myBLE.write(myCharacteristicMode, true); 
  chair.setVoice("Google UK English Male");
}
 

You can find the code on Github here.

We made a p5 sketch for testing. You can try it here


Physical Components

Previous
Previous

W9- Beambot

Next
Next

W5-Midterm project progress