ECE 4180 Mbed WAG-Boy Project
Project Overview
The WAG-Boy (What A Good Boy) is a personal companion that is made using the mbed and its ecosystem. This project makes use of the mbed, robot chassis, DC motors, dual H-bridge, sonar sensor, I2C touchpad, LCD, class D amp, and speaker to create an interactive robot that can avoid objects while roaming a room, respond to physical touch, and express its needs through sight and sound. The WAG-Boy is mainly marketed towards children/young families to teach responsibility or to the elderly or anyone that needs companionship but cannot have an actual pet for whatever reason.
Bot Behavior
Roaming
- Roam around the room (default state)
- Avoid collisions by turning around in place
Petting
- Activates by touching I2C Touchpad
- Wag tail and purr
Feeding
- Activates by putting object in front of Sonar
- Wag tail and make eating noises
Whining
- Activated by no interaction after awhile
- Whimper for attention, then Roam away
Hungry
- Activates by not being fed for long time
- Bark for attention
Sleeping
- Activates when not fed for long time
- Stop all activity briefly and snore
Devices Used
- Mbed
- Robot chassis
- 2 DC motors & Dual H-bridge : Used to provide movement to the bot
mbed | H-bridge | Motor 1 | =Motor 2 |
---|---|---|---|
5V | VM | ||
GND | GND | ||
VOUT | VCC | ||
A01 | + | ||
A02 | - | ||
p23 | PWMA | ||
p30 | AI1 | ||
p8 | AI2 | ||
B01 | + | ||
B02 | - | ||
p24 | PWMB | ||
p9 | BI1 | ||
p10 | BI2 | ||
VOUT | STBY |
- Sonar sensor : Used for collision avoidance
mbed | Sonar |
---|---|
5V | VCC |
GND | GND |
p11 | TRIG |
p12 | ECHO |
- I2C touchpad : Used for tactile interactivity
mbed | Touchpad |
---|---|
GND | GND |
p28 | SDA |
p27 | SCL |
p26 | IRQ |
VOUT | VCC |
- LCD screen : Used to provide visual status feedback (the "eye")
mbed | uLCD | uLCD cable |
---|---|---|
5V | 5V | 5V |
GND | GND | GND |
p13 | RX | TX |
p14 | TX | RX |
p29 | RESET | RESET |
- Speaker & Class D amp : Used to prodive aural status feedback (the "mouth")
mbed | Class D amp | Speaker |
---|---|---|
GND | PWR-, IN- | |
5V | PWR+ | |
p18 | IN+ | |
OUT+ | + | |
OUT- | - |
- SD card reader : Used to load realistic sounds for the speaker (purring, barking, etc.)
mbed | SD Card Reader |
---|---|
p21 | CS |
p5 | DI |
VOUT | VCC |
p7 | SCK |
GND | GND |
p6 | DO |
CD |
- Servo : Used for the wagging tail
mbed | Servo |
---|---|
5V | 5V |
GND | GND |
p22 | PWM |
Demo Video
Code
Import programWAGBoy
Code for a robotic pet to interact with.
main.cpp
#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 } }
Please log in to post comments.