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.