Code for a robotic pet to interact with.

Dependencies:   mbed wave_player Servo Motordriver mbed-rtos 4DGL-uLCD-SE SDFileSystem_OldbutworkswithRTOS HC_SR04_Ultrasonic_Library

main.cpp

Committer:
jprocter3
Date:
2019-04-22
Revision:
15:02e772571d48
Parent:
14:7e45dbeb0acf

File content as of revision 15:02e772571d48:

#include "mbed.h"
#include "motordriver.h"
#include "rtos.h"
#include "uLCD_4DGL.h"
#include "mpr121.h"
#include "ultrasonic.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include "Servo.h"
uLCD_4DGL uLCD(p13,p14,p29); // serial tx, serial rx, reset pin;
SDFileSystem sd(p5, p6, p7, p21, "sd"); //SD card
AnalogOut DACout(p18);
wave_player waver(&DACout);
Motor m1(p23, p30, p8, 1); // pwm, fwd, rev
Motor m2(p24, p9, p10, 1); // pwm, fwd, rev
InterruptIn interrupt(p26);
I2C i2c(p28, p27);
Mpr121 mpr121(&i2c, Mpr121::ADD_VSS);
Servo myservo(p22);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

enum {ROAM, STOP, SLEEP};
volatile int state;

volatile int energy;
volatile bool touched;
volatile bool fed;
volatile bool touchpad;

void fallInterrupt() {
      touchpad = true;
      mpr121.read(0x00);
      mpr121.read(0x01);
}

void dist(int distance) {
    //control wheels
    if (state == ROAM) {
        if(distance < 250) {
            m1.stop(0);
            m2.stop(0);
            Thread::wait(100);
            m1.speed(.6);
            m2.speed(-.6);
            Thread::wait(400);
        } else {
            m1.speed(.5);
            m2.speed(.5);
        }    
    } else { // stop for STOP and SLEEP
        m1.stop(0);
        m2.stop(0);    
    }

    if (state == STOP && distance < 60) {
        //increase food status
        fed = true;
        Thread::wait(3000); // make sure fed state lasts atleast 3 seconds
        fed = false;
    }
}

ultrasonic mu(p11, p12, .1, 1, &dist);

void sonar(void const *argument) {
    while(1) {
        mu.checkDistance();
        Thread::wait(100);
    }
}

void touch(void const *argument) {
    while(1) {
        if (touchpad) {
            touched = true;
            Thread::wait(5000);
            touchpad = false;   
        } else {
            touched = false;
        }
        Thread::wait(100); // runs 10 times a second
    }
}

void screen(void const *argument) {
    while(1) {
        uLCD.filled_rectangle(0, 0, 127, 127, BLACK); // clear screen
        switch(state) {
            case ROAM: {
                uLCD.circle(64, 64, 30, BLUE); // blue circle in the center
                uLCD.filled_circle(64, 64, 5, BLUE); // blue circle in the center
            } break;
            case STOP: {
                uLCD.locate(0,0);
                uLCD.text_width(12);
                uLCD.text_height(12);
                if (fed || touched) { // touched or fed
                    uLCD.text_width(9);
                    uLCD.text_height(9);
                    uLCD.color(RED);
                    uLCD.printf("<3");
                } else if (energy < 30) { // tired
                    uLCD.color(RED+GREEN);
                    uLCD.printf("0"); // yellow 0's
                } else { // wondering
                    uLCD.color(BLUE);
                    uLCD.printf("?"); // blue ?'s
                }
            } break;
            case SLEEP: {
                uLCD.locate(0,0);
                uLCD.text_width(12);
                uLCD.text_height(12);
                uLCD.color(BLUE);
                uLCD.printf("Z"); // blue Z's
            }
        }
        
        Thread::wait(100);    
    }
}

void sound(void const *argument) {
    FILE *wave_file;
    while(1) {
        switch(state) {
            case STOP: {
                if (fed) { // fed
                    wave_file=fopen("/sd/eat.wav","r"); // 2 seconds
                } else if (touched) { // touched
                    wave_file=fopen("/sd/purr.wav","r"); // 3 seconds
                } else if (energy < 30) { // tired
                    wave_file=fopen("/sd/bark.wav","r"); // < 1 second
                    Thread::wait(500);
                } else { // wondering
                    wave_file=fopen("/sd/curious.wav","r"); // 1 second
                    Thread::wait(1000);
                }
                waver.play(wave_file);
                fclose(wave_file);
            } break;
            case SLEEP: {
                wave_file=fopen("/sd/sleep.wav","r"); // 8 seconds
                waver.play(wave_file);
                fclose(wave_file);
            }
        }
        
        Thread::wait(100);    
    }
}

void tail(void const *argument) {
    while(1) {
        if (state == STOP && (touched || fed)) {
            for(int i=0; i<100; i++) {
                myservo = i/100.0;
                Thread::wait(10);
            }
            for(int i=100; i>0; i--) {
                myservo = i/100.0;
                Thread::wait(10);
            }
        } else {
            myservo = 0.5;   
        }
        Thread::wait(500);
    }
}

int main() {
    uLCD.cls();
    uLCD.printf("Change baudrate.....");
    uLCD.baudrate(3000000); //jack up baud rate to max
    uLCD.background_color(BLACK);
    uLCD.cls();
    uLCD.text_bold(ON);
    uLCD.text_mode(OPAQUE);

    mu.startUpdates();
    
    interrupt.fall(&fallInterrupt);
    interrupt.mode(PullUp);

    state = ROAM;
    energy = 70;

    Thread thread1(sonar);
    Thread thread2(touch);
    Thread thread3(screen);
    Thread thread4(sound);
    Thread thread5(tail);
    
    while(1) {
        // Status LEDS
        led3 = touched;
        led4 = fed;
        
        // Update state
        if (energy < 5) { // sleeps for 10 seconds and wake up with 50 more energy
            state = SLEEP;
            led1 = 1;
            led2 = 1;
            Thread::wait(10000);
            energy += 50;
        } else if (energy < 30 || touched || fed) {
            state = STOP;
            led1 = 0;
            led2 = 1;
        } else if (state == STOP) {
            Thread::wait(6000); // wait wondering for 5 seconds after touched or fed
            state = ROAM;
        } else {
            state = ROAM;
            led1 = 1;
            led2 = 0;
        }
        
        // Update energy
        switch(state) {
            case ROAM: energy -= 2;
                break;
            case STOP : energy -= 1;
                if (fed) {
                    energy += 10; // +10 energy a second while fed
                }
                break;
        }
        
        // Make sure energy stays in 0-100
        if (energy < 0) {
            energy = 0;
        } else if (energy > 100) {
            energy = 100;
        }
        
        Thread::wait(1000); // runs once per second
    }
}