Introduction: Homemade Cleanning Robot With Bluetooth

INTRODUCTION

Always wanted a Roomba, but is it too expensive for a piece of plastic? How about inventing your own? I, myself, find vacuum cleaner / sweeper robots too overpriced and overrated. There is nothing absurd in it that you can't make your own. Also, doing something from scratch, to be able to tell you did it yourself is something you will enjoy. And more, to start something and being able to finish it will certainly improve you capability of solving problems, not only in robotics, but mostly in life.

Through this project, the developer is able to play, improve and be tested in multiple number of areas. You can say it is a "multiple knowledge" project, because you will need abilities and to learn in the fields of mechanical, electrical engineering, computer programming and calculus / numerical methods in general. Your capacity of solving problems will be tested, and to be successful you will need also a certain dose of creativity.

Well, that's how I started this project. With an idea in mind, not knowing exactly how it would end. I wanted my own self-made Roomba. So I started building a 2WD (two wheeled drive) robot with an Arduino Uno, some H-bridges and DC motors. Eventually I improved it, putting ultrasonic sensors in order for it to avoid simple obstacles, like walls, or tables. Then, the project begin growing, and I tested several other sensors, from accelerometers, to encoders on the wheels, to digital compass.

So, I got to a point where the robot is already able to perform its main tasks, and the only part where there is field of improvement is the robot's behavior towards the obstacles found. There is no more need to continue the project: it is finished. Then I wanted to share with you guys, so you could do it too, and avoid some of the suffering I went through, and build an even better robot. To begin describing the it's main points, here is the list of its overall features:

  • 2WD robot, one motor for each wheel;
  • Cleaning is done using a carpet sweeper connected to an extra DC motor;
  • Motors are controlled separately through two H-bridges;
  • Uses PID control method, implemented via Arduino;
  • Digital compass gives the directions the robot is going, in order to control its wheels;
  • Obstacle detection is obtained with ultrasonic sensors;*
  • Stuck position can be found checking the results from the ultrasonic sensors;**
  • Rechargeable battery capable of running around for about an hour;
  • Can be controlled via Bluetooth, and this interface is already implemented;***
  • Has an specific Windows Phone software, made by myself, however you can use other platforms too;

NOTES:

* It is possible to use an infrared module with reflective photoelectric sensor to detect walls, and it could probably be more efficient, because the infrared is a good option for detecting objects that are very near, and the ultrasonic is good for ranges from 10 cm to 2 meters. ** An encoder using a photoelectric sensor could be used to detect when the robot is stuck, just by looking if the wheels are spinning or not, however, I opted for the cheaper option, once I was already using ultrasonic sensors. *** The robot is completely autonomous, and will avoid walls, so the Bluetooth interface is just used if you want to control the robot yourself, or to have some fun!

Step 1: What Do You Need?

THE PARTS:

For building this robot, you will need to buy some items on Ebay. You can build some sensors by yourself, but you have to see it is worth your time - there is no need to reinvent the wheel. So here is the list:

  • HC-06 Bluetooth module (optional) Ebay (4);
  • 2 x Dual H-bridges (will need two of these) Ebay (5);
  • Prototype shield for Arduino Uno Ebay (6);
  • I2C LCD display 1602 (optional) Ebay (8);
  • 3 Ultrasonic sensor HC-SR04 (at least) Ebay (9);
  • Ultrasonic Sensor Fixed Bracket or similar (optional) Ebay (10);
  • Two pieces of acrylic to the make layers of the robot;

If you want optocoupler on the wheels to work as encoders, I suggest:

And, if you want an photoelectric sensor to detect walls:

Step 2: Soldering the Eletronics

WHAT YOU NEED TO KNOW:

Before starting to solder, you need to observe the figure above. You can use between 3 to 6 ultrasonic sensors. If you use 3, you have to put one in front of the robot, and the other two 120 degrees spaced from each other. The one in front will detect objects as they come closer, and the other two will be pointing to the back of the robot. Both of them will find the distance to the nearer object (behind), so the "SweeperBot" can decide, if after finding a wall, it will go back more to its right side, or more to its left side. That is because, of course, if after finding a wall the robot went straight backward, it would be always going in a straight line, and would never clean the whole room.

If you desire more readings, more information, and for the robot to detect objects coming from the sides, and also to detect objects right behind it, you can use all 6 possible sensors. One method of control possible to use in order to avoid obstacles is the Potential Fields, which would make great use of all this information. However I have not implemented this yet.

Still writing about the sonars, another thing to take note is that, using the code I'll provide as follows, you can use just one wiring to all the six of them as the trigger pin, which means you will trigger all 6 together, with the same command. This way you will avoid using more 5 wires to trigger them. Usually, using the standard library of this sensor, you would not be able to do so, because each sensor would have issues one with the other. However, each sensor will have its own echo (pin and wiring) because, as their readings differ, each of them will send different signals to the Arduino.

The other two pins of the HC-SR04 sonar are the positive and the ground. These two are the same to all the other electronics: the compass, the display, and the bluetooth. The compass will have communications via I2C (IIC), connecting its SDA and SCL to the ones on the Arduino. The Bluetooth will connect its transmitter pin and receiver pin to pins digital 0 and 1 from the micro-controller. Observe that their configuration is made via software, and if you switch these pins the Bluetooth wont be able to pair to the device. The display will also connect I2C on the same pins as the compass, because using I2C the Arduino can control many devices simultaneously with the same pins.

Relative to the H-bridge, you have to connect enable A and enable B to the positive pin (which is by its side, just use a jumper) otherwise the motors wont run. Then, connect each motor to a terminal positive and negative from the H-bridge (the side pins with the screws), and the three connectors remaining with screws are: the ground, which will go to the arduino and all other devices, including the battery, the positive 9V-12V that comes exclusively from the battery, and the 5V out that will supply all other devices that are not the DC motors. The for remaining connectors are two pairs of logic signals to control the direction and power given to each motor.

THE PINOUT:

  • HMC5883L digital compass;
    • PIN 0 - SDA >>> Arduino Analog Pin A4;
    • PIN 1 - SCL >>> Arduino Analog Pin A5;
    • PIN 2 - GND >>> GND;
    • PIN 3 - VCC >>> VCC 5V;
  • HC-06 Bluetooth;
    • PIN 0 - RX >>> Arduino Digital Pin 0;
    • PIN 1 - TX >>> Arduino Digital Pin 1;
    • PIN 2 - GND>>> GND;
    • PIN 3 - VCC>>> VCC 5V;
  • 1st Dual H-bridge;
    • PIN 0 >>> Arduino Digital Pin 4;
    • PIN 1 >>> Arduino Digital Pin 5;
    • PIN 2 >>> Arduino Digital Pin 6;
    • PIN 3 >>> Arduino Digital Pin 7;
    • Enable A >>> VCC;
    • Enable B >>> VCC;
    • Power >>> Battery Positive 9 - 12V;
    • GND >>> Battery GND and Arduino GND;
    • +5V OUT >>> Arduino VCC;
  • 2nd Dual H-bridge;
    • PIN 0 >>> Arduino Digital Pin 3;
    • PIN 1 >>> GND;
    • PIN 2 >>> Not Connected;
    • PIN 3 >>> Not Connected;
    • Enable A >>> VCC;
    • Enable B >>> GND;
    • Power >>> Battery Positive 9 - 12V;
    • GND >>> Battery GND and Arduino GND;
    • +5V OUT >>> Not connected;

  • I2C LCD display 1602;
    • Pin 0 - GND >>> Arduino GND;
    • Pin 1 - VCC >>> Arduino VCC;
    • Pin 2 - SDA >>> Arduino Analog Pin A4;
    • Pin 3 - SCL >>> Arduino Analog Pin A5;
  • 6 Ultrasonic sensor HC-SR04;
    • Pin 0 - VCC >>> Arduino VCC;
    • Pin 1 - Trigger >>> Arduino Digital Pin 2;
    • Pin 2 - Echo >>> Connected on Arduino Digital Pins 8, 9, 10, 11, 12, and 13;
    • Pin 3 - GND >>> Arduino GND.

Step 3: MOUNTING THE ROBOT

Get the ultrasonic sensor fixed each of them with equal angles between each other, for instance, if you use six, place the first in front of the robot and the others with 60 degrees from it. Use the acrylic boards as layers of the robot, so it is easier to mount and get the pieces in position. Screw everything on the layers, and put the battery just above the motors, but under the electronics. This way you will lower its gravity center, thus making it more stable.

Solder all the positive wires together and the ground pins too. I made a connector with all the pins from the sensors and another with the 5 DC motors pins, so it got easier to understand, when mounting and dismounting. Place a final layer above the H-bridges and put the Arduino there. I used a Prototyping Shield above the micro-controller, because it gets easier to solder and fix the compass, that is a part that needs special attention. There is no need to place it at the center of the robot, but it needs to be distant from big metal parts, as the motors and the battery.

It is possible to mount the DC motor together with the carpet sweeper in many different ways, but some are better than others. Because I had only one sweeper, mine got a little ugly during my attempts. I found that gluing the axis of the motor to the axis of the sweeper was really difficult, and usually after some minutes of work, they would break, specially because there is no way to get them together correctly aligned. So I took off the motors's reduction shaft and placed a small gear glued on the axis of the sweeper. Then I placed the motor's gear in contact with and everything worked as a charm. However, I wish I had a 3D printer, things would be so much easier and much more professional.

Step 4: The Code

THE LIBRARIES:

The "SweeperBot" makes use of Wire, I2Cdev, TimerOne (for interruptions), Adafruit Sensor, HMC5883, and LCD libraries. You can download the Zip file, that contains the code for the Arduino, and all libraries. Also contains the Bluetooth project for Windows Phone.

THE WINDOWS PHONE 8.1 CODE:

The project that controls the robot via Bluetooth from the Windows Phone was adapted from an example available on the internet. It was altered to have four buttons, one to each direction. Up, down, left and right. Each button send a letter to the robot, respectively U, D, L and R. When the robot receives these, it makes one of the following:

  • U - the robot will set the direction to follow straight forward;
  • D - the robot will turn to its back and go straight;
  • L - the robot will set the direction to follow exactly 90 degrees left from where it is currently "looking";
  • R - the robot will set the direction to follow exactly 90 degrees right from where it is currently "looking";

The way the robot handles these commands can be changed with the code on the Arduino. It is possible to add more buttons to turn the robot, or to stop it, or even to make it go backward. This code is just an example. It is also possible to make similar programs to other devices, such as Androids an for IOS. The only thing you have to send the robot are these letters - U, D, L or R.

private async void RedButton_Click_1(object sender, RoutedEventArgs e) {
    string command = "U";
    await connectionManager.SendCommand(command);
}

private async void GreenButton_Click_1(object sender, RoutedEventArgs e) {
    string command = "L";
    await connectionManager.SendCommand(command);
}

private async void YellowButton_Click_1(object sender, RoutedEventArgs e) {
    string command = "R";
    await connectionManager.SendCommand(command);
}

private async void RedButton_Copy_Click(object sender, RoutedEventArgs e) {
    string command = "D";
    await connectionManager.SendCommand(command);
} 

To deploy this code to your Windows Phone you will need Visual Studio and a developer unlocked phone. This can be done following the instructions on this link.

THE ARDUINO CODE:

In resume, the main logic of the robot is as follows:

  1. Distance to nearer object found in each of 6 possibles sensors;
  2. Behavior of robot process distances and point desired direction with a vector X,Y (however, if a message is received from the smartphone, step 2 is substituted by the direction sent from the device);
  3. Digital compass gives the direction the robot is going, in order to control its wheels;
  4. Information X',Y' from compass is normalized to space [-1,1];
  5. Cross product between vector of desired direction and actual direction finds error between them;
  6. PID method calculates PWM (power) to each DC motor for the two wheels (2WD);
  7. Interruption activates PWM;

As the project evolved, I found out the standard library available on GitHub for the ultrasonic sensors were conflicting with the PWM activation of the motors, because they both used the same timer. As this project use 5 pins to configure the PWM of the three DC motors (and this is only possible because the carpet sweeper only turns to one direction), and more 7 to the sensors, which the micro-controller have to be constantly checking if the reading was received, it wasn't possible to use the material available on internet.

So, to avoid conflicts, it was configured only the timer 1 interrupt. Through this interruption, the Arduino can check if there was readings on each sensor: if not, it increases a variable to each of them, that will be used as parameter to find the distance to the object.

void callback() { //callback is the interruption name
  noInterrupts();
  //if no reading, increases variable sonarCount[n], where n is the number of sensor
  if ((sonar[0] == 1) && (digitalRead(ECHO))) sonarCount[0]++; 
  //if there is readind on that sensor, sonar[n] = 2 accuses object found
  if ((sonar[0] == 1) && (!digitalRead(ECHO)) && (sonarCount[0] > 0)) sonar[0] = 2;

Also, inside this interruption, it throws full power to the motor. If there have been a certain number of interruptions that exceeds the number of PWM_R or PWM_L variables, then it throws zero potency to that given motor.

  if (PWMCount == 0) {
    if (PWML) { //if pwm left is positive then turn to a certain way
      digitalWrite(MOTOR + 2, HIGH);
      digitalWrite(MOTOR + 3, LOW);
    } else { //else turn to the other side the left motor
      digitalWrite(MOTOR + 2, LOW);
      digitalWrite(MOTOR + 3, HIGH);
    }

  (...)

  if (PWMCount >= abs(PWM_L)) { //if the counter equals the power we want
    digitalWrite(MOTOR + 2, LOW); //shut down both pins of this motor
    digitalWrite(MOTOR + 3, LOW);
  }

  (...)

  PWMCount++; //increases counter
  if (PWMCount == 250) PWMCount = 0; //if counter equals maximum value we want
  Timer1.attachInterrupt(callback); //250 equals 100% power
}

During the main loop, the robot stays searching obstacles and calculating routes to avoid them, or change its path. If the developer wants to configure Potential Fields control method, or change the robot's behavior, he just have to work a better obst() function. The other parts of the program are necessary and don't need to be changed. When the robot receives a message through Bluetooth, it stops avoiding obstacles and just listen for user inputs.

void loop() //main loop
{
  lcd.clear(); //clears previous messages on lcd
  delay(10); 
  search(); //search obstacles and saves the distance value to each sensor
  readings(); //reads compass and calculates the error from its desired direction
  calcPWM(); //calculates the PWM for each motor based on PID
  if (!mensagem) { //message from Bluetooth? if not, continue doing this
    obst(); //here is where the robot defines its behavior
  }	    //and where it defines the direction it want to go
  
(...) 

From all the parts of the code, all of them are pretty basic, the only one function that is interesting to take note here, is the readings(). Inside it, the robot gets the value X, Y and Z for the current position on the digital compass. So, how to turn that reading into something that makes the robot know to which direction it is looking?

First you get the raw values:

double rawX = event.magnetic.x;
double rawY = event.magnetic.y;
double rawZ = event.magnetic.z;

Then check if the robot is on the right plane. This can be done be seeing if the Z (perpendicular axis) is with a value between a certain small range

if ((rawZ > Zprim + 10) || (rawZ < Zprim - 10)) return; //if not right, return

Now it is time to normalize X and Y values to a space between [-1,1], in order to calculate sin() and cos() from these values.

//Ymin, Ymax, Xmin and Xmax are obtained when the calibration occurs
vector[1] = ((rawY) - ((Ymax + Ymin) / 2)) / ((Ymax - Ymin) / 2);
vector[0] = ((rawX)  - ((Xmax + Xmin) / 2)) / ((Xmax - Xmin) / 2);

We now make vectorOBJ[n] a bidirectional vector pointing to where, on the plan, we want the robot to go. So, to find the error between two vectors we have to make the cross product between them both. The resulting value is another vector, but perpendicular to both, pointing up or down, depending on its sign.

error = (vectorOBJ[0] * vector[0] + vectorOBJ[1] * vector[1]) / 
	 	(sqrt(vectorOBJ[0] * vectorOBJ[0] + vectorOBJ[1] * vectorOBJ[1]) 
		* sqrt(vector[0] * vector[0] + vector[1] * vector[1]));

error = (acos(error)) * 180 / PI; //from rad to degrees
//find out the way the result vector is pointing
sentido = vector[0] * vectorOBJ[1] - vector[1] * vectorOBJ[0];
if (sentido > 0) error = -error;

Step 5: Conclusions

FINAL WORDS

After solder, mount the robot and deploy the code to the Arduino and to your phone, you will still need to configure many of its attributes. For example, maybe positive PWM value on the code will turn the wheel making the robot go backward, not forward. Maybe positive will turn one motor to a side and the other to the opposite. In this case, just switch the wires on the motors' terminals, and that's fine.

Perhaps you have to change the variable read, instead of X, and Y, perhaps your compass' plan will be with X and Z, or Y and Z. Depends on how you placed and configured the digital compass. Perhaps your sensor named 0 (zero) wont be in front of the robot, and you will have to connect or configure them differently.

After all this, you will probably have finished your robot. You can change its behavior as you like, but I can guarantee it will work, or at least the code will. The robot will read correctly the compass, will figure where he is headed, which direction he want to go, how much power to provide to each motor and see how far are the obstacles to each sensor. There is plenty of ROM memory left, so you can implement a different strategy as you wish.

Again, as I wrote in my previous Instructable (link), which was about an alarm clock with Bluetooth and infrared remote, I have some other projects I wanted to share with you guys. If people like this one, please comment and follow me here, because I will probably write another one about a Smart-watch I made for Windows Phone (or any other platform) with a digital compass, accelerometer and Bluetooth (again - "everything is better with Bluetooth"). Sorry for the bad english.

Thanks guys!

Move It

Participated in the
Move It

Coded Creations

Participated in the
Coded Creations

Automation Contest

Participated in the
Automation Contest