classdef Finch < handle
% Finch MATLAB Class for your Finch Robot that is consistent with the
% Java interface, but uses MATLAB plots for the graphics and has a simulation mode.
%
% Please visit http://www.finchrobot.com for more information about
% the Finch Robot teaching platform.
%
% Usage:
% x=Finch(); % Connects to Finch so make sure your hardware is
% connected
%
% x=Finch('test'); % Creates Finch object using simulation. This
% allows you to run your code even if you don't have a Finch
% connected. Simulated sensor output returns random data.
% MATLAB Support Package for Finch Robot
% Version 1.0
% Copyright 2011 The MathWorks, Inc.
%%
% See getting started guide in pdf <./gettingStarted.pdf here>
% or in html <./gettingStarted.html here>
properties (Hidden=true)
finchObj = []; % Object for underline communication to Finch Robot
hLightSensor = []; % Graphics handle to Light Sensor graph
hAccelerometer = [];% Graphics handle to Accelerometer graph
hTemperature = [];% Graphics handle to Temperature graph
end
properties (SetAccess = private, GetAccess = public, Dependent = true)
obstacleSensors
temperature
accelerations
lightSensors
end
%% Methods
methods
function obj = Finch(varargin)
%Finch Constructor
% check nargin for simulation mode or not
if nargin==0
% Connect to hardware
obj.finchObj = finchComm();
else
% Run in simulation mode
obj.finchObj = finchComm(varargin);
end
end
function delete(obj)
% distructor, closes connection and deletes object
delete(obj.finchObj);
obj.finchObj = [];
end
function disp(obj) % display
% disp, displays the object
if ~isvalid(obj)
disp('Connection close')
else
obj.finchObj.disp();
Finch.getMethods();
end
end
%% UTILITIES
function buzz(obj,freq,duration)
% buzz(frequency, duration)
% Plays a tone at the specified frequency for the specified
% duration in milliseconds on the Finch's internal buzzer.
% Error checking on passed parameters
validateattributes(freq,{'numeric'},{'real','scalar','<',8192,'>',100},'buzz','frequency',1);
validateattributes(freq,{'numeric'},{'real','finite','scalar','nonnegative'},'buzz','duration',2);
obj.finchObj.buzz(freq,duration);
end
function sleep(obj,val) %#ok
% sleep(duration)
% This method uses Thread.sleep to cause the currently running
% program to sleep for the specified number of milliseconds.
validateattributes(val,{'numeric'},{'real','finite','scalar','nonnegative'},'sleep','time',1);
pause(val/1000); % They should pass value in milliseconds
end
function quit(obj)
% quit()
% This method properly closes the connection with the Finch and
% resets the Finch so that it is immediately ready to be
% controlled by subsequent programs. It also calls the
% destrutor on the object
delete(obj);
end
function playClip(obj,str) %#ok
% playClip(String fileLocation)
% Plays a wav file over computer speakers at the specificied fileLocation path.
validateattributes(str,{'string'},{},'playClip','Wave file name',1);
if ~exist(str,'file')
error('Please pass in a valid wave file');
end
[y,fs,nbits]=wavread(str); %%TODO need to make sure the file exists and is a .wav file
sound(y,fs,nbits);
end
function playTone(obj,frequency,duration,c) %#ok
% playTone(frequency, duration)
% Plays a tone over the computer speakers or headphones at a given frequency (in Hertz) for a specified duration in milliseconds
%
% playTone(int frequency, int volume, int duration)
% Plays a tone over the computer speakers or headphones at a given frequency (in Hertz) for a specified duration in milliseconds at a specified volume
validateattributes(frequency,{'numeric'},{'real','scalar','<',8192,'>',100},'playTone','frequency',1);
if exist('c','var')
validateattributes(c,{'numeric'},{'real','finite','scalar','nonnegative'},'playTone','duration',2);
freqArray = sin(2*pi*(0:1/8192:c*1000)*frequency)*duration;
else
validateattributes(duration,{'numeric'},{'real','finite','scalar','nonnegative'},'playTone','duration',2);
freqArray = sin(2*pi*(0:1/8192:duration*1000)*frequency);
end
sound(freqArray);
end
function saySomething(obj,str,rep)
% Not Implemented yet
% saySomething(String sayThis)
% Takes the text of 'sayThis' and synthesizes it into a sound file and plays the sound file over computer speakers.
%
% saySomething(String sayThis, int duration)
% Takes the text of 'sayThis' and synthesizes it into a sound file and plays the sound file over computer speakers.
%%TODO Check for valid input
% if obj.chkp
% if exist('rep','var')
% obj.javaObj.saySomething(str,rep);
% else
% obj.javaObj.saySomething(str);
% end
% else
% %%TODO Add speach on Windows using .NET interface to speach
% end
end
%% MOTOR CONTROL
function stopWheels(obj)
% stopWheels()
% Stops both wheels.
obj.finchObj.stop();
end
function setWheelVelocities(obj,leftWheel,rightWheel,duration)
% setWheelVelocities(int leftVelocity, int rightVelocity)
% This method simultaneously sets the velocities of both wheels.
%
% setWheelVelocities(int leftVelocity, int rightVelocity, int timeToHold)
% This method simultaneously sets the velocities of both wheels.
validateattributes(leftWheel,{'numeric'},{'real','finite','scalar','<=',255,'>=',-255},'setWheelVelocities','LeftVelocity',1);
validateattributes(rightWheel,{'numeric'},{'real','finite','scalar','<=',255,'>=',-255},'setWheelVelocities','RightVelocity',2);
%setWheelVelocities(leftWheel,rightWheel,[lengthTime in msec])
if exist('duration','var')
validateattributes(duration,{'numeric'},{'real','finite','scalar','nonnegative'},'setWheelVelocities','timeToHold',3);
obj.finchObj.motor(leftWheel,rightWheel,duration);
else
obj.finchObj.motor(leftWheel,rightWheel);
end
end
%% GET VALUE
function valArray=get.obstacleSensors(obj)
% valArray = getObstacleSensors()
% Returns the value of both obstacle sensors.
valArray = obj.finchObj.obstacleSensors();
end
function val = get.temperature(obj)
% val = getTemperature()
% The current temperature reading at the temperature probe.
val = obj.finchObj.temperature();
end
function valArray = get.accelerations(obj)
% val = getAccelerations()
% Use this method to simultaneously return the current X, Y, and Z accelerations experienced by the robot.
valArray = obj.finchObj.accelerometer();
end
function valArray = get.lightSensors(obj)
% getLightSensors()
% Returns a 2 integer array containing the current values of both light sensors.
valArray = obj.finchObj.lightSensors();
end
%% SET
function setLED(obj, ledColor, duration)
%SETLED(RGB Color Value Triplet)
%
% setLED([red, green, blue])
% Sets the color of the LED in the Finch's beak
%
validateattributes(ledColor,{'numeric'},{'2d','nonnegative','<=',255},'setLED');
if exist('duration','var')
validateattributes(duration,{'numeric'},{'scalar','nonnegative','<=',255},'setLED');
obj.finchObj.led(ledColor(1),ledColor(2),ledColor(3),duration);
else
obj.finchObj.led(ledColor(1),ledColor(2),ledColor(3));
end
end
%% IS functions
function val = isFinchUpsideDown(obj)
% isFinchUpsideDown()
% This method returns true if the Finch is upside down, false otherwise
accVal = obj.accelerations;
% Check to see if z acceleration is negative or not
if accVal(3)>0
val = true;
else
val = false;
end
end
function val = isLeftWingDown(obj)
% isLeftWingDown()
% This method returns true if the Finch's left wing is pointed
% at the ground
accVal = obj.accelerations;
% Check to see if z acceleration is negative or not
if accVal(3)<0 && accVal(2)>0
val = true;
else
val = false;
end
end
function val = isRightWingDown(obj)
% isRightWingDown()
% This method returns true if the Finch's right wing is pointed at the ground
accVal = obj.accelerations;
% Check to see if z acceleration is negative or not
if accVal(3)<0 && accVal(2)<0
val = true;
else
val = false;
end
end
function val = isFinchLevel(obj)
% isFinchLevel()
% This method returns true if the Finch is on a flat surface
accVal = obj.accelerations;
% Check to see if x,y acceleration are close to zero all Acc is
% down
if accVal(1)<5 && accVal(2)<5
val = true;
else
val = false;
end
end
function val = isBeakDown(obj)
% val = isBeakDown()
% This method returns true if the beak is pointed at the floor,
% false otherwise
accVal = obj.accelerations;
% Check to see if x acceleration is negative
if accVal(1)<0
val = true;
else
val = false;
end
end
function val = isBeakUp(obj)
% val = isBeakUp()
% This method returns true if the beak is up (Finch sitting on its tail), false otherwise
accVal = obj.accelerations;
% Check to see if x acceleration is positive
if accVal(1)>0
val = true;
else
val = false;
end
end
function val = isShaken(obj)
% Not Implimented yet
% val = isShaken()
% Returns true if the Finch has been shaken since the last accelerometer read
accVal = obj.accelerations;
% Check to see if x acceleration is negative
if accVal(3)>0
val = true;
else
val = false;
end
end
function val = isTapped(obj)
% Not Implimented Yet
% val = isTapped()
% Returns true if the Finch has been tapped since the last accelerometer read
accVal = obj.accelerations;
% Check to see if x acceleration is negative
if accVal(3)>0
val = true;
else
val = false;
end
end
function val = isTemperature(obj,val)
% isTemperature(limit)
% Returns true if the temperature is greater than the value specified by limit, false otherwise.
tempVal = obj.temperature;
if tempVal<val
val = true;
else
val = false;
end
end
function val = isLeftLightSensor(obj,sensorVal)
% isLeftLightSensor(limit)
% Returns true if the left light sensor is great than the value specified by limit, false otherwise.
lightVal = obj.lightSensors;
if lightVal(2)<sensorVal
val = true;
else
val = false;
end
end
function val = isRightLightSensor(obj,sensorVal)
% val = isRightLightSensor(limit)
% Returns true if the right light sensor is greater than the value specified by limit, false otherwise.
lightVal = obj.lightSensors;
if lightVal(1)<sensorVal
val = true;
else
val = false;
end
end
function val = isObstacle(obj)
% val = isObstacle()
% Returns true if either left or right obstacle sensor detect an obstacle.
obstVal = obj.obstacleSensors;
val = obstVal(1)||obstVal(2);
end
function val = isObstacleLeftSide(obj)
% isObstacleLeftSide()
% Returns true if there is an obstruction in front of the left side of the robot.
obstVal = obj.obstacleSensors;
val = obstVal(1);
end
function val = isObstacleRightSide(obj)
% isObstacleRightSide()
% Returns true if there is an obstruction in front of the right side of the robot.
obstVal = obj.obstacleSensors;
val = obstVal(2);
end
%% GRAPHICS
function showLightSensorGraph(obj)
% showLightSensorGraph()
% Displays a graph of the left and right light sensor values.
val=obj.lightSensors;
obj.hLightSensor=plot(1,[val(1);val(2)]);
xlabel(get(obj.hLightSensor(1),'parent'),'Reading');
ylabel(get(obj.hLightSensor(1),'parent'),'Value');
set(obj.hLightSensor(1),'LineWidth',2);
set(obj.hLightSensor(2),'LineWidth',2);
title(['Light Sensor Graph:',obj.finchObj.disp]);
drawnow;
end
function updateLightSensorGraph(obj,a,b)
% updateLightSensorGraph(int leftSensor, int rightSensor)
% Updates the light sensor graph with the left and right light sensor data.
% Just in case people send the return value from property which
% has both values in a single variable do the right thing.
if nargin==2
b = a(2);
end
if ishandle(obj.hLightSensor(1))
xData = get(obj.hLightSensor(1),'xdata');
yData = get(obj.hLightSensor(1),'ydata');
set(obj.hLightSensor(1),'XData',[xData,xData(end)+1],'YData',[yData,a]);
yData = get(obj.hLightSensor(2),'ydata');
set(obj.hLightSensor(2),'XData',[xData,xData(end)+1],'YData',[yData,b]);
drawnow;
else
error('Plot closed');
end
end
function closeLightSensorGraph(obj)
% closeLightSensorGraph()
% Closes the opened Light sensor Graph
if ishandle(obj.hLightSensor(1))
close(get(get(obj.hLightSensor(1),'parent'),'parent'));
end
obj.hLightSensor = [];
end
function showTemperatureGraph(obj)
% showTemperatureGraph()
% Displays a graph of the temperature value
t=obj.temperature;
obj.hTemperature=plot(1,t);
xlabel(get(obj.hTemperature,'parent'),'Reading');
ylabel(get(obj.hTemperature,'parent'),'Temperature');
set(obj.hTemperature,'LineWidth',2);
title(['Temperature Sensor Graph:',obj.finchObj.disp]);
drawnow;
end
function updateTemperatureGraph(obj,val)
% updateTemperatureGraph(double temp)
% Updates the temperature graph with the most recent temperature data
if ishandle(obj.hTemperature)
xData = get(obj.hTemperature,'xdata');
yData = get(obj.hTemperature,'ydata');
set(obj.hTemperature,'XData',[xData,xData(end)+1],'YData',[yData,val]);
drawnow;
else
error('Plot closed');
end
end
function closeTemperatureGraph(obj)
% closeTemperatureGraph()
% Closes the opened temperature Graph
if ishandle(obj.hTemperature)
close(get(get(obj.hTemperature,'parent'),'parent'));
end
obj.hTemperature = [];
end
function showAccelerometerGraph(obj)
% showAccelerometerGraph()
% Displays a graph of the X, Y, and Z accelerometer values.
val = obj.accelerations;
obj.hAccelerometer=plot3([0,val(1)],[0,val(2)],[0,val(3)]);
xlabel(get(obj.hAccelerometer,'parent'),'X - Accelerometer');
ylabel(get(obj.hAccelerometer,'parent'),'Y - Accelerometer');
zlabel(get(obj.hAccelerometer,'parent'),'Z - Accelerometer');
set(obj.hAccelerometer,'LineWidth',2);
title(['Accelerometer Sensor Graph:',obj.finchObj.disp]);
drawnow;
end
function updateAccelerometerGraph(obj,a,b,c)
% updateAccelerometerGraph(double xVal, double yVal, double zVal)
% updates the accelerometer graph with accelerometer data specified by xVal, yVal, and zVal.
if ishandle(obj.hAccelerometer)
if nargin~=4
set(obj.hAccelerometer,'XData',[0,a(1)],'YData',[0,a(2)],'ZData',[0,a(3)]);
else
set(obj.hAccelerometer,'XData',[0,a],'YData',[0,b],'ZData',[0,c]);
end
drawnow;
else
error('Plot closed');
end
end
function closeAccelerometerGraph(obj)
% closeAccelerometerGraph()
% Closes the opened Accelerometer Graph
if ishandle(obj.hAccelerometer)
close(get(get(obj.hAccelerometer,'parent'),'parent'));
end
obj.hAccelerometer = [];
end
end
%% static methods
methods(Static)
% Methods available to users without create object
%
function getMethods()
% Finch.getMethods()
% Prints a nicely formatted list of Finch Robot's methods with links
% to their relevant help dialogs.
fprintf('\nMethods for Finch Robot\n');
fprintf(' <a href="matlab:help Finch.Finch">Finch()</a>\n');
fprintf(' <a href="matlab:help Finch.delete">delete()</a>\n');
fprintf(' <a href="matlab:help Finch.quit">quit()</a>\n');
fprintf('\nUtilities\n');
fprintf(' <a href="matlab:help Finch.buzz">buzz(frequency,timeDuration)</a>\n');
fprintf(' <a href="matlab:help Finch.playClip">playClip(wavFile)</a>\n');
fprintf(' <a href="matlab:help Finch.playTone">playTone(frequency,timeDuration)</a>\n');
fprintf(' <a href="matlab:help Finch.sleep">sleep(timeDuration)</a>\n');
% fprintf(' <a href="matlab:help Finch.saySomething">saySomething(text)</a>\n');
fprintf('\nMotor Control\n');
fprintf(' <a href="matlab:help Finch.stopWheels">stopWheels()</a>\n');
fprintf(' <a href="matlab:help Finch.setWheelVelocities">setWheelVelocities(LeftVelocity,RightVelocity,timeDuration)</a>\n');
fprintf('\nSet LED\n');
fprintf(' <a href="matlab:help Finch.setLED">setLED(obj, [red,green,blue],duration)</a>\n');
fprintf('\nGet Sensor Data\n');
fprintf(' <a href="matlab:help Finch.obstacleSensors">varArray(R,L)=obstacleSensors()</a>\n');
fprintf(' <a href="matlab:help Finch.temperature">temp = temperature()</a>\n');
fprintf(' <a href="matlab:help Finch.accelerations">varArray(x,y,z) = accelerations()</a>\n');
fprintf(' <a href="matlab:help Finch.lightSensors">varArray(R,L) = lightSensors()</a>\n');
fprintf('\nBoolean Tests\n');
fprintf(' <a href="matlab:help Finch.isFinchUpsideDown">boolean = isFinchUpsideDown()</a>\n');
fprintf(' <a href="matlab:help Finch.isLeftWingDown">boolean = isLeftWingDown()</a>\n');
fprintf(' <a href="matlab:help Finch.isRightWingDown">boolean = isRightWingDown()</a>\n');
fprintf(' <a href="matlab:help Finch.isFinchLevel">boolean = isFinchLevel()</a>\n');
fprintf(' <a href="matlab:help Finch.isTemperature">boolean = isTemperature(testVal)</a>\n');
fprintf(' <a href="matlab:help Finch.isLeftLightSensor">boolean = isLeftLightSensor(testVal)</a>\n');
fprintf(' <a href="matlab:help Finch.isRightLightSensor">boolean = isRightLightSensor(testVal)</a>\n');
fprintf(' <a href="matlab:help Finch.isObstacle">boolean = isObstacle()</a>\n');
fprintf(' <a href="matlab:help Finch.isObstacleLeftSide">boolean = isObstacleLeftSide()</a>\n');
fprintf(' <a href="matlab:help Finch.isObstacleRightSide">boolean = isObstacleRightSide()</a>\n');
fprintf(' <a href="matlab:help Finch.isBeakDown">boolean = isBeakDown()</a>\n');
fprintf(' <a href="matlab:help Finch.isBeakUp">boolean = isBeakUp()</a>\n');
% fprintf(' <a href="matlab:help Finch.isShaken">boolean = isShaken()</a>\n');
% fprintf(' <a href="matlab:help Finch.isTapped">boolean = isTapped()</a>\n');
fprintf('\nGraphics\n');
fprintf(' <a href="matlab:help Finch.showLightSensorGraph">showLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.updateLightSensorGraph">updateLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.closeLightSensorGraph">closeLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.showTemperatureGraph">showTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.updateTemperatureGraph">updateTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.closeTemperatureGraph">closeTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.showAccelerometerGraph">showAccelerometerGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.updateAccelerometerGraph">updateAccelerometerGraph()</a>\n');
fprintf(' <a href="matlab:help Finch.closeAccelerometerGraph">closeAccelerometerGraph()</a>\n');
fprintf('\n');
end
function setup()
% Walk users through getting and installing connectivity code
finchComm.setup();
end
end
end