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:

/media/uploads/rduan8/20170430_031606.jpg

Block Diagram of Robot:

/media/uploads/rduan8/cleaning_robot.jpg

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.

/media/uploads/rduan8/autonomous_mode.gif

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.

/media/uploads/rduan8/2.png

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

/media/uploads/rduan8/roaming_mode.png

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 signalMBED/peripherals
Vmmotor power supply
Vcc5V
Gndcommon ground
A01motorA pos. side
A02motorA neg. side
PWMAp21
B01motorB pos. side
B02motorB neg. side
PWMBp26
Bin1p30
Bin2p29
An1p22
An2p23
Stbypull to high

2. Wheel Encoder for Motor A

EncoderMBED pins
clkp25
Pos.5V
Gndcommon ground

3. Wheel Encoder for Motor B

EncoderMBED pins
clkp24
Pos.5V
Gndcommon ground

4. HC-SR04 Sonar Sensor (forward)

SensorMBED pins
echop28
triggerp27
Pos.5V
Gndcommon ground

5. HC-SR04 Sonar Sensor (left)

SensorMBED pins
echop13
triggerp12
Pos.5V
Gndcommon ground

6. HC-SR04 Sonar Sensor (right)

SensorMBED pins
echop7
triggerp6
Pos.5V
Gndcommon ground

7. Adafruit Bluefruit LE UART

Adafruit BLEMBED pin
GNDGND
VU(5v)Vin
ncRTS
GndCTS
p9 (Serial RX)TXO
p10RXI

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.