Vacuum Buddy
Team Members: Hao Fu, Zachary Crawford, Richard Duan
Overview
Vacuum Buddy is an attempt at making a Roomba inspired vacuum cleaner self-driving robot. It consists of a sheet of aluminium strapped to form a circle, with a circle cut of wood forming the base. The mbed is mounted in the center of the robot, with connections to 4 sensors and 2 motors used to drive and steer the robot, and a bluetooth sensor to allow for manual user input. A Raspberry Pi with a video camera attachment is mounted on the top of the robot to provide video streaming capabilities.
Picture of Robot:
Block Diagram of Robot:
Modes of Operation
The robot features three modes of operation:
1) Autonomous Mode:
In this mode, the robot will calculate the size of the room it is in using its attached sensors, and drive around the room in a sweeping pattern as if it were a vacuum cleaner trying to clean every square inch of the room.
The autonomous operation mode also features collision detection. It accomplishes this by dividing a room into square units of area. When an object is detected, the robot will change path to avoid a collision and attempt to return to its original path by determining which square blocks were in the original intended path.
2) Roaming Mode:
In this mode, the robot will move in random directions, using its sensors to avoid objects by realigning itself in random directions
3) Manual Mode:
In this mode, the end user can control the robot's directional movement via a bluetooth app interface.
Power
The Robot is powered by 4x AA batteries connected to a 5V barrel jack to supply power to the DC motors via breadboard connections. Each motor requires it's own 5V power supply, so two battery packs and barrel jack connections are required.
Video Streaming
The Raspberry Pi 3 with 5MP camera module attached to the top of the robot provides video streaming capability. The Raspberry Pi 3 is not connected directly to the mbed, and operates independently from the mbed robot, requiring a separate power supply.
The Pi 3 runs the latest build of Raspbian Jessie, and runs a special program called Dataplicity Agent, which allows the Pi 3 to create server with a 2.4GHz 802.11n wireless chip. A special bashscript was created to navigate through files, server and image transmission code automatically when the Pi 3 starts up.
Demo
Components
Pinouts
1. TB6612FNG Dual Motor H Bridge This chip allows voltage to be applied across a load in either direction, to run the DC motors to run forwards and backwards
| Motor H-Bridge signal | MBED/peripherals |
|---|---|
| Vm | motor power supply |
| Vcc | 5V |
| Gnd | common ground |
| A01 | motorA pos. side |
| A02 | motorA neg. side |
| PWMA | p21 |
| B01 | motorB pos. side |
| B02 | motorB neg. side |
| PWMB | p26 |
| Bin1 | p30 |
| Bin2 | p29 |
| An1 | p22 |
| An2 | p23 |
| Stby | pull to high |
2. Wheel Encoder for Motor A
| Encoder | MBED pins |
|---|---|
| clk | p25 |
| Pos. | 5V |
| Gnd | common ground |
3. Wheel Encoder for Motor B
| Encoder | MBED pins |
|---|---|
| clk | p24 |
| Pos. | 5V |
| Gnd | common ground |
4. HC-SR04 Sonar Sensor (forward)
| Sensor | MBED pins |
|---|---|
| echo | p28 |
| trigger | p27 |
| Pos. | 5V |
| Gnd | common ground |
5. HC-SR04 Sonar Sensor (left)
| Sensor | MBED pins |
|---|---|
| echo | p13 |
| trigger | p12 |
| Pos. | 5V |
| Gnd | common ground |
6. HC-SR04 Sonar Sensor (right)
| Sensor | MBED pins |
|---|---|
| echo | p7 |
| trigger | p6 |
| Pos. | 5V |
| Gnd | common ground |
7. Adafruit Bluefruit LE UART
| Adafruit BLE | MBED pin |
|---|---|
| GND | GND |
| VU(5v) | Vin |
| nc | RTS |
| Gnd | CTS |
| p9 (Serial RX) | TXO |
| p10 | RXI |
Code
The following is the main code that runs on the mbed robot
#include "mbed.h"
#include "motordriver.h"
#include "rtos.h"
Serial pc(USBTX, USBRX); // tx, rx
Serial blue(p9,p10);
BusOut myled(LED1,LED2,LED3,LED4);
int stateB = 1; //state = 1 (autonomous), state = 0 (manual mode)
Motor left(p21, p22, p23, 1); // pwm, fwd, rev, has brake feature
Motor right(p26, p30, p29, 1);
DigitalOut triggerL(p12);
DigitalOut triggerR(p6);
DigitalOut triggerF(p15);
DigitalIn echoL(p13);
DigitalIn echoR(p7);
DigitalIn echoF(p16);
InterruptIn encoderR(p24);
InterruptIn encoderL(p25);
AnalogIn trueValL(p19);
AnalogIn trueValR(p20);
float R = 0;
float L = 0;
int countL = 0;
int pulseL = 0;
int countR = 0;
int pulseR= 0;
int lDist = 0;
int rDist = 0;
int fDist = 0;
bool action=1;
int correction = 0;
Timer sonar;
Timer t;
float timeRead;
int distCheckL(void);
int distCheckR(void);
int distCheckF(void);
void fMotion();
void bMotion();
void lTurn();
void rTurn();
void stopM();
void state(int state);
////(state: 0 forward motion; 1 backward motion; 2 left motion; 3 right motion; 4 return to the last position)
int state_1 =0;
////current position
int x=0;
int y=0;
void move(float SpeedLeft,float SpeedRight,int pulseVal,int dir1,int dir2,int distance){
L = dir1*SpeedLeft;
R = dir2*SpeedRight;
pulseL = pulseVal;
pulseR = pulseVal;
do{
left.speed(L);
right.speed(R);
fDist = distCheckF();
// pc.printf("%d\n\r",fDist);
}while(((L!=0) && fDist>distance) || ((R!=0) && fDist>distance) );
left.speed(0);
right.speed(0);
wait(0.5);
countL = 0;
countR = 0;
}
void checkR() {
float voltage = 0;
voltage = trueValR.read() * 5.0;
if(voltage>=1.85){
countR++;
//pc.printf("countR is %d\n\r",countR);
if(countR == pulseR){
R = 0;
countR = 0;
}
}
}
void checkL() {
float voltage = 0;
voltage = trueValL.read() * 5.0;
if(voltage>=1.85){
countL++;
//pc.printf("countL is %d\n\r",countL);
if(countL == pulseL){
L = 0;
countL = 0;
}
}
}
Mutex bluetooth_mutex;
void bluetooth(void const *args)
{
bluetooth_mutex.lock();
char bnum=0;
char bhit=0;
while(1) {
if (blue.getc()=='!') {
if (blue.getc()=='B') { //button data packet
bnum = blue.getc(); //button number
bhit = blue.getc(); //1=hit, 0=release
if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK?
//myled = bnum - '0'; //current button number will appear on LEDs
switch (bnum) {
case '1': //number button 1
if (bhit=='1') {
printf("Number 1 pressed!");
//add hit code here
myled = 15; //all LEDs are blink
//switch state to autonomous mode
state_1 = 0;//fix cleaning
} else {
//add release code here
myled = 0;
//left.speed(0);
//right.speed(0);
}
break;
case '2': //number button 2
if (bhit=='1') {
//add hit code here
printf("Number 2 pressed!");
myled = 12; //turn half of LEDs on
//switch states,
state_1 = 1; // make roaming robot
} else {
//add release code here
myled = 0;
}
break;
case '3': //number button 3
if (bhit=='1') {
//add hit code here
printf("Number 3 pressed!");
} else {
//add release code here
}
break;
case '4': //number button 4
if (bhit=='1') {
//add hit code here
printf("Number 4 pressed!");
} else {
//add release code here
}
break;
case '5': //button 5 up arrow
printf("Up pressed!");
if (bhit=='1') {
//add hit code here
myled = 1;
//robot go straight (forward)
//go forward for a short time
//move(0.74,0.73,20,1,1,20);
left.speed(0.74);
right.speed(0.73);
wait(1);
} else {
//add release code here
myled = 0;
left.speed(0);
right.speed(0);
}
break;
case '6': //button 6 down arrow
printf("Down pressed!");
if (bhit=='1') {
//add hit code here
myled = 2;
//go backwards (for a short time)
//move(-0.74,0.73,20,1,1,20);
left.speed(-0.74);
right.speed(-0.73);
wait(1);
} else {
//add release code here
myled = 0;
left.speed(0);
right.speed(0);
}
break;
case '7': //button 7 left arrow
printf("left pressed!");
if (bhit=='1') {
//add hit code here
myled = 4;
//turn left
// move(0,0.73,26,0,1,-5);
right.speed(0.73);
left.speed(0);
wait(1);
} else {
//add release code here
myled = 0;
left.speed(0);
right.speed(0);
}
break;
case '8': //button 8 right arrow
printf("right pressed!");
if (bhit=='1') {
//add hit code here
myled = 8;
//turn right
//move(0.73,0,26,1,0,-5);
left.speed(0.73);
right.speed(0);
wait(1);
} else {
//add release code here
myled = 0;
left.speed(0);
right.speed(0);
}
break;
default:
break;
}
}
}
}
}
}
int main()
{
encoderR.rise(&checkR);
encoderL.rise(&checkL);
//Thread thread1 (bluetooth);
//Thread::wait(1000);
//Loop to read Sonar distance values, scale, and print
while(action==1) {
state(state_1);
}
}//end of main()
int distCheckL(void){
triggerL = 1;
sonar.reset();
wait_us(10.0);
triggerL = 0;
//wait for echo high
while (echoL==0) {};
//echo high, so start timer
sonar.start();
//wait for echo low
while (echoL==1) {};
//stop timer and read value
sonar.stop();
//subtract software overhead timer delay and scale to cm
lDist = (sonar.read_us()-correction)/58.0;
printf("lDist: %d cm \n\r",lDist);
//wait so that any echo(s) return before sending another ping
wait(0.2);
return lDist;
}
int distCheckR(void){
triggerR = 1;
sonar.reset();
wait_us(10.0);
triggerR = 0;
//wait for echo high
while (echoR==0) {};
//echo high, so start timer
sonar.start();
//wait for echo low
while (echoR==1) {};
//stop timer and read value
sonar.stop();
//subtract software overhead timer delay and scale to cm
rDist = (sonar.read_us()-correction)/58.0;
printf("rDist: %d cm \n\r",rDist);
//wait so that any echo(s) return before sending another ping
wait(0.2);
return rDist;
}
int distCheckF(void){
triggerF = 1;
sonar.reset();
wait_us(10.0);
triggerF = 0;
//wait for echo high
while (echoF==0) {};
//echo high, so start timer
sonar.start();
//wait for echo low
while (echoF==1) {};
//stop timer and read value
sonar.stop();
//subtract software overhead timer delay and scale to cm
fDist = (sonar.read_us()-correction)/58.0;
printf("fDist: %d cm \n\r",fDist);
//wait so that any echo(s) return before sending another ping
wait(0.2);
return fDist;
}
void fMotion(){
left.speed(0.93);
right.speed(0.9);
}
void bMotion(){
left.speed(-0.53);
right.speed(0.5);
}
void stopM(){
left.speed(0);
right.speed(0);
}
void lTurn(){
left.speed(0);
right.speed(0.54);
wait(1.5);
right.speed(0);
wait(0.1);
}
void rTurn(){
left.speed(0.5);
right.speed(0);
wait(1.75);
left.speed(0);
}
void state(int state){
switch (state){
//fix cleaning
case 0:
wait(0.2);
while(state_1==0){
//go straight for a long time
move(0.75,0.73,200,1,1,25);//move(left speed, right speed, pulses,left direction, right direction, distance to check) note:-5 distance means(don't care)
wait(1);
//turn left at 90 deg.
move(0,0.73,26,0,1,-5);
wait(1);
//go straight for a short time
move(0.74,0.73,20,1,1,25);
wait(1);
//turn left
move(0,0.73,26,0,1,-5);
wait(1);
//go staight long time
move(0.74,0.73,200,1,1,25);
wait(1);
//go right
move(0.73,0,26,1,0,-5);
wait(1);
//go sraight for a short time
move(0.74,0.73,20,1,1,25);
wait(1);
//go right
move(0.73,0,26,1,0,-5);
wait(1);
}
break;
//roaming robot
case 1:
while(state_1==1){
if(fDist<25){
fMotion();
}
else if (lDist<25){
rTurn();
}
else if (rDist<25){
lTurn();
}
}
break;
//bluetooth control
case 2:
break;
}//end of switch (state)
}
The following script is run on the Pi 3 to start video transmission:
#!/bin/bash cd /home/pi/mjpg-streamer/ sudo ./mjpg_streamer -i "./input_uvc.so -f 10 -r 640x320 -n -y" -o "./output_http.so -w ./www -p 80"
Future Works
- Improve power supply to allow for stronger drive motors and vacuum
- Coordinates (x, y, and # of unit square)
- Virtual walls
- Improved traction and wheel syncing
Please log in to post comments.
