Introduction: Reading RPM From Arduino-based IR Tachometer With MATLAB GUI

Hello again, a couple days back I posted an instructable of infrared tachometer using arduino, then I realized that rather than reading the RPM value in the Arduino IDE serial monitor, presenting the RPM in a proper frame would look more hi-tech. So, I tried to make a small program with MATLAB GUI.

I know I can merge this project with my previous instructable, but I prefer to make a new one because maybe some people have already done their sensing and sending the data to the serial and only want to see how to make MATLAB retrieve and show that value sent through serial. Of course, this way I can have more instructables also :)

Therefore, I will just go directly to the MATLAB part because that is the main thing we are going to discuss here. Anything else beyond your computer's USB port please refer to my previous instructable: https://www.instructables.com/id/Infrared-Tachomete...

Step 1: Create GUI Layout in MATLAB

Open your MATLAB, then in type a command: "guide"

If everything is OK, a window will open for you to design the layout. If you cannot get that window, please check of you have that module in your MATLAB installation or not. My MATLAB version is R2012b installed with default settings & packages.

Let us assume that you get something good after typing "guide". Place window components as follows:

- 1 Toggle button

- 2 Static Texts

Arrange the layout as shown in the picture (actually the layout is up to you, as long as it is easy to use and read), change the text (anything you wish) in each object by modifying the "String" value in the Property Inspector (select object - right click - Property Inspector, or double click)

Then, save that gui fig file.

Step 2: Write the Code

ARDUINO CODE

The code for arduino is basically the same as you can find here: https://www.instructables.com/id/Infrared-Tachomete... but because here I only want to show the rpm value (not the rps value and all the "rps" and "rpm" text) so I edited some lines (those that have Serial.print(), because previously the program was designed to present the reading on notepad-style serial monitor but now we only need the rpm value to feed into the static text string). OK, to make it quick and easy I copy the code here, you can check by your self for comparison with the previous code. Remember that the main purpose of the arduino code is only to pass a value to serial comm, so this program is just as an example, if you have your own program that prints the value of any sensor reading to serial then ignore this go ahead to the MATLAB code.

int sensorvalue;<br>int state1 = HIGH;
int state2;
float rps;
float rpm;
long prevMillis = 0;
long interval = 100;
long currentTime;
long prevTime = 1;
long diffTime;
int sensorthreshold = 30;  // this value indicates the limit reading between dark and light,
                           // it has to be tested as it may change acording on the 
                           // distance the leds are placed.
                           // to see what number is good, check the sensorvalue variable value
                           // as printed out in the serial monitor</p><p>void setup()
{
  Serial.begin(9600);
  pinMode(13,OUTPUT);      // assign pin 13 led as indicator because we cannot se the IR light
}

void loop()
{
  sensorvalue = analogRead(0); // read from pin 0
  if(sensorvalue < sensorthreshold)
    state1 = HIGH;
   else
    state1 = LOW;
   digitalWrite(13,state1); // as iR light is invisible for us, the led on pin 13 
                            // indicate the state of the circuit.

   if(state2!=state1){      //counts when the state change, thats from (dark to light) or 
                            //from (light to dark), remember that IR light is invisible for us.
     if (state2>state1){
       currentTime = micros();   // Get the arduino time in microseconds
       diffTime = currentTime - prevTime;  // calculate the time difference from the last sensors meet-up
       rps = 1000000/diffTime;   // calculate how many rev per second - good to know
       rpm = 60000000/diffTime;  // calculate how many rev per minute
       
       unsigned long currentMillis = millis();
       
       // print to serial at every interval - defined at the variables declaration
       if(currentMillis - prevMillis > interval){ // see if now already an interval long
       prevMillis = currentMillis;       
       Serial.println(rpm); // this line is edited from the code in the prev instructable
       }
       
       prevTime = currentTime;
     }
     state2 = state1;
   }
 /* only for testing to determine the sensorthreshold value
 delay(500);
 Serial.println(sensorvalue);
 */

}

MATLAB CODE

In your MATLAB GUI layout design window, click View - Editor (or find in the toolbar a picture of paper and pencil without hand). An editor window will open with some codes written already, MATLAB wrote them for you no problem. Only write the callback function for the toggle button, the rest of the code can be left untouched. In my case, I named my toggle button OnOffToggle, so the function under which I wrote the code is function OnOffToggle_Callback(hObject, eventdata, handles).

Any data sent through the serial is retrieved here as a variable rpmdata, so we just want to print that rpm data to the screen, that's it. One more thing, verify that you are connecting your arduino to the correct COM port as you write in the code. In this code I wrote COM3 because I connected my arduino to COM3.

Then save your m-file.

Below is the full code (edit only the OnOffToggle_Callback function):

function varargout = gui(varargin)
% GUI MATLAB code for gui.fig
%      GUI, by itself, creates a new GUI or raises the existing
%      singleton*.
%
%      H = GUI returns the handle to a new GUI or the handle to
%      the existing singleton*.
%
%      GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GUI.M with the given input arguments.
%
%      GUI('Property','Value',...) creates a new GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before gui_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to gui_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help gui
% Last Modified by GUIDE v2.5 14-Mar-2015 01:06:09</p><p>% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @gui_OpeningFcn, ...
                   'gui_OutputFcn',  @gui_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before gui is made visible.
function gui_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to gui (see VARARGIN)
% Choose default command line output for gui
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes gui wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = gui_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
function currentEdit_Callback(hObject, eventdata, handles)
function currentEdit_CreateFcn(hObject, eventdata, handles)
% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function OnOffToggle_Callback(hObject, eventdata, handles)
button_state = get(hObject,'Value');
if button_state == get(hObject,'Max')
    set(handles.OnOffToggle,'String','Stop');
    drawnow;
    i=2;
    while i > 1
        rpmdata = serial('COM3','BaudRate',9600); % this Baud rate should be the same as that in Arduino code
        fclose(instrfindall);
        fopen(rpmdata);
        b = fscanf(rpmdata);
        set(handles.textCurrent,'String',b);
        drawnow;
        delete(rpmdata)
        if get(hObject,'Value') == get(hObject,'Min')
            break
        end
    end
    set(handles.OnOffToggle,'String','Start');
    drawnow;
    rpmdata = serial('COM3','BaudRate',9600);
    fclose(rpmdata);
end

Step 3: Run the Rpm Reader

Once you finished with your code, connect your arduino, turn the wheel and run your program (green triangle play-like button on editor or layout editor window). A window of your program will come out (mine is as shown in the picture), click the toggle button and you will see the current rpm of your wheel there.

You can see how the program works in the video.

Hopefully someone will find this useful... Any feedback will be appreciated :) thanks!

Comments

author
Mario' (author)2015-11-27

hello, and thank you for this tutorial.....

btw in your example, you use one hole..
in my case i use 36 hole (sensor kit) will this affect the readings?

also could you send me the matlab program? somehow i keep getting error about the button....

thank you...

author
pinodisco (author)Mario'2015-11-27

Hi Mario, glad that you stopped by here, thank you. Unfortunately I am currently out, away from my test rig, arduino kit and the laptop where I have those tools, so I can't give you an accurate, proven comment. Yet I would like to suggest something that may worth testing. Mario are those 36 holes equally spaced? Like 10 degree spacing one to another? If so, probably you can try to modify the rpm calculation line in the arduino code:
rpm = 60000000/(diffTime*36)
That returns the value of rpm based on that 10 degree revolution instant, giving you 36 available readings every one rev, then which reading will be sent depends on the period you set in delay(), meaning that if you set the delay of 500 ms (0.5 s) and your wheel rotates 1 rev/s then you will get 2 readings only, most likely from the instant between hole 17-18 and 35-36. You can set the delay shorter anyways, if somehow you want it. The thing is that I am not sure if the matlab can retrieve all of the quickly sent data through the port. When I wrote this instructable, I could only retrieve the data every 1 second or more, so do not rely on my matlab code here if you want to read the data every 1 second or faster, I think I need another method to do fast reading (if indeed it can), please let me know if you find another method :).
For the matlab code I have written the full code in my instructable, again sorry currently I can't send you the file as I am away from my playing laptop, I would obviously send you if I could. Have you checked all the buttons/controls properties to make sure the name and props corresponds to the written code?
I will come again once I am home and check my laptop. Please let me know if you have anything. Sorry that not much I can do from here, also sorry if my reply does not bring you significant help.

author
Mario' (author)pinodisco2015-11-27

anyway, is there any method to made tachometer?
I need to measure shaft speed so i can control it eith another motor...

thanks/

author
Mario' (author)pinodisco2015-11-27

no problem.....
thank you for your help..
i will try to verify about the sensor...

btw this is the error i get:


Error using handle.handle/set

Invalid or deleted object.

Error in gui>button_Callback (line 86)

set(handles.text1,'String',b);

Error in gui_mainfcn (line 96)

feval(varargin{:});

Error in gui (line 42)

gui_mainfcn(gui_State, varargin{:});

Error in

@(hObject,eventdata)gui('button_Callback',hObject,eventdata,guidata(hObject))

Error using drawnow

Error while evaluating uicontrol Callback

Error using handle.handle/get

Invalid or deleted object.

Error in gui>button_Callback (line 89)

if get(hObject,'Value') == get(hObject,'Min')

Error in gui_mainfcn (line 96)

feval(varargin{:});

Error in gui (line 42)

gui_mainfcn(gui_State, varargin{:});

Error in

@(hObject,eventdata)gui('button_Callback',hObject,eventdata,guidata(hObject))

Error while evaluating uicontrol Callback

i named my toggle button as = button

was the berror caused by matlab 2013 vs 2012?

anyway... thank you so much for your fast response

author
tomatoskins (author)2015-04-22

This is so cool! I've never thought to intigrate Arduino and MATLAB.

author
pinodisco (author)tomatoskins2015-04-22

Tomato actually I also only learned this from others' posts in internet :)