I have included 4 files that you can download:

Brobot.apk:

This is the app I made using MIT App Inventor, a free online android app IDE. Put this file on your Android device, and it will show up as an application. Above you will see how I wrote this app in App Inventor. You can design the menu layout with buttons and control options, then you go to a block view where you can actually program the app using preset blocks. This makes the programming very easy.





Brobot.zip:





This zipped folder contains Brobot.h and Brobot.cpp.

Brobot.h contains the Brobot class function instantiations, variable declarations, and the bit maps for all of the emotions displayed on the LED eyes. These bit maps allow me to change how each emotion looks quickly by changing each bit individually.

Brobot.cpp contains all of the function definitions for the Brobot class. The most important functions here include:

updateFace: This function controls what emotion Brobot is currently displaying and what emotion he will be displaying next. It also handles the random blinks and what the LCD is showing.

playComplete: This function handles the different sounds Brobot will make depending on his emotions.

checkProx: This is the function that determines whether Brobot should immediately stop what he is doing and act surprised. It generates an interrrupt.

brobot_sketch.zip:

This folder is self explanatory. It contains the main sketch that I wrote for Brobot. It basically instantiates all of Brobot's timers and variables, and updates the face every loop. It also handles all of the servo control because for some reason I couldn't get the servos to work in their own function in Brobot.cpp. The servos all have current and next angle variables which enable the servos to move one or less times ever loop until the current angle is equal to the net angle.

BBSounds.zip:

This folder contains all of the wav files for each sound Brobot can make. To load these onto the wave shield, just pop out the SD card, put it in your computer, and drag and drop which sounds you want to use for Brobot onto the SD card. Then just pop it back into the wave shield, change the file names in the playComplete function to the file names you loaded onto the card, and listen to Brobot make funny noises! All of the free open source sounds were downloaded from this website: http://wiki.laptop.org/go/Sound_samples

/************************************************************* // Brobot: Header File

// This file contains the Brobot class function and variable

// declarations as well as the led bitmaps for each emotion // Programmer: Chris Frazier // Date: 4/8/2015 **************************************************************/

#ifndef BROBOT_H #define BROBOT_H

#include "Arduino.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\Wire\Wire.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\SoftwareServo\SoftwareServo.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\Adafruit_LEDBackpack\Adafruit_LEDBackpack.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\Adafruit_GFX\Adafruit_GFX.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\WaveHC\FatReader.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\WaveHC\SdReader.h" #include #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\WaveHC\WaveUtil.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\WaveHC\WaveHC.h" #include "C:\Users\ChristopherEvan\Documents\Arduino\libraries\LiquidCrystal_I2C\LiquidCrystal_I2C.h"

// Each emotion is represented by an integer from 0 - 6 #define NEUTRAL 0xF0 #define HAPPY 0xF1 #define SAD 0xF2 #define ANGRY 0xF3 #define SURPRISED 0xF4 #define LOVE 0xF5 #define BLINK 0xF6 #define NECK_SPEED 1 #define MAX_TILT_ANGLE 135 #define MIN_TILT_ANGLE 65 #define MAX_PAN_ANGLE 120 #define MIN_PAN_ANGLE 40

class Brobot{ public: Brobot(byte, byte, byte, byte, byte, byte); //Constructor void setup(); void setEmotion(byte); // Allows main file to access current emotion void updateFace(); bool checkProx(); void playComplete(); void playFile(char*); byte freeRam(); void sdErrorCheck(); void checkBT(); SoftwareServo pan; SoftwareServo tilt; SoftwareServo leftBrow; SoftwareServo rightBrow; byte currentEmotion; byte nextEmotion; byte incomingByte; byte currentPanAngle; byte currentTiltAngle; byte nextPanAngle; byte nextTiltAngle; byte currentLBAngle; byte currentRBAngle; byte nextLBAngle; byte nextRBAngle; byte neckSpeed; byte neckTimer; bool headMoveToggle; bool upToggle; bool downToggle; bool leftToggle; bool rightToggle; bool soundToggle; bool togglePause; SdReader card; // This object holds the information for the card FatVolume vol; // This holds the information for the partition on the card FatReader root; // This holds the information for the filesystem on the card FatReader f; // This holds the information for the file we're play WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time private: void displayString(const char *); byte previousEmotion; byte blinkTimer; byte surpriseTimer; byte triggerPin; byte echoPin; bool _setup; byte randSound; byte k; char myChar; };

#endif

static const uint8_t PROGMEM happyL_bmp[] = { B00000000, B00011100, B00100100, B01011100, B01011100, B00100100, B00011100, B00000000 }, happyR_bmp[] = { B00000000, B00011100, B00100100, B01011100, B01011100, B00100100, B00011100, B00000000 }, neutralL_bmp[] = { B00000000, B00111100, B01000010, B01011010, B01011010, B01000010, B00111100, B00000000 }, neutralR_bmp[] = { B00000000, B00111100, B01000010, B01011010, B01011010, B01000010, B00111100, B00000000 }, angryL_bmp[] = { B00000000, B00001100, B00010010, B00111010, B01011010, B11000010, B00111100, B00000000 }, angryR_bmp[] = { B00000000, B00111100, B11000010, B01011010, B00111010, B00010010, B00001100, B00000000 }, surprisedL_bmp[] = { B01111110, B10000001, B10000001, B10011001, B10011001, B10000001, B10000001, B01111110 }, surprisedR_bmp[] = { B01111110, B10000001, B10000001, B10011001, B10011001, B10000001, B10000001, B01111110 }, sadL_bmp[] = { B00000000, B00111100, B01000010, B01011010, B00111010, B00010010, B00001100, B00000000 }, sadR_bmp[] = { B00000000, B00001100, B00010010, B00111010, B01011010, B01000010, B00111100, B00000000 }, loveL_bmp[] = { B01111000, B10000100, B10000010, B01011001, B01011001, B10000010, B10000100, B01111000 }, loveR_bmp[] = { B01111000, B10000100, B10000010, B01011001, B01011001, B10000010, B10000100, B01111000 }, blink_bmp[] = { B00000000, B00000100, B00000010, B00000010, B00000010, B00000010, B00000100, B00000000 }; <p>/*************************************************************<br>// Brobot: Source File // This file contains the Brobot class function // definitions // Programmer: Chris Frazier // Date: 4/8/2015 **************************************************************/</p><p>#include "Brobot.h"</p><p>// Create led matrix instance using Adafruit's library Adafruit_8x16matrix ledmatrix = Adafruit_8x16matrix(); LiquidCrystal_I2C myDisplay = LiquidCrystal_I2C(0x27, 16, 2); // save some messages const char emotion[] PROGMEM = {"Emotion: "}; const char blank[] PROGMEM = {" "}; const char hello[] PROGMEM = {"Hello, "}; const char imBrobot[] PROGMEM = {"I'm Brobot! "}; const char neutral[] PROGMEM = {"NEUTRAL "}; const char happy[] PROGMEM = {"HAPPY "}; const char sad[] PROGMEM = {"SAD "}; const char angry[] PROGMEM = {"ANGRY "}; const char surprised[] PROGMEM = {"SURPRISED "}; const char love[] PROGMEM = {"LOVE "}; // Constructor: lets user set the pins Brobot::Brobot(byte pp, byte tp, byte lbp, byte rbp, byte ep, byte trgp){ triggerPin = trgp; echoPin = ep; neckTimer = 0; neckSpeed = NECK_SPEED; previousEmotion = NEUTRAL; currentEmotion = HAPPY; nextEmotion = HAPPY; pinMode(echoPin, INPUT); //set pinmodes for prox sensor pinMode(triggerPin, OUTPUT); soundToggle = false; togglePause = false; }</p><p>void Brobot::displayString(const char *message){ for (k = 0; k < 15; k++) { myChar = pgm_read_byte_near(message + k); myDisplay.print(myChar); } }</p><p>// Used during setup; initializes Brobot's face void Brobot::setup() { ledmatrix.begin(0x70); myDisplay.init(); //initialize the lcd myDisplay.backlight();//this turns the backlight on displayString(hello); //this sets the cursor of the display to the second row and 9th character position in that row myDisplay.setCursor(1,8); //then we print at the cursor position displayString(imBrobot); playComplete(); delay(2000); myDisplay.setCursor(0,0); displayString(emotion); myDisplay.setCursor(1,8); displayString(neutral); _setup = true; updateFace(); _setup = false; }</p><p>// Allows main file access to next emotion void Brobot::setEmotion(byte i) { nextEmotion = i; }</p><p>// Decides which emotion to display on Brobot's face void Brobot::updateFace() { // Generates random blinks if(currentEmotion != BLINK) { if(random(1000) == 0) { nextEmotion = BLINK; blinkTimer = 50; } } // decrements blink timer to make sure Brobot doesn't fall asleep! else if (currentEmotion == BLINK) { if(blinkTimer > 0) { blinkTimer--; } else { // Return to previous emotion after blink nextEmotion = previousEmotion; } } // check the prox sensor and surprise Brobot if(!_setup && !togglePause){ if (checkProx()) { nextEmotion = SURPRISED; surpriseTimer = 100; } // make sure Brobot doesn't go into shock! else if(!checkProx()){ if(surpriseTimer > 0) { surpriseTimer--; } else if(currentEmotion != BLINK){ if (nextEmotion == currentEmotion) { // Return to previous emotion after surprise nextEmotion = previousEmotion; } } } } // Change emotions if next emotion is different // This prevents from updating every loop and wasting power if (nextEmotion != currentEmotion) { if (nextEmotion == NEUTRAL) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, neutralR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, neutralL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = NEUTRAL; previousEmotion = NEUTRAL; myDisplay.setCursor(1,8); displayString(neutral); soundToggle = true; } else if (nextEmotion == HAPPY) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, happyR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, happyL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = HAPPY; previousEmotion = HAPPY; myDisplay.setCursor(1,8); displayString(happy); soundToggle = true; } else if (nextEmotion == SAD) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, sadR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, sadL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = SAD; previousEmotion = SAD; myDisplay.setCursor(1,8); displayString(sad); soundToggle = true; } else if (nextEmotion == ANGRY) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, angryR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, angryL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = ANGRY; previousEmotion = ANGRY; myDisplay.setCursor(1,8); displayString(angry); soundToggle = true; } else if (nextEmotion == SURPRISED) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, surprisedR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, surprisedL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = SURPRISED; myDisplay.setCursor(1,8); displayString(surprised); soundToggle = true; } else if (nextEmotion == LOVE) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, loveR_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, loveL_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = LOVE; previousEmotion = LOVE; myDisplay.setCursor(1,8); displayString(love); soundToggle = true; } else if (nextEmotion == BLINK) { ledmatrix.clear(); ledmatrix.drawBitmap(0, 0, blink_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); ledmatrix.drawBitmap(0, 8, blink_bmp, 8, 8, LED_ON); ledmatrix.writeDisplay(); currentEmotion = BLINK; } }SoftwareServo::refresh(); }</p><p>// Check and see if someone is too close to Brobot bool Brobot::checkProx(){ digitalWrite(triggerPin, HIGH); // make a 10usec pulse delayMicroseconds(10);</p><p> digitalWrite(triggerPin, LOW);</p><p> float distance = pulseIn(echoPin, HIGH); //now read the pulse that is sent back by the sensor //pulseIn returns the pulse length in usec</p><p> distance = distance / 58; if (distance < 6){ return true; } else{ return false; } }</p><p>void Brobot::checkBT(){ while (Serial.available()) { delay(3); incomingByte = Serial.read(); } if ((incomingByte < 0xFE) && (incomingByte >= 0xE0)) { // Set emotion corresponding to byte received if (incomingByte > -1) { Serial.println(incomingByte); setEmotion(incomingByte); if(incomingByte == 0xE0) { headMoveToggle = !headMoveToggle; } if(incomingByte == 0xE1){ upToggle = !upToggle; } else if(incomingByte == 0xE3){ leftToggle = !leftToggle; } else if(incomingByte == 0xE2){ rightToggle = !rightToggle; } else if(incomingByte == 0xE4){ downToggle = !downToggle; } } incomingByte = -1; } }</p><p>// Plays a full file from beginning to end with no pause. void Brobot::playComplete() { // call our helper to find and play this name //SoftwareServo::refresh(); //delay(30);</p><p> if(currentEmotion == NEUTRAL){ randSound = random(1,15); if(randSound == 1) { playFile("NEUT1.WAV"); } else if(randSound == 2){ playFile("NEUT2.WAV"); } } else if(currentEmotion == HAPPY){ randSound = random(1,3); if(randSound == 1) { playFile("HAPPY1.WAV"); } else if(randSound == 2){ playFile("HAPPY2.WAV"); } else if(randSound == 3){ playFile("HAPPY3.WAV"); } } else if(currentEmotion == SAD){ randSound = random(1,3); if(randSound == 1) { playFile("SAD1.WAV"); } else if(randSound == 2){ playFile("SAD2.WAV"); } else if(randSound == 3){ playFile("SAD3.WAV"); } else if(randSound == 4){ playFile("SAD4.WAV"); } } else if(currentEmotion == ANGRY){ randSound = random(1,3); if(randSound == 1) { playFile("ANGRY1.WAV"); } else if(randSound == 2){ playFile("ANGRY2.WAV"); } else if(randSound == 3){ playFile("ANGRY3.WAV"); } } else if(currentEmotion == SURPRISED){ randSound = random(1,6); if(randSound == 1) { playFile("SURP1.WAV"); } else if(randSound == 2){ playFile("SURP2.WAV"); } else if(randSound == 3){ playFile("SURP3.WAV"); } else if(randSound == 4){ playFile("SURP4.WAV"); } else if(randSound == 5){ playFile("SURP6.WAV"); } else if(randSound == 6){ playFile("SURP6.WAV"); } } else if(currentEmotion == LOVE){ randSound = random(1,3); if(randSound == 1) { playFile("LOVE1.WAV"); } else if(randSound == 2){ playFile("LOVE2.WAV"); } else if(randSound == 3){ playFile("LOVE3.WAV"); } }soundToggle = false;</p><p> while(wave.isplaying) { // pause } // now its done playing } void Brobot::playFile(char *name) { // see if the wave object is currently doing something if (wave.isplaying) {// already playing something, so stop it! wave.stop(); // stop it } // look in the root directory and open the file if (!f.open(root, name)) { putstring("Couldn't open file "); Serial.print(name); return; } // OK read the file and turn it into a wave object if (!wave.create(f)) { putstring_nl("Not a valid WAV"); return; } // ok time to play! start playback wave.play(); } // this handy function will return the number of bytes currently free in RAM, great for debugging! byte Brobot::freeRam(void) { extern int __bss_end; extern int *__brkval; int free_memory; if((int)__brkval == 0) { free_memory = ((int)&free_memory) - ((int)&__bss_end); } else { free_memory = ((int)&free_memory) - ((int)__brkval); } return free_memory; } </p><p>void Brobot::sdErrorCheck(void) { if (!card.errorCode()) return; putstring("

\rSD I/O error: "); Serial.print(card.errorCode(), HEX); putstring(", "); Serial.println(card.errorData(), HEX); while(1); }</p><p>/*************************************************************<br>// Brobot: Main File // This file contains the setup and execution loop for the Arduino // while Brobot is in operation. // Programmer: Chris Frazier // Date: 4/8/2015 **************************************************************/</p><p>#include "Wire.h" #include "SoftwareServo.h" #include "Adafruit_LEDBackpack.h" #include "Adafruit_GFX.h" #include #include #include "WaveHC.h"</p><p>#define panPin 14 // This is the pan servo pin #define tiltPin 15 // This is the tilt servo pin #define leftBrowPin 16 // This is the left eyebrow servo pin #define rightBrowPin 17 // This is the right eyebrow servo pin #define echoPin 8 // This is the echo pin #define triggerPin 7 // This is the trigger pin</p><p>// Create an instance of Brobot Brobot myBrobot(panPin, tiltPin, leftBrowPin, rightBrowPin, echoPin, triggerPin);</p><p>void setup() { Serial.begin(9600); // Set baud rate for serial protocol putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad Serial.println(myBrobot.freeRam()); // if this is under 150 bytes it may spell trouble! // Set the output pins for the DAC control. This pins are defined in the library pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); // if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you if (!myBrobot.card.init()) { //play with 8 MHz spi (default faster!) putstring_nl("Card init. failed!"); // Something went wrong, lets print out why myBrobot.sdErrorCheck(); while(1); // then 'halt' - do nothing! } // enable optimize read - some cards may timeout. Disable if you're having problems myBrobot.card.partialBlockRead(true); // Now we will look for a FAT partition! uint8_t part; for (part = 0; part < 5; part++) { // we have up to 5 slots to look in if (myBrobot.vol.init(myBrobot.card, part)) break; // we found one, lets bail } if (part == 5) { // if we ended up not finding one :( putstring_nl("No valid FAT partition!"); myBrobot.sdErrorCheck(); // Something went wrong, lets print out why while(1); // then 'halt' - do nothing! } // Lets tell the user about what we found putstring("Using partition "); Serial.print(part, DEC); putstring(", type is FAT"); Serial.println(myBrobot.vol.fatType(),DEC); // FAT16 or FAT32? // Try to open the root directory if (!myBrobot.root.openRoot(myBrobot.vol)) { putstring_nl("Can't open root dir!"); // Something went wrong, while(1); // then 'halt' - do nothing! } // Initialize all of Brobot's public variables myBrobot.incomingByte = -1; myBrobot.currentPanAngle = 90; myBrobot.currentTiltAngle = 90; myBrobot.nextPanAngle = 90; myBrobot.nextTiltAngle = 90; myBrobot.currentLBAngle = 90; myBrobot.currentRBAngle = 90; myBrobot.neckTimer = 400; myBrobot.neckSpeed = NECK_SPEED; myBrobot.headMoveToggle = 0; myBrobot.leftToggle = 0; myBrobot.rightToggle = 0; myBrobot.upToggle = 0; myBrobot.downToggle = 0; // Run Brobot setup function (initializes LED eyes) myBrobot.setup(); // Attach and initialize all 4 servos myBrobot.pan.attach(panPin); myBrobot.tilt.attach(tiltPin); myBrobot.leftBrow.attach(leftBrowPin); myBrobot.rightBrow.attach(rightBrowPin); myBrobot.pan.write(myBrobot.currentPanAngle); delay(20); myBrobot.tilt.write(myBrobot.currentTiltAngle); myBrobot.leftBrow.write(myBrobot.currentLBAngle); myBrobot.rightBrow.write(myBrobot.currentRBAngle); //SoftwareServo::refresh(); delay(20); myBrobot.updateFace(); delay(2000); SoftwareServo::refresh(); } void loop() { // Every loop check for Bluetooth data myBrobot.checkBT(); // The following code sets Brobot's eyebrow positions // - - if(myBrobot.nextEmotion == NEUTRAL) { //myBrobot.togglePause = true; myBrobot.nextLBAngle = 90; myBrobot.nextRBAngle = 90; while((myBrobot.currentLBAngle != myBrobot.nextLBAngle) || (myBrobot.currentRBAngle != myBrobot.nextRBAngle)){ if(myBrobot.currentLBAngle < myBrobot.nextLBAngle){ myBrobot.currentLBAngle++; } else if(myBrobot.currentLBAngle > myBrobot.nextLBAngle){ myBrobot.currentLBAngle--; } if(myBrobot.currentRBAngle < myBrobot.nextRBAngle){ myBrobot.currentRBAngle++; } else if(myBrobot.currentRBAngle > myBrobot.nextRBAngle){ myBrobot.currentRBAngle--; } myBrobot.leftBrow.write(myBrobot.currentLBAngle); myBrobot.rightBrow.write(myBrobot.currentRBAngle); SoftwareServo::refresh(); } //if((myBrobot.currentLBAngle == myBrobot.nextLBAngle) && (myBrobot.currentRBAngle == myBrobot.nextRBAngle)){ // myBrobot.togglePause = false; //} } // / \ else if(myBrobot.nextEmotion == SURPRISED || myBrobot.nextEmotion == HAPPY || myBrobot.nextEmotion == SAD || myBrobot.nextEmotion == LOVE) { //myBrobot.togglePause = true; myBrobot.nextLBAngle = 120; myBrobot.nextRBAngle = 60; while((myBrobot.currentLBAngle != myBrobot.nextLBAngle) || (myBrobot.currentRBAngle != myBrobot.nextRBAngle)){ if(myBrobot.currentLBAngle < myBrobot.nextLBAngle){ myBrobot.currentLBAngle++; } else if(myBrobot.currentLBAngle > myBrobot.nextLBAngle){ myBrobot.currentLBAngle--; } if(myBrobot.currentRBAngle < myBrobot.nextRBAngle){ myBrobot.currentLBAngle++; } else if(myBrobot.currentRBAngle > myBrobot.nextRBAngle){ myBrobot.currentRBAngle--; } myBrobot.leftBrow.write(myBrobot.currentLBAngle); myBrobot.rightBrow.write(myBrobot.currentRBAngle); SoftwareServo::refresh(); } //if((myBrobot.currentLBAngle == myBrobot.nextLBAngle) && (myBrobot.currentRBAngle == myBrobot.nextRBAngle)){ // myBrobot.togglePause = false; //} } // \ / else if(myBrobot.nextEmotion == ANGRY) { //myBrobot.togglePause = true; myBrobot.nextLBAngle = 60; myBrobot.nextRBAngle = 120; while((myBrobot.currentLBAngle != myBrobot.nextLBAngle) || (myBrobot.currentRBAngle != myBrobot.nextRBAngle)){ if(myBrobot.currentLBAngle < myBrobot.nextLBAngle){ myBrobot.currentLBAngle++; } else if(myBrobot.currentLBAngle > myBrobot.nextLBAngle){ myBrobot.currentLBAngle--; } if(myBrobot.currentRBAngle < myBrobot.nextRBAngle){ myBrobot.currentRBAngle++; } else if(myBrobot.currentRBAngle > myBrobot.nextRBAngle){ myBrobot.currentRBAngle--; } myBrobot.leftBrow.write(myBrobot.currentLBAngle); myBrobot.rightBrow.write(myBrobot.currentRBAngle); SoftwareServo::refresh(); } //if((myBrobot.currentLBAngle == myBrobot.nextLBAngle) && (myBrobot.currentRBAngle == myBrobot.nextRBAngle)){ // myBrobot.togglePause = false; //} } SoftwareServo::refresh(); // Update Brobot's face each loop myBrobot.updateFace(); /* The following code controls the pan/tilt neck servos // Brobot will randomly look in a defined set of angles for both pan and tilt. // Each loop, if the current servo position variable is not at the same position // as the next position variable, the servos will increment/decrement the current // angle by 1 as needed. The neckSpeed variable causes the pan/tilt servos to only // change every *neckspeed* loop cycle. The neckTimer variable causes Brobot to pause // before looking in another direction. */ if(myBrobot.headMoveToggle == 0){ if (myBrobot.currentPanAngle == myBrobot.nextPanAngle){ if(myBrobot.neckTimer == 0){ myBrobot.nextPanAngle = random(MIN_PAN_ANGLE, MAX_PAN_ANGLE); myBrobot.nextTiltAngle = random(MIN_TILT_ANGLE, MAX_TILT_ANGLE); } else { myBrobot.neckTimer--; } } else { myBrobot.neckSpeed--; myBrobot.neckTimer = random(60, 80); if(myBrobot.neckSpeed == 0){ if(millis() % 2 == 0) { if(myBrobot.currentPanAngle < myBrobot.nextPanAngle){ myBrobot.currentPanAngle++; } else if(myBrobot.currentPanAngle > myBrobot.nextPanAngle){ myBrobot.currentPanAngle--; } myBrobot.pan.write(myBrobot.currentPanAngle); SoftwareServo::refresh(); //delay(10); } else { if(myBrobot.currentTiltAngle < myBrobot.nextTiltAngle){ myBrobot.currentTiltAngle++; } else if(myBrobot.currentTiltAngle > myBrobot.nextTiltAngle){ myBrobot.currentTiltAngle--; } myBrobot.tilt.write(myBrobot.currentTiltAngle); SoftwareServo::refresh(); } myBrobot.neckSpeed = NECK_SPEED; } } } else { myBrobot.neckSpeed--; if(myBrobot.neckSpeed == 0){ if(myBrobot.currentTiltAngle <= MAX_TILT_ANGLE) { if(myBrobot.upToggle){ myBrobot.currentTiltAngle++; } } if(myBrobot.currentTiltAngle >= MIN_TILT_ANGLE) { if(myBrobot.downToggle){ myBrobot.currentTiltAngle--; } } if(myBrobot.currentPanAngle <= MAX_PAN_ANGLE) { if(myBrobot.rightToggle){ myBrobot.currentPanAngle++; } } if(myBrobot.currentPanAngle >= MIN_PAN_ANGLE) { if(myBrobot.leftToggle){ myBrobot.currentPanAngle--; } } myBrobot.pan.write(myBrobot.currentPanAngle); myBrobot.tilt.write(myBrobot.currentTiltAngle); SoftwareServo::refresh(); delay(10); myBrobot.neckSpeed = NECK_SPEED; } } if(myBrobot.soundToggle && !myBrobot.togglePause){ SoftwareServo::refresh(); //delay(200); myBrobot.playComplete(); } }</p>