Interfacing with Matlab

Here is a library of classes for interfacing with mbed from MATLAB. This might be useful for things like:

  • Using MATLAB to aquire and process data from sensors connected to mbed
  • Using MATLAB to control actuators connected to your mbed.
  • Implementing hardware in the loop programs in MATLAB, where the sensors and actuators are connected to mbed but MATLAB carries out the calculations and control.

This page gives examples of two methods of interfacing between MATLAB and mbed.

  • MATLAB RPC This is a set of classes which allows you to control the mbeds inputs and outputs directly from MATLAB. For many applications you may not need to write any mbed code.
  • Serial Comunication These examples show how you can send and receive information over serial in MATLAB and so transfer information between a program running on mbed and MATLAB.

MATLAB RPC

Updated

The MATLAB RPC library has been updated to improve the way it works. The classes are now all in a separate namespace. This means that the interface can now be used from within a function, callback or custom class, as well from the command line or within scripts.

Existing scripts will work with the new library but require you to add a line of code to the top of the script

import mbed.*
mymbed= SerialRPC('COM5', 9600);
myled = DigitalOut(mybed, LED1);

Or address classes using the name space

mymbed = mbed.SerialRPC('COM5', 9600);
myled = mbed.DigitalOut(mymbed, mbed.LED1);

To avoid a clash with the namespace name it is recommended that you do not use "mbed" as a variable/object name. A test connection, more robust argument checking and help infomation have also been added. Thanks goto Gautam Vallabha for these improvements.

In this example we control the mbed using the RPC. This makes it possible to remotely create objects and then execute their methods over any transport mechanism by sending the commands as a string. For methods which return a value the mbed returns that value as a string. Here are a set of MATLAB classes which expose a lot of the mbed API.

This has been tested and confimed to work using:

  • R2008a and R2008b (32-bit Windows), with a minor warning
  • R2009a and later (both 32 and 64 bit Windows)

Using the mbed MATLAB classes

To use these classes download the above zip and extract the files to somewhere on your computer. Then add the location of these files to the MATLAB path, the files contain a function "add_mbed_to_path.m" which will do this for you.

The aim in developing these classes has been to mirror the mbed API as closely as possible. This means that they follow the same object oriented approach as when you program on mbed, but with one key difference. In MATLAB you must first create an mbed object and then when you create interface objects pass them that mbed object as this effectively passes information about how the mbed is connected and how to communicate with it. This method will allow you to communicate with multiple mbeds from MATLAB.

Information

To use this library of code for MATLAB your mbed must be running code which can receive and then execute RPC commands. The Interfacing Using RPC page explains this and has some example programs. You can use the RPC_Serial program or the HTTP server with the examples on this page.

MATLAB Code

The MATLAB classes have been designed to make it feel very similar to programming directly on mbed. Here is the complete MATLAB code required to flash an LED ten times and then close the serial port.

Hello_World

import mbed.*
mymbed = SerialRPC('COM5', 9600)
myled = DigitalOut(mymbed, LED1);
for i = 1:1:10
   myled.write(1);
   pause(0.5);
   myled.write(0);
   pause(0.5);
end
mymbed.delete;
clear;

The RPC library is contained within the "mbed" namespace, this means that you must first either import the mbed package (using "import mbed.*") or prefix all classes with the namespace (eg "mbed.SerialRPC(...)"). More examples of this format can be found in the source files.

The first step when programming for mbed in MATLAB is to create your mbed object. You do this by creating an mbed object from the class for the relevant transport mechanism. This can be Serial or HTTP.

import mbed.*
%Create an mbed Object
mymbed = SerialRPC('COM5', 9600)
%OR
mymbed = HTTPRPC('192.168.2.6');

You can then create objects from the mbed API, eg AnalogIn, DigitalIn, DigitalOut etc. These must all the passed the mbed object created above and then the arguments for that type of object as defined in the Handbook.

%Creating Interface Objects on mbed from MATLAB
dout1 = DigitalOut(mymbed, p21);
dout2 = DigitalOut(mymbed, LED1);
pwm1 = PwmOut(mymbed, p22);
pwm2 = PwmOut(mymbed, LED2);
ain1 = AnalogIn(mymbed, p20);
device = Serial(mymbed, p13, p14);

If you have objects already created on mbed, say a DigitalOut with the name "myled" then you can tie a MATLAB object to control this object

C++

//Create object in c++ code on mbed
DigitalOut myled(LED1, "myled");

MATLAB

%tie to that object in MATLAB
dout3 = DigitalOut(mymbed,'myled')'

Having created your objects you can now use the methods defined for those objects in the mbed API. However, there isn't the overloading of the operators that you are probably used to from programming the mbed directly. This means that to control a DigitalOut you have to call the "write" method.

%Calling methods from MATLAB
%to set a DigitalOut
dout1.write(1);
dout3.write(0);

%to set PwmOut
pwm1.write(0.5);
pwm2.period(1);
pwm2.write(0.5);

%to read an AnalogIn
x = ain1.read()

%to read and write to a serial port
device.puts('data to send out of p13 and p14');
if device.readable == 1
    Data =  device.gets;
end

Note that the serial class only supports gets, getc, puts, putc, baud and readable/writeable.

As the MATLAB classes actually create objects on the mbed it can become important to reset your mbed before running your MATLAB code as this will prevent there being too many objects or conflicting objects created on the same pin. You can of course do this by pressing the button or alternatively by using the reset function in the mbedSerial class.

%Reset mbed remotely from MATLAB
mymbed.reset;

Finally once you have finished communicating with the mbed then you must delete the mbed object which also closes the serial port so that it will be avaliable to other applications.

%Deleting mbed object and so closing transport mechanism
mymbed.delete;

The mbed MATLAB library includes a test transport mechanism which simulates an mbed connection.

This could be useful for testing the interface code, and potentially to test your own code without needing to connect an mbed, though note for methods which return an argument the test connection will return a random value.

mymbed = mbed.TestRPC();

When you have finished testing your code, all you need to do is change this line of code to the type of transport mechanism you want to use.

Communicating with Custom Code

Most projects require not only simply Digital or Analog I/O but also make use of some of the many libraries for the mbed. These don't support RPC and nor does the MATLAB library provided here include support from them. Instead a mechanism which allows you to directly access variables on mbed or call custom functions is provided by the RPC-Interface-Library. The MATLAB library provided here includes support for these objects.

%Attach to an Existing RPCFunction on mbed
RangeFinder = RPCFunction(mymbed, "RangeFinder");
%Run its methods
range = RangeFinder.run;

%Read and Write to a variable on mbed
Variable = RPCVariable(mymbed, "f");
f = Variable.read();

Variable.write(0.123);

Theres a more complete example of the mbed code and MATLAB script required to gather data from a RangeFinder at the bottom of this page.

Information

If you want to run completly custom RPC reqeusts then you can use the RPC method of the mbed object. The arguments must be passed as an array of strings.

mbed = SerialRPC('COM7', 9600)
mymbed.RPC('myled', 'write', {'1'})

Serial Communication

Using the basic serial over usb communication method, it is possible to interact with Matlab using the Matlab "serial" object. Using this method it is very easy to dump data from mbed into Matlab to be displayed or processed.

The code on the mbed side is exactly the same as you would use to talk to a pc with terraterm or similar. I have been using it to read analogue data from an accellerometer, so basically just dumping data from 3 AnalogIn's over the serial connection, using the code below:

main.cpp

#include "mbed.h"

AnalogIn x(18);
AnalogIn y(19);
AnalogIn z(20);

int main() {
    while(1) {
       printf("%d,%d,%d\n", x.read_mv(), y.read_mv(), z.read_mv());
    wait(0.1);
    }
}

The Matlab code I have been using basically just reads in the data from the serial port and displays it as a graph. The graph overwrites itself every n samples and the x-labels update to match. The try/catch block is important as if an error occurs while the serial object is instantiated before fclose() is called then the port remains open and cannot be closed. The only solution I have found to this is to restart the PC, so using a try/catch to close the port on an error is important!

function accell()

TIMEOUT = 5;    %time to wait for data before aborting
XPOINTS = 50;   %number of points along x axis

try
    %create serial object to represent connection to mbed
    mbed = serial('COM4', ...
                  'BaudRate', 9600, ...
                  'Parity', 'none', ...
                  'DataBits', 8, ...
                  'StopBits', 1);       %change depending on mbed configuration
    
    set(mbed,'Timeout',TIMEOUT);        %adjust timeout to ensure fast response when mbed disconnected
    
    fopen(mbed);        %open serial connection

    position = 1;       %initialise graph variables
    time = 1;
    x = [(1:XPOINTS)' (1:XPOINTS)' (1:XPOINTS)'];
    xlabels = (1:XPOINTS);
    y = zeros(XPOINTS,3);
    
    while (1)       %loop forever (or until an error occurs)
        
        values = fscanf(mbed, '%f,%f,%f');    %get values into vector
                                              %assumes data formatted as
                                              %'1,2,3'
        y(position,:) = values';    %put into y to be displayed
        
        %update position on x-axis and x-axis labels
        xlabels(position) = time;
        time = time + 1;
        if (position < XPOINTS)
            position = position + 1;
        else
            position = 1;
        end

        %display
        plot(x,y);
        set(gca, 'XTick', 1:XPOINTS);
        set(gca, 'XTickLabel', xlabels);

        drawnow;    %this is required to force the display to update before the function terminates
    end

    fclose(mbed);   %close connection (this should never be reached when using while(1), but included for completeness)
    
catch
    %in case of error or mbed being disconnected
    disp('Failed!');
    fclose(mbed);   %close connection to prevent COM port being lokced open
end 

When this is executed (assuming mbed is already churning out data), a plot window appears and is continually updated until mbed is disconnected. At this point, after the timeout period has elapsed, the read fails and the control is safely passed back to the Matlab command line by the catch block. This is certainly not very elegant, but does seem safe and reliable, though I'm sure it must be possible to do this better by sending synchronisation data back and forth across the link.

The code for just reading in the data from mbed into a variable is only a few lines long, the majority of this code is concerned with formatting and displaying the data. Using fscanf the data can be automatically converted from the string receieved back into seperate variables using (I think!) exactly the same syntax as was used in printf on mbed to put it into a string in the first place. The actual important bits of code for doing things are just:

mbed = serial('COM4', ...
                  'BaudRate', 9600, ...
                  'Parity', 'none', ...
                  'DataBits', 8, ...
                  'StopBits', 1);
             
fopen(mbed);
values = fscanf(mbed, '%f,%f,%f');
	
fclose(mbed);

There is also an fprintf function which can be used to write data back to mbed over the same serial connection using the same syntax, though I've not played with this yet.

Range Finder Demo

MATLAB can be very useful for processing and manipulating data, particuarly when you have a lot of data points. This example shows how you can use the library above to work with both standard IO and custom code to allow use of many other interfaces such as I2C or SPI sensors This demo uses a SRF08 UltraSonic Ranger mounted on a servo pan tilt mount to record lots of data and then uses MATLAB to process and display this data. This could be mounted on the front of a robot and used by the robot to find its way around its surroundings. Matlab has complete control of the servos and the range finder in real time.

The servos that control the direction of the Range Finder can be controlled directly from MATLAB as they just use PWMOut (though an external power supply needs to be used). The Ranger Finder is read using a RPCFunction object which returns a string consisting of just the measured distance in cm. The actual read is done using the library that has already been written for the SRF08.

The MATLAB script controls the servos, reads from the range finder and plots the points on a graph. The Matlab script ignores points which are out of range. A PTM button is also included on the circuit to demonstrate reading from the a DigitalIn and so that the range finder can be stopped during a scan.

/media/uploads/MichaelW/scan3.jpg

This image shows the results for a singal sweep, there were too boxes infront of the scanner and you can clearly see where the gap is between them. The range finder gives good results but as it has a conical beam shape it tends to see edges as very blured, in this case it extends the edges of the boxes slightly. However the great advatage of having loaded the data from matlab is that it would now be possible to use Matlab to process the data to get a better idea of what objects are where. The points are held in a matirx and so it would be relativly easy to filter or manipulate them in a number ways so that your device could interpret what was in front of it.

As the RangeFinder is mounted on a pan tilt mount the scan above can be repeated at different angles and could then be used to build up a 3D image of the surroundings and the extra data used to refine the accuracy. This is the matlab script used: ScanDemo.m

Coming soon - video of the range finder in action.

Here is a slightly simplified version of the Matlab script which highlights the key parts of the program

import mbed.*
%Set up variables
MaxRange = 80;
MaxServoAngle = 150;
READINGS = 35;
Angles = zeros((READINGS+1), 1);
Range = zeros((READINGS+1), 1);
plotPoints = zeros((READINGS+1), 2);
n = 1;
p = 1;

%Set up communication to mbed
mymbed = SerialRPC('COM7', 9600);
mymbed.reset();
pause(0.5);
theta_Servo = PwmOut(mymbed, p21);
phi_Servo = PwmOut(mymbed, p22);
StopButton = DigitalIn(mymbed, p5);
srf08 = RPCFunction(mymbed,'RangeFinder');

%Set up the servos
theta_Servo.period(0.020);
phi_Servo.period(0.020);
theta_Servo.pulsewidth(0.002);    
phi_Servo.pulsewidth(1.2/1000);

for t = 1:(1/READINGS):2;     
    theta_Servo.pulsewidth((3 - t)/1000);
    %give the servo time to get into position
    pause(0.001);

    %Read the distance into the Range matrix - add 3 cm to account for distance of range finder from pivot.
    Range(n) = str2double(srf08.run(' ')) + 3;
    if Range(n) < 4
       Range(n) = 0;
    end
    if Range(n) > MaxRange
       Range(n) = 0;
    end

    %Calculate the angle    
    Angles(n) = (MaxServoAngle/2) * ((t-1.5) * 2); 
    %Add the points which are valid to the maxtrix
    if Range(n) > 0
       plotPoints(p,1) = pi .* Angles(n) ./ 180 + pi/2;
       plotPoints(p,2) = Range(n);
       p = p + 1;
    end
    n = n + 1; 
    %plot the hits
    polar(plotPoints(:,1), plotPoints(:,2), 'r-');
    if StopButton.read() == 0
         display('Stop button pressed');
    break;  
    end
end

display('Completed RangeFinder demo');
mymbed.delete
clear

Here is the code for mbed.

Import program

00001 /**
00002 * Copyright (c)2010 ARM Ltd.
00003 * Released under the MIT License: http://mbed.org/license/mit
00004 */
00005 #include "mbed.h"
00006 #include "SerialRPCInterface.h"
00007 #include "SRF08.h"
00008 
00009 using namespace mbed;
00010 
00011 //Create the interface on the USB Serial Port
00012 SerialRPCInterface RPC(USBTX, USBRX);
00013 void ReadRange(char * input, char * output);
00014 RPCFunction RangeFinder(&ReadRange, "RangeFinder");
00015 SRF08 srf08(p9, p10, 0xE0);      // Define SDA, SCL pin and I2C address 
00016 DigitalOut myled(LED1);
00017 
00018 int main() {
00019 
00020     while(1) {
00021         
00022     
00023         myled = 1;
00024         wait(0.2);
00025         myled = 0;
00026         wait(0.2);
00027     }
00028 }
00029 
00030 //As neither I2C nor the SRF08 library is avalible directly over RPC we create a Custom Function which we make RPCable by attaching to an RPCFunction
00031 void ReadRange(char * input, char * output){
00032     //Format the output of the srf08 into the output string
00033     sprintf(output, "%f", srf08.read());
00034 }

Reference


All wikipages