The Kraken is the first robot built by TechLabs as part of its instructor training boot camp. It is named after a fearsome mythical sea creature. The instructors have experimented a great deal with both its physical build, and its software (sketch) to reach its current, battle-ready state. The Kraken sketch started with the „Sumo-Base“ sketch as a template, designed by Eric Ryan, author of „An Introduction to Robot Programming“. We continue to try out new ideas for interesting Sumo Robot League behaviors on the Kraken. Below is its state-of-the-art sketch as of July, 2017 which features some interesting „battle cry“ behavior, battle-ring edge avoidance, and multiple attack modes- feel free to copy:
/********************************************************************
TechLabs – „The Kraken“ sketch – July 2017 – Instructor Robot
credit: Miles Prinzen @ TechLabs and Eric Ryan Harrison for portions of code in „Sumo-Base“ (https://github.com/SumoRobotLeague/MRK-1/blob/master/Chapter_8/CompetitiveSumoRobot.ino)
********************************************************************/
#include „Motor.h“
#include „Pitches.h“
/************************/
/** PIN CONFIGURATIONS **/
/************************/
// LED pin
#define led 7
// IR Sensor pins
#define leftSensor A1
#define rightSensor A2
#define rearSensor A3
#define IREmitter 6
// Hardware pins
#define button 2
#define buzzer 5
// Ultrasonic sensor pins
#define echoPin A0
#define pingPin 3
// Motor pins
#define rightMotorSpeed 10
#define rightMotorDirection 8
#define leftMotorSpeed 9
#define leftMotorDirection 4
/*************************************************/
/** Global Variables and Configuration Settings **/
/*************************************************/
// Competition configuration settings
#define abortsThreshold 980
#define searchTime 2000
#define attacksDistance 18
// competition configuration variables
int turnDirection = 1; // 1 = left, 2 = right
unsigned long turnTime = 0; // holds the return from millis()
unsigned long forwardTime = 0;
int dAttack = 0; // holds attack duration in ticks
// Create our motor object
Motor motor;
// State variables
int buttonState = 1; // 1 = up, 0 = pressed
int state = 1; // 1 = idle, 2 = competing
void setup() {
Serial.begin(9600);
// pin setup
pinMode(button, INPUT_PULLUP);
pinMode(buzzer, OUTPUT);
// IR sensors
pinMode(leftSensor, INPUT);
pinMode(rightSensor, INPUT);
pinMode(rearSensor, INPUT);
pinMode(IREmitter, OUTPUT);
// Turn on our IR Emitter
digitalWrite(IREmitter, HIGH);
// ultrasonic sensors
pinMode(pingPin, OUTPUT);
pinMode(echoPin, INPUT);
// Motor setup
motor.setupRight(rightMotorSpeed, rightMotorDirection);
motor.setupLeft(leftMotorSpeed, leftMotorDirection);
Serial.println(„The Kraken is powered up. Waiting for button press.“);
}
void loop() {
if ( buttonState == 1 && digitalRead(button) == 0 ) {
buttonState = 0;
}
if ( buttonState == 0 && digitalRead(button) == 1 ) {
buttonState = 1;
if ( state == 1 ) {
// we were in idle mode, so let’s begin our
// competition countdown
Serial.println(„Competition countdown starting…“);
Serial.println(„Good luck!“);
begin_countdown();
} else {
state = 1;
motor.left(0);
motor.right(0);
Serial.println(„Kraken entering idle mode.“);
}
}
// if the countdown has ended, we’re now in competition mode
if ( state == 2 ) {
compete();
}
}
/***************************************************/
/** Competition State Functions **/
/** These functions control the operational state **/
/** of our robot while it’s in state 2. **/
/***************************************************/
// This function is the primary competition control
// function and controls the operational flow and state
// of the robot in competition mode (state 2).
void compete() {
// declare local function variables to read our sensor values and determine what we
// need our robot to do.
int distance = msToCm( ping() );
int leftIR = analogRead(leftSensor);
int rightIR = analogRead(rightSensor);
int rearIR = analogRead(rearSensor);
int rotDirection = random(1, 3); // curve direction
if ( rearIR < abortsThreshold ) {
if (rotDirection == 1) { curveFLeft(); delay(800); } else { curveFRight(); delay(800); }
} else if ( (leftIR < abortsThreshold || rightIR < abortsThreshold) && distance > 5 ) {
aborts();
} else if ( distance < attacksDistance ) {
// We have detected an enemy. attacks!
if ( dAttack < random(50, 300) ) attacks(); else {
playNote(NOTE_G1, 100, 0);
if (rotDirection == 1) reverseL(); else reverseR();
}
} else {
// We don’t see an enemy, search until we find one.
search();
}
Serial.print(„Left/“); Serial.print(leftIR);
Serial.print(“ – Rear/“); Serial.print(rearIR);
Serial.print(“ – Right/“); Serial.println(rightIR);
}
void reverseR() {
motor.left(-255);
motor.right(-255);
delay(300);
curveBRight(); delay(800); attacks(); delay(500);
}
void reverseL() {
motor.left(-255);
motor.right(-255);
delay(300);
curveBLeft(); delay(800); attacks(); delay(500);
}
void curveFLeft() {
Serial.println(„Rot.FL“);
motor.left(random(-127, 127));
motor.right(random(128, 255));
}
void curveFRight() {
Serial.println(„Rot.FR“);
motor.left(random(128, 255));
motor.right(random(-127, 127));
}
void curveBLeft() {
Serial.println(„Rot.BL“);
dAttack -= random(10, 50);
motor.left(120);
motor.right(-255);
}
void curveBRight() {
Serial.println(„Rot.BR“);
dAttack -= random(10, 50);
motor.left(-255);
motor.right(120);
}
// This function is a simple search algorithm that
// attempts to locate the opponent before moving
// into attacks mode.
void search() {
Serial.println(„Searching…“);
if ( dAttack > 1 ) dAttack -= 3;
digitalWrite(led, LOW);
// our time has exceeded our configured searchTime, reset.
if ( turnTime != 0 && ((millis() – turnTime) > searchTime) ) {
turnTime = 0;
}
if ( forwardTime != 0 && ((millis() – forwardTime) > 5000) ) {
forwardTime = 0;
}
// get random direction and store the start time
if ( turnTime == 0 ) {
turnDirection = random(1, 3);
turnTime = millis();
}
if ( forwardTime == 0 ) {
forwardTime = millis();
}
if ( millis() – forwardTime < 3000) {
// start our turn, 1 = left, 2 = right
if ( turnDirection == 1 ) {
motor.left(255);
motor.right(-255);
} else {
motor.left(-255);
motor.right(255);
}
} else {
motor.left(200);
motor.right(200);
}
}
// The attacks() function is used to control the robot
// when an opponent has been detected closer than the
// defined attacksDistance. It will move ahead at full
// speed in an attempt to push the opponent outside of
// the ring.
void attacks() {
dAttack++;
Serial.println(„Attack!“);
digitalWrite(led, HIGH);
playNote(NOTE_B2, 100, 0);
motor.left(255);
motor.right(255);
}
// The aborts() function is an interrupting function that
// is called whenever the infrared sensors detect the
// ring border. This function will immediately halt
// other control function operations and move in reverse
// at full speed.
void aborts() {
Serial.println(„Run away!“);
motor.left(-255);
motor.right(-255);
delay(800);
}
// This function will begin our competition countdown sequence.
// When the button is depressed when in idle mode, this function
// will be called and begin a 5 second countdown with audible
// beeps at every second.
//
// PRACTICAL EXERCISE SOLUTION:
// This function also turns on the LED each time a note is
// played on the buzzer.
void begin_countdown() {
for ( int i = 0; i < 8; i++ ) {
delay(200); // wait 1 full second
// blinky angrily at our opponent
digitalWrite(led, HIGH);
playNote(NOTE_B2, 100, 0);
digitalWrite(led, LOW);
}
// wait one more full second before playing our next note
delay(1000);
digitalWrite(led, HIGH);
playNote(NOTE_D3, 80, 5);
digitalWrite(led, LOW);
playNote(NOTE_F3, 80, 5);
digitalWrite(led, HIGH);
playNote(NOTE_GS3, 80, 5);
digitalWrite(led, LOW);
playNote(NOTE_D4, 800, 5);
digitalWrite(led, LOW);
playNote(NOTE_F4, 800, 5);
digitalWrite(led, HIGH);
playNote(NOTE_GS4, 800, 5);
digitalWrite(led, LOW);
playNote(NOTE_D5, 80, 5);
digitalWrite(led, LOW);
playNote(NOTE_F5, 80, 5);
digitalWrite(led, HIGH);
playNote(NOTE_GS5, 80, 5);
playNote(NOTE_D6, 800, 5);
playNote(NOTE_F6, 800, 5);
playNote(NOTE_GS6, 800, 5);
// Our countdown is nearly complete. Wait 1
// more second and then set state to 2 so that
// we can begin our competition!
delay(2000);
digitalWrite(led, LOW);
state = 2;
}
/**********************/
/** Helper Functions **/
/**********************/
// Note-playing buzzer helper function.
void playNote(int note, int duration, int rest) {
tone(buzzer, note, duration);
delay(rest);
}
// Helper function to manage our ultrasonic sensor.
long ping() {
long duration;
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(10);
digitalWrite(pingPin, LOW);
duration = pulseIn(echoPin, HIGH);
return duration;
}
// Helper function to return the distance to an object
// detected by the ultrasonic sensor in centimeters.
long msToCm(long microseconds) {
return microseconds / 29 / 2;
}
// Simple blinky function called in loop() whenever a state
// change is made by a user button press.
void blinky(int blinkys) {
for ( int i = 0; i <= blinkys; i++ ) {
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
}
}