/* Xander Polk and Gavin Espejo * 6/5/2024 * Code for the 'Emotion Challenge' for the Spring 2024 ENGR 103 Final Project * Contains 4 main functions, Happy, Sad, Angry, and Scared -- descriptions can be found before the respective function definitions. * Work attribution: Angry/Happy - Gavin , Scared/Sad - Xander * Some code taken from Professor Heer's examples, will be labelled when it shows up * Expected Serial output: Distance sensor readings, descriptions of robot's current action. */ #include // motor and LED setup taken from example #include VL53L0X sensor; #include #define NUM_LEDS 2 CRGB leds[NUM_LEDS]; #define M2A 17 #define M2B 16 #define M1A 19 #define M1B 18 #define WSLED 4 uint32_t lastTime = 0; // used for shorter millis() usages uint32_t longTime = 0; // used to control transitions into different emotions void reverse(uint8_t mySpeed){ //basic motor control functions taken from example ledcWrite(2, mySpeed); //Set M2B to mySpeed ledcWrite(3, 0); //Set M2A to LOW ledcWrite(0, mySpeed);//Set M1B to mySpeed ledcWrite(1, 0); //Set M1A to LOW } void forward(uint8_t mySpeed){ ledcWrite(3, mySpeed); //Set M2A to mySpeed ledcWrite(2, 0); //Set M2B to LOW ledcWrite(1, mySpeed);//Set M1A to mySpeed ledcWrite(0, 0); //Set M1B to LOW } void cw(uint8_t mySpeed){ ledcWrite(3, mySpeed); //Set M2B to mySpeed ledcWrite(2, 0); //Set M2A to LOW ledcWrite(1, 0); //Set M1B to LOW ledcWrite(0, mySpeed); //Set M1A to mySpeed } void ccw(uint8_t mySpeed){ ledcWrite(2, mySpeed); //Set M2A to mySpeed ledcWrite(3, 0); //Set M2B to LOW ledcWrite(0, 0); //Set M1A to LOW ledcWrite(1, mySpeed); //Set M1BA to mySpeed } void stopMotors() { ledcWrite(2, 0); //Set M2A to mySpeed ledcWrite(3, 0); //Set M2B to LOW ledcWrite(0, 0); //Set M1A to LOW ledcWrite(1, 0); //Set M1BA to mySpeed } void errorLed(int count = 1){ // errorLED function taken from example for (int i = 0; i< count; i++){ leds[0] = CRGB::Red; FastLED.show(); delay(100); leds[0] = CRGB::Black; FastLED.show(); delay(100); } delay(1000); } //ChangeColor function takes 3 int values 0-255 and turns the LEDs to match the RGB value void changeColor(uint8_t r, uint8_t g, uint8_t b) { leds[0].setRGB(r, g, b); leds[1].setRGB(r, g, b); FastLED.show(); } // checkCharge function, used for angry() -- charges if it detects something less than 400 mm away, otherwise continues forward int checkCharge(int distance){ if(distance < 400){ changeColor(255, 0, 0); cw(190); delay(100); ccw(190); delay(100); cw(190); delay(100); forward(255); delay(1000); reverse(250); delay(200); cw(250); delay(250); }else{ forward(200); changeColor(100, 0, 0); } return 1; } //checkRun function, used for scared() -- runs away if something is next to it and freezes (returns 1) if something is nearby. int checkRun(int distance) { if (distance < 50) { Serial.println("RUNNING AWAY!"); leds[0].setRGB(255, 0, 255); leds[1].setRGB(255, 0, 255); FastLED.show(); reverse(255); //back up delay(200); ccw(255); //turn around delay(300); forward(255); //run away delay(500); return 0; } else if (distance < 200) { Serial.println("cautious..."); return 1; } return 0; } //Happy() Function: Written by Gavin, causes robot to do a little dance repeatedly void happy() { changeColor(0, 255, 0); cw(200); delay(300); ccw(200); delay(300); reverse(190); delay(400); cw(255); delay(300); ccw(255); delay(300); forward(190); delay(400); cw(190); delay(300); ccw(190); delay(300); forward(200); delay(500); stopMotors(); } //angry() Function: Written by Gavin, robot will drive forward and 'charge' at anything it detects in front of it void angry() { int distance = sensor.readRangeSingleMillimeters(); checkCharge(distance); } //Sad() function: Written by Xander, robot will drive slowly around, turning when it runs into an obstacle, and occasionally turning around randomly //meant to be akin to a sad person meandering around aimlessly void sad() { changeColor(0, 0, 64); int distance = sensor.readRangeSingleMillimeters(); Serial.println(distance); if (distance < 50) { cw(190); delay(500); } else { forward(190); } if (millis() > lastTime + (5000 + 10 * (rand() % 10))) { ccw(190); delay(500); lastTime = millis(); } } //Scared function: Written by Xander, robot will turn in place, scanning its surroundings, randomly turning faster; Robot will stop if it sees something near it and run away fast if something is too close. void scared() { int distance = sensor.readRangeSingleMillimeters(); Serial.println(distance); if (checkRun(distance)== 1) { // stops motors if something is nearby stopMotors(); changeColor(200, 0, 200); } else { // code to run after running away or if nothing detected if (millis() < lastTime + 1500) { //Serial.println("test1"); changeColor(100, 0, 100); cw(200); } else if ((millis() > lastTime + 1000) && (millis() < lastTime + 1700)){ //Serial.println("test2"); changeColor(150, 0, 150); ccw(255); } } if (millis() > lastTime + 1700) { // reset time after 1.7 seconds lastTime = millis(); } delay(10); } void setup() { // some setup code taken from examples Serial.begin(115200); FastLED.addLeds(leds, NUM_LEDS); // GRB ordering is assumed // This section creates the I2C (Wire) connection and quieries for a VL53LX Wire.begin(); sensor.setTimeout(500); if (!sensor.init()) { Serial.println("Failed to detect and initialize sensor!"); while (1) {errorLed();} } // Set the 4 motor controll lines as outputs pinMode(M1A, OUTPUT); pinMode(M1B, OUTPUT); pinMode(M2A, OUTPUT); pinMode(M2B, OUTPUT); //These lines connect 4 PWM channels to the 4 motor control Pins ledcSetup(0, 30000, 8); ledcAttachPin(M1A, 0); ledcSetup(1, 30000, 8); ledcAttachPin(M1B, 1); ledcSetup(2, 30000, 8); ledcAttachPin(M2A, 2); ledcSetup(3, 30000, 8); ledcAttachPin(M2B, 3); delay(5000); // 5 second delay after resetting -- mainly for making interfacing w/ laptops easier lastTime = millis(); longTime = millis(); } void loop() { if (millis() < longTime + 15000) { happy(); } else if (millis() < longTime + 30000) { angry(); } else if (millis() < longTime + 45000) { sad(); } else if (millis() < longTime + 60000) { scared(); } else if (millis() > longTime + 60000){ longTime = millis(); } }