Context and Significance:
My partner, Emma DeLeon, and I began crafting an engaging and interactive game, but initially, we were unsure about the direction to take. Reflecting on past projects like the Kinetic Wearable project, where we made wings controlled by thin film pressure sensors, allowing the wearer to control their movement. While we found this interaction enjoyable for the wearer, we aimed to enhance the engagement of the audience too.
In various previous projects, such as the cat-stealing-money bank and retractable whip-sword, we observed diverse user interactions. In the case of the cat-stealing-money bank, the user exemplifies physical interaction, where users’ actions directly affect the machine’s behavior: placing coins in a designated area, triggering a response from the machine, wherein a cat will emerge to “steal” the coin. On the other hand, in the retractable whip-sword project, the users’ movements, such as swinging the sword, dictate whether or not the sword would retract or protract, demonstrating kinetic interaction, where motion or gestures initiate a response from the machine.
These examples led us to define interaction as a reciprocal exchange of actions and responses between users and systems, encompassing various modes. Interaction is not merely a one-way process but rather a dynamic interplay that shapes user experiences and system behaviors.
Inspired by this, we stumbled upon a YouTube video by The Q, featuring a claw machine made out of cardboard and powered by hydraulics. Intrigued by the interactive and nostalgic appeal of claw machines, we embarked on our version. Further research, such as Sean’s Crafts’ video, offered insights into different mechanisms to move the claw in case our idea of using steppers or servo motors did not work (this came true! but more about this later in the blog).
Initially, we wanted to keep it a single-player game, but we felt it did not add to the existing machine.
As a result, we decided to make it into a two-player game. Rather than adhering to our initial competitive concept, we opted for a cooperative approach. Two players will work together to operate the claw machine and get the rewards, the plushie! We wanted to make this a fun and collaborative game that allows people of all ages to build a bond when playing our game, emphasizing the importance of friendship and togetherness.
Conception and Design:
Understanding how users would interact with the project heavily influenced our design decisions. We positioned the users on opposite sides of the claw machine to facilitate engagement, ensuring each participant could only control the buttons on their respective sides. This setup enhances the interactive experience and encourages collaborative play.
As for materials, we opted for cardboard due to its accessibility and structural integrity. Cardboard provided the necessary sturdiness to maintain the shape of the machine and support the mechanism responsible for moving the claw. Its lightweight nature also simplified transportation and assembly.
Alternative materials such as plastic or wood were initially considered but ultimately ruled out. Plastic was deemed unsuitable due to its flimsiness and environmental impact. Wood, while sturdy, presented challenges in fabrication due to weight, and costliness. As a result, cardboard balanced affordability, durability, and eco-friendliness, perfectly aligning with our project’s objectives.
Thick strings replaced servo motors and steppers as the power controlling the claw, as neither servo motors nor steppers possessed the necessary strength to manipulate the cardboard mechanism we constructed. Hence, we opted to redesign the control panels to accommodate the use of strings, providing a manual alternative that better suited our project.
Coins were integrated into our claw design to reopen the claw after the closure. Despite their small size, the coins possess sufficient weight, which proved advantageous for our claw mechanism, especially considering the limited space available. This inclusion ensured smooth functionality and enhanced the overall user experience of our project.
Fabrication and Production:
As I stated before, due to the servo motors and steppers, lacking the necessary strength to manipulate the claw mechanism, likely due to the weight and friction of our cardboard setup, we opted for a manual approach in our project. Despite having a backup plan involving hydraulics, created using syringes, tubes, and water, this alternative still couldn’t provide sufficient force. Consequently, we made a last-minute decision to switch to a manual approach using strings.
Despite these changes, we created a fun and interactive experience. By embracing a more manual approach, players were compelled to collaborate even more closely. This was because controlling the claw now required coordinated effort from both sides of the controls to maneuver it in the desired direction. This perfectly aligns with the goal of our game, which was to foster friendship and togetherness among players, emphasizing that ‘it takes two’ to play this game.
For our project, I constructed the claw machine infrastructure entirely from cardboard. While time-consuming due to its large size, the process was relatively straightforward, mainly involving measuring and cutting.
Also, I crafted the claw using cardboard, toothpicks, strings, and coins, following Sean’s video tutorial. This assembly was also straightforward and didn’t take much time.
As I constructed the claw machine infrastructure, Emma crafted the popsicle stick mechanism to move the claw up and down. Although straightforward, the process was somewhat tedious as she manually created holes in the popsicles using a screwdriver, as the drill did not have the size that we needed. Note: Figures 43 to 45 were intended for use with steppers, which we did not include due to our switch to a manual approach.
Emma also created cardboard tubes to support and mobilize the claw. Initially, the shorter tubes were too narrow to fit over the longer ones, but promptly resolved this by cutting a slit along the shorter tubes to widen them.
I focused on configuring the strings, which proved to be a bit challenging. Initially, the strings required additional pulling to activate the claw. However, by arranging them to lay atop each other and tying them near the claw platform, we resolved the string configuration issue.
Furthermore, I implemented new control panels using repurposed syringes, which required careful attention to ensure smooth knob rotation. However, their lack of sturdiness posed a challenge in turning the knobs without breakage. To address this, I devised a solution where users could either wrap the string around the knobs or pull directly on the strings to manipulate the claw.
To create the controls, Emma sawed the syringes around the 4mL mark, sawing both the barrel and the plunger. Next, I glued the black suction, originally on the plunger tip, onto the bottom barrel. After removing the finger flange, I reattached it to the newly trimmed barrel opening. Emma then sawed the plunger to have it slightly protrude from the barrel, allowing players to wrap strings around it for claw control. Finally, I reattached the new plunger to the black suction, completing the control panel.
I also made the curtain for the claw machine, designed to conceal the strings and holes on top of the claw machine. While creating the curtains was straightforward, even such small details significantly enhanced the overall appearance and user experience for the players.
Emma and I collaborated on the code, working together on a shared Google doc where we continuously updated and refined it for our claw machine. Initially, our code included instructions for controlling the claw mechanisms with steppers, as depicted in the first three codes below.
First code:
#include <AccelStepper.h> #include <Servo.h> int stage = 1; // Define pressure sensors int sensorVal1; // coin slot 1 int sensorVal2; // coin slot 2 // Define Claw servo + pins Servo claw; int buttonPin5 = A2; // player 1 claw button int buttonPin6 = A3; // player 2 claw button // Define stepper 1 pins int DIR_PIN1 = 2; int STEP_PIN1 = 3; int EN_PIN1 = 4; int buttonPin1 = 7; int buttonPin3 = A4; AccelStepper stepper1(AccelStepper::DRIVER, STEP_PIN1, DIR_PIN1); // Define stepper 2 pins int DIR_PIN2 = 5; int STEP_PIN2 = 6; int EN_PIN2 = 8; int buttonPin2 = 9; int buttonPin4 = A5; AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2); // Define stepper 3 pins int DIR_PIN3 = 10; int STEP_PIN3 = 11; int EN_PIN3 = 12; AccelStepper stepper3(AccelStepper::DRIVER, STEP_PIN3, DIR_PIN3); unsigned long startTime = 0; bool lastButtonState1 = HIGH; // Button 1 not pressed bool lastButtonState2 = HIGH; // Button 2 not pressed bool lastButtonState3 = HIGH; // Button 3 not pressed bool lastButtonState4 = HIGH; // Button 4 not pressed bool lastButtonState5 = HIGH; // Button 5 not pressed bool lastButtonState6 = HIGH; // Button 6 not pressed void setup() { Serial.begin(9600); // Initialize analog pins 6 and 7 as inputs (with pull-up resistors): // LEDs to indicate if sensor was activated pinMode(A6, INPUT_PULLUP); pinMode(A7, INPUT_PULLUP); // Enable the stepper1 driver pinMode(EN_PIN1, OUTPUT); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); digitalWrite(EN_PIN1, LOW); // Enable the stepper2 driver pinMode(EN_PIN2, OUTPUT); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); digitalWrite(EN_PIN2, LOW); // Enable the stepper3 driver pinMode(EN_PIN3, OUTPUT); digitalWrite(EN_PIN3, LOW); // Attach the claw servo to pin 13 claw.attach(13); // Set initial speed & acceleration for stepper1 stepper1.setMaxSpeed(500); stepper1.setAcceleration(100); // Set initial speed & acceleration for stepper2 stepper2.setMaxSpeed(500); stepper2.setAcceleration(100); // Set initial speed & acceleration for stepper3 stepper3.setMaxSpeed(500); stepper3.setAcceleration(100); // Turn off LED digitalWrite(A4, LOW); digitalWrite(A5, LOW); // Reset positions of all steppers delay(100); stepper3.runToNewPosition(0); delay(1000); stepper2.runToNewPosition(0); delay(1000); stepper1.runToNewPosition(0); delay(1000); // Reset claw position claw.write(0); delay(10); // Record the start time startTime = millis(); } void loop() { unsigned long currentTime = millis(); unsigned long elapsedTime = currentTime - startTime; // Convert milliseconds to seconds unsigned long elapsedTimeSeconds = elapsedTime / 1000; Serial.print("Millis: "); Serial.print(currentTime); Serial.print(", Time(s): "); Serial.println(elapsedTimeSeconds); if (stage == 1) { stage1(); } else if (stage == 2) { stage2(elapsedTime); } else if (stage == 3) { stage3(); } delay(10); } // Standby mode: Buttons will not work until pressure sensors are activated void stage1() { Serial.println("Stage 1"); delay(10); // Read the input on analog pin 0 (coin slot 1) sensorVal1 = analogRead(A0); Serial.println(sensorVal1); // Read the input on analog pin 1 (coin slot 2) sensorVal2 = analogRead(A1); Serial.println(sensorVal2); // Activate output pins if sensors are triggered if (sensorVal1 > 1) { digitalWrite(A6, HIGH); //Player 1 LED } if (sensorVal2 > 1) { digitalWrite(A7, HIGH); //Player 2 LED } // Proceed to stage 2 if both sensors are triggered if (digitalRead(A4) == HIGH && digitalRead(A5) == HIGH) { stage = 2; Serial.println("Stage 2"); } } // Game started: All buttons will work void stage2(unsigned long elapsedTime) { // Button 1 controls stepper1 (left -> right) bool buttonState1 = digitalRead(buttonPin1); if (buttonState1 != lastButtonState1) { if (buttonState1 == LOW) { Serial.println("Button 1 pressed"); stepper1.runToNewPosition(100); delay(1000); } else { Serial.println("Button 1 released"); stepper1.stop(); } } lastButtonState1 = buttonState1; // Button 3 controls stepper1 (left <- right) bool buttonState3 = digitalRead(buttonPin3); if (buttonState3 != lastButtonState3) { if (buttonState3 == LOW) { Serial.println("Button 3 pressed"); stepper1.runToNewPosition(0); delay(1000); } else { Serial.println("Button 3 released"); stepper1.stop(); } } lastButtonState3 = buttonState3; // Button 2 controls stepper2 (left -> right) bool buttonState2 = digitalRead(buttonPin2); if (buttonState2 != lastButtonState2) { if (buttonState2 == LOW) { Serial.println("Button 2 pressed"); stepper2.runToNewPosition(100); delay(1000); } else { Serial.println("Button 2 released"); stepper2.stop(); } } lastButtonState2 = buttonState2; // Button 4 controls stepper2 (left <- right) bool buttonState4 = digitalRead(buttonPin4); if (buttonState4 != lastButtonState4) { if (buttonState4 == LOW) { Serial.println("Button 4 pressed"); stepper2.runToNewPosition(0); delay(1000); } else { Serial.println("Button 4 released"); stepper2.stop(); } } lastButtonState4 = buttonState4; // A2 and A3 control stepper3 when activated together bool buttonState5 = digitalRead(buttonPin5); bool buttonState6 = digitalRead(buttonPin6); if (buttonState5 == LOW && buttonState6 == LOW) { Serial.println("Claw Activated"); stepper3.runToNewPosition(100); // Drops claw delay(2500); claw.write(180); // Closes claw delay(2000); // Turn off LED digitalWrite(A4, LOW); digitalWrite(A5, LOW); delay(10); } lastButtonState5 = buttonState5; lastButtonState6 = buttonState6; // Proceed to stage 3 after 60 seconds or when LED turns off if (elapsedTime >= 60000 || digitalRead(A4) == LOW) { stage = 3; Serial.println("Stage 3"); } } // Reset game: Reset machine (releases claw over exit) void stage3() { // Reset positions of all steppers stepper3.runToNewPosition(0); delay(2000); stepper2.runToNewPosition(0); delay(2000); stepper1.runToNewPosition(0); delay(5000); // Reset claw position claw.write(0); delay(10); // Reset stage to 1 stage = 1; Serial.println("Stage 1"); } |
Second Code:
#include <AccelStepper.h> #include <Servo.h> int state = 1; int startTime; // Define stepper 1 pins int DIR_PIN1 = 2; int STEP_PIN1 = 3; int EN_PIN1 = 4; int buttonPin1 = 7; int buttonPin3 = A4; AccelStepper stepper1(AccelStepper::DRIVER, STEP_PIN1, DIR_PIN1); // Define stepper 2 pins int DIR_PIN2 = 5; int STEP_PIN2 = 6; int EN_PIN2 = 8; int buttonPin2 = 9; int buttonPin4 = A5; AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2); int sensorVal1; // coin slot 1 int sensorVal2; // coin slot 2 Servo claw; int buttonPin5 = A2; // player 1 claw button int buttonPin6 = A3; // player 2 claw button bool lastButtonState1 = HIGH; // Button 1 not pressed bool lastButtonState2 = HIGH; // Button 2 not pressed bool lastButtonState3 = HIGH; // Button 3 not pressed bool lastButtonState4 = HIGH; // Button 4 not pressed bool lastButtonState5 = HIGH; // Button 5 not pressed bool lastButtonState6 = HIGH; // Button 6 not pressed bool ledOn = false; // Initialize to off void setup() { Serial.begin(9600); pinMode(A6, OUTPUT); pinMode(A7, OUTPUT); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); pinMode(buttonPin5, INPUT_PULLUP); pinMode(buttonPin6, INPUT_PULLUP); // Enable the stepper1 driver pinMode(EN_PIN1, OUTPUT); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); digitalWrite(EN_PIN1, LOW); // Enable the stepper2 driver pinMode(EN_PIN2, OUTPUT); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); digitalWrite(EN_PIN2, LOW); stepper1.setMaxSpeed(500); stepper1.setAcceleration(100); // Set initial speed & acceleration for stepper2 stepper2.setMaxSpeed(500); stepper2.setAcceleration(100); stepper1.runToNewPosition(0); delay(1000); stepper2.runToNewPosition(0); delay(1000); // Reset claw position claw.attach(13); claw.write(0); delay(10); } void loop() { if (state == 1) { state1(); } else if (state == 2) { state2(); } //else if (state == 3) { // state3(); // } } void state1() { //Game Standby Mode (coins must be inserted) // Check if both coin slots are active if (digitalRead(A6) == HIGH && digitalRead(A7) == HIGH) { Serial.println("Game Start!"); state = 2; } sensorVal1 = analogRead(A0); sensorVal2 = analogRead(A1); if (sensorVal1 > 200) { Serial.println("Player 1 has inserted a coin"); digitalWrite(A6, HIGH); } if (sensorVal2 > 200) { Serial.println("Player 2 has inserted a coin"); digitalWrite(A7, HIGH); } } void state2() { bool buttonState1 = digitalRead(buttonPin1); if (buttonState1 != lastButtonState1) { if (buttonState1 == LOW) { Serial.println("Button 1 pressed: Moving Left"); stepper1.runToNewPosition(100); delay(1000); } else { Serial.println("Button 1 released"); stepper1.stop(); } } lastButtonState1 = buttonState1; bool buttonState3 = digitalRead(buttonPin3); if (buttonState3 != lastButtonState3) { if (buttonState3 == LOW) { Serial.println("Button 3 pressed: Moving Right"); stepper1.runToNewPosition(0); delay(1000); } else { Serial.println("Button 3 released"); stepper1.stop(); } } lastButtonState3 = buttonState3; bool buttonState2 = digitalRead(buttonPin2); if (buttonState2 != lastButtonState2) { if (buttonState2 == LOW) { Serial.println("Button 2 pressed: Moving Forwards"); stepper2.runToNewPosition(100); delay(1000); } else { Serial.println("Button 2 released"); stepper2.stop(); } } lastButtonState2 = buttonState2; bool buttonState4 = digitalRead(buttonPin4); if (buttonState4 != lastButtonState4) { if (buttonState4 == LOW) { Serial.println("Button 4 pressed: Moving Backwards"); stepper2.runToNewPosition(0); delay(1000); } else { Serial.println("Button 4 released"); stepper2.stop(); } } lastButtonState4 = buttonState4; bool buttonState5 = digitalRead(buttonPin5); bool buttonState6 = digitalRead(buttonPin6); if (buttonState5 == LOW && buttonState6 == LOW) { Serial.println("Claw Activated"); // stepper3.runToNewPosition(100); // Drops claw claw.write(180); // Closes claw delay(100); } lastButtonState5 = buttonState5; lastButtonState6 = buttonState6; }
Third Code:
#include <AccelStepper.h> #include <Servo.h> int state = 1; long startTime; // suggested, long stores more number bool gameStarted = false; //suggested // Define stepper 1 pins int DIR_PIN1 = 2; int STEP_PIN1 = 3; int EN_PIN1 = 4; int buttonPin1 = 7; int buttonPin3 = A4; AccelStepper stepper1(AccelStepper::DRIVER, STEP_PIN1, DIR_PIN1); // Define stepper 2 pins int DIR_PIN2 = 5; int STEP_PIN2 = 6; int EN_PIN2 = 8; int buttonPin2 = 9; int buttonPin4 = A5; AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2); int sensorVal1; // coin slot 1 int sensorVal2; // coin slot 2 Servo claw; int buttonPin5 = A2; // player 1 claw button int buttonPin6 = A3; // player 2 claw butto bool lastButtonState1 = HIGH; // Button 1 not pressed bool lastButtonState2 = HIGH; // Button 2 not pressed bool lastButtonState3 = HIGH; // Button 3 not pressed bool lastButtonState4 = HIGH; // Button 4 not pressed bool lastButtonState5 = HIGH; // Button 5 not pressed bool lastButtonState6 = HIGH; // Button 6 not pressed bool ledOn = false; // Initialize to off void setup() { state = 1; //suggested gameStarted = false; //suggested Serial.begin(9600); pinMode(A6, OUTPUT); pinMode(A7, OUTPUT); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); pinMode(buttonPin5, INPUT_PULLUP); pinMode(buttonPin6, INPUT_PULLUP); // Enable the stepper1 driver pinMode(EN_PIN1, OUTPUT); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); digitalWrite(EN_PIN1, LOW); // Enable the stepper2 driver pinMode(EN_PIN2, OUTPUT); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); digitalWrite(EN_PIN2, LOW); stepper1.setMaxSpeed(500); stepper1.setAcceleration(100); // Set initial speed & acceleration for stepper2 stepper2.setMaxSpeed(500); stepper2.setAcceleration(100); stepper1.runToNewPosition(0); delay(1000); stepper2.runToNewPosition(0); delay(1000); // Reset claw position claw.attach(13); claw.write(0); delay(10); } void loop() { if (state == 1) { state1(); } else if (state == 2) { if (!gameStarted) { //suggested startTime = millis(); //suggested gameStarted = true; //suggested } long currentTime = state2(); //suggested Serial.print("Elapsed Time: "); //suggested Serial.println(currentTime - startTime); //suggested if (currentTime - startTime >= 45000) { //suggested Serial.print("Time is Up!"); //suggested setup(); //suggested } } } void state1() { //Game Standby Mode (coins must be inserted) // Check if both coin slots are active if (digitalRead(A6) == HIGH && digitalRead(A7) == HIGH) { Serial.println("Game Start!"); state = 2; } sensorVal1 = analogRead(A0); sensorVal2 = analogRead(A1); if (sensorVal1 > 200) { Serial.println("Player 1 has inserted a coin"); digitalWrite(A6, HIGH); } if (sensorVal2 > 200) { Serial.println("Player 2 has inserted a coin"); digitalWrite(A7, HIGH); } } long state2() { //suggested bool buttonState1 = digitalRead(buttonPin1); if (buttonState1 != lastButtonState1) { if (buttonState1 == LOW) { Serial.println("Button 1 pressed: Moving Left"); stepper1.runToNewPosition(100); delay(1000); } else { Serial.println("Button 1 released"); stepper1.stop(); } } lastButtonState1 = buttonState1; bool buttonState3 = digitalRead(buttonPin3); if (buttonState3 != lastButtonState3) { if (buttonState3 == LOW) { Serial.println("Button 3 pressed: Moving Right"); stepper1.runToNewPosition(0); delay(1000); } else { Serial.println("Button 3 released"); stepper1.stop(); } } lastButtonState3 = buttonState3; bool buttonState2 = digitalRead(buttonPin2); if (buttonState2 != lastButtonState2) { if (buttonState2 == LOW) { Serial.println("Button 2 pressed: Moving Forwards"); stepper2.runToNewPosition(100); delay(1000); } else { Serial.println("Button 2 released"); stepper2.stop(); } } lastButtonState2 = buttonState2; bool buttonState4 = digitalRead(buttonPin4); if (buttonState4 != lastButtonState4) { if (buttonState4 == LOW) { Serial.println("Button 4 pressed: Moving Backwards"); stepper2.runToNewPosition(0); delay(1000); } else { Serial.println("Button 4 released"); stepper2.stop(); } } lastButtonState4 = buttonState4; bool buttonState5 = digitalRead(buttonPin5); bool buttonState6 = digitalRead(buttonPin6); if (buttonState5 == LOW && buttonState6 == LOW) { Serial.println("Claw Activated"); claw.write(180); // Closes claw delay(100); } lastButtonState5 = buttonState5; lastButtonState6 = buttonState6; return millis(); //suggested }
Once we switched to using strings, we removed the stepper control section and modified the code to include functionality for LED lights and three thin film pressure sensors: two for the coin slots and one for detecting when the plushie drops to stop the game. Additionally, I incorporated code for playing a melody, which I learned from Tigran’s GitHub, as shown below in the fourth code.
Fourth code:
#include "pitches.h" #define BUZZER_PIN 11 int sensorVal1; // coin slot 1 int sensorVal2; // coin slot 2 int sensorVal3; // toy exit int state = 1; long startTime; bool gameStarted = false; bool ledOn = false; // Initialize to off // Melody data int melody[] = { NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, REST, NOTE_G5, NOTE_FS5, NOTE_F5, NOTE_DS5, NOTE_E5, REST, NOTE_GS4, NOTE_A4, NOTE_C4, REST, NOTE_A4, NOTE_C5, NOTE_D5, REST, NOTE_DS5, REST, NOTE_D5, NOTE_C5, REST, REST, NOTE_G5, NOTE_FS5, NOTE_F5, NOTE_DS5, NOTE_E5, REST, NOTE_GS4, NOTE_A4, NOTE_C4, REST, NOTE_A4, NOTE_C5, NOTE_D5, REST, NOTE_DS5, REST, NOTE_D5, NOTE_C5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, // Game over sound NOTE_C5, NOTE_G4, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_A4, NOTE_GS4, NOTE_AS4, NOTE_GS4, NOTE_G4, NOTE_D4, NOTE_E4 }; // Duration data int durations[] = { 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 2, 2, 4, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 2, 2, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 1, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 1, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, //game over sound 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 2 }; void setup() { state = 1; gameStarted = false; Serial.begin(9600); pinMode(A4, OUTPUT); //Player 1 LED pinMode(A5, OUTPUT); //Player 2 LED ledOn = false; } void loop() { if (state == 1) { state1(); } else if (state == 2) { if (!gameStarted) { startTime = millis(); gameStarted = true; } long currentTime = state2(); Serial.print("Elapsed Time: "); Serial.println(currentTime - startTime); if (currentTime - startTime >= 60000) { Serial.print("Time is Up!"); setup(); } } } void state1() { //Game Standby Mode (coins must be inserted) // Check if both coin slots are active if (digitalRead(A4) == HIGH && digitalRead(A5) == HIGH) { Serial.println("Game Start!"); state = 2; } sensorVal1 = analogRead(A0); //P1 sensorVal2 = analogRead(A1); //P2 if (sensorVal1 > 200) { Serial.println("Player 1 has inserted a coin"); digitalWrite(A4, HIGH); } if (sensorVal2 > 200) { Serial.println("Player 2 has inserted a coin"); digitalWrite(A5, HIGH); } } long state2() { // Game start // Play the melody continuously for (int i = 0; i < sizeof(melody) / sizeof(melody[0]); i++) { int noteDuration = 1000 / durations[i]; tone(BUZZER_PIN, melody[i], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); noTone(BUZZER_PIN); //Toy Sensor sensorVal3 = analogRead(A2); if (sensorVal3 > 200) { Serial.println("Toy Won!"); digitalWrite(2, HIGH); } // Check if sensor on then reset the game if (digitalRead(2) == HIGH) { Serial.println("Game Over! . . . Restarting"); setup(); } } // If the melody has finished playing and the game is still active, return the current time return millis(); }
While relatively straightforward, the challenge emerged when programming the game to start and stop based on the pressure sensors. Specifically, I needed to ensure that when both coin slot sensors were pressed, the game and music would start, and when the drop site sensor was pressed, the game would end, and the music would stop.
This functionality required some time to figure out, but I resolved the issue by placing the setup() function at the end of the second “if” statement within the state2 function, as well as at the end of the loop() function. Additionally, I inserted a break; statement at the beginning of the loop() function to ensure proper execution, as shown in the Fifth code.
Fifth and Last code:
#include "pitches.h" #define BUZZER_PIN 11 int sensorVal1; // coin slot 1 int sensorVal2; // coin slot 2 int sensorVal3; // toy exit int state = 1; long startTime; bool gameStarted = false; bool ledOn = false; // Initialize to off // Melody data int melody[] = { NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, REST, NOTE_G5, NOTE_FS5, NOTE_F5, NOTE_DS5, NOTE_E5, REST, NOTE_GS4, NOTE_A4, NOTE_C4, REST, NOTE_A4, NOTE_C5, NOTE_D5, REST, NOTE_DS5, REST, NOTE_D5, NOTE_C5, REST, REST, NOTE_G5, NOTE_FS5, NOTE_F5, NOTE_DS5, NOTE_E5, REST, NOTE_GS4, NOTE_A4, NOTE_C4, REST, NOTE_A4, NOTE_C5, NOTE_D5, REST, NOTE_DS5, REST, NOTE_D5, NOTE_C5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_C5, NOTE_G4, REST, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_AS4, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_G5, NOTE_A5, NOTE_F5, NOTE_G5, REST, NOTE_E5, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, REST, NOTE_C5, NOTE_C5, NOTE_C5, REST, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_E5, REST, NOTE_E5, REST, NOTE_C5, NOTE_E5, NOTE_G5, REST, NOTE_G4, REST, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_D5, NOTE_A5, NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5, NOTE_E5, NOTE_C5, NOTE_A4, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, REST, NOTE_GS4, NOTE_A4, NOTE_F5, NOTE_F5, NOTE_A4, NOTE_B4, NOTE_F5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_E4, NOTE_E4, NOTE_C4, // Game over sound NOTE_C5, NOTE_G4, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_A4, NOTE_GS4, NOTE_AS4, NOTE_GS4, NOTE_G4, NOTE_D4, NOTE_E4 }; // Duration data int durations[] = { 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 2, 2, 4, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 2, 2, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 1, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 4, 8, 4, 4, 4, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 4, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 1, 8, 4, 8, 8, 8, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 8, 8, 8, 8, 8, 8, 4, 8, 2, 8, 4, 8, 4, 4, 8, 4, 8, 2, 8, 4, 8, 8, 8, 8, 8, 4, 8, 2, //game over sound 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 2 }; void setup() { state = 1; gameStarted = false; Serial.begin(9600); pinMode(A4, OUTPUT); //Player 1 LED pinMode(A5, OUTPUT); //Player 2 LED pinMode(2, OUTPUT); //Toy Exit ledOn = false; digitalWrite(A4, LOW); digitalWrite(A5, LOW); digitalWrite(2, LOW); } void loop() { if (state == 1) { state1(); } else if (state == 2) { if (!gameStarted) { startTime = millis(); gameStarted = true; } // Play the melody continuously for (int i = 0; i < sizeof(melody) / sizeof(melody[0]); i++) { int noteDuration = 1000 / durations[i]; tone(BUZZER_PIN, melody[i], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); noTone(BUZZER_PIN); long currentTime = state2(); if (state == 1) { break; } Serial.print("Elapsed Time: "); Serial.println(currentTime - startTime); if (currentTime - startTime >= 60000) { Serial.print("Time is Up!"); setup(); break; } } } } void state1() { //Game Standby Mode (coins must be inserted) // Check if both coin slots are active if (digitalRead(A4) == HIGH && digitalRead(A5) == HIGH) { Serial.println("Game Start!"); state = 2; } sensorVal1 = analogRead(A0); //P1 sensorVal2 = analogRead(A1); //P2 if (sensorVal1 > 200) { Serial.println("Player 1 has inserted a coin"); digitalWrite(A4, HIGH); } if (sensorVal2 > 200) { Serial.println("Player 2 has inserted a coin"); digitalWrite(A5, HIGH); } } long state2() { // Game start //Toy Sensor sensorVal3 = analogRead(A2); if (sensorVal3 > 50) { Serial.println("Toy Won!") setup(); } // If the melody has finished playing and the game is still active, return the current time return millis(); } |
During our user testing session, we were still planning to use steppers for our claw machine. We explained the functionality of the three buttons on each side: two for directional movements, and one for claw control. While some suggestions couldn’t be applied to our manual approach, two stood out: incorporating a theme of friendship and unity and labeling the controls. Despite the debate on labeling, we decided against it to enhance interactivity, encouraging players to explore and communicate, promoting problem-solving and deeper engagement between players.
Conclusion:
In conclusion, our project aimed to create a fun, interactive game underscoring friendship and togetherness. We successfully developed a collaborative claw machine experience requiring players to work together. While the manual controls encouraged closer collaboration, they introduced challenges not present in our original plan with automated mechanisms. Additionally, the decision not to label the controls may have enhanced interactivity but could have confused them.
Despite initial difficulties in navigating the controls, players interacted positively, engaging in collaborative gameplay and embracing the theme of friendship. We also aimed to keep our audience engaged by presenting a novel concept of a multiplayer claw machine, focusing on collaboration.
Given more time, we would refine the user interface, possibly exploring automation through servo motors and steppers (that are powerful enough) to enhance the precision and accuracy of the claw. Moreover, using lighter-weight materials with minimal friction, such as metal rods or 3D-printed components, could facilitate smoother movements and reduce strain on the motors or actuators, improving performance and user experience.
From setbacks, we gained valuable lessons about adaptability and the iterative nature of design, highlighting the need to address challenges creatively and continuously refine our approach. Moreover, we learned the importance of expecting the unexpected and recognizing that not everything will work perfectly on the first try, underscoring the beauty of building, where innovation and problem-solving are essential components of progress.
From our accomplishments, we take pride in creating an engaging, collaborative gaming experience that deeply resonates with our audience. We succeeded in developing a project that aligns perfectly with our overarching goals of togetherness and friendship. Moving forward, we eagerly anticipate applying these lessons to future endeavors, confident in our ability to create meaningful and impactful projects!
FINAL PRODUCT OF OUR CLAW MACHINE:
Video 1:
Video 2:
Disassembly:
Appendix:
We attempted to replicate The Q’s hydraulic system using syringes, tubes, and water to control the claw’s movement. However, our attempts failed due to hydraulics’ insufficient strength to push our cardboard mechanism effectively, mainly due to its weight and friction. Despite this setback, I decided to include our experimentation with hydraulics in the blog to showcase the alternative methods we explored before transitioning to a manual approach.