LCM
MATLAB Tutorial

Sending and receiving LCM messages with MATLAB

Introduction

This tutorial will walk you through the main tasks for exchanging LCM messages using the MATLAB API. The topics covered in this tutorial are:

Using LCM with MATLAB is almost identical to using LCM through Java, since the MATLAB API relies on the LCM Java bindings. However, there are some differences, which mainly consist of how incoming messages are handled.

Setting up MATLAB to use LCM

This tutorial uses the example_t message type defined in the type definition tutorial, and assumes that you have compiled lcm.jar (see the Java notes page), and generated the Java bindings for the example type by running the following (from a command shell, not the MATLAB prompt):

1 lcm-gen -j example_t.lcm

After running this command, you should have a file named exlcm/example_t.java. You can then compile this into a .class file, and then create a .jar archive. Assuming that lcm.jar is in the current directory, you could then run (also from a command shell):

1 javac -cp lcm.jar exlcm/*.java
2 jar cf my_types.jar exlcm/*.class

You should then have a file my_types.jar, which is a Java archive containing the Java bindings for the example message.

Note
on Windows, use '\' instead of '/' for directory separators.

The next task is to tell MATLAB how to find LCM and the message bindings. You will first need to add lcm.jar and my_types.jar into the MATLAB classpath. You can do this from the MATLAB prompt or a MATLAB script by running:

1 javaaddpath lcm.jar
2 javaaddpath my_types.jar

Once this is all setup, you can start using LCM from your MATLAB scripts.

Initializing LCM

You can initialize LCM from MATLAB as follows:

1 lc = lcm.lcm.LCM.getSingleton();

The lc object now contains the communications context and interface for LCM. Since we're simply calling into the Java API here, see the Java API documentation for other ways on setting up LCM.

Publishing a message

We can instantiate and publish some sample data as follows:

1 lc = lcm.lcm.LCM.getSingleton();
2 
3 msg = exlcm.example_t();
4 msg.timestamp = 0;
5 msg.position = [1 2 3];
6 msg.orientation = [1 0 0 0];
7 msg.ranges = 1:15;
8 msg.num_ranges = length(msg.ranges);
9 msg.name = 'example string';
10 msg.enabled = 1;
11 
12 lc.publish('EXAMPLE', msg);

For the most part, this example should be pretty straightforward. The application initializes LCM, creates a message, fills in the message data fields, then publishes the message using lc.publish().

The call to lc.publish serializes the data into a byte stream and transmits the packet to any interested receivers. The string 'EXAMPLE' is the channel name, which is a string transmitted with each packet that identifies the contents to receivers. Receivers subscribe to different channels using this identifier, allowing uninteresting data to be discarded quickly and efficiently.

The full example is available in runnable form in the examples/matlab directory in the LCM source distribution.

Receiving LCM Messages

As discussed above, each LCM message is transmitted with an attached channel name. You can use these channel names to determine which LCM messages your application receives, by subscribing to the channels of interest. It is important for senders and receivers to agree on the channel names which will be used for each message type.

Here is a sample program that sets up LCM and adds a subscription to the 'EXAMPLE' channel. Whenever a message is received on this channel, its contents are printed out. If messages on other channels are being transmitted over the network, this program will not see them because it only has a subscription to the 'EXAMPLE' channel. A particular instance of LCM may have an unlimited number of subscriptions.

1 lc = lcm.lcm.LCM.getSingleton();
2 aggregator = lcm.lcm.MessageAggregator();
3 
4 lc.subscribe('EXAMPLE', aggregator);
5 
6 while true
7  disp waiting
8  millis_to_wait = 1000;
9  msg = aggregator.getNextMessage(millis_to_wait);
10  if length(msg) > 0
11  break
12  end
13 end
14 
15 disp(sprintf('channel of received message: %s', char(msg.channel)))
16 disp(sprintf('raw bytes of received message:'))
17 disp(sprintf('%d ', msg.data'))
18 
19 m = exlcm.example_t(msg.data);
20 
21 disp(sprintf('decoded message:\n'))
22 disp([ 'timestamp: ' sprintf('%d ', m.timestamp) ])
23 disp([ 'position: ' sprintf('%f ', m.position) ])
24 disp([ 'orientation: ' sprintf('%f ', m.orientation) ])
25 disp([ 'ranges: ' sprintf('%f ', m.ranges) ])
26 disp([ 'name: ' m.name) ])
27 disp([ 'enabled: ' sprintf('%d ', m.enabled) ])

After initializing the LCM object, the application creates a MessageAggregator and subscribes it to the 'EXAMPLE' channel. The sole purpose of the message aggregator is to receive messages on that channel and queue them up for later handling. This is different from how messages would normally be handled in Java, as MATLAB is not well suited to callback functions or multiple threads.

The example application then repeatedly calls MessageAggregator.getNextMessage() which simply waits for a message of interest to arrive and then returns the raw data.

Once a message has arrived, the application decodes it by passing msg.data to the constructor for the example message type, and displays some message fields.

For more information on how to use the MessageAggregator, see the API documentation. This includes configuring messsaging limits such as a maximum number of messages to queue up to avoid falling behind real-time.

The full example is available in runnable form in the examples/matlab directory in the LCM source distribution.