For the midterm, Tong Wu and I built an interactive installation that lets a person play “Rock, Paper, Scissors” against a robotic hand by wearing a glove outfitted with flex sensors.
3D Printed Hand & Forearm
To build the hand and forearm, we used the models from InMoov, an open source project for a 3D printed life-size robot. All of the joints are connect with PLA filament or 3D printed bolts. The finger movements are controlled by high strength fishing line, which runs down through the fingers/arm like tendons to a servo bed at the end.
Flex Sensitive Glove
On the glove there are two flex sensors, a “start” button, and a “throw” button. These are all sewed into a right-hand glove and connected to a Nano mounted on a perf board. The Arduino is connected to a nRF24L01 wireless transceiver that talks to an identical transceiver on the robot hand.
To play the game, the player puts on the glove, presses the “start" button, then press the “throw” button twice, and makes a hand gesture indicating his/her choice of rock, paper, or scissors.
Robotic Hand & Forearm Assembly
Playing the game
Player code
// include SPI and radio libs
#include <SPI.h>
#include <'RF24.h>
#include <'nRF24L01.h>
// define flex sensor pins
#define sensorPointer A0
#define sensorPinkie A1
// define button pins
#define startButton 2
#define tapButton 3
// initialize button variables
int gameState = 0;
int lastGameState = 0;
int throwInput = 0;
int lastThrowInput = 0;
int throwCount = 0;
int computerStart = 4;
int playerChoice = 0;
// initialize radio and variables
RF24 radio(8, 9);
int msg[1];
const uint64_t pipe = 0xE8E8F0F0E1LL;
void setup() {
Serial.begin(9600);
// start radio transmitter on channel 115
radio.begin();
radio.setChannel(115);
radio.openWritingPipe(pipe);
radio.stopListening();
// set sensor inputs
pinMode(sensorPointer, INPUT);
pinMode(sensorPinkie, INPUT);
// set button inputs
pinMode(startButton, INPUT);
pinMode(tapButton, INPUT);
}
void loop() {
// has the player triggered the game to start
gameState = digitalRead(startButton);
if (gameState == HIGH && lastGameState == LOW) {
Serial.println("Game started!");
// tell computer to start game
msg[0] = computerStart;
radio.write(msg, 1);
Serial.println("Sent start game to computer");
computerStart++;
// wait till player throws 2 times
while (throwCount != 2) {
throwInput = digitalRead(tapButton);
delay(100);
// increase the count after each tap
if (throwInput == HIGH) {
throwCount++;
Serial.print("Throw count: ");
Serial.println(throwCount);
// send update to computer
msg[0] = computerStart++;
radio.write(msg, 1);
delay(100);
}
}
delay(10);
// reset throw variables
throwCount = 0;
computerStart = 4;
// get user input
userChoice();
Serial.print("Player choice: ");
Serial.println(playerChoice);
Serial.println("paper = 1, scissors = 2, rock = 3");
Serial.println();
msg[0] = playerChoice;
radio.write(msg, 1);
}
// reset game state
lastGameState = gameState;
}
void userChoice() {
// get player choice based on sensors
int pinkieSensor = analogRead(sensorPinkie);
pinkieSensor = map(pinkieSensor, 650, 460, 0, 100); // map values 0-100
Serial.print("Pinkie sensor: ");
Serial.println(pinkieSensor);
if ( pinkieSensor > 40) { // finger is bent
pinkieSensor = 1;
} else {
pinkieSensor = 0;
}
int pointerSensor = analogRead(sensorPointer);
pointerSensor = map(pointerSensor, 550, 400, 0, 100); // map values 0-100
Serial.print("Pointer sensor: ");
Serial.println(pointerSensor);
if ( pointerSensor > 40) { // finger is bent
pointerSensor = 1;
} else {
pointerSensor = 0;
}
// no sensors flex = paper, pinkie flexed = scisors, both flexed = rock
if (pinkieSensor == 1 && pointerSensor == 1) { //rock
playerChoice = 3;
} else if (pinkieSensor == 1 & pointerSensor == 0) { //scisors
playerChoice = 2;
} else { // paper
playerChoice = 1;
}
}
Rrobot hand code:
// include SPI, radio, and servo libs
#include <SPI.h>
#include <'RF24.h>
#include <'nRF24L01.h>
#include <'Servo.h>
// define servo finger pins
#define servoThumb 6
#define servoPointer 5
#define servoMiddle 4
#define servoRing 3
#define servoPinkie 2
// setup radio
RF24 radio(7, 8);
// initialize servo fingers
Servo thumbFinger, pointerFinger, middleFinger, ringFinger, pinkieFinger;
// initialize game variables
int aiChoice = 0;
int playerChoice = 0;
// initialize radio variables
int msg[1];
const uint64_t pipe = 0xE8E8F0F0E1LL;
void setup() {
Serial.begin(9600);
// attach the servos
thumbFinger.attach(servoThumb);
pointerFinger.attach(servoPointer);
middleFinger.attach(servoMiddle);
ringFinger.attach(servoRing);
pinkieFinger.attach(servoPinkie);
// set fingers straight
thumbFinger.write(0);
pointerFinger.write(0);
middleFinger.write(0);
ringFinger.write(0);
pinkieFinger.write(0);
// start the radio receiver on channel 115
radio.begin();
radio.setChannel(115);
radio.openReadingPipe(1, pipe);
radio.startListening();
// generate seed for random function via floating pin
randomSeed(analogRead(A2));
}
void loop() {
// wait to receive start code from player
while (msg[0] != 4) {
radio.read(msg, 1);
Serial.println("Waiting to start game...");
}
Serial.println();
Serial.println("----------------------------------");
Serial.println("Game started!");
aiChoice = random(300); // generate psuedo-random number 0-300
aiChoice = map(aiChoice, 0, 300, 1, 3);
while (msg[0] != 5) {
radio.read(msg, 1);
}
// count to one
Serial.println("Moving fingers to 1...");
pinkieFinger.write(180);
ringFinger.write(180);
middleFinger.write(180);
thumbFinger.write(180);
delay(100);
while (msg[0] != 6) {
radio.read(msg, 1);
}
// count to two
Serial.println("Moving fingers to 2...");
Serial.println();
delay(100);
// move robot hand per computer choice
switch (aiChoice) {
case 1: // paper
// leave all fingers open
delay(2000);
Serial.println("Computer choice: paper");
break;
case 2: // scissors
// move thumb, ring, and pinkie fingers
pinkieFinger.write(180);
ringFinger.write(180);
thumbFinger.write(180);
delay(2000);
Serial.println("Computer choice: scissors");
break;
case 3: // rock
// move all fingers
pinkieFinger.write(180);
ringFinger.write(180);
middleFinger.write(180);
pointerFinger.write(180);
thumbFinger.write(180);
delay(2000);
Serial.println("Computer choice: rock");
break;
}
Serial.println();
// wait for choice from player
while (msg[0] != 1 && msg[0] != 2 && msg[0] != 3) {
radio.read(msg, 1);
Serial.println("Waiting for player choice");
}
playerChoice = msg[0];
Serial.println();
Serial.print("Player choice: ");
Serial.println(playerChoice);
Serial.println("paper = 1, scissors = 2, rock = 3");
Serial.println();
// compare choices to see who wins
if (playerChoice == aiChoice) { // tie game
// countdown code and throw again code here
//break;
Serial.println("Tie game!");
} else {
switch (aiChoice) {
// computer chooses paper
case 1:
switch (playerChoice) {
case 2: // player chooses scissors
// player wins!
Serial.println("Player wins!");
// scissors cuts paper
break;
case 3: //player chooses rock
// computer wins!
Serial.println("Computer wins!");
// paper wraps rock
break;
}
break;
// computer chooses scissors
case 2:
switch (playerChoice) {
case 1: // player chooses paper
// computer wins!
Serial.println("Computer wins!");
// scissors cuts paper
break;
case 3: // player chooses rock
// player wins!
Serial.println("Player wins!");
// rock crushes scissors
break;
}
break;
// computer chooses rock
case 3:
switch (playerChoice) {
case 1: // player chooses paper
// player wins!
Serial.println("Player wins!");
// paper covers rock
break;
case 2: // player chooses scissors
// computer wins!
Serial.println("Computer wins!");
// rock crushes scissors
break;
}
break;
}
}
Serial.println("----------------------------------");
Serial.println();
// reset game variables
playerChoice = 0;
aiChoice = 0;
// reset servos
thumbFinger.write(0);
pointerFinger.write(0);
middleFinger.write(0);
ringFinger.write(0);
pinkieFinger.write(0);
delay(1000);
}