CONTEXT AND SIGNIFICANCE
We were inspired by Nintendo Labo, which shows the fusion of physical elements with digital interactions. In the previous research, I was inspired by the Fascinating Face, produced by Bingxin Feng(2020). A single blink can derive an on-screen visual change. That inspired me to view the feature of developing expansive responses to behavior as an important part of the definition of the interaction. When we were planning our midterm project, I saw a boxing game made of cardboard online and I came up with the idea of making this boxing game with Arduino to simplify the movement of hands and advance the movement of the “boxing robot”. We aim to create an entertaining and engaging experience for users seeking thrilling fun. We also considered adding some strategic challenges for players to make the game more attractive.
CONCEPTION AND DESIGN
We separate the interaction of our project into two parts. Firstly, attack and dodge. We decided to use buttons to control the arms. Two buttons for each player and each button corresponds to one servo. When the button is pushed, the servo will rotate quickly to a specific angle and restore the original, which can drive the arm raise. Previously, we designed to use the joystick to control the horizontal movement of the boxer to help them avoid the attack. However, in practice, we only found examples of servos controlled by the joystick. Using the angle changes to drive a horizontal movement is very complex. Also, when the boxers move horizontally, their arms will hit each other, which will easily damage their structure. To solve these problems, we discussed and brainstormed. We tried to find a way to move that would make the game more difficult and fun, but without bumping and giving one side an overwhelming advantage. Finally, we chose rotary movement to meet our assumptions—secondly, I am displaying the scoring and winning mechanism. We were inspired by the speeding game we made in the recitation. We decided to use the hands and heads of the boxer as the two sides of the button. Andy gave us three methods to achieve this. We chose the first way because it’s easier to apply on the breadboard.
For the appearance, we used the tongue depressor as the body, ping-pong balls as the head, and cardboard as the arena.
FABRICATION AND PRODUCTION
- arms’ structure:
The difficulties appeared when we tried to stick the servo on the body. It needed to be strong enough to help the arm move to the maximum degree. So we added another stick on the back to tie the servo on and start the motor at a 45° angle to make its moving track close to a line.
2. The joystick controls the rotation
We stuck a round board on the servo and inserted the boxer into the board. We followed the instructions on the Arduino Project Hub website to build the circuit and code.
However, in the following steps, we found that the servo 9G was too small to support the boxer to turn, even stuck it by the foam board. So we replaced the servo 9G with the servo 996, which is bigger. It needs the 220V to support and we also edited our code by the map function to make the turning more accurate.
3. Copper tape.
We covered the head and fist with the copper tapes. Shuyu covered many layers on the head to make the wire connection stronger and we adjusted the surface to make it more sensitive.
Users Test:
The advice we got is below.
We took some of them which are feasible. They made our project clearer, especially the servo966, it solved the most serious problem–unstable. We didn’t add the screen because we thought that showing the winner by LED was enough.
I was in charge of building circuits and coding. I met many difficulties in adapting the example code to fit the specific requirements of our project. I reviewed the codes we learned in class thought about the function of every line and tried if they could still work in the new conditions. Because our project has many sets of repeating components, the codes are repeating too. however, when copying the code, we should be careful with identifying every constant with correct pins and every variable with corresponding values. When I added the second arm’s servo, I forgot to identify “servo servo2”, which led to a disorder in the correlation between buttons and the servo. I discovered an effective way to write complex code. I opened an independent sketch for each part of our project (buttons control servos, joysticks control servos, and scoring.) In that way, I could quickly find which part the bugs were. For the part of the circuit, our Arduino Uno pins were full in the middle of the process, so we had to move the circuits to Arduino Mega, which is bigger than Uno. It was a chance for me to rearrange the circuits. There is the sketch.
code:
```cpp
/*
* The servo control with joystick
* This was adapted from a the tutorial found here:
*https://projecthub.arduino.cc/RiddledExistence/3a17cd50-c1c7-44c4-a29a-0501fb84faf0
* The Scoring mechanism
* This was adapted from a the tutorial found here:
https://www.tinkercad.com/things/6MzvN5rlZlr-race-the-led-spring19
* Servo control with button
* This was adapted from a the tutorial found here:
* https://arduinogetstarted.com/tutorials/arduino-button-servo-motor
*/
#include <Servo.h>
// constants won't change
const int BUTTON1_PIN = 7; // Arduino pin connected to button's pin
const int SERVO1_PIN = 8; // Arduino pin connected to servo motor's pin
const int BUTTON2_PIN = 6; // Arduino pin connected to button's pin
const int SERVO2_PIN = 9; // Arduino pin connected to servo motor's pin
const int BUTTON3_PIN = 52; // Arduino pin connected to button's pin
const int SERVO3_PIN = 53; // Arduino pin connected to servo motor's pin
const int BUTTON4_PIN = 50; // Arduino pin connected to button's pin
const int SERVO4_PIN = 51; // Arduino pin connected to servo motor's pin
int buzzerPin = 3;
int button1 = 11;
int button2 = 49;
int led1 = 2;
int led2 = 48;
int goal = 10;
int buttonState1 = LOW;
int previousState1 = LOW;
int buttonState2 = LOW;
int previousState2 = LOW;
int counter1 = 0;
int counter2 = 0;
boolean winner1 = false;
boolean winner2 = false;
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
Servo servo1; // create servo object to control a servo
Servo servo2; // create servo object to control a servo
Servo servo3; // create servo object to control a servo
Servo servo4; // create servo object to control a servo
// variables will change:
int angle1 = 0; // the current angle of servo motor
int lastButtonState1; // the previous state of button
int currentButtonState1; // the current state of button
int angle2 = 180; // the current angle of servo motor
int lastButtonState2; // the previous state of button
int currentButtonState2; // the current state of button
int angle3 = 0; // the current angle of servo motor
int lastButtonState3; // the previous state of button
int currentButtonState3; // the current state of button
int angle4 = 180; // the current angle of servo motor
int lastButtonState4; // the previous state of button
int currentButtonState4; // the current state of button
#define SERVOjoy1_PIN 4
#define GROUND_JOY1_PIN A3 //joystick ground pin will connect to Arduino analog pin A3
#define VOUT_JOY1_PIN A2 //joystick +5 V pin will connect to Arduino analog pin A2
#define XJOY1_PIN A1 //X axis reading from joystick will go into analog pin A1
Servo myservo1 ;
#define SERVOjoy2_PIN 12
#define GROUND_JOY2_PIN A10 //joystick ground pin will connect to Arduino analog pin A3
#define VOUT_JOY2_PIN A9 //joystick +5 V pin will connect to Arduino analog pin A2
#define XJOY2_PIN A8 //X axis reading from joystick will go into analog pin A1
Servo myservo2 ;
void setup() {
Serial.begin(9600); // initialize serial
pinMode(BUTTON1_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo1.attach(SERVO1_PIN); // attaches the servo on pin 9 to the servo object
servo1.write(angle1);
currentButtonState1 = digitalRead(BUTTON1_PIN);
pinMode(BUTTON2_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo2.attach(SERVO2_PIN); // attaches the servo on pin 9 to the servo object
servo2.write(angle2);
currentButtonState2 = digitalRead(BUTTON2_PIN);
pinMode(BUTTON3_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo3.attach(SERVO3_PIN); // attaches the servo on pin 9 to the servo object
servo3.write(angle3);
currentButtonState3 = digitalRead(BUTTON3_PIN);
pinMode(BUTTON4_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo4.attach(SERVO4_PIN); // attaches the servo on pin 9 to the servo object
servo4.write(angle4);
currentButtonState4 = digitalRead(BUTTON4_PIN);
pinMode(buzzerPin, OUTPUT);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Serial.println("******************* Boxing Showdown *******************");
delay(1000);
Serial.println("READY");
delay(1000);
Serial.println("SET");
delay(1500);
Serial.println("GO!!!!!!!!!!!!!!!!");
Serial.begin(9600);
pinMode(VOUT_JOY1_PIN, OUTPUT) ; //pin A3 shall be used as output
pinMode(GROUND_JOY1_PIN, OUTPUT) ; //pin A2 shall be used as output
digitalWrite(VOUT_JOY1_PIN, HIGH) ; //set pin A3 to high (+5V)
digitalWrite(GROUND_JOY1_PIN,LOW) ; //set pin A3 to low (ground)
myservo1.attach(4);
pinMode(VOUT_JOY2_PIN, OUTPUT) ; //pin A3 shall be used as output
pinMode(GROUND_JOY2_PIN, OUTPUT) ; //pin A2 shall be used as output
digitalWrite(VOUT_JOY2_PIN, HIGH) ; //set pin A3 to high (+5V)
digitalWrite(GROUND_JOY2_PIN,LOW) ; //set pin A3 to low (ground)
myservo2.attach(12);
}
void loop() {
lastButtonState1 = currentButtonState1; // save the last state
currentButtonState1 = digitalRead(BUTTON1_PIN); // read new state
lastButtonState2 = currentButtonState2; // save the last state
currentButtonState2 = digitalRead(BUTTON2_PIN); // read new state
lastButtonState3 = currentButtonState3; // save the last state
currentButtonState3 = digitalRead(BUTTON3_PIN); // read new state
lastButtonState4 = currentButtonState4; // save the last state
currentButtonState4 = digitalRead(BUTTON4_PIN); // read new state
if(lastButtonState1 == HIGH && currentButtonState1 == LOW) {
servo1.write(90);
delay(200);
servo1.write(0);
}
if(lastButtonState2 == HIGH && currentButtonState2 == LOW) {
servo2.write(90);
delay(200);
servo2.write(180);
}
if(lastButtonState3 == HIGH && currentButtonState3 == LOW) {
servo3.write(90);
delay(200);
servo3.write(0);
}
if(lastButtonState4 == HIGH && currentButtonState4 == LOW) {
servo4.write(90);
delay(200);
servo4.write(180);
}
buttonState1 = digitalRead(button1);
buttonState2 = digitalRead(button2);
//this checks the times player 01 has pressed the button
if (counter2 < goal && winner2 == false) { //player 2 not win yet. // counter1 records the number of sucesssful hits launched by player1.
if (buttonState1 != previousState1 && millis() - time > debounce) { // player 1 hit
if (buttonState1 == HIGH) {
counter2++; // add points to player 2
Serial.print("player 02: ");
Serial.println(counter2);
time = millis();
}
}
previousState1 = buttonState1;
if (counter2 == goal && winner1 == false) {
winner2 = true;
digitalWrite(led2, HIGH);
Serial.println("PLAYER 02 WINS");
playMelody();
}
}
//this checks the times player 02 has pressed the button
if (counter1 < goal && winner1 == false) {
if (buttonState2 != previousState2 && millis() - time > debounce) {
if (buttonState2 == HIGH) {
counter1++;
Serial.print("player 01: ");
Serial.println(counter1);
time = millis();
}
}
previousState2 = buttonState2;
if (counter1 == goal && winner2 == false) {
winner1 = true;
digitalWrite(led1, HIGH);
Serial.println("PLAYER 01 WINS");
playMelody();
}
}
int joystickXVal1 = analogRead(XJOY1_PIN) ; //read joystick input on pin A1
myservo1.write(map(joystickXVal1, 15, 1005, 0, 90)); //write the calculated value to the servo
int joystickXVal2 = analogRead(XJOY2_PIN) ; //read joystick input on pin A1
//myservo2.write((joystickXVal2+520)/10); //write the calculated value to the servo
myservo2.write(map(joystickXVal2, 15, 1005, 0, 90));
//Serial.println(joystickXVal2);
delay(10);
}
void playFreq(double freqHz, int durationMs) {
//Calculate the period in microseconds
int periodMicro = int((1 / freqHz) * 1000000);
int halfPeriod = periodMicro / 2;
//store start time
long startTime = millis();
//(millis() - startTime) is elapsed play time
while ((millis() - startTime) < durationMs) {
digitalWrite(buzzerPin, HIGH);
delayMicroseconds(halfPeriod);
digitalWrite(buzzerPin, LOW);
delayMicroseconds(halfPeriod);
}
}
void playMelody() {
playFreq(262, 250);
playFreq(196, 125);
playFreq(196, 125);
playFreq(220, 250);
playFreq(196, 250);
//delay(100);
playFreq(0, 250);
playFreq(247, 250);
//delay(300);
playFreq(262, 250);
//playFreq(294, 100);
//playFreq(349, 100);
//playFreq(294, 100);
//playFreq(392, 200);
//delay(100);
//playFreq(392, 400);
//playFreq(349, 400);
}
```
CONCLUSIONS
Our project results align perfectly with my definition of interaction. We not only realized the interaction between people and devices but also realized the interaction between people through this boxing game. I think our scoring and winning system can be improved. Andy gave us a suggestion about using vibration sensors as receptors for aggression. We can transport its signals into different scores and subtract them from the total score, which is on behalf of the boxer’s “life”. This not only avoids the problem of poor head-to-hand contact, but also defines the offense as a variable, making the game richer and more interesting. In the process, I learned about using known information to create new things. We tried hard to find the similarities between the class’s content and our project. We extract the useful parts from it and then go back to its roots, which are circuits and code. This experience also made me more deeply feel the original intention of Arduino design: to let users enjoy the making without struggling with starting from zero. Additionally, I can learn by trial and error. Once I uploaded the code, there always were the successful parts and failing parts. So I kept the correct parts and thought about why there were still mistakes. The process feels like stacking toy blocks, which means trying step by step.
Referance:
Feng, B. (2020). Mana – Global New Media Art Platform – art / Design / Technology Cross-industry lnnovation. MANA全球新媒体艺术平台艺术/设计/科技/跨界创新.https://www.manamana.net/video/detail?id=107126#!zh
机灵小山姆:如何用纸板做出好玩的拳击游戏,快学起来啊! 呜哩哗哩 biibii,些哩哗哩 biibii.(2022.March9). https://www.bilibili.com/video/BV1qU4y1f7tT/?share source copy web
RiddledExistence. (n.d.). Controlling a servo motor with thumb joystick. projecthub.arduino.cchttps://projecthub.arduino.cc/RiddledExistence/3a17cd50-c1c7-44c4-a29a-0501fb84faf0
anonymous. (n.d.). Arduino – button – servo motor: Arduino tutorial. Arduino Getting Started. (2023, October 11)https://arduinogetstarted.com/tutorials/arduino-button-servo-motor
Mgodoy. (2019).Circuit design race the LED – interaction lab IMA. Tinkercad. https://www.tinkercad.com/things/6MzvN5r1Zlr-
race-the-led-spring19