War:

Ceasefire:

How They Work:

The Dragon and Knight robots communicate through the simple language of violence. Upon booting up, there is a chance that one of the robots will lash out at the other, starting the “conversation”. Alternatively, they may simply glare at each other and an outside user can participate by instigating the violence.

Upon being hit, the robot will rock forward and trigger its roller switch so that it knows that it has been hit. Upon receiving a hit, the robot will wait a randomly determined amount of time before swing back at the other robot and continuing the conversation. After a certain randomly determined number of hits received, a robot will surrender by raising its white flag. Upon seeing the white flag, the other robot will stop attacking. Upon achieving victory, the dragon will let out a triumphant roar.

Solidworks Files:

Knight vs Dragon

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <Servo.h>
 
#define PHOTO_PIN   0
 
#define NUM_PINS    1
#define NUM_SAMPLES 8
 
int16_t avg_samples [NUM_PINS][NUM_SAMPLES];
uint8_t ind         [NUM_PINS];
int16_t avg_total   [NUM_PINS];
int16_t avg         [NUM_PINS];
 
void update_avg(uint8_t pin){
  uint8_t i = ind[pin];
   
  //Subtract old value
  avg_total[pin] = avg_total[pin] - avg_samples[pin][i];
 
  //Measure and add new value
  avg_samples[pin][i] = analogRead(pin);
  avg_total[pin] = avg_total[pin] + avg_samples[pin][i];
   
  //Increment counter
  ind[pin] = i + 1;
  ind[pin] %= (uint8_t)NUM_SAMPLES;
 
  avg[pin] = avg_total[pin] / NUM_SAMPLES;
}
 
void update_avgs(){
  for(uint8_t i = 0; i < NUM_PINS; i++){
    update_avg(i);
  }
}
 
void init_avgs(){
  //Zero out AVG array
  for(uint8_t i = 0; i < NUM_PINS; i++){
    for(uint8_t j = 0; j < NUM_SAMPLES; j++){
      avg_samples[i][j] = 0;
    }
    ind[i] = 0;
    avg_total[i] = 0;
    avg[i] = 0;
  }
}
 
#define HAMMER_PIN 9
#define FLAG_PIN 10
#define SWITCH_PIN 3
#define LED_PIN 2
 
//Angles for servos
#define FLAG_REST 40
#define FLAG_ACTV 180
#define HAMM_REST 0
#define HAMM_ACTV 90
 
#define LIGHT_THRESHOLD 650
 
Servo hammer_servo;
Servo flag_servo;
uint8_t loss_ct;
 
void setup() {
  init_avgs();
 
  hammer_servo.attach(HAMMER_PIN);
  flag_servo.attach(FLAG_PIN);
 
  hammer_servo.write(HAMM_REST);
  flag_servo.write(FLAG_REST);
 
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
 
  pinMode(SWITCH_PIN, INPUT);
 
  Serial.begin(9600);
  randomSeed(analogRead(4));
 
  loss_ct = random(5, 10);
}
 
#define WAIT  0
#define HIT1  1
#define HIT2  2
#define HIT3  3
#define DBNC  4
#define FLAG  5
#define VICT  6
uint8_t state = WAIT;
 
uint8_t delay_ct = 0;
uint8_t hit_ct = 0;
 
float mult = 1.06;
float base = 440;
uint8_t counter = 0;
void do_tone(){
  counter++;
  counter%=24;
  tone(11, base*pow(mult, counter));
  delay(50);
}
 
 
void loop() {
  update_avgs();
  switch(state){
    //Wait for something to happen
    case WAIT:
      //If we get signaled that we won
      if(avg[PHOTO_PIN] > LIGHT_THRESHOLD) state = VICT;
 
      if(hit_ct > loss_ct) state = FLAG;
       
      //If we get hit
      if(digitalRead(SWITCH_PIN)){
        hit_ct++;
        state = HIT1; //Retaliate
        delay_ct = 20 + random(20); //After random amount of time
      }
    break;
 
 
    //Initial Wait
    case HIT1:
      if(delay_ct > 0) delay_ct--;
      else state = HIT2;
    break;
 
    //Downswing
    case HIT2:
      hammer_servo.write(HAMM_ACTV);
      delay_ct = 5;
      state = HIT3;
    break;
 
    //Upswing
    case HIT3:
      if(delay_ct > 0){
        delay_ct--;
      }else{
        hammer_servo.write(HAMM_REST);
        delay_ct = 20;
        state = DBNC;
      }
    break;
 
    //Debouncing
    case DBNC:
      if(delay_ct > 0){
        delay_ct--;
      } else {
        state = WAIT;
      }
    break;
 
    //Raise flag
    case FLAG:
      flag_servo.write(FLAG_ACTV);
    break;
 
    //Victory Screech
    case VICT:
      do_tone();
    break;
  }
  delay(50);
  Serial.println(avg[0]);
}