Using LCM from Matlab with MEX functions

360 views
Skip to first unread message

David Pearson

unread,
Jan 16, 2014, 11:15:53 PM1/16/14
to lcm-...@googlegroups.com
Hello, 

I am extremely new to using LCM and have been working with a research partner (a bit of an LCM Guru around the lab) to develop LCM functions for Matlab by developing a mex file which can be run from a Matlab script or command line. 

Using a simplified version of the provided C++ example we have been successful in creating a publisher function which can take any scalar variable form matlab and post it to the "Example" channel. 

In matlab command line,
=======================================================
>> Variable = 10; %% set any scalar variable 
>> LCMPublish(Variable);  %% LCMPulish.mexw32 is called and the Variable is then published to the channel 
=======================================================

...this runs the following cpp program in the background.
=======================================================
#include <lcm/lcm-cpp.hpp>
#include "test3/test3_t.hpp"
#include "mex.h"

/* the gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
 
{
double value;
value = mxGetScalar(prhs[0]); // gets the scalar value from the right hand side of the mex function called 
// Create the LCM object handle 
lcm::LCM lcm;

// define the structure 
test3::test3_t my_data; // header file <test_t> struture <my_data> 
// fill in the variable
my_data.heading = value;
// publish using object <lcm>
lcm.publish("EXAMPLE", &my_data);
}

================================================================

This function is confirmed to be publishing by using the listener example without any bugs yet...

We were also somewhat successful in developing a listener function to catch a variable that is being published to the channel and store it for processing in matlab. 

In matlab command line,
=======================================================

>> Variable = LCMListen; %% stores the scalar value from the published channel 

======================================================= 

This works so far but with a strange catch...

After 55 consecutive calls  of the listener function LCM basically crashes (from my understanding)...

We believe this is from not disconnects from the LCM network, and destroying the subscription objects.

As a very green newcomer to programming (outside of using matlab for developing simulations) I am at a loss on how to do this yet! 

I learn from examples and would greatly appreciate it if anyone could point me the right direction, or show me what I am missing?

The cpp code that runs outside is as follows. 
=============================================================

#include <Windows.h>
#include <stdio.h>
#include <lcm/lcm-cpp.hpp>
#include "test3/test3_t.hpp"
#include "mex.h"

double compass;

class Handler 
{
    public:
        ~Handler() {}

        void handleMessage(const lcm::ReceiveBuffer* rbuf, const std::string& chan, const test3::test3_t* msg)
        {
extern double compass;
            
compass = msg->heading;
            
            mexPrintf("2");
        }
};


/* the gateway function */
void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
extern double compass;  
    
    lcm::LCM lcm;
    
    Handler handlerObject;
    
    // subscibe to the lcm channel on the network 
    lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject);
    mexPrintf("1");
    
    // open the lcm channel handler and grab whats inside
    lcm.handle();
    mexPrintf("3");
    
    // clears the data... if something there before...
    mxFree(plhs[0]);
    
    // store published variable to left hand side of mex function in matlab
    plhs[0] = mxCreateDoubleScalar(compass);
    mexPrintf("4");
    
    
    // destroy lcm with fire!!!!
    ~lcm(); // this does not work... 
    
    //lcm.unsubscribe(lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject));
    mexPrintf("5");
    
    //delete [] &handlerObject;
    //mexPrintf("6");
    
    mxDestroyArray(plhs[0]);
    
    return;
}

Albert Huang

unread,
Jan 16, 2014, 11:45:42 PM1/16/14
to lcm-...@googlegroups.com
Hi David,

Out of curiosity, do the MATLAB bindings not work for your purposes (http://lcm.googlecode.com/svn/www/reference/lcm/tut_matlab.html)?

I haven't created mex files in many years now, but the mxFree and mxDestroyArray calls looks a little suspicious to me...

Albert


--
You received this message because you are subscribed to the Google Groups "Lightweight Communications and Marshalling" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lcm-users+...@googlegroups.com.
To post to this group, send email to lcm-...@googlegroups.com.
Visit this group at http://groups.google.com/group/lcm-users.
For more options, visit https://groups.google.com/groups/opt_out.

floria...@gmail.com

unread,
Jan 16, 2014, 11:23:40 PM1/16/14
to lcm-...@googlegroups.com
Hi,

Before I try to debug your code, is there a certain reason why you chose to access LCM via the C++ API ? The Java API interfaces nicer with Matlab as it can be called directly within scripts, does not require compilation and only depends on a jar file that can be distributed with your scripts. Examples can be found on the wiki at https://code.google.com/p/lcm/wiki/Documentation

Your Matlab scripts would look something like this:

%% Get Access to Java API
javaaddpath(<lcm>.jar)

%% Send data
lc = lcm.lcm.LCM.getSingleton()
my_data = <type>
my_data.heading = value
lc.publish(‘EXAMPLE’, my_data)

%% Receive data
% 1) setup
lc = lcm.lcm.LCM.getSingleton()
aggregator = lcm.lcm.MessageAggregator()
lc.subscribe(‘EXAMPLE’, aggregator)
% 2) receive one message (call this from loop)
raw = aggregator.getNextMessage(timeoutMs) % max timeout in milliseconds
my_data = struct(<type>(raw.data)) % if msg != empty
value = my_data.heading

Florian

David Pearson

unread,
Jan 17, 2014, 10:27:58 AM1/17/14
to lcm-...@googlegroups.com
the mxFree and mxDestroyArray calls were used to try to debug things from the matlab side of things, but we have for now ruled it out as the culprit. seems we cannot call the lcm destructor properly.. or at least matlab doesn't like it... 

We did not try the matlab bindings because of the time required to set everything up and lack of experience with java. I am certainly not able to it on my own and my research partner does not have the time to dedicate undertaking the task at this time. This is our attempt at working around it which has so far been fairly successfully, until now. 

this is where are as of this morning, with matlab either shutting down after the fist call or same issue as before ( lcm crashes after 55th call )

================================================================================================= 
#include <Windows.h>
#include <stdio.h>
#include <lcm/lcm-cpp.hpp>
#include "test3/test3_t.hpp"
#include "mex.h"

double compass;

class Handler 
{
    public:
        ~Handler() {}

        void handleMessage(const lcm::ReceiveBuffer* rbuf, const std::string& chan, const test3::test3_t* msg)
        {
extern double compass;
            
compass = msg->heading;
            
            mexPrintf("2");
        }
};


/* the gateway function */
void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
extern double compass;  
    lcm::Subscription * sub;
    lcm::LCM lcm;
    
    Handler handlerObject;
    
    // subscibe to the lcm channel on the network 
    sub = lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject);
    mexPrintf("1");
    
    // open the lcm channel handler and grab whats inside
    lcm.handle();
    mexPrintf("3");
    
    // clears the data... if something there before...
   // mxFree(plhs[0]);
    
    // store published variable to left hand side of mex function in matlab
    plhs[0] = mxCreateDoubleScalar(compass);
    mexPrintf("4");
    
    
    // destroy lcm with fire!!!!
    //lcm.~lcm();
    
    //lcm.unsubscribe(sub);
    
    mexPrintf("5");
    delete [] &lcm;
    //mexPrintf("6");
    
    //mxDestroyArray(plhs[0]);
    
    return;
}

======================================================================================================== 

Albert Huang

unread,
Jan 17, 2014, 10:35:44 AM1/17/14
to lcm-...@googlegroups.com
I'm sorry.  You can't be bothered to go through the step-by-step tutorial we created exactly for your use case, and yet you expect other people to spend their own time debugging your own uninformed code for you?

Albert

David Pearson

unread,
Jan 17, 2014, 10:54:22 AM1/17/14
to lcm-...@googlegroups.com
Well that was quite harsh Albert and  I am sorry if I offend you in any way. I didn't ask for anyone to take time to deeply debug my code. I just was wondering if there was anything I was overlooking or missing.. as I am a beginner. I think LCM is a great program for  experienced programmers but I am not experienced and I am just politely asking the community for help as the wiki pages have been either over my head or vague to me in my understanding.

Albert Huang

unread,
Jan 17, 2014, 11:44:15 AM1/17/14
to lcm-...@googlegroups.com
Hi David,

Try following the MATLAB tutorial and looking through the examples.  They really are designed exactly for MATLAB users.  Don't be intimidated by the Java aspects, as you don't actually need to know Java to use them.  If you have trouble understanding any part of the tutorial or the examples, post your questions and people will be happy to try and help.

Good luck,
Albert


On Fri, Jan 17, 2014 at 10:54 AM, David Pearson <dmoti...@gmail.com> wrote:
Well that was quite harsh Albert and  I am sorry if I offend you in any way. I didn't ask for anyone to take time to deeply debug my code. I just was wondering if there was anything I was overlooking or missing.. as I am a beginner. I think LCM is a great program for  experienced programmers but I am not experienced and I am just politely asking the community for help as the wiki pages have been either over my head or vague to me in my understanding.

David Pearson

unread,
Jan 18, 2014, 4:14:39 PM1/18/14
to lcm-...@googlegroups.com
Thanks Albert, I have started doing just that!

I will also keep working on my code for developing the LCM MEX functions as well. hopefully I will be able to find the bug soon...
We believe the issue is coming from the system being unable to deallocate resources used by LCM after it has been called by the mex function (form not using the lcm destructor properly / lcm destructor not working properly on my system).  So we have updated from lcm-0.9.0 to lcm-1.0.0 in hopes this may be the issue since there was a large C++ update.

David Pearson

unread,
Jan 21, 2014, 4:42:16 PM1/21/14
to lcm-...@googlegroups.com
Good News!!! 

The lcm-1.0.0 update fixed our issue with developing mex functions that use lcm! We can now listen for and publish any variable we want from a single line in matlab without the java binding. 

Here is a figure that shows the time it took to open, capture, close and store a random variable being published on my network at ~100 hz. A sample size of 1000 was taken. 


Florian Enner

unread,
Jan 21, 2014, 10:02:14 PM1/21/14
to lcm-...@googlegroups.com
Congratulations on getting your mex functions running. I'd like to add some constructive feedback, so please don't be offended by the next paragraphs.

1) When posting benchmarks you generally need to include more information about the environment they ran on.

-) does "on my network" mean TTL was set to 1 ? this makes a huge difference, especially when you start sending large messages or images.
-) what OS and which JDK were you using ?
-) what hardware ?
-) what does 100hz mean ? Did you try to spam as fast as possible and you ended up with 100hz ? If so, what is measured on the y axis ? Looking at the chart I'd assume that single calls to your mex function take on average 15ms, but that would result in only 66hz.

2) I don't think you realize just how horribly slow it is to create lcm objects every time and what limitations you are introducing into your system. Using mex you can only receive messages while you are inside the function, which means that messages broadcasted outside of that window are dropped. Additionally, receives are handled in the same thread as Matlab itself. The Java bindings effectively create an asynchronous receive thread that runs separate from Matlab, which will give you a huge performance benefit and potentially no dropped messages.

3) The following test publishes 100k garbage messages to lcm (ttl=0). It takes 9.5 seconds on my 1.6ghz laptop, which means that I can run lcm.publish at more than >10 kilohertz. I'm not sure what other things one of your samples does, but you are probably degrading your performance by 1-2 orders of magnitude for not needing to read a (very short) tutorial.

Step 2) Open Matlab in that folder
Step 3) Create a new .m script
Step 4) Copy and paste the following 7 lines of code

javaaddpath('lcm-java-1.0.0-unofficial.jar');
lc = lcm.lcm.LCM.getSingleton();
tic
for i = 1:1E5
    lc.publish('TEST','bla')
end
toc

Step 5) Press Run or F5

Good luck :)


2014/1/21 David Pearson <dmoti...@gmail.com>

David Pearson

unread,
Feb 26, 2014, 9:12:43 PM2/26/14
to lcm-...@googlegroups.com
Hello again,

I have been working with the LCM MEX functions I developed for about a month now and it has been working well. As noted before, using LCM with MEX functions dose limit the speed and times when messages can be received, but I have been able get away with doing this for my application because I only need to the most recent message being published and I am only publishing messages once every second, ~1 Hz. My main loop runs at <= 5 Hz, this is primarily due to to the maximum allowed time (using 'select()' ) it takes the LCM MEX function to run twice (once per data channel).  

An issue we have seen with using LCM in this way is the dropping of messages and an inconsistency of overall usage. Though these problems are minor in the scope of the project and my application, they are headaches that I would rather not deal with any longer. So I am trying my hand at getting the java binding to work with Matlab. I know this is what I should of done all along but I was under the gun to get something working at the time....   
 
I am running this from my 32 bit version of Matlab on Windows 7. I have JDK 1.7 and have been able to get the .java and .jar files complied  for the example. 

I did not have an lcm.jar file as the tutorial said I would, so I copied one from the Matlab thread on the forum (hoping it would be compatible... ). 
If this is not the case, I am not sure how to compile it on windows as I only see references to compile on Eclipse/Apache Ant, with g++ ??? 

I am getting the same issue as the others on the Matlab thread, 

LCM: Disabling IPV6 support
LCM: TTL set to zero, traffic will not leave localhost.
Undefined variable "exlcm" or
class "exlcm.example_t".
Error in sendmessage (line 3)
msg = exlcm.example_t(); 

I tried the import function but that did help... 
 

floria...@gmail.com

unread,
Feb 26, 2014, 10:16:47 PM2/26/14
to lcm-...@googlegroups.com
Hi,

since Java is cross platform you can actually compile in Linux and then copy and paste the .jar file to Windows. However, the fact that you can see the following lines means that the core LCM system is already running correctly.

>LCM: Disabling IPV6 support
>LCM: TTL set to zero, traffic will not leave localhost.

The error messages indicate that you do not have the LCM type exlcm.example_t in your classpath. It is not distributed with the lcm core.

>Undefined variable "exlcm" or
>class "exlcm.example_t".

Try to compile your own messages into a jar file and then call “javaaddpath(<types>.jar)”. You can then instantiate a message with

> message = <classpath>.<MessageName>

Once you get this line working the rest should work as well. When you receive messages you can use the matlab function struct(message) to quickly convert lcm message contents to Matlab types.

Florian
--

David Pearson

unread,
Feb 26, 2014, 11:53:15 PM2/26/14
to lcm-...@googlegroups.com
Thanks for the quick reply! 

I used Cygwin to compile my <types>.jar files from the example_t file as shown in the tutorial. I will develop my own types and try again; I will also try to compile on linux.

Q: I see that changing to JDK1.6 helped this issue for some users, should also give that a shot? 

Q: By setting the "classpath"   you mean just “javaaddpath(<types>.jar)” in matlab. 

Thanks again, I am so grateful for you and your team in developing LCM, keep up the good work! 

- David

floria...@gmail.com

unread,
Feb 26, 2014, 11:55:53 PM2/26/14
to lcm-...@googlegroups.com
I have never done that particular tutorial, so I can’t comment on that. I’ve always just worked with lcm-gen compiled by VS2008 (2010/2012 didn’t work).

Q1: I’m often switching back and forth between Oracle JDK 6/7/8 on Windows and they all work. The only problem I’ve encountered so far is that OpenJDK 6/7 on Ubuntu does not interpret TTL=0 correctly and always broadcasts.

Q2: yes.

I am not a developer, but I agree that they have done some great work.

- Florian

David Pearson

unread,
Apr 29, 2014, 12:40:21 PM4/29/14
to lcm-...@googlegroups.com
hello again,

Florian, I have tried to compile my own messages into jar file as shown in the following tutorial but I still can not get this to work... I am getting the same error as before. 

----------------------------------------------------------------------------------------------------------------------
Step 0:
  Compile the Java bindings for the LCM message types that you intend to use.
  These need to be placed in a JAR file.  
 
  This is typically done from outside of MATLAB, from a command-line shell, and
  is the exact same procedure you'd follow if you wanted to use LCM from Java.

  For example, if the message type definition file we want is located here:
    ../types/example_t.lcm

  Then we could run the following commands:
  
  $ lcm-gen -j C:/lcm-1.0.0/examples/types/example_t.lcm

  Notice: enclosing LCM types without package into java namespace 'exlcm'.

  $ javac -cp C:/lcm-1.0.0/lcm-java/lcm.jar exlcm/*.java

  $ jar cf my_types.jar exlcm/*.class

  This is summarized in the shell script "buildjar.sh"
------------------------------------------------------------------------------------------------

this produces a new folder  ../exlcm/ with example_t.java and example_t.class files 
along with my_types.jar file

from the matlab working directory window the my_types.jar file has two folders, the first is and exlcm folder with example_t.class within it and the second is META-INF folder with MANIFEST.MF file in it. 

I then follow the next step in the tutorial to add the java path
 -----------------------------------------------------------------------------------------
Step 1:
  Once you have the message types compiled to a JAR file, you can use them from
  MATLAB.

  To use a JAR file from MATLAB, you need to tell MATLAB where that JAR file
  is.  In this case, there are two JAR files: the one for the message types we
  just compiled, and the one for the general LCM functionality.

  Use the javaaddpath command for this.

  >> javaaddpath /path/to/lcm.jar

  >> javaaddpath my_types.jar

  This is summarized in addjars.m
--------------------------------------------------------------------------------------------
I confirm this with javaclasspath that they are now in my dynamic path. 

I run the example code in matlab and I am able to receive the raw data bytes, but when I input the raw bytes message into the the exlcm.example_t() constructor I get the error. 

I don't believe there is anything I am missing, I think there may be a problem with the way I am compiling my .jar files from my computer (I am running on windows with JDK7). 


lcm.jar
test3.lcm
test3_types.jar
test3_t.class
test3_t.java

Florian Enner

unread,
May 2, 2014, 3:19:34 PM5/2/14
to lcm-...@googlegroups.com
Hi David,

I tried your examples and I'm getting the same error. One obvious problem is that you are trying to decode "exlcm.example_t()" even though your only defined message is "test3.test3_t()". However, that unfortunately still doesn't fix it. I've tried compiling it the same way you did and there seems to be a problem in javac 1.7+ and Matlab 2013a (potentially others).

I've debugged this a bit using the tutorial here https://lcm.googlecode.com/svn-history/r723/www/reference/lcm/tut_matlab.html . Maybe one of the developers has some insight into this problem ?

> "javac -cp lcm.jar exlcm/*.java"
Oracle JDK 1.6.0_45 -> worked
Oracle JDK 1.7.0_45 -> types could not be read by Matlab
Oracle JDK 1.8.0 -> types could not be read by Matlab

> "jar cf my_types.jar exlcm/*.class"
worked with any version

So for now just compile types with JDK 1.6. I have attached files that worked for me so that you can test it out. Just run the matlab script and you should see messages in lcm-spy.

- Florian



--
You received this message because you are subscribed to the Google Groups "Lightweight Communications and Marshalling" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lcm-users+...@googlegroups.com.
To post to this group, send email to lcm-...@googlegroups.com.
Visit this group at http://groups.google.com/group/lcm-users.
For more options, visit https://groups.google.com/d/optout.

tutorial.zip

David Pearson

unread,
May 2, 2014, 6:00:07 PM5/2/14
to lcm-...@googlegroups.com
Yes this works, I will go ahead and download JDK 1.6, Thank you!
 


--
You received this message because you are subscribed to a topic in the Google Groups "Lightweight Communications and Marshalling" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/lcm-users/bjjie-0rxcc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to lcm-users+...@googlegroups.com.

Florian Enner

unread,
May 23, 2014, 11:52:16 AM5/23/14
to lcm-...@googlegroups.com
David,

I've looked a bit more into this and it's probably caused by Matlab bundling their own JRE, which in my case is only 1.6. You can check the version via "version -java". This means that the messages can't be higher than compiled as 1.7 or 1.8.

I've tried compiling the messages with version flags "javac -source 1.5 -target 1.5 <x>" and it worked just fine.

Florian


Reply all
Reply to author
Forward
0 new messages