Final: Soft game controller

For my final project I want to re-do the game controller, but with the haptic feedback we did for the music controller. In my first attempt at the game controller, I made a hard controller but with soft buttons using conductive fabric (which is typically how I make soft buttons). The biggest takeaway I had was that people couldn’t tell if they had pressed a button or not, as they did not hear the typical clicking noise you get when you press a regular tactile push button. I thought for this project I could have a vibration feedback to help the user know when they press a button. And since I wanted to also challenge myself to make a soft controller, I thought a vibration would be easily felt throughout the controller, regardless of where the user’s hands are placed.

My inspiration for the outside design:

I am not sure what these portable tables are called, but the closest definition would be a cushion table. To achieve this, I started by making a pillow using a jersey fabric I found in the soft lab and stuffed it with stuffing to make it soft. I made a button board using copper tape  (my new found love for making soft buttons), a soft felt, and a harder felt. I decided to do this, so I could easily take board out to fix all the buttons together. It took a long time of testing to get the buttons working consistently, as soft buttons tend to wear down, or stick together.

 

Materials:

Arduino Leonardo

Breadboard

Wire

220 ohm resistors

vibration motor

jersey fabric

copper tape

felt

foam

stuffing

cardboard

Fritzing:

//code//

#include <Keyboard.h>

//keyboard variablesiables

int buttonA = 3;
int buttonD = 4;
int buttonW = 6;
int buttonS = 7;

int reload = 8;
int enter = 9;

int feedback = 10;

int previousButtonStateA = LOW;
int previousButtonStateD = LOW;
int previousButtonStateW = LOW;
int previousButtonStateS = LOW;
void setup() {
// put your setup code here, to run once:
pinMode(buttonA, INPUT);
pinMode(buttonD, INPUT);
pinMode(buttonW, INPUT);
pinMode(buttonS, INPUT);

pinMode(feedback, OUTPUT);
Keyboard.begin();
}

void loop() {
// put your main code here, to run repeatedly:
//8
if (digitalRead(reload) == HIGH) {
Keyboard.press(135);
Keyboard.press(‘r’);
Serial.println(“reload”);
analogWrite(feedback, 125);
delay(1000);
} else {
Keyboard.releaseAll();
analogWrite(feedback, 0);
}
// 9
if (digitalRead(enter) == HIGH) {
Keyboard.press(176);
Serial.println(“enter”);
analogWrite(feedback, 125);
delay(1000);

} else {
Keyboard.release(176);
analogWrite(feedback, 0);

}

//yellow
int buttonStateA = digitalRead(buttonA);

if ((buttonStateA != previousButtonStateA) && (buttonStateA == HIGH)) {
Keyboard.press(KEY_LEFT_ARROW);
Serial.println(“left”);
analogWrite(feedback, 125);
delay(500);
} else if (digitalRead(buttonStateA) == LOW) {
Keyboard.release(KEY_LEFT_ARROW);
digitalWrite(feedback, LOW);
analogWrite(feedback, 0);
}

//blue
int buttonStateD = digitalRead(buttonD);

if ((buttonStateD != previousButtonStateD) && (buttonStateD == HIGH)) {
Keyboard.press(KEY_DOWN_ARROW);
analogWrite(feedback, 125);
delay(1000);
Serial.println(“down”);
} else if (digitalRead(buttonStateD) == LOW) {
Keyboard.release(KEY_RIGHT_ARROW);
analogWrite(feedback, 0);
}

//red
int buttonStateW = digitalRead(buttonW);
if ((buttonStateW != previousButtonStateW) && (buttonStateW == HIGH)) {
Keyboard.press(KEY_UP_ARROW);
analogWrite(feedback, 125);
Serial.println(“up”);
delay(1000);
} else if (digitalRead(buttonStateW) == LOW) {
Keyboard.release(KEY_UP_ARROW);
analogWrite(feedback, 0);
}

//white
int buttonStateS = digitalRead(buttonS);

if ((buttonStateS != previousButtonStateS) && (buttonStateS == HIGH)) {
Keyboard.press(KEY_RIGHT_ARROW);
analogWrite(feedback, 125);
Serial.println(“right”);
delay(1000);
} else if (digitalRead(buttonStateS) == LOW) {
Keyboard.release(KEY_DOWN_ARROW);
analogWrite(feedback, 0);
}

}

Music Player

This assignment I had more of a difficult time setting up the circuit than focusing on the design. I eventually got the buttons to work with an output of a vibration, but still ran into a few hiccups. Ultimately, this project was more of the issues I ran into, then making something work. I am planning on re-doing this project for the final by using a vibration motor without the haptic controller. I think the library gave me a lot of issues.

When I eventually got the circuit working, I thought of trying out some housing ideas, just to get the feel for how someone would interact with the controller. I found a small cardboard box and cut out a spot for the buttons.

Since it wasn’t laser cut or anything, I just put some electric tape over it to clean up the look. Clearly, from below, the button sizes didn’t work for this.

Code

#include <Adafruit_DRV2605.h>
#include <Wire.h>

int lastOnOff = LOW; //start/stop button

Adafruit_DRV2605 drv;

//keyboard variables

//int buttonA = 3;
//int buttonD = 4;
int first = 5;
int second = 6;
int third = 7;
int fourth = 8;
int fifth = 9;

int previousButtonStateFirst = LOW;
int previousButtonStateSecond = LOW;
int previousButtonStateThird = LOW;
int previousButtonStateFourth = LOW;
int previousButtonStateFifth = LOW;
void setup() {
Serial.begin(9600);
// put your setup code here, to run once:

pinMode(first, INPUT);
pinMode(second, INPUT);
pinMode(third, INPUT);
pinMode(fourth, INPUT);
pinMode(fifth, INPUT);

drv.begin();
drv.selectLibrary(1);
//I2C trigger sends “go”
//default internal trigger when sending GO
drv.setMode(DRV2605_MODE_INTTRIG);

}

void loop() {
// put your main code here, to run repeatedly:
int buttonStateFirst = digitalRead(first);

if ((buttonStateFirst != previousButtonStateFirst) && (buttonStateFirst == HIGH)) {

Serial.println(“1st working”);
drv.setWaveform(0, 84); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
delay(500);
} else {
drv.setWaveform(0, 0); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
delay(500);
}
previousButtonStateFirst = first;

int buttonStateSecond = digitalRead(second);
if ((buttonStateSecond != previousButtonStateSecond) && (buttonStateSecond == HIGH)) {
Serial.println(“2nd working”);
drv.setWaveform(0, 84); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
} else {
drv.setWaveform(0, 0); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
}
previousButtonStateSecond = buttonStateSecond;

int buttonStateThird = digitalRead(third);
if ((buttonStateThird != previousButtonStateThird) && (buttonStateThird == HIGH)) {
Serial.println(“3rd working”);
drv.setWaveform(0, 84); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
} else {
drv.setWaveform(0, 0); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
}
previousButtonStateThird = buttonStateThird;

int buttonStateFourth = digitalRead(fourth);
if ((buttonStateFourth != previousButtonStateFourth) && (buttonStateFourth == HIGH)) {
Serial.println(“4th working”);
drv.setWaveform(0, 84); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
} else {
drv.setWaveform(0, 0); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
}
previousButtonStateFourth = buttonStateFourth;

int buttonStateFifth = digitalRead(fifth);
if ((buttonStateFifth != previousButtonStateFifth) && (buttonStateFifth == HIGH)) {
Serial.println(“5th working”);
drv.setWaveform(0, 84); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
} else {
drv.setWaveform(0, 0); //effect
drv.setWaveform(1, 0); // end wave form

//play the effect
drv.go();
//wait a bit
Serial.write(49);
}
previousButtonStateFifth = buttonStateFifth;
}

Weird things

Below I have a screenshot of what happens in the serial monitor. Basically, when I open the serial monitor it just starts printings 1s. I have combed through my code many times and have no idea where the 1 is coming from. However, the sketch works–when I press the buttons I get a vibration and it prints in the serial monitor that is has been pressed. This doesn’t work continuously though. It seems to only work with a few buttons at a time. Or just works for a certain amount of time and then stops working.

If I take out the “else” statement, it only prints out that the button has been pressed, but there is a “1” printing before each line. Why?

If I put it back in, but comment out “drv.go” for the vibration effect, this happens. But no vibration.

If I uncomment that line, but comment out “Serial.write(49)”, then it prints and the vibration works. But why the “1”?

By adding another button to the equation, the serial monitor still print quite normally, with the exception of the “1” before the line. But it does not vibrate.

Light Controller

Summary

This assignment was very challenging for me. I started off working alone, being able to control 3 potentiometers with 3 RGB LEDs, which each showed either Red, Green, or Blue. Although, the pots were controlling the LEDs, I wanted there to just be 1 pot and 1 LED. And then I moved on to work with Jesal, who was having a different issue– he was using 1 LED and 1 Pot, but wasn’t able to control the LED in the way he wanted. We began working together and eventually were able to move to 1 LED being controlled by 3 potentiometers. We had issues with mapping along the way, for example, when we were at 672, which was our max for the pots, the LEDs were showing zero values. Regardless, of the mapping working in the opposite way, we were happy it was working. Then we moved to adding a switch to turn everything off and on. For whatever reason when I ran into this step during the past week, it’s where I had the most trouble. We eventually decided to work on the enclosure and worry about the switch after. Jesal then laser cut a shoe box we had, and I soldered the pots, LEDs, and button. However, when we came back just to assemble everything, nothing worked! We were reading completely different values for the pots. And without understanding, the LED now just blinks between all of the colors. Ultimately, we decided to cut our losses and house everything and hope a miracle would ensue in the day to come.

Circuit Diagram

Code       

const int analogInPin1 = A0; //red
const int analogInPin2 = A1; //green
const int analogInPin3 = A2; //blue
const int analogOutPin1 = 9; // Analog output pin that the LED is attached to
const int analogOutPin2 = 10;
const int analogOutPin3 = 11;

int turnon = 6;
int previousButtonState = LOW;

int sensorValue1 = 0;
int outputValue1 = 0;
int sensorValue2 = 0;
int outputValue2 = 0;
int sensorValue3 = 0;
int outputValue3 = 0;

//#define COMMON_ANODE
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
pinMode(turnon, INPUT);

////pinMode(LEDpin, OUTPUT);
// pinMode(turnon, INPUT);
// digitalWrite(turnon, HIGH); // turn on pullup resistor

}

void loop() {
// if(digitalRead(turnon) == HIGH) {
Serial.println(“working”);

// read the analog in value:
sensorValue1 = analogRead(analogInPin1);
// map it to the range of the analog out:
outputValue1 = map(sensorValue1, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(analogOutPin1, outputValue1);

sensorValue2 = analogRead(analogInPin2);
// map it to the range of the analog out:
outputValue2 = map(sensorValue2, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(analogOutPin2, outputValue2);

sensorValue3 = analogRead(analogInPin3);
// map it to the range of the analog out:
outputValue3 = map(sensorValue3, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(analogOutPin3, outputValue3);

// print the results to the serial monitor:
Serial.print(“sensor1 = “);
Serial.print(sensorValue1);
Serial.print(“\t output1 = “);
Serial.println(outputValue1);

Serial.print(“sensor2 = “);
Serial.print(sensorValue2);
Serial.print(“\t output2= “);
Serial.println(outputValue2);

Serial.print(“sensor3 = “);
Serial.print(sensorValue3);
Serial.print(“\t output3 = “);
Serial.println(outputValue3);

// wait 2 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading:
delay(400);
// }
//else {
// if (digitalRead(turnon) == LOW) {
// Serial.println(“fuck your mom”);
//// digitalWrite(analogInPin1) = LOW;
//// digitalWrite(analogInPin2) = LOW;
//// digitalWrite(analogInPin3) = LOW;
// digitalRead(turnon) == LOW;
// }

}

 

 

Getting 3 Pots to control 3 RGB LEDs

1 Pot controlling 1 RGB LED

Board before soldering

Front of controller

Back of controller

Sources

https://www.arduino.cc/en/Reference/BooleanVariables

https://www.arduino.cc/en/Tutorial/AnalogInOutSerial

Turn ON an LED with a Button and Arduino – Tutorial #4

https://gist.github.com/stelles/8189613

Lunar Lander Game Controller

My main objective in making the game controller for Atari’s Lunar Lander was to have it be large so a player would have to move around a bit in order to play. Initially I thought about making it into a foot controller, retrospectively inspired by Dance Dance Revolution. But veered away from that idea after being discouraged about what materials to use. I also played around with the idea to use an accelerometer and have the controller be a wearable. And then decided against that, as it would require housing a lot of wires on the body and difficult to scale. Then suddenly, the idea of using shoe boxes came to me. What if I used a couple of shoe boxes to stack making the controller more physical? Additionally, the traditional opening of the shoe box would mean easy access to get to my circuit in case I needed to change, or fix anything (which became many times).

 

Code

#include <Mouse.h>
#include <Keyboard.h>

//mouse variables
int leftClick = 7;
//keyboard variables

int buttonA = 3;
int buttonD = 4;
int buttonW = 6;
int buttonS = 5;

int reload = 7;
int enter = 8;

int previousButtonStateA = LOW;
int previousButtonStateD = LOW;
int previousButtonStateW = LOW;
int previousButtonStateS = LOW;
void setup() {
// put your setup code here, to run once:
pinMode(buttonA, INPUT);
pinMode(buttonD, INPUT);
pinMode(buttonW, INPUT);
pinMode(buttonS, INPUT);
pinMode(leftClick, INPUT);
Serial.print(“hi”);
Mouse.begin();
Keyboard.begin();

}

void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(reload) == HIGH) {
Keyboard.press(135);
Keyboard.press(‘r’);
} else {
Keyboard.releaseAll();
}

if (digitalRead(enter) == HIGH) {
Keyboard.press(176);
delay(500);
} else {
Keyboard.release(176);
}
int buttonStateA = digitalRead(buttonA);

if ((buttonStateA != previousButtonStateA) && (buttonStateA == HIGH)) {
Keyboard.press(65);
delay(500);
} else if (digitalRead(buttonStateA) == LOW) {
Keyboard.release(65);
}

int buttonStateD = digitalRead(buttonD);

if ((buttonStateD != previousButtonStateD) && (buttonStateD == HIGH)) {
Keyboard.press(68);
delay(500);
} else if (digitalRead(buttonStateA) == LOW) {
Keyboard.release(68);
}

int buttonStateW = digitalRead(buttonW);

if ((buttonStateW != previousButtonStateW) && (buttonStateW == HIGH)) {
Keyboard.press(87);
delay(500);
} else if (digitalRead(buttonStateW) == LOW) {
Keyboard.release(87);
}

int buttonStateS = digitalRead(buttonS);

if ((buttonStateS != previousButtonStateS) && (buttonStateS == HIGH)) {
Keyboard.press(83);
delay(500);
} else if (digitalRead(buttonStateS) == LOW) {
Keyboard.release(83);
}

}

 

Initial sketch

Circuit Diagram

Testing with the circuit (buttons: A, D, S, W)

Attempting to use Mouse Move with potentiometers. Each of the pots were controlling one x and y-axis.

I used the code below found from the Arduino documentation on Mouse Move

#include <Mouse.h>

const int xAxis = A0; //analog sensor for X axis
const int yAxis = A1; // analog sensor for Y axis

int range = 12; // output range of X or Y movement
int responseDelay = 2; // response delay of the mouse, in ms
int threshold = range/4; // resting threshold
int center = range/2; // resting position value
int minima[ ] = {
1023, 1023}; // actual analogRead minima for {x, y}
int maxima[ ] = {
0,0}; // actual analogRead maxima for {x, y}
int axis[ ] = {
xAxis, yAxis}; // pin numbers for {x, y}
int mouseReading[2]; // final mouse readings for {x, y}
void setup() {
Mouse.begin();
}

void loop() {

// read and scale the two axes:
int xReading = readAxis(0);
int yReading = readAxis(1);

// move the mouse:
Mouse.move(xReading, yReading, 0);
delay(responseDelay);
}

/*
reads an axis (0 or 1 for x or y) and scales the
analog input range to a range from 0 to <range>
*/

int readAxis(int axisNumber) {
int distance = 0; // distance from center of the output range

// read the analog input:
int reading = analogRead(axis[axisNumber]);

// of the current reading exceeds the max or min for this axis,
// reset the max or min:
if (reading < minima[axisNumber]) {
minima[axisNumber] = reading;
}
if (reading > maxima[axisNumber]) {
maxima[axisNumber] = reading;
}

// map the reading from the analog input range to the output range:
reading = map(reading, minima[axisNumber], maxima[axisNumber], 0, range);

// if the output reading is outside from the
// rest position threshold, use it:
if (abs(reading – center) > threshold) {
distance = (reading – center);
}

// the Y axis needs to be inverted in order to
// map the movemment correctly:
if (axisNumber == 1) {
distance = -distance;
}

// return the distance for this axis:
return distance;
}

Ultimately, I decided against using mouse move for this version and talked to some other people from the class. After speaking to Angela, she gave me the great idea of adding a reload and enter button. I used pins 7 and 8 to add a restart and start button.

Fabrication

Materials:

Two shoe boxes (one slightly larger)

Wire

Buttons for test

Conductive fabric

Electric tape

Felt

Canvas to cover the buttons

Acrylic paint

The first thing I did was test each button with wires. Then I connect a small piece of conductive fabric to each side for positive and negative. Then I made holes for each switch to come through the top of the boxes. The right, left, down arrows came out through 3 holes in the first, bottom box. The wires for the up arrow, restart, and start were fed through the top of the first box and then into the second.

Once everything was done with the circuits, I decided to paint the shoe boxes to look a little bit nicer (at least cover the brands).

After the second coat of paint had dried, I cut out 6 pieces of fabric using a canvas material to cover the soft buttons.

The final touch was just to paint the title of the game for a little fun. But it was late and I called the game Lunar Landing, instead of the real title, Lunar Lander. Forgive me, Atari.