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:

#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]);
}