#include #include #include #define FASTLED_INTERNAL #include #include // Include the ESP32 LEDC library VL53L0X sensor; #define NUM_LEDS 2 CRGB leds[NUM_LEDS]; #define M2A 17 #define M2B 16 #define M1A 19 #define M1B 18 #define WSLED 4 #define RED_PIN 21 #define YELLOW_PIN 22 #define BLUE_PIN 23 unsigned long emotionTime = 0; // declare time keeper int mode = 0; // declares what emotion mode is happening int randDirection = 0; int randSpeed = 0; int i = 0; // index variable int distance[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // declare distance variable stack int avgDistance[2] = { 0, 0 }; //declare averages variable void errorLed(int count = 1) { 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); } void reverse(uint8_t mySpeed) { ledcWrite(2, mySpeed); // Set M2A to mySpeed ledcWrite(3, 0); // Set M2B to LOW ledcWrite(0, mySpeed); // Set M1A to mySpeed ledcWrite(1, 0); // Set M1B to LOW } void forward(uint8_t mySpeed) { ledcWrite(3, mySpeed); // Set M2B to mySpeed ledcWrite(2, 0); // Set M2A to LOW ledcWrite(1, mySpeed); // Set M1B to mySpeed ledcWrite(0, 0); // Set M1A 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 M1B to mySpeed } void setColor(int redValue, int yellowValue, int blueValue) { analogWrite(RED_PIN, redValue); analogWrite(YELLOW_PIN, yellowValue); analogWrite(BLUE_PIN, blueValue); } void setup() { Serial.begin(115200); Serial.println("Initializing..."); randomSeed(analogRead(0)); // Seed the random number generator pinMode(14, INPUT_PULLUP); // declare pins for happy button in the turtle shell pinMode(27, INPUT_PULLUP); FastLED.addLeds(leds, NUM_LEDS); // GRB ordering is assumed // This section creates the I2C (Wire) connection and queries for a VL53L0X Wire.begin(); sensor.setTimeout(500); if (!sensor.init()) { Serial.println("Failed to detect and initialize sensor"); while (1) { errorLed(); } } // Set the 4 motor control lines outputs pinMode(M1A, OUTPUT); pinMode(M1B, OUTPUT); pinMode(M2A, OUTPUT); pinMode(M2B, OUTPUT); // different color LED pins as outputs pinMode(RED_PIN, OUTPUT); pinMode(YELLOW_PIN, OUTPUT); pinMode(BLUE_PIN, 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); } void loop() { Serial.println("Please enter a number (1 - 4): "); // ask user for emotion number while (Serial.available() == 0) {} // Wait for user input if (Serial.parseInt() != 0) { //if we actually get an input that is not 0 mode = Serial.parseInt(); //store it in mode // Print the number to the serial monitor Serial.print("You entered: "); Serial.println(mode); } while (Serial.available() > 0) { // Clear any remaining characters in the serial buffer Serial.read(); } // EMOTION DEFINITIONS switch (mode) { // Use a switch statement to handle different modes case 1: //happy emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { //run all of this for 10 seconds if (digitalRead(14) == LOW || digitalRead(27) == LOW) { // if turtle is being pet leds[0].setRGB(255, 255, 0); //set color to yellow leds[1].setRGB(255, 255, 0); FastLED.show(); //This command makes the LEDs change to match values in the array leds[] emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { //run for 10 seconds ccw(200); delay(150); //turn ccw for a short time and then stop for a bit forward(0); delay(250); cw(200); // turn cw for a short time and stop for a bit. delay(150); forward(0); delay(250); } } } break; //exit emotion switch case 2: //scared emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { //run all of this for 10 seconds //store a list of readings for (i = 8; i >= 0; i--) { // shift list up distance[i + 1] = distance[i]; //shift each element up a position } distance[0] = sensor.readRangeSingleMillimeters(); // update distance avgDistance[0] = (distance[0] + distance[1] + distance[2] + distance[3] + distance[4]) / 5; //calculate an current and past average to compare with avgDistance[1] = (distance[5] + distance[6] + distance[7] + distance[8] + distance[9]) / 5; if (avgDistance[1] - avgDistance[0] > 100) { // if smoething has jumped in front emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { //run movement for 10 seconds leds[0].setRGB(133, 0, 255); //set color to purple leds[1].setRGB(133, 0, 255); FastLED.show(); //This command makes the LEDs change to match values in the array leds[] // Startle Response: Quick backward motion reverse(240); // Move backward at high speed delay(200); //generate random motion for 100 ms to 300 ms over and over after // Rapid random movements to simulate panic randDirection = random(4); // Randomly choose a direction randSpeed = random(100, 255); // Random speed between 100 and 255 switch (randDirection) { //based on random driection choose a move case 0: //forward forward(randSpeed); break; //exit random movement switch case 1: //backward reverse(randSpeed); break; //exit random movement switch case 2: //right ccw(randSpeed); break; //exit random movement switch case 3: //left cw(randSpeed); break; //exit random movement switch } delay(random(100, 300)); //carry out that movement for a random amount of time between 100 and 299 ms } } } for (i = 0; i < 10; i++) { //cear all data out for current distance so we dont get any more refires based on an uncleared average distance[i] = sensor.readRangeSingleMillimeters(); //set distance at index i to current sensor reading } break; //exit emotion switch case 3: // angry emotionTime = millis(); while (millis() - emotionTime < 10000) { //for 10 seconds read to see if something is too close if (sensor.readRangeSingleMillimeters() < 160) { //if something is too cose run angry code leds[0].setRGB(255, 0, 0); //set color to red leds[1].setRGB(255, 0, 0); FastLED.show(); //This command makes the LEDs change to match values in the array leds[] emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { //for 10 seconds run movement if (sensor.readRangeSingleMillimeters() < 50) { // if ramming into something then switch direction reverse(255); //reverse for a bit delay(200); } else { forward(255); // continue ramming ahead if no object is seen really close } } } } break; //exit emotion switch case 4: // sad leds[0].setRGB(0, 0, 255); //set colors to blue leds[1].setRGB(0, 0, 255); FastLED.show(); //This command makes the LEDs change to match values in the array leds[] emotionTime = millis(); //reset emotion timer while (millis() - emotionTime < 10000) { // for 10 seconds if (sensor.readRangeSingleMillimeters() < 300) { //roam around but dont ever get very close to anything reverse(200); // reverse and turn a new direction delay(300); cw(200); delay(300); } else { //if nothing detected then continue sulking forward(175); } } break; //exit emotion switch default: Serial.println("Invalid number. Please enter a number between 1 and 4."); //error handling for input break; //exit emotion switch } forward(0); //cancel movement that is happening leds[0].setRGB(0, 0, 0); //turn off all LEDs leds[1].setRGB(0, 0, 0); FastLED.show(); //This command makes the LEDs change to match values in the array leds[] }