Introduction: Turning Your Roomba Into a Mars Rover
.
Step 1: Gather Your Materials
In order to complete this project, you will need to gather the following materials:
1 Roomba Robot
1 Raspberry Pi Kit
1 Video Camera
Access to MATLAB
Step 2: Download the Roomba Toolboxes for MATLAB
Run the following code in order to install the necessary toolboxes to complete this project.
function roombaInstall
clc;
% list of files to install
files = {'roomba.m','roombaSim.m','roombaSimGUI.m','roombaSimGUI.fig'};
% location to install from
options = weboptions('CertificateFilename',''); % tell it to ignore certificate requirements
server = 'https://ef.engr.utk.edu/ef230/projects/roomba-f2016/install/';
dlgTitle = 'Roomba Install/Update';
% display purpose and get confirmation
prompt = {
'This program will download these EF 230 Roomba files:'
''
strjoin(files,' ')
''
'to this folder:'
''
cd
''
'Do you want to continue? '
};
beep;
yn = questdlg(prompt, ...
dlgTitle, ...
'Yes','No','Yes');
if ~strcmp(yn,'Yes'), return; end
% get list of files that exist
existing_files = files( cellfun(@exist,files) > 0 );
if ~isempty(existing_files)
% make sure it is really ok to replace them
prompt = {'You are replacing these file(s): '
''
strjoin(existing_files,' ')
''
'OK to replace?'
};
beep;
yn = questdlg(prompt, ...
dlgTitle, ...
'Yes','No','Yes');
if ~strcmp(yn,'Yes'), return; end
end
% download the files
cnt = 0;
for i=1:length(files)
f=files{i};
disp(['Downloading ' f]);
try
url = [server f];
websave(f,url,options); % added options to avoid security errors
cnt = cnt + 1;
catch
disp(['Error downloading ' f]);
dummy = [f '.html'];
if exist(dummy,'file')==2
delete(dummy)
end
end
end
if cnt == length(files)
msg = 'Installation Successful';
waitfor(msgbox(msg,dlgTitle));
else
msg = 'Installation Error - see command window for details';
waitfor(errordlg(msg,dlgTitle));
end
end %roombaInstall
Attachments
Step 3: Connect to Your Roomba
Now it is time to connect to your Roomba using WiFi. Using 2 fingers, press the Dock and Spot buttons simultaneously to turn on or reset your Roomba. Next, Run the code r=roomba(# of your Roomba) in the command window of MATLAB to connect to your robot. Once you have executed this command, your Roomba should be ready to go.
Step 4: Choose How You Want to Control Your Roomba
There are two ways that you can control your Roomba: autonomously or using a smartphone as a controller.
If you choose to drive the Roomba autonomously, you will need to use the three built-in sensors: cliff sensors, bump sensors, and light sensors.
In order to use a smartphone, you first need to connect your smartphone to your computer by following the steps below.
NOTE: Your computer and smartphone need to be on the same WiFi network in order to connect properly!
1. Download the MATLAB app from the app store on your device.
2. Type "connector on" into your command window and set a password that will need to be input into both devices.
3. After doing so, MATLAB will give you your computers IP address. You need to go into the settings page in the MATLAB app on your smartphone and add a computer using the given IP address and the password you entered earlier.
4. In the command window on your computer, type the code m=mobiledev and this should initialize your smartphone as a controller for your Roomba.
5. Your computer and smartphone should be ready to go now.
Step 5: Drive Your Roomba
Now that you have all of the necessary tools to create your Mars Rover, you are ready to create your own code. We have attached an example code below for both the autonomous driving and the smartphone-controlled driving.
Autonomous Driving
function Explore_modified(r)
%input arguments: 1 roomba object, r
%output arguments: none
%description:
%function utilizes an infinite while loop to allow autonomous
%exploration of the bot's surroundings.
%
%funciton also provides instructions to the roomba for what to do in
%the following situations: Wheel(s) lose(s) contact with the ground, an
%object is detected in front of or to either side of the bot, and a
%sudden drop is detected in front of or to either side of the bot.
%
%typical instructions include movement commands intended to maximize
%exploration or avoid a detected danger and commands to communicate
%information regarding the bots's discoveries(pictures), position (graph),
%and state (stranded warning)with the user via matlab and/or email. Several
%sound commands are added for enjoyment.
%setup email capabilities
mail = 'marsrovers59@gmail.com';
password = 'EF230Roomba';
setpref('Internet','SMTP_Server','smtp.gmail.com');
setpref('Internet','E_mail',mail);
setpref('Internet','SMTP_Username',mail);
setpref('Internet','SMTP_Password',password);
props = java.lang.System.getProperties;
props.setProperty('mail.smtp.starttls.enable','true');
props.setProperty('mail.smtp.auth','true');
props.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory');
props.setProperty('mail.smtp.socketFactory.port','465');
% r=roomba(19)
r.beep('G2^^,G2^^,G2^^,G2^^,A2^^,A2^^,G1^^,E1^^,C2^^,C2^^,C1^^,C1^^,D1^^,C1^^,D2^^,E4^^,G2^^,G2^^,G2^^,G2^^,A2^^,A2^^,G1^^,E1^^,C2^^,C2^^,C2^^,E1^^,E1^^,E1^^,D1^^,C4^^');
v = .1;
reflect_datum=2700; %set cliff sensors reference value
lightBumper_datum = 200; %set light Bumper sensors reference value
pos=[0,0]; %variable for position storage with datum initialized
angle=0; %set reference angle
netangle=0; %net angle displacement
i=2; %iterator for adding rows to position storage variable
dist = 0;
r.setDriveVelocity(v,v); %start roomba moving forward
while true
Cliff = r.getCliffSensors;
Bump = r.getBumpers;
Light = r.getLightBumpers;
RandAngle = randi([20,60],1); %generates 1 random angle between 20 and 60 degrees. Used to prevent bot from getting stuck in a loop
%What to do if one or more wheel loses contact with the ground:
%stop movement, send a warning email with picture of surroundings,
%and ask user whether to proceed or wait for help
if Bump.rightWheelDrop == 1 || Bump.leftWheelDrop == 1
r.stop
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
r.beep('F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^,F#1^^,C1^^')
img = r.getImage;
imwrite(img,'stuck.png');
%--------------------------
imfile='stuck.png';
position=savepos(pos);
%---------------------------
sendmail(mail,'HELP!','I am stranded on a cliff!',{imfile,position})
list = {'Continue', 'Stop'};
idx = menu('What should I do?',list);
if idx == 2
break
end
%What to do if an object is detected in front of bot:
%stop, move back, take picture, alert user of discovery
%via email, turn 90 degrees, and keep exploring
elseif Light.leftCenter > lightBumper_datum || Light.rightCenter > lightBumper_datum || Bump.front == 1
r.stop;
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
r.moveDistance(-.125);
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
r.beep('A1^,A1^,A4^,A2^,G2^,G2^,G4^,Bb2^,Bb2^,Bb3.5^,G1^,A8^')
img = r.getImage;
imwrite(img,'FrontBump.png')
%--------------------------
imfile='FrontBump.png';
position=savepos(pos);
%---------------------------
sendmail(mail,'Alert!','I found something!',{imfile,position})
angle = 90;
netangle=netangle+angle;
r.turnAngle(angle);
r.setDriveVelocity(v,v);
%What to do if object is detected to the left of bot:
%stop, turn towards object, back up, take picture, alert
%user of discovery via email, turn 90 degrees and keep exploring
elseif Light.leftFront > lightBumper_datum || Light.left > lightBumper_datum || Bump.left == 1
r.stop;
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
angle=30;
netangle=netangle+angle;
r.turnAngle(angle);
r.moveDistance(-.125);
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
r.beep('A4^,A4^,G1^,E1^,C3.5^,C2^^,C1^,C1^,C2^,D2^,D2^,E8^')
img = r.getImage;
imwrite(img,'LeftBump.png')
%--------------------------
imfile='LeftBump.png';
position=savepos(pos);
%---------------------------
sendmail(mail,'Alert!','I found something!',{imfile,position})
angle=-90;
netangle=netangle+angle;
r.turnAngle(angle);
r.setDriveVelocity(v,v);
%What to do if object is detected to the right of bot:
%stop, turn towards object, back up, take picture, alert
%user of discovery via email, turn 90 degrees and keep exploring
elseif Light.rightFront > lightBumper_datum || Light.right > lightBumper_datum || Bump.right == 1
r.stop;
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
angle=-30;
netangle=netangle+angle;
r.turnAngle(angle);
r.moveDistance(-.125);
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
pause(1.5);
r.beep('C1^,C1^,C2^,D2^,D2^,C8^')
img = r.getImage;
imwrite(img,'RightBump.png')
%--------------------------
imfile='RightBump.png';
position=savepos(pos);
%---------------------------
sendmail(mail,'Alert!','I found something!',{imfile,position});
angle=90;
netangle=netangle+angle;
r.turnAngle(angle);
r.setDriveVelocity(v,v);
%What to do if cliff is detected to the left of bot:
%stop, move backwards, turn right, continue exploring
elseif Cliff.left < reflect_datum || Cliff.leftFront < reflect_datum
r.stop;
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
r.moveDistance(-.125);
dist = r.getDistance;
pos(i,1)= pos(i-1,1) + dist * sind(netangle); %get x coordinate
pos(i,2)= pos(i-1,2) + dist * cosd(netangle); %get y coordinate
i=i+1;
angle=-RandAngle;
netangle=netangle+angle;
r.turnAngle(angle);
r.setDriveVelocity(v,v);
%What to do if cliff is detected to the right of bot:
%stop, move backwards, turn left, continue exploring
elseif Cliff.right < reflect_datum || Cliff.rightFront < reflect_datum
r.stop;
dist = r.getDistance;
pos(i,1)= dist * sind(angle); %get x coordinate
pos(i,2)= dist * cosd(angle); %get y coordinate
i=i+1;
r.moveDistance(-.125);
angle=RandAngle;
netangle=netangle+angle;
r.turnAngle(angle);
r.setDriveVelocity(v,v);
end
end
Smartphone Controller
Options = {'Autonomous','Manual Control'}
Prompt = menu('How would you like to control the rover?',Options)
m = mobiledev
r = roomba(19)
if Prompt == 1
Explore(r)
else
while true
pause(.5)
PhoneData=m.Orientation;
Azi=PhoneData(1);
Pitch=PhoneData(2);
Side=PhoneData(3);
if Side>130 || Side<-130 %if the phone is flipped face down stop the roomba and exit loop
r.stop
r.beep('C,C,C,C')
break
elseif Side>25 && Side<40 %if the phone is turned sideways between 25 and 40 deg turn left 5 deg
r.turnAngle(-5);
elseif Side>40 %if the phone is turned sideways over 40 deg turn left 45 deg
r.turnAngle(-45)
elseif Side<-25 && Side>-40 %if the phone is turned sideways between -25 and -40 deg turn right 5 deg
r.turnAngle(5);
elseif Side<-40 %if the phone is turned sideways less than -40 deg turn left 45 deg
r.turnAngle(45)
end
%If phone is held near verticle take an image and plot it
if Pitch<-60 && image<=9
r.beep
img=r.getImage;
subplot(3,3,image)
imshow(img)
end
%move forward and backward based on the front and back orientation
if Pitch>15 && Pitch<35 %if pitch between 15 and 35 deg move forward short distance
%get light bumper data before moving
litBump=r.getLightBumpers;
if litBump.leftFront>500 || litBump.leftCenter>500 || litBump.rightCenter>500 || litBump.rightFront>500 %if something is in front of the roomba and will hit if it moves forward make noise and display message
r.beep('C^^,F#^,C^^,F#^')
else %move
r.moveDistance(.03);
%Get bumper data after moving
Bump=r.getBumpers;
if Bump.right==1 || Bump.left==1 || Bump.front==1
r.beep('A,C,E')
r.moveDistance(-.01)
end
%get cliff sensor data
Cliff=r.getCliffSensors;
if Cliff.left>1500 || Cliff.leftFront>1500 || Cliff.rightFront>1500 || Cliff.right>1500 %if something triggers the cliff sensor treat it as lava and back up
r.beep('C^^,C,C^^,C,C^^,C,C^^,C,C^^,C,C^^,C')
r.moveDistance(-.031)
end
end
elseif Pitch>35 %if pitch greater 35 deg move forward longer distance
%get light bumper data before moving
litBump=r.getLightBumpers;
if litBump.leftFront>15 || litBump.leftCenter>15 || litBump.rightCenter>15 || litBump.rightFront>15 %if something is in front of the roomba and will hit if it moves forward make noise and display message
r.beep('C^^,F#^,C^^,F#^')
else %move
r.moveDistance(.3)
%Get bumper data after moving
Bump=r.getBumpers;
if Bump.right==1 || Bump.left==1 || Bump.front==1 %if you hit something make a noise, display message, and back up
r.beep('A,C,E')
r.moveDistance(-.01)
end
%get cliff sensor data after moving
Cliff=r.getCliffSensors;
if Cliff.left>1500 || Cliff.leftFront>1500 || Cliff.rightFront>1500 || Cliff.right>1500 %if something triggers the cliff sensor treat it as lava and back up
r.beep('C^^,C,C^^,C,C^^,C,C^^,C,C^^,C,C^^,C')
r.moveDistance(-.31)
end
end
elseif Pitch<-15 && Pitch>-35 %if pitch between -15 and -35 deg move back short distance
r.moveDistance(-.03);
%get cliff sensor data after moving
Cliff=r.getCliffSensors;
if Cliff.left>1500 || Cliff.leftFront>1500 || Cliff.rightFront>1500 || Cliff.right>1500 %if something triggers the cliff sensor treat it as lava and back up
r.beep('C^^,C,C^^,C,C^^,C,C^^,C,C^^,C,C^^,C')
r.moveDistance(.04)
end
elseif Pitch<-35 && Pitch>-60 %if pitch between -35 and -60 deg move back longer distance
r.moveDistance(-.3)
%get cliff sensor data after moving
Cliff=r.getCliffSensors;
if Cliff.left>1500 || Cliff.leftFront>1500 || Cliff.rightFront>1500 || Cliff.right>1500 %if something triggers the cliff sensor treat it as lava and back up
r.beep('C^^,C,C^^,C,C^^,C,C^^,C,C^^,C,C^^,C')
r.moveDistance(.31)
end
end
end
end