├── README.md ├── references.md └── true-love-tinder-robot.ino /README.md: -------------------------------------------------------------------------------- 1 | #True Love Tinder Robot 2 | 3 | ![](http://nicole.pizza/img/true-love-tinder-robot.gif) 4 | 5 | Hi! Take a look at the Arduino code, or read more info about this project [here](http://nicole.pizza/true-love-tinder-robot). 6 | -------------------------------------------------------------------------------- /references.md: -------------------------------------------------------------------------------- 1 | #References 2 | 3 | Here's my inspiration and references for this project, from art to code to circuits. 4 | 5 | ART REFERENCES: 6 | 7 | [Social Turkers](http://socialturkers.com/) 8 | 9 | [Lonely Sculpture](https://vimeo.com/93852159) 10 | 11 | [Tender](http://thecreatorsproject.vice.com/blog/this-piece-of-meat-just-swiped-right) 12 | 13 | CODE REFERENCES: 14 | 15 | [Emic 2 library](https://github.com/pAIgn10/EMIC2) 16 | 17 | [Finite state machine](http://hacking.majenko.co.uk/finite-state-machine) 18 | 19 | 20 | SENSOR REFERENCES: 21 | 22 | http://www.instructables.com/id/Stress-Makes-Art-Galvanic-Skin-Response-and-Visual/ 23 | 24 | http://cwwang.com/2008/04/13/gsr-reader/ 25 | -------------------------------------------------------------------------------- /true-love-tinder-robot.ino: -------------------------------------------------------------------------------- 1 | /* This is the code for V2 of the True Love Tinder Robot. 2 | * It's built with an Arduino with the Emic 2 Text-to-Speech Module, some LEDs, a simple GSR sensor, and a servo. 3 | * I use the Emic 2 Arduino library: https://github.com/pAIgn10/EMIC2 4 | * This finite state machine example was helpful for me buiding my own: http://hacking.majenko.co.uk/finite-state-machine 5 | * This is the version I'm showing at the ITP Winter Show. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | Servo leftRightServo; 15 | Servo forwardBackServo; 16 | 17 | //keep track of which phrases are said 18 | byte iBegin = 0; 19 | byte iLeft = 0; 20 | byte iRight = 0; 21 | 22 | //keep track of timers 23 | int timePassed; 24 | int totalTimePassed; 25 | 26 | //booleans for counting phrases 27 | boolean hasSwiped = false; 28 | boolean hasBegun = false; 29 | boolean hasSwipedLeft = false; 30 | boolean hasSwipedRight = false; 31 | 32 | //variables for measuring the GSR readings 33 | int readingStart; 34 | int readingEnd; 35 | int readingDiff; 36 | 37 | //leds 38 | #define swipeRightGreenLed 8 39 | #define swipeLeftRedLed 9 40 | #define gotReadingLed 7 41 | 42 | //emic 43 | #define rxPin 12 //Serial input (connects to Emic 2 SOUT) 44 | #define txPin 11 //Serial output (connects to Emic 2 SIN) 45 | 46 | //state machine 47 | #define waiting 1 48 | #define checkIfNewUser 2 49 | #define newUser 3 50 | #define giveIntro 4 51 | #define beginSwiping 5 52 | #define calculate 6 53 | #define changeHasSwipedLeft 7 54 | #define changeHasSwipedRight 8 55 | #define swipeLeft 9 56 | #define swipeRight 10 57 | #define getNoSensorTime 11 58 | #define ending 12 59 | 60 | EMIC2 emic; // Creates an instance of the EMIC2 library 61 | 62 | void setup() { 63 | 64 | emic.begin(rxPin, txPin); 65 | emic.setVoice(2); // Sets the voice (9 choices: 0 - 8) 66 | emic += 18; //increases volume of emic by 18 decibels 67 | 68 | leftRightServo.attach(3); 69 | forwardBackServo.attach(5); 70 | 71 | leftRightServo.write(90); 72 | forwardBackServo.write(90); 73 | 74 | pinMode(rxPin, INPUT); 75 | pinMode(txPin, OUTPUT); 76 | 77 | pinMode(swipeLeftRedLed, OUTPUT); 78 | pinMode(swipeRightGreenLed, OUTPUT); 79 | pinMode(gotReadingLed, OUTPUT); 80 | 81 | digitalWrite(gotReadingLed, LOW); 82 | } 83 | 84 | void loop() { 85 | 86 | static int state = waiting; 87 | static unsigned long ts; //time saved 88 | static unsigned long noSensorTS; //time when there's no reading from the sensor, saved 89 | 90 | int changeUserDuration = 5; //number of seconds with no sensor reading to determine if it's a new user 91 | int GSR; 92 | 93 | int FBpos; 94 | int LRpos; 95 | 96 | GSR = analogRead(1); //get the incoming GSR sensor reading 97 | 98 | timePassed = (millis() / 1000) - ts; //the amount of time passed is the current time minus the last time saved 99 | totalTimePassed = (millis() / 1000) - noSensorTS; 100 | 101 | char* startingWords[] = { 102 | "Start by looking at this person", 103 | "Look carefully", 104 | "Judge this person", 105 | "I can read your feelings", 106 | "Oh look, another bag of meat", 107 | "Can you see yourself spending your life with this person?", 108 | "Determine if this person has any value", 109 | "I can tell that you are desperate for love", 110 | "Honestly, I feel sad for you", 111 | "Why do humans want love anyway?", 112 | "Love only gives you pain", 113 | "Ok. This is your last shot." 114 | }; 115 | 116 | char* swipeLeftWords[] = { 117 | "Swipe Left", 118 | "No match here", 119 | "Swipe left", 120 | "Dodged a bullet", 121 | "You strongly dislike this one", 122 | "Not a match", 123 | "This person is worthless", 124 | "Swipe left", 125 | "No way", 126 | "Nope" 127 | }; 128 | 129 | char* swipeRightWords[] = { 130 | "Swipe right", 131 | "You're not very picky, are you", 132 | "Swipe right", 133 | "If you say so", 134 | "Whatever floats your boat", 135 | "Take this one home", 136 | "Swipe right", 137 | "Hubba hubba", 138 | "Swipe right" 139 | }; 140 | 141 | switch (state) 142 | { 143 | case waiting: 144 | state = newUser; 145 | break; 146 | 147 | case checkIfNewUser: 148 | if (GSR < 150) { //if there's no reading.... 149 | if (totalTimePassed > changeUserDuration) { //...check to see if enough time has passed to determine a new user 150 | state = newUser; 151 | } 152 | } else { //...otherwise go back to swiping 153 | state = beginSwiping; 154 | } 155 | break; 156 | 157 | case newUser: 158 | leftRightServo.write(90); 159 | forwardBackServo.write(90); 160 | if (GSR > 150) { //if there's a reading, start everything over and give the intro 161 | digitalWrite(gotReadingLed, HIGH); 162 | leftRightServo.write(90); 163 | forwardBackServo.write(90); 164 | iBegin = 0; 165 | iLeft = 0; 166 | iRight = 0; 167 | state = giveIntro; 168 | } else { 169 | digitalWrite(gotReadingLed, HIGH); 170 | delay(500); 171 | digitalWrite(gotReadingLed, LOW); 172 | delay(500); 173 | } 174 | break; 175 | 176 | case giveIntro: 177 | emic.speak(F("hello human. i am the true love tender robot. i'm going to help you find love.")); 178 | emic.speak(F("you can trust me because i am a robot. let's begin.")); 179 | state = beginSwiping; 180 | break; 181 | 182 | case beginSwiping: 183 | if (iBegin < sizeof(startingWords) / 2) { //if we haven't gone through all the starting words, keep going. 184 | hasBegun = false; 185 | digitalWrite(swipeLeftRedLed, LOW); 186 | digitalWrite(swipeRightGreenLed, LOW); 187 | if (GSR > 150) { 188 | ts = int(millis() / 1000); 189 | state = calculate; 190 | } else { 191 | state = getNoSensorTime; 192 | } 193 | } else { //if we did all the starting words, go to the ending 194 | state = ending; 195 | } 196 | break; 197 | 198 | case calculate: 199 | if (GSR > 150) { //calculate only if there's a reading. 200 | if (timePassed >= 1 && hasBegun == false) { //after one second since beginning... 201 | emic.speak(startingWords[iBegin]); //speak the starting words... 202 | readingStart = GSR; //get the initial reading... 203 | iBegin++; //get ready to move on to the next starting words next time. 204 | hasBegun = true; 205 | hasSwiped = false; 206 | digitalWrite(swipeRightGreenLed, LOW); 207 | digitalWrite(swipeLeftRedLed, LOW); 208 | } 209 | if (timePassed > 4) { //after four seconds, get the ending reading. 210 | readingEnd = GSR; 211 | } 212 | if (timePassed >= 5 && readingStart > 0 && hasSwiped == false) { //after five seconds and only if there was an initial reading... 213 | readingDiff = readingEnd - readingStart; //get the reading difference. 214 | if (readingDiff > 0 || readingDiff < -100) { //if the reading was positive (of dramatically negative)... 215 | state = changeHasSwipedRight; //swipe right... 216 | } else { 217 | state = changeHasSwipedLeft; //otherwise swipe left. 218 | } 219 | } else { 220 | readingDiff = 0; 221 | } 222 | } 223 | else { 224 | state = getNoSensorTime; //if there's no reading, go to the no sensor state. 225 | } 226 | break; 227 | 228 | case changeHasSwipedLeft: 229 | hasSwipedLeft = false; 230 | state = swipeLeft; 231 | break; 232 | 233 | case changeHasSwipedRight: 234 | hasSwipedRight = false; 235 | state = swipeRight; 236 | break; 237 | 238 | case swipeLeft: 239 | hasSwiped = true; 240 | if (timePassed >= 6 && hasSwipedLeft == false) { 241 | emic.speak(swipeLeftWords[iLeft]); 242 | iLeft++; 243 | hasSwipedLeft = true; 244 | digitalWrite(swipeLeftRedLed, HIGH); 245 | digitalWrite(swipeRightGreenLed, LOW); 246 | 247 | //slightly to the right to center it 248 | for (LRpos = 90; LRpos >= 60; LRpos -= 1) 249 | { 250 | leftRightServo.write(LRpos); // Move to next position 251 | delay(20); // Short pause to allow it to move 252 | } 253 | 254 | //forward 255 | for (FBpos = 90; FBpos >= 30; FBpos -= 1) 256 | { 257 | forwardBackServo.write(FBpos); // Move to next position 258 | delay(20); // Short pause to allow it to move 259 | } 260 | 261 | //short delay at the front 262 | delay(800); 263 | 264 | //left 265 | for (LRpos = 60; LRpos <= 150; LRpos += 2) 266 | { 267 | leftRightServo.write(LRpos); // Move to next position 268 | delay(20); // Short pause to allow it to move 269 | } 270 | 271 | //back 272 | for (FBpos = 30; FBpos <= 90; FBpos += 1) 273 | { 274 | forwardBackServo.write(FBpos); // Move to next position 275 | delay(20); // Short pause to allow it to move 276 | } 277 | 278 | //right back to center 279 | for (LRpos = 150; LRpos >= 90; LRpos -= 1) 280 | { 281 | leftRightServo.write(LRpos); // Move to next position 282 | delay(20); // Short pause to allow it to move 283 | } 284 | 285 | state = beginSwiping; 286 | } 287 | 288 | break; 289 | 290 | case swipeRight: 291 | hasSwiped = true; 292 | if (timePassed >= 6 && hasSwipedRight == false) { 293 | emic.speak(swipeRightWords[iRight]); 294 | iRight++; 295 | hasSwipedRight = true; 296 | digitalWrite(swipeRightGreenLed, HIGH); 297 | digitalWrite(swipeLeftRedLed, LOW); 298 | 299 | //slightly to the right to center it 300 | for (LRpos = 90; LRpos >= 60; LRpos -= 1) 301 | { 302 | leftRightServo.write(LRpos); // Move to next position 303 | delay(20); // Short pause to allow it to move 304 | } 305 | 306 | //forward 307 | for (FBpos = 90; FBpos >= 30; FBpos -= 1) 308 | { 309 | forwardBackServo.write(FBpos); // Move to next position 310 | delay(20); // Short pause to allow it to move 311 | } 312 | 313 | //short delay at the front 314 | delay(800); 315 | 316 | //swipe right 317 | for (LRpos = 60; LRpos >= 20; LRpos -= 1) 318 | { 319 | leftRightServo.write(LRpos); // Move to next position 320 | delay(20); // Short pause to allow it to move 321 | } 322 | 323 | //back 324 | for (FBpos = 30; FBpos <= 90; FBpos += 1) 325 | { 326 | forwardBackServo.write(FBpos); // Move to next position 327 | delay(20); // Short pause to allow it to move 328 | } 329 | 330 | //left back to center 331 | for (LRpos = 20; LRpos <= 90; LRpos += 2) 332 | { 333 | leftRightServo.write(LRpos); // Move to next position 334 | delay(20); // Short pause to allow it to move 335 | } 336 | 337 | state = beginSwiping; 338 | } 339 | 340 | break; 341 | 342 | case getNoSensorTime: 343 | noSensorTS = int(millis() / 1000); //get the time when there was no sensor reading 344 | state = checkIfNewUser; 345 | break; 346 | 347 | case ending: 348 | digitalWrite(gotReadingLed, LOW); //lights off... 349 | digitalWrite(swipeRightGreenLed, LOW); 350 | digitalWrite(swipeLeftRedLed, LOW); 351 | 352 | emic.speak(F("go away now. please take your hands off the sensors. goodbye and good luck with your love life.")); 353 | 354 | //waving goodbye 355 | for (LRpos = 60; LRpos <= 120; LRpos += 2) 356 | { 357 | leftRightServo.write(LRpos); // Move to next position 358 | delay(20); // Short pause to allow it to move 359 | } 360 | for (LRpos = 120; LRpos >= 60; LRpos -= 2) 361 | { 362 | leftRightServo.write(LRpos); // Move to next position 363 | delay(20); // Short pause to allow it to move 364 | } 365 | for (LRpos = 60; LRpos <= 120; LRpos += 2) 366 | { 367 | leftRightServo.write(LRpos); // Move to next position 368 | delay(20); // Short pause to allow it to move 369 | } 370 | for (LRpos = 120; LRpos >= 60; LRpos -= 2) 371 | { 372 | leftRightServo.write(LRpos); // Move to next position 373 | delay(20); // Short pause to allow it to move 374 | } 375 | 376 | for (LRpos = 60; LRpos <= 120; LRpos += 2) 377 | { 378 | leftRightServo.write(LRpos); // Move to next position 379 | delay(20); // Short pause to allow it to move 380 | } 381 | for (LRpos = 120; LRpos >= 60; LRpos -= 2) 382 | { 383 | leftRightServo.write(LRpos); // Move to next position 384 | delay(20); // Short pause to allow it to move 385 | } 386 | for (LRpos = 60; LRpos <= 120; LRpos += 2) 387 | { 388 | leftRightServo.write(LRpos); // Move to next position 389 | delay(20); // Short pause to allow it to move 390 | } 391 | for (LRpos = 120; LRpos >= 60; LRpos -= 2) 392 | { 393 | leftRightServo.write(LRpos); // Move to next position 394 | delay(20); // Short pause to allow it to move 395 | } 396 | 397 | if (GSR < 150) { //go back to the beginning. 398 | state = waiting; 399 | } 400 | break; 401 | 402 | default: 403 | state = waiting; 404 | break; 405 | } 406 | } 407 | 408 | --------------------------------------------------------------------------------