The Experience Generator
For my project, I wanted to process my user’s interactions into actual control of their desktop. I utilize the arduino’s serial connections and java’s ability to control your keyboard and mouse to turn a big red button and a sliber bar into an “Interactive Reddit Experience Generator.” By Translating the slider movement to be a scaled value from “Mundane and Probably SFW” to “Different and Probably NSFW” I allow the user to dictate the browsing experience of the current session with the click of a button. The Decisions on what is “Different” or “Mundane” is currently up to my personal taste but I would like to write an algorithm which automatically does this for me.
Here are a few stills of what the experience generator can throw out.
Here is my Arduino and Processing Code (The Arduino code is about the same as the example code, while the processing code uses quite a few java libraries.”
Special thanks to Alvin Alexander at alvinalexander.com for a well documented java typing example!
// This Processing program reads serial data for two sensors,
// presumably digitized by and transmitted from an Arduino.
// It displays two rectangles whose widths are proportional
// to the values 0-1023 received from the Arduino.
// Import the Serial library and create a Serial port handler
import processing.serial.*;
import java.awt.Desktop;
import java.net.URI;
Serial myPort;
import java.awt.Robot;
import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
Robot rob;
boolean run = false;
int timeHit = 0;
ArrayList<Tuple> rankings;
int listLength;
// Hey you! Use these variables to do something interesting.
// If you captured them with analog sensors on the arduino,
// They're probably in the range from 0 ... 1023:
int valueA; // Sensor Value A
int valueB; // Sensor Value B
//------------------------------------
void setup() {
size(50,50);
rankings = new ArrayList<Tuple>();
initList();
//Set up Bot to move mouse
try {
rob = new Robot();
}
catch (AWTException e) {
e.printStackTrace();
}
// List my available serial ports
int nPorts = Serial.list().length;
for (int i=0; i < nPorts; i++) {
println("Port " + i + ": " + Serial.list()[i]);
}
// Choose which serial port to fetch data from.
// IMPORTANT: This depends on your computer!!!
// Read the list of ports printed by the code above,
// and try choosing the one like /dev/cu.usbmodem1411
// On my laptop, I'm using port #4, but yours may differ.
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);
serialChars = new ArrayList();
rob.delay(300);
}
//------------------------------------
void draw() {
// Process the serial data. This acquires freshest values.
processSerial();
if ((valueB > 0) && (!run) && (millis() - timeHit > 50)) {
run = true;
timeHit = millis();
runWindow();
delay(300);
}
if ((run) && valueB > 0) {
findSub();
rect(0,0,width,height);
}
}
ArrayList serialChars; // Temporary storage for received serial data
int whichValueToAccum = 0; // Which piece of data am I currently collecting?
boolean bJustBuilt = false; // Did I just finish collecting a datum?
void processSerial() {
while (myPort.available () > 0) {
char aChar = (char) myPort.read();
// You'll need to add a block like one of these
// if you want to add a 3rd sensor:
if (aChar == 'A') {
bJustBuilt = false;
whichValueToAccum = 0;
} else if (aChar == 'B') {
bJustBuilt = false;
whichValueToAccum = 1;
} else if (((aChar == 13) || (aChar == 10)) && (!bJustBuilt)) {
// If we just received a return or newline character, build the number:
int accum = 0;
int nChars = serialChars.size();
for (int i=0; i < nChars; i++) {
int n = (nChars - i) - 1;
int aDigit = ((Integer)(serialChars.get(i))).intValue();
accum += aDigit * (int)(pow(10, n));
}
// Set the global variable to the number we captured.
// You'll need to add another block like one of these
// if you want to add a 3rd sensor:
if (whichValueToAccum == 0) {
valueA = accum;
// println ("A = " + valueA);
} else if (whichValueToAccum == 1) {
valueB = accum;
// println ("B = " + valueB);
}
// Now clear the accumulator
serialChars.clear();
bJustBuilt = true;
} else if ((aChar >= 48) && (aChar <= 57)) {
// If the char is between '0' and '9', save it.
int aDigit = (int)(aChar - '0');
serialChars.add(aDigit);
}
}
}
void runWindow() {
if(Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI("http://www.google.com"));
} catch (Exception e) {
println("Oh no");
}
}
}
void initList() {
//Initialize List (Yes it's ugly but it was a
//quick conversion from python)
rankings.add(new Tuple("pics", -1));
rankings.add(new Tuple("funny", 0));
rankings.add(new Tuple("aww", 0));
rankings.add(new Tuple("cats", 0));
rankings.add(new Tuple("dIY", 0));
rankings.add(new Tuple("todayilearned", 1));
rankings.add(new Tuple("videos", 1));
rankings.add(new Tuple("gaming", 1));
rankings.add(new Tuple("politics", 1));
rankings.add(new Tuple("technology", 1));
rankings.add(new Tuple("space", 1));
rankings.add(new Tuple("bitcoin", 1));
rankings.add(new Tuple("art", 1));
rankings.add(new Tuple("foodporn", 1));
rankings.add(new Tuple("blep", 1));
rankings.add(new Tuple("askreddit", 2));
rankings.add(new Tuple("atheism", 2));
rankings.add(new Tuple("imgoingtohellforthis", 2));
rankings.add(new Tuple("gentlemanboners", 2));
rankings.add(new Tuple("tattoos", 2));
rankings.add(new Tuple("nosleep", 2));
rankings.add(new Tuple("malefashionadvice", 2));
rankings.add(new Tuple("woodworking", 2));
rankings.add(new Tuple("christianity", 2));
rankings.add(new Tuple("nononono", 2));
rankings.add(new Tuple("gaybros", 2.3));
rankings.add(new Tuple("tinder", 2.5));
rankings.add(new Tuple("microgrowery", 2.7));
rankings.add(new Tuple("trees", 3));
rankings.add(new Tuple("relationships", 3));
rankings.add(new Tuple("shittynosleep", 3));
rankings.add(new Tuple("lifehacks", 3));
rankings.add(new Tuple("girlsinyogapants", 3));
rankings.add(new Tuple("politota", 3));
rankings.add(new Tuple("forwardsfromgrandma", 3.2));
rankings.add(new Tuple("ebola", 3.5));
rankings.add(new Tuple("WTF", 4));
rankings.add(new Tuple("nsfw", 4));
rankings.add(new Tuple("realgirls", 4));
rankings.add(new Tuple("ladyboners", 4));
rankings.add(new Tuple("exmormon", 4));
rankings.add(new Tuple("odd", 4));
rankings.add(new Tuple("nofap", 4));
rankings.add(new Tuple("swoleacceptance", 4));
rankings.add(new Tuple("colanders", 4));
rankings.add(new Tuple("4chan", 5));
rankings.add(new Tuple("nsfw_gif", 5));
rankings.add(new Tuple("ass", 5));
rankings.add(new Tuple("youtubehaiku", 5));
rankings.add(new Tuple("asstastic", 5));
rankings.add(new Tuple("humanporn", 5));
rankings.add(new Tuple("classic4chan", 5));
rankings.add(new Tuple("milf", 6));
rankings.add(new Tuple("creepypms", 6));
rankings.add(new Tuple("mensrights", 6));
rankings.add(new Tuple("translucent_porn", 6));
rankings.add(new Tuple("fiftyfifty", 7));
rankings.add(new Tuple("futanari", 7));
rankings.add(new Tuple("watchpeopledie", 9));
rankings.add(new Tuple("spacedicks", 10));
listLength = rankings.size();
}
void leftClick() {
rob.mousePress(InputEvent.BUTTON1_MASK);
rob.delay(200);
rob.mouseRelease(InputEvent.BUTTON1_MASK);
rob.delay(200);
}
void type( String s) {
rob.keyPress(KeyEvent.VK_CONTROL);
rob.keyPress(KeyEvent.VK_L);
rob.keyRelease(KeyEvent.VK_CONTROL);
rob.keyRelease(KeyEvent.VK_L);
byte[] bytes = s.getBytes();
for (byte b : bytes)
{
int code = b;
if (code > 96 && code < 123){
code = code - 32;
rob.delay(100);
rob.keyPress(code);
rob.keyRelease(code);
}
else if (code == 46) {
rob.keyPress(KeyEvent.VK_PERIOD);
rob.keyRelease(KeyEvent.VK_PERIOD);
}
else if (code == 47) {
rob.keyPress(KeyEvent.VK_SLASH);
rob.keyRelease(KeyEvent.VK_SLASH);
}
else if (code == 95) {
}
}
rob.keyPress(KeyEvent.VK_ENTER);
rob.keyRelease(KeyEvent.VK_ENTER);
}
class Tuple {
public String value;
public float rating;
public Tuple(String v, float r) {
value = v;
rating = r;
}
}
void findSub() {
delay(100);
int i = (int)map(valueA, 0, 1000, 0, listLength-2) ;
String sub = rankings.get(i).value;
String url = String.format("reddit.com/r/%s",sub);
type(url);
}
Here’s the Arduino code
int sensorValue0 = 0; // variable to store the value coming from the sensor
int sensorValue1 = 0; // variable to store the value coming from the other sensor
void setup() {
Serial.begin(9600); // initialize serial communications
}
void loop() {
// Read the value from the sensor(s):
sensorValue0 = analogRead (A0); // reads value from Analog input 0
sensorValue1 = analogRead (A1); // reads value from Analog input 1
Serial.print ("A");
Serial.println (sensorValue0);
Serial.print ("B");
Serial.println (sensorValue1);
delay (50); // wait a fraction of a second, to be polite
}
Here’s a fritzing diagram of the circuit I used.