classdef mFinch < handle
% mFinch 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=mFinch(); % Connects to Finch so make sure your hardware is
% connected
%
% x=mFinch('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
properties (Access=private)
javaObj = [];
end
properties (Hidden=true)
chkp = true; % Checks parameters before every operation
hLightSensor = []; % Graphics handle to Light Sensor graph
hAccelerometer = [];% Graphics handle to Accelerometer graph
hTemperature = [];% Graphics handle to Temperature graph
end
%% Methods
methods
function obj = mFinch(varargin)
%MFINCH Constructor
% check nargin
if nargin==0
try
if isempty(regexp(javaclasspath,'finch.jar','once'))
javaaddpath finch.jar
end
%import edu.cmu.ri.createlab.terk.robot.finch.*
obj.javaObj = edu.cmu.ri.createlab.terk.robot.finch.Finch();
catch ME
error(['Was not able to find/load the finch.jar file. ',...
'Please make sure this file is located with the mFinch.m file']);
end
else
disp('Note: DEMO connection will be created');
disp('Do not pass anything to constructor to connect with the hardware.');
obj.javaObj = [];
obj.chkp = false; % Used to flag Simulation mode
end
end
function delete(obj)
% distructor, closes connection and deletes object
if obj.chkp
obj.javaObj.quit();
end
end
function disp(obj) % display
% disp, displays the object
if obj.chkp
disp('Connected to your Finch');
else
disp('Currently using Simulation mode');
end
mFinch.getMethods();
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(duration,{'numeric'},{'real','finite','scalar','nonnegative'},'buzz','duration',2);
if obj.chkp
obj.javaObj.buzz(freq,duration);
else
% Simulate the buzz sound from Finch
freqArray = sin(2*pi*(0:1/8192:duration/1000)*freq); %Expect duration to be in milliseconds
sound(freqArray);
end
end
function sleep(obj,val)
% 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);
if obj.chkp
obj.javaObj.sleep(val);
else
pause(val/1000); % They should pass value in milliseconds
end
end
function playClip(obj,str)
% playClip(String fileLocation)
% Plays a wav file over computer speakers at the specificied fileLocation path.
[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)
% 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 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 saySomething(obj,str,rep)
% 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.
if obj.chkp
obj.javaObj.stopWheels();
end
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);
if obj.chkp
%setWheelVelocities(leftWheel,rightWheel,[lengthTime in msec])
if exist('duration','var')
validateattributes(duration,{'numeric'},{'real','finite','scalar','nonnegative'},'setWheelVelocities','timeToHold',3);
obj.javaObj.setWheelVelocities(leftWheel,rightWheel,duration);
else
obj.javaObj.setWheelVelocities(leftWheel,rightWheel);
end
end
end
%% GET VALUE
function [Rval,Lvar]=getObstacleSensors(obj)
% [R,L] = getObstacleSensors()
% Returns the value of both obstacle sensors.
if obj.chkp
valArray = obj.javaObj.getObstacleSensors();
Rval = double(valArray(1));
Lval = double(valArray(2));
else
Rval = round(rand(1));
Lval = round(rand(1));
end
end
function val = getTemperature(obj)
% getTemperature()
% The current temperature reading at the temperature probe.
if obj.chkp
val = double(obj.javaObj.getTemperature());
else
val = rand(1)*100;
end
end
function valArray = getAccelerations(obj)
% val = getAccelerations()
% Use this method to simultaneously return the current X, Y, and Z accelerations experienced by the robot.
if obj.chkp
valArray = double(obj.javaObj.getAccelerations());
else
valArray = rand(3,1);
end
end
function val = getXAcceleration(obj)
% val = getXAcceleration()
% This method returns the current X-axis acceleration value experienced by the robot.
if obj.chkp
val = double(obj.javaObj.getXAcceleration());
else
val = rand(1);
end
end
function val = getYAcceleration(obj)
% val = getYAcceleration()
% This method returns the current Y-axis acceleration value experienced by the robot.
if obj.chkp
val = double(obj.javaObj.getYAcceleration());
else
val = rand(1);
end
end
function val = getZAcceleration(obj)
% val = getZAcceleration()
% This method returns the current Z-axis acceleration value experienced by the robot.
if obj.chkp
val = double(obj.javaObj.getZAcceleration());
else
val = rand(1);
end
end
function valArray = getLightSensors(obj)
% getLightSensors()
% Returns a 2 integer array containing the current values of both light sensors.
if obj.chkp
valArray = double(obj.javaObj.getLightSensors());
else
valArray = rand(2,1);
end
end
function val = getRightLightSensor(obj)
% getRightLightSensor()
% Returns the value of the right light sensor
if obj.chkp
val = double(obj.javaObj.getRightLightSensor());
else
val = rand(1);
end
end
function val = getLeftLightSensor(obj)
% getLeftLightSensor()
% Returns the value of the left light sensor
if obj.chkp
val = double(obj.javaObj.getLeftLightSensor());
else
val = rand(1);
end
end
%% SET
function setLED(obj, red,green,blue,duration)
%SETLED(RGB Color Value)
%
% setLED(int red, int green, int blue)
% Sets the color of the LED in the Finch's beak
%
% setLED(int red, int green, int blue, int duration)
% Sets the color of the LED in the Finch's beak for the length of time specified by duration.
validateattributes(red,{'numeric'},{'scalar','nonnegative','<=',255},'setLED','red',1);
validateattributes(green,{'numeric'},{'scalar','nonnegative','<=',255},'setLED','green',2);
validateattributes(blue,{'numeric'},{'scalar','nonnegative','<=',255},'setLED','blue',3);
if obj.chkp
if exist('duration','var')
validateattributes(red,{'numeric'},{'real','finite','scalar','nonnegative'},'setLED','duration',3);
obj.javaObj.setLED(red,green,blue,duration);
else
obj.javaObj.setLED(red,green,blue);
end
end
end
%% IS functions
function val = isFinchUpsideDown(obj)
% isFinchUpsideDown()
% This method returns true if the Finch is upside down, false otherwise
if obj.chkp
val = boolean(obj.javaObj.isFinchUpsideDown());
else
val = round(rand(1));
end
end
function val = isLeftWingDown(obj)
% isLeftWingDown()
% This method returns true if the Finch's left wing is pointed
% at the ground
if obj.chkp
val = boolean(obj.javaObj.isLeftWingDown());
else
val = round(rand(1));
end
end
function val = isRightWingDown(obj)
% isRightWingDown()
% This method returns true if the Finch's right wing is pointed at the ground
if obj.chkp
val = boolean(obj.javaObj.isRightWingDown());
else
val = round(rand(1));
end
end
function val = isFinchLevel(obj)
% isFinchLevel()
% This method returns true if the Finch is on a flat surface
if obj.chkp
val = boolean(obj.javaObj.isFinchLevel());
else
val = boolean(round(rand(1)));
end
end
function val = isTemperature(obj,val)
% isTemperature(double limit)
% Returns true if the temperature is greater than the value specified by limit, false otherwise.
if obj.chkp
val = boolean(obj.javaObj.isTemperature(val));
else
t = obj.getTemperature();
val = (t>=val);
end
end
function val = isLeftLightSensor(obj,sensorVal)
% isLeftLightSensor(int limit)
% Returns true if the left light sensor is great than the value specified by limit, false otherwise.
if obj.chkp
val = boolean(obj.javaObj.isLeftLightSensor(sensorVal));
else
val = boolean(round(rand(1)));
end
end
function val = isRightLightSensor(obj,sensorVal)
% val = isRightLightSensor(int limit)
% Returns true if the right light sensor is greater than the value specified by limit, false otherwise.
if obj.chkp
val = boolean(obj.javaObj.isRightLightSensor(sensorVal));
else
val = boolean(round(rand(1)));
end
end
function val = isObstacle(obj)
% val = isObstacle()
% Returns true if either left or right obstacle sensor detect an obstacle.
if obj.chkp
val = boolean(obj.javaObj.isObstacle());
else
val = boolean(round(rand(1)));
end
end
function val = isObstacleLeftSide(obj)
% isObstacleLeftSide()
% Returns true if there is an obstruction in front of the left side of the robot.
if obj.chkp
val = boolean(obj.javaObj.isObstacleLeftSide());
else
val = boolean(round(rand(1)));
end
end
function val = isObstacleRightSide(obj)
% isObstacleRightSide()
% Returns true if there is an obstruction in front of the right side of the robot.
if obj.chkp
val = boolean(obj.javaObj.isObstacleRightSide());
else
val = boolean(round(rand(1)));
end
end
function val = isBeakDown(obj)
% val = isBeakDown()
% This method returns true if the beak is pointed at the floor,
% false otherwise
if obj.chkp
val = boolean(obj.javaObj.isBreakDown());
else
val = boolean(round(rand(1)));
end
end
function val = isBeakUp(obj)
% val = isBeakUp()
% This method returns true if the beak is up (Finch sitting on its tail), false otherwise
if obj.chkp
val = boolean(obj.javaObj.isBreakUp());
else
val = boolean(round(rand(1)));
end
end
function val = isShaken(obj)
% val = isShaken()
% Returns true if the Finch has been shaken since the last accelerometer read
if obj.chkp
val = boolean(obj.javaObj.isShaken());
else
val = boolean(round(rand(1)));
end
end
function val = isTapped(obj)
% val = isTapped()
% Returns true if the Finch has been tapped since the last accelerometer read
if obj.chkp
val = boolean(obj.javaObj.isTapped());
else
val = boolean(round(rand(1)));
end
end
%% GRAPHICS
function showLightSensorGraph(obj)
% showLightSensorGraph()
% Displays a graph of the left and right light sensor values.
[val]=obj.getLightSensors();
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);
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.
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.getTemperature();
obj.hTemperature=plot(1,t);
xlabel(get(obj.hTemperature,'parent'),'Reading');
ylabel(get(obj.hTemperature,'parent'),'Temperature');
set(obj.hTemperature,'LineWidth',2);
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.getAccelerations();
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);
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)
%% nicely formatted methods list with help links
function getMethods()
% mFinch.getMethods()
% Prints a nicely formatted list of Finch Robot's methods with links
% to their relevant help dialogs.
fprintf('\nMethods for mFinch Robot\n');
fprintf(' <a href="matlab:help mFinch.mFinch">mFinch()</a>\n');
fprintf(' <a href="matlab:help mFinch.delete">delete()</a>\n');
fprintf(' <a href="matlab:help mFinch.quit">quit()</a>\n');
fprintf('\nUtilities\n');
fprintf(' <a href="matlab:help mFinch.buzz">buzz(frequency,timeDuration)</a>\n');
fprintf(' <a href="matlab:help mFinch.playClip">playClip(wavFile)</a>\n');
fprintf(' <a href="matlab:help mFinch.playTone">playTone(frequency,timeDuration)</a>\n');
fprintf(' <a href="matlab:help mFinch.sleep">sleep(timeDuration)</a>\n');
fprintf(' <a href="matlab:help mFinch.saySomething">saySomething(text)</a>\n');
fprintf('\nMotor Control\n');
fprintf(' <a href="matlab:help mFinch.stopWheels">stopWheels()</a>\n');
fprintf(' <a href="matlab:help mFinch.setWheelVelocities">setWheelVelocities(LeftVelocity,RightVelocity,timeDuration)</a>\n');
fprintf('\nSet LED\n');
fprintf(' <a href="matlab:help mFinch.setLED">setLED(obj, red,green,blue,duration)</a>\n');
fprintf('\nGet Sensor Data\n');
fprintf(' <a href="matlab:help mFinch.getObstacleSensors">[R,L]=getObstacleSensors()</a>\n');
fprintf(' <a href="matlab:help mFinch.getTemperature">temp = getTemperature()</a>\n');
fprintf(' <a href="matlab:help mFinch.getAccelerations">varArray = getAccelerations()</a>\n');
fprintf(' <a href="matlab:help mFinch.getAccelerations">varArray = getAccelerations()</a>\n');
fprintf(' <a href="matlab:help mFinch.getXAccelerations">var = getXAccelerations()</a>\n');
fprintf(' <a href="matlab:help mFinch.getYAccelerations">var = getYAccelerations()</a>\n');
fprintf(' <a href="matlab:help mFinch.getZAccelerations">var = getZAccelerations()</a>\n');
fprintf(' <a href="matlab:help mFinch.getLightSensors">varArray = getLightSensors()</a>\n');
fprintf(' <a href="matlab:help mFinch.getRightLightSensors">var = getRightLightSensors()</a>\n');
fprintf(' <a href="matlab:help mFinch.getLeftLightSensors">var = getLeftLightSensors()</a>\n');
fprintf('\nBoolean Tests\n');
fprintf(' <a href="matlab:help mFinch.isFinchUpsideDown">boolean = isFinchUpsideDown()</a>\n');
fprintf(' <a href="matlab:help mFinch.isLeftWingDown">boolean = isLeftWingDown()</a>\n');
fprintf(' <a href="matlab:help mFinch.isRightWingDown">boolean = isRightWingDown()</a>\n');
fprintf(' <a href="matlab:help mFinch.isFinchLevel">boolean = isFinchLevel()</a>\n');
fprintf(' <a href="matlab:help mFinch.isTemperature">boolean = isTemperature(testVal)</a>\n');
fprintf(' <a href="matlab:help mFinch.isLeftLightSensor">boolean = isLeftLightSensor(testVal)</a>\n');
fprintf(' <a href="matlab:help mFinch.isRightLightSensor">boolean = isRightLightSensor(testVal)</a>\n');
fprintf(' <a href="matlab:help mFinch.isObstacle">boolean = isObstacle()</a>\n');
fprintf(' <a href="matlab:help mFinch.isObstacleLeftSide">boolean = isObstacleLeftSide()</a>\n');
fprintf(' <a href="matlab:help mFinch.isObstacleRightSide">boolean = isObstacleRightSide()</a>\n');
fprintf(' <a href="matlab:help mFinch.isBeakDown">boolean = isBeakDown()</a>\n');
fprintf(' <a href="matlab:help mFinch.isBeakUp">boolean = isBeakUp()</a>\n');
fprintf(' <a href="matlab:help mFinch.isShaken">boolean = isShaken()</a>\n');
fprintf(' <a href="matlab:help mFinch.isTapped">boolean = isTapped()</a>\n');
fprintf('\nGraphics\n');
fprintf(' <a href="matlab:help mFinch.showLightSensorGraph">showLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.updateLightSensorGraph">updateLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.closeLightSensorGraph">closeLightSensorGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.showTemperatureGraph">showTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.updateTemperatureGraph">updateTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.closeTemperatureGraph">closeTemperatureGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.showAccelerometerGraph">showAccelerometerGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.updateAccelerometerGraph">updateAccelerometerGraph()</a>\n');
fprintf(' <a href="matlab:help mFinch.closeAccelerometerGraph">closeAccelerometerGraph()</a>\n');
fprintf('\n');
end
end
end