Panic Puzzle Box (Midterm)

Puzzle Box

For this project I wanted to explore and play with the idea of user interface a bit. As great as I think touchscreens are in their way…I mean you can’t really have a smartphone without one…I kind of also hate them. I don’t know, they just aren’t very satisfying to use in my opinion. Tapping a screen just doesn’t feel the same as pushing a button, turning a knob, or switching a…switch. So I wanted to create some kind of device that would be all about the way you physically interact with it.

I came up with a box that vibrates until you make it stop vibrating. You make it stop by turning the three knobs on its top surface to the correct spot (randomly determined each time you turn it on). As you get closer the vibrations lessen until they finally stop. So the idea was that you have to physically interact with the box to get it to stop shaking, but this interaction is made more difficult BECAUSE it’s shaking. Okay, so in reality, it doesn’t really shake violently enough to significantly interfere with turning the knobs, but that was the idea anyway.

The Arduino code is pretty straightforward. When it starts up, it picks random values for each of the knobs that are the ‘right’ values that they need to be turned to to stop the vibration. When the knob is as far from the right value as possible, the vibration is set to max, as it gets closer it reduces until it gets to zero. That’s the basic formula, but since I’m controlling 2 vibration motors with 3 knobs, I tweaked it slightly. Motor 1 is actually controlled 2/3 by the left knob, and 1/3 by the middle knob, while motor 2 is controlled 2/3 by the right knob and 1/3 by the middle knob.

Fresh from the laser cutter

Fresh from the laser cutter

Finishing up by hand where the laser cutter didn't go all the way through

Finishing up by hand where the laser cutter didn’t go all the way through

First test video

Finished box video

One limitation with the box in its current state is that the vibrations are almost always significantly less than the maximum. This is because the random sweet spot chosen for each knob can potentially be near or even exactly the same as the starting position of the knob. So unless you turn all the knobs to the far left before turning on the box, and then the box chooses the far right for all the sweet spots (or vice versa) the vibration will start out at less than its maximum (and usually a lot less) and go down from there unless you turn the knob the wrong way a lot. A way to fix this in a future version would be to first of all, check to see if the chosen value is too close to the starting value and, if so, choose again. But that would only fix the worst-case scenarios…you’d also want to maybe do something where the difference between the starting knob position and the target position is artificially considered the ‘maximum’ difference, giving max vibration. Then, if the user turns the knob in the wrong direction and the difference exceeds this artificial maximum, you could update the artificial maximum, so it could increase up to the ‘real’ maximum, but never go back down. Another approach would be to make the vibration increase exponentially (logarithmically?) with distance…so that at moderate distances the vibration is close to max, and you have to be pretty close to the sweet spot for it to decrease substantially. You could also combine the two approaches.

Unfortunately, with the current construction, the Arduino is blocked by the vibration motors, clay, the battery holder, etc. so it’s difficult to tweak the program without taking the whole thing apart, which limited how much I was able to mess with it once it was basically working and assembled.

The code is heavily borrowed from the seeedstudio Motor Shield code with some slight modifications:

// From: http://www.seeedstudio.com/wiki/Motor_Shield_V1.0
// Notes by Steven Khong YF: If the Jumper J4 is connected / not removed form the board, then
// you can just power the motor using the USB cable from the PC.
// Then if you unplug the USB cable, then you can power both the Arduino UNO
// and the motor using the power supply terminals i.e. 9V battery
// as the internal regulator will regulate the voltage to 5V for the Arduino.
// With the USB port opposite you / facing the other way, you are facing the
// black heatsink with the L298N CZOPC209 chip,
// Green terminal: Leftmost = Ground = Negative / Black Cable to your power supply
// Rightmost = Positive / Red Cable to your power supply
//
// With the USB port facing you, the Green motor connectors are:
// Left = Out 4 = M2 positive / Red cable to the Motor #2,
// Out 3 / Step Motor = M2 negative / Ground / Black cable to the Motor #2
// Out 2 / Step Motor = M1 positive / Red cable to the Motor #1,
// Rightmost = Out 1 = M1 negative / Ground / Black cable to the Motor #1
//. Motor driver shield- 2012 Copyright (c) Seeed Technology Inc.
//
// Original Author: Jimbo.we
// Contribution: LG
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

int pinI1=8;//define I1 interface
int pinI2=11;//define I2 interface
int speedpinA=9;//enable motor A
int pinI3=12;//define I3 interface
int pinI4=13;//define I4 interface
int speedpinB=10;//enable motor B
int turnSpeedA =0;//define the speed of motor
int turnSpeedB =0;//define the speed of motor
int turnSpeedC =0;//define the speed of motor

int potPinA = 0;    // select the input pin for the potentiometer
int valA = 0;       // variable to store the value coming from the sensor
int potPinB = 1;    // select the input pin for the potentiometer
int valB = 0;       // variable to store the value coming from the sensor
int potPinC = 2;    // select the input pin for the potentiometer
int valC = 0;       // variable to store the value coming from the sensor
int targetA = 0;
int targetB = 0;
int targetC = 0;
int diffA = 0;
int diffB = 0;
int diffC = 0;

void setup()
{
pinMode(pinI1,OUTPUT);
pinMode(pinI2,OUTPUT);
pinMode(speedpinA,OUTPUT);
pinMode(pinI3,OUTPUT);
pinMode(pinI4,OUTPUT);
pinMode(speedpinB,OUTPUT);

randomSeed(analogRead(4));
targetA = random(1024);
targetB = random(1024);
targetC = random(1024);

Serial.begin(9600);

}

void stop()//
{
digitalWrite(speedpinA,LOW);// Unenble the pin, to stop the motor. this should be done to avid damaging the motor.
digitalWrite(speedpinB,LOW);
delay(1000);

}

void loop()
{
valA = analogRead(potPinA);    // read the value from the sensor
valB = analogRead(potPinB);
valC = analogRead(potPinC);
diffA = valA – targetA;
diffA = abs(diffA);
diffB = valB – targetB;
diffB = abs(diffB);
diffC = valC – targetC;
diffC = abs(diffC);
turnSpeedA = (diffA/6) + (diffC/12);
//if (turnSpeedA < 5){turnSpeedA = 0;}
turnSpeedB = (diffB/6) + (diffC/12);
//if (turnSpeedB < 5){turnSpeedB = 0;}
Serial.print(targetA);
Serial.print(” “);
Serial.print(valA);
Serial.print(” “);
Serial.print(targetB);
Serial.print(” “);
Serial.print(valB);
Serial.print(” “);
Serial.print(targetC);
Serial.print(” “);
Serial.print(valC);
Serial.print(” “);
Serial.print(turnSpeedA);
Serial.print(” “);
Serial.println(turnSpeedB);

analogWrite(speedpinA,turnSpeedA);//input a simulation value to set the speed
analogWrite(speedpinB,turnSpeedB);
digitalWrite(pinI4,HIGH);//turn DC Motor B move clockwise
digitalWrite(pinI3,LOW);
digitalWrite(pinI2,HIGH);//turn DC Motor A move clockwise
digitalWrite(pinI1,LOW);
}