This demo features two dogs: Rory and Gabe. Rory is a bright and enthusiastic pup whereas Gabe is a pup who has seen the other side of the fence, so to say. While these twin brothers have much different personalities, they also synergize and get along very well; they are fiercely loyal to each other to the point where they share the same responses to various interactions with humans. When Rory is petted, he wags his tail, which makes Gabe happy so both dogs wag. When Gabe is petted he gets angry, which makes Rory angry too and the dogs stop wagging and begin to bark. Petting Rory a lot will increase the level of happiness of the dogs, and petting Gabe too much will decrease the level of happiness in the dogs to the point of them becoming standoffish. (Rory isn’t perfect either, however, and if you pet him too much he will get mad like Gabe). The only way to make the dogs get less mad is to leave them alone for a little bit so Rory can cheer Gabe back up. Enjoy interacting with this quintessential tag team of twin puppers, Rory & Gabe!

 


#include <Servo.h>

//pin number variables
Servo arm, tail;
int tail_pos = 0;
const int tailPin = 10;
const int armPin = 9;
const int speakerPin = 6;
const int sensorPin = 5;
const int switchPin = 3;

//update variables
unsigned long lastUpdate = 0;
unsigned long wagLastUpdate = 0;
unsigned long sweepLastUpdate = 0;
unsigned long angryLastUpdate = 0;
unsigned long moodLastUpdate = 0;
unsigned long angryInterval = 100;
unsigned long wagUpdateInterval = 100;
unsigned long sweepUpdateInterval = 5;
unsigned long sweepIncrement = 5;
unsigned long updateInterval = 100;
unsigned long moodUpdateInterval = 20;

String interaction = "ignore";
bool sweepDone = true;
bool wagDone = true;
int times_angry = 1;
int time_last_pet = 0;
int mood = 10;
int hlim = 100; //happiness limit: after this, the dog will start sweeping its tail
int alim = -10;
int n = 0; // keeps track of num times tail was wagged, so it knows when to stop

int currentSwitch = LOW;
int currentSensor = LOW;
int previousSwitch = LOW;
int previousSensor = LOW;

int angry_freq = 2000;
int happy_freq = 440;

/* ------------------ UPDATE INTERACTION ----------------------*/
void update_interaction(long now) {
currentSwitch = digitalRead(switchPin);
currentSensor = digitalRead(sensorPin);

if (currentSwitch == HIGH && currentSwitch != previousSwitch) {
interaction = "pet";
n = 0;
previousSwitch = HIGH;
moodLastUpdate = now;
}
else if (currentSensor == HIGH && currentSensor != previousSensor) {
interaction = "person";
n = 0;
previousSensor = HIGH;
moodLastUpdate = now;
}
else if (currentSensor == LOW && currentSwitch == LOW) {
if (sweepDone && wagDone) {
interaction = "ignored";
}
previousSensor = LOW;
previousSwitch = LOW;
}
else {
interaction = "ignored";
}
//if !sweepDone and no other input, then continue sweeping
}

/* ------------------ TAIL WAGGING ----------------------*/

void sweep(long now) {
if ((now - sweepLastUpdate) > sweepUpdateInterval) {
sweepLastUpdate = now;
tail_pos += sweepIncrement;
tail.write(tail_pos);
if ((tail_pos >= 180) || (tail_pos <= 0)) {
sweepIncrement = -sweepIncrement; //switch directions
}
}
}

void wag(long now) {
if (n > 5) {
wagDone = true;
if (tail_pos < 170) tail_pos += 10;
tail.write(tail_pos);
}
else if ((now - wagLastUpdate) > wagUpdateInterval) { //not done wagging
wagLastUpdate = now;
if (tail_pos > tail.read()) {
if (tail_pos > 170) tail.write(180);
else tail.write(tail_pos + 10);

}
else {
if (tail_pos < 10) {
tail.write(0);
}
else tail.write(tail_pos - 10);
}
n++;
}
}

/* ------------------ REACTIONS ----------------------*/

void react_happy(long now) {
Serial.println("REACT HAPPY");
if (mood >= hlim || tail_pos >= 180) {
Serial.println("happiest");
sweepDone = false;
wagDone = true;

if (interaction.equals("pet") && now - time_last_pet < 200) { //if dog pet too frequently, get more annoyed
Serial.println("pet - happy decrease");
mood = 4;
tail_pos -= 20;
sweepDone = true;
time_last_pet = now;
}
} else if (interaction.equals("pet")) {
if (now - time_last_pet < 1000) { //if dog pet too frequently, get more annoyed
Serial.println("pet - happy decrease");
mood--;
tail_pos -= 50;
sweepDone = true;
if (mood < 0) alim--;
} else {
Serial.println("pet - should wag");
mood++;
wagDone = false;
sweepDone = true;
}
time_last_pet = now;
} else if (interaction.equals("person")) {
tone(speakerPin, happy_freq, 100); //bark and move tail up
wagDone = false;
Serial.println("person - move tail");
}
if (!sweepDone) sweep(now);
else if (!wagDone) wag(now);
}

void react_angry(long now) {
Serial.println("REACT ANGRY");
tail_pos = 0;
tail.write(tail_pos);

if (interaction.equals("pet")) {
mood -= times_angry; //the more times the dog's gotten angry, the harder it is to make him happy
tone(speakerPin, angry_freq, 10); //growls
time_last_pet = now;
} else if (interaction.equals("person")) {
mood--;
tone(speakerPin, angry_freq, 10); //warning growl
}
else {
Serial.println("getting less mad");
if (now - angryLastUpdate > angryInterval) {
angryLastUpdate = now;
mood++ ; //leave him alone and he will get less mad
}
}

if (mood < alim) mood = alim;

}

/* ------------------ SETUP ----------------------*/
void setup() {
pinMode(speakerPin, OUTPUT);
pinMode(switchPin, INPUT);
pinMode(sensorPin, INPUT);
tail.attach(tailPin);
arm.attach(armPin);
tail.write(0);
arm.write(0);
Serial.begin(9600);
Serial.println("hello");
}

/* ------------------ LOOP ----------------------*/
void loop() {
unsigned long now = millis();

if (now - lastUpdate > updateInterval) {
lastUpdate = now;
update_interaction(now);
}

if (mood < 0) react_angry(now);
else react_happy(now);
Serial.println(mood, DEC);

if (tail_pos > 180) tail_pos = 180;
if (tail_pos < 0) tail_pos = 0;
}