Concept
This build started with a contemplation of what it means to design for the brave. A quick brainstorm, pictured below, brought about four concepts. Each concept requires the user to perform an action despite the use of positive punishments when that action is taken. Positive punishment in psychological jargon just means some stimulus is presented in order to inhibit the repetition or persistence of a behavior. The Moody Cat would have the user pet the right spot on a screaming and angrily vibrating cloth blob. Used would have the user actually kill the robot, a commentary on how bravery and persistence can have unintended consequences. Danger Chamber would test the users dedication to stopping an annoying or terrifying noise, giving them the choice to be brave and endure the noise or be brave and risk slicing their hands open. Audio Lock Picking, the design I developed further, would provide a challenge similar to physical lock picking in order to stop an annoying or terrifying sound. After a consultation with our TA, I decided to pursue Audio Lock Picking due to time and skill constraints; it was the design I could most clearly understand in terms of both back end and front end work.
The origin of the idea came from a work break I had with some friends in the Engineering & Design Studio. After some coffee, we went over to a little table filled with physical puzzles and began trying to solve them. Among these puzzles were several different types of lock. After a few minutes of playing with them, I realized my week three build was similar in that the user had to find the right combination. During the brainstorm, I tried to extend the concept from the simple mental note I had, and the result was Audio Lock Picking.
Circuit
After the brainstorm, I started by prototyping the circuit. I knew I would need a potentiometer, buzzer, motor, and several LEDs, all in parallel. This was the result:
Behavior
Edit: I made the mistake of not filming the fully functioning build and letting it sit for an entire day. I have encountered a problem, discussed later, where the driving shaft keeps unscrewing itself from the DC motor. As a result, I have two videos to showcase the build’s functionality.
When the Arduino turns on, two things happen simultaneously. The motor begins to spin and the speaker begins to play a tone. The spinning of the motor drives a simple slider-crank mechanism which is attached to the motor by an M1 bolt threaded into the center hole and an M1 nut.
As the motor turns, the rotary motion is converted into linear motion and the head of the long M4 bolt strikes the two fixed l-brackets repeatedly, creating an annoying noise. The angled placement of the L brackets was not ideal, but necessitated by the way their holes overlap.
At the same time, the speaker begins to play a tone. The tone is based upon the value of the potentiometer read by the Arduino, which has been mapped in the code so that “continuous” tones between 120 and 1500 Hz are played.
As the user turns the potentiometer an LED will turn on based upon the range of values from the potentiometer that the Arduino is checking for. If the user moves to quickly, they will see a blink or nothing, as the potentiometer values might jump the key range. As in physical lock picking, where pins rarely set easily, the tone does not immediately turn the LED on permanently. The user must hold the tone within the range for two seconds in order for the LED “pin” to “set” or turn on permanently. When the first LED is on, a brief arpeggio plays, and the key range changes. When this range is set, the second LED turns on, another arpeggio plays, and the key range changes. When this range is set, the third LED turns on, and a final arpeggio will play. Upon the completion of this arpeggio, the speaker plays an inaudible tone, and the motor stops. The user has successfully picked the lock.
Discussion
This build was not incredibly challenging in terms of hardware, but the coding was a stretch. I spent a long time messing around with for loops and nested if statements before I asked our wonderful TA for help. He helped me work through the proper logic. However, I did drop a few functions. Initially, I wanted to have the speed of the motor decrease with each successful LED light-up in order to more clearly signify the connection between turning on the LEDs and stopping the annoying noise. I also wanted to have the tone ranges change with each activation. Initial experimentation, though, resulted in several unexpected problems that I could not resolve in a timely fashion and that would not be significant improvements to the user experience. While I accomplished the most important functions for the purposes of the assignment, I would like to figure these features out when I have a spare block of time.
I did have a few hardware problems. I snapped an LED and a motor cable (PICTURES) and had to replace them.
I also had difficulties with the driving shaft of the slider crank unwinding itself and falling off. I solved this by adjusting the tension of the nuts to lock the driving shaft to the motor and the crank, so they behave as a single unit, leaving only the rod to rotate freely.
There was also the problem of not designing the physical structure as well as I would have liked. If I were to improve the build, I would move the Arduino and breadboard to the center of the lower third of the panel so that I could have equal bracing on either side rather than the current staggered bracing, which makes the side with the smaller l-bracket more susceptible to damage. I also should have planned out my layout better and figured out some way of marking the acrylic in a temporary way. This would have helped prevent the several misplaced holes in the panel, and would have allowed me to put the LEDs in a straight horizontal or vertical line. I also would have experimented with whether a vertical or horizontal crank-slider mechanism would have been better. A vertical crank-slider would have made more efficient use of space and materials, requiring only a single l-bracket whose footprint on the panel could have overlapped with the crank-slider. However, I am wondering if the motor would be able to lift and drop the rod repeatedly, without it falling off, without the support provided on the Slider by the current two-l-bracket system. Finally, if I were to create this as a more permanent build, I would have used lock nuts and maybe some glue on the LEDs.
Edit: The crank slider keeps unscrewing itself from the motor. The direct cause is that the drive shaft stops while the motor spins, resulting in a reverse threading of the drive shaft. There are three potential contributing causes of the stopping of the drive shaft.
- The torque required to move the drive shaft will vary with the position of the crank it its rotation. As a result, of this, there may be a moment where the drive shaft stops, a moment which may be exacerbated by an angling of the motor due to poor placement. I lack the physics knowledge to explain this problem entirely.
- Every time the rod strikes the l-bracket, it stops, causing the entire mechanism to stop briefly. Over time, this reverse-threads the drive shaft. One fix would be to adjust the length of the rod.
- As the rod slides back along the horizontal l-bracket, it catches briefly on a hole designed for the l-bracket to attach to another piece.
A specific fix for problem one would be to create a better, custom attachment for the DC motor which embeds it into the panel, rather than holding it by hanging it from a bolt and putting a zip-tie around it. This would at least eliminate any sort of angling of the mechanism. Problem two could be solved by adjusting the length of the rod. Problem three could be solved by using a continuous smooth surface for the slider to move along. A comprehensive fix, on the other hand, would be to create a drive shaft which fits around the motor instead of threading inside of it.
Code
int const LED1Pin = 12; int const LED2Pin = 11; int const LED3Pin = 10; int const potPin = A0; int const speakerPin = 9; int const motorPin = 5; #include "pitches.h" //notes in feedback melody for when LEDs are activated for 2s int LED1FeedbackMelody[] = {NOTE_A4, NOTE_CS5, NOTE_E5, NOTE_A5}; int LED2FeedbackMelody[] = {NOTE_CS5, NOTE_E5, NOTE_A5, NOTE_CS6}; int LED3FeedbackMelody[] = {NOTE_E5, NOTE_A5, NOTE_CS6, NOTE_E6}; //setting trigger variable for melody to play bool LED1FeedbackMelodyTriggered = false; bool LED2FeedbackMelodyTriggered = false; bool LED3FeedbackMelodyTriggered = false; //length of notes variables int const noteDuration = 100; int const pauseBetweenNotes = 130; //note position variables int const initialNote = 0; int const totalNotes = 4; //setting variables for checking that the LED has been on for 2s bool LED1Triggered = false; bool LED1Over2s = false; bool LED2Triggered = false; bool LED2Over2s = false; bool LED3Triggered = false; bool LED3Over2s = false; int LED1MillisCounter = 0; bool LED1MillisTriggered = false; int LED2MillisCounter = 0; bool LED2MillisTriggered = false; int LED3MillisCounter = 0; bool LED3MillisTriggered = false; //set motor speed variables int const motorFullSpeed = 255; int const motorOff = 0; void setup() { pinMode(12, OUTPUT); pinMode(11, OUTPUT); pinMode(10, OUTPUT); } void loop() { //code to make speaker play accoding to pot input //read potentiometer and map pitch to it int potValue = analogRead(potPin); int pitch = map(potValue, 0, 1023, 120, 1500); //code to light up first LED when certain pitch plays //set variables for LED states bool LED1State = digitalRead(LED1Pin); //make first LED triggered if between pitches of 550 and 650 if (pitch >= 550 && pitch <= 650) { LED1Triggered = true; } //if LED1 is triggered, then turn on LED1 if (LED1Triggered) { digitalWrite(LED1Pin, HIGH); //these next lines capture the exact moment the LED turns on if (!LED1MillisTriggered) { LED1MillisCounter = millis(); LED1MillisTriggered = true; } else digitalWrite(LED1Pin, LOW); //if the millis counter = //the inital moment it was turned on is greater than 2000 //then it has been turned on over 2s if (millis() - LED1MillisCounter > 2000) { LED1Over2s = true; } //if LED1 is outside the range //and it has been more then two seconds //then we want the rest of the things to trigger //otherwise, turn it all off, reset the counter if (pitch > 650 || pitch < 550) { if (millis() - LED1MillisCounter > 2000) { LED1Over2s = true; } else { LED1Triggered = false; LED1MillisTriggered = false; } } //if LED has been turn on over two seconds, then turn on the LED "permanently" if (LED1Over2s) { digitalWrite(LED1Pin, HIGH); // and play notes of feedback melody: if (!LED1FeedbackMelodyTriggered) { for (int thisNote = initialNote; thisNote < totalNotes; thisNote++) { tone(speakerPin, LED1FeedbackMelody[thisNote], noteDuration); delay(pauseBetweenNotes); noTone(speakerPin); LED1FeedbackMelodyTriggered = true; } } } } //LED 2 bool LED2State = digitalRead(LED2Pin); if (pitch >= 1150 && pitch <= 1250 && LED1Triggered == true) { LED2Triggered = true; } if (LED2Triggered) { digitalWrite(LED2Pin, HIGH); //these next lines capture the exact moment the LED turns on if (!LED2MillisTriggered) { LED2MillisCounter = millis(); LED2MillisTriggered = true; } else digitalWrite(LED2Pin, LOW); //if the millis counter = //the inital moment it was turned on is greater than 2000, //then it has been turned on over 2s if (millis() - LED2MillisCounter > 2000) { LED2Over2s = true; } //if LED1 is outside the range, //and it has been more then two seconds, //then we want the rest of the things to trigger, //otherwise, turn it all off, reset the counter if (pitch > 1250 || pitch < 1150) { if (millis() - LED2MillisCounter > 2000) { LED2Over2s = true; } else { LED2Triggered = false; LED2MillisTriggered = false; } } //if LED has been turn on over two seconds, then turn on the LED "permanently" if (LED2Over2s) { digitalWrite(LED2Pin, HIGH); // and play notes of feedback melody: if (!LED2FeedbackMelodyTriggered) { for (int thisNote = initialNote; thisNote < totalNotes; thisNote++) { tone(speakerPin, LED2FeedbackMelody[thisNote], noteDuration); delay(pauseBetweenNotes); noTone(speakerPin); LED2FeedbackMelodyTriggered = true; } } } } //LED 3 bool LED3State = digitalRead(LED3Pin); if (pitch >= 350 && pitch <= 450 && LED1Triggered == true && LED2Triggered == true) { LED3Triggered = true; } if (LED3Triggered) { digitalWrite(LED3Pin, HIGH); //these next lines capture the exact moment the LED turns on if (!LED3MillisTriggered) { LED3MillisCounter = millis(); LED3MillisTriggered = true; } else digitalWrite(LED3Pin, LOW); //if the millis counter = //the inital moment it was turned on is greater than 2000, //then it has been turned on over 2s if (millis() - LED3MillisCounter > 2000) { LED3Over2s = true; } //if LED1 is outside the range, //and it has been more then two seconds //then we want the rest of the things to trigger, //otherwise, turn it all off, reset the counter if (pitch > 450 || pitch < 350) { if (millis() - LED3MillisCounter > 2000) { LED3Over2s = true; } else { LED3Triggered = false; LED3MillisTriggered = false; } } //if LED has been turn on over two seconds, then turn on the LED "permanently" if (LED3Over2s) { digitalWrite(LED3Pin, HIGH); // and play notes of feedback melody: if (!LED3FeedbackMelodyTriggered) { for (int thisNote = initialNote; thisNote < totalNotes; thisNote++) { tone(speakerPin, LED3FeedbackMelody[thisNote], noteDuration); delay(pauseBetweenNotes); noTone(speakerPin); LED3FeedbackMelodyTriggered = true; } } } } //if the last melody is triggered, stop playing tones, and stop motor //otherwise set tone based on pot values put motor to full speed if (LED3FeedbackMelodyTriggered) { analogWrite(motorPin, motorOff); noTone(speakerPin); } else { analogWrite(motorPin, motorFullSpeed); tone(speakerPin, pitch, 100); } }