This package is to subscribe to and republish Lightweight Communications and Marshalling (LCM) messages into ROS messages (and vice-versa). LCM is an open-source messaging tool for high-bandwidth, low-latency communications based on UDP multicast.
The goal is to make a relatively generic system that requires only LCM message files and automatically generate republishers that either:
- subscribe to an LCM topic and republish the equivalent (same data) messages onto a ROS topic, OR
- subscribe to a ROS topic and republish the equivalent (same data) messages onto a LCM topic.
This package automatically generates ROS message files, CPP files, a launch file and corresponding CMakeLists for catkin_make to create a set of republisher nodes. The system has only been tested on Ubuntu 14.04 with ROS Indigo.
The user should only need to create the *.lcm message files.
Note that this code is restricted to a generating ROS messages from LCM files and not the other way around (partially because LCM has a more limited number of data types but mostly because that's what I needed). The LCM primitive list is available here. We have tested:
LCM Primitive | Scalar | Fixed length array | Variable length array |
---|---|---|---|
int8_t | ✅ | ✅ | ✅ |
int16_t | ✅ | ✅ | ✅ |
int32_t | ✅ | ✅ | ✅ |
int64_t | ✅ | ✅ | ✅ |
float | ✅ | ✅ | ✅ |
double | ✅ | ✅ | ✅ |
string | n/a | n/a | ✅ |
boolean | ✅ | ✅ | ✅ |
byte | ✅ | ✅ | ✅ |
The LCM primitive types work fine because they can be directly converted into ROS types (really the types are standard data types). It is important to note that the code uses a reinterpret cast to directly refer to the incoming LCM message as a ROS message. This means that you should NOT directly edit the autogenerated msg file, because changing the order of items in the msg with respect to the LCM will mess things up. I'm also not 100% confident in my memory management, but it seems to work. The supplied example code shows an example of all the tested types listed above. Subclass messages work fine and an example is included (the simple_channel
message is included in the example_type
type message in example_type.lcm
).
A possibly better approach would be to try and read out the field names from the message and then set them directly, which might be safer than the pointer cast but uglier in terms of generating the CPP file, possible future work.
First, you need to install LCM. Instead of copying the intructions here, I'll link to the LCM build instructions, that contains instructions for various platforms.
Then, clone this repository (assuming default catkin workspace at ~/catkin_ws
):
cd ~/catkin_ws/src
git clone https://github.com/nrjl/lcm_to_ros.git
cd lcm_to_ros
The code works via two primary bash scripts:
rosmsg-gen.sh
- This script takes as input a list of lcm message files and, for each file:- uses the LCM tool
lcm-gen [-x]
to generate a CPP header definition for the message, - generates a corresponding ROS message type, and
- if an lcm fingerprint value is supplied as a comment line in the lcm message file (see the
lcm/example_type.lcm
file), the program also generates a derived class definition that will use the overridden hash value for that message (not usually recommended, if you don't know if you need this, ignore it).
- uses the LCM tool
rosrepub-gen.sh
- This script takes as input a configuration file and generates CPP code and a ROS launch file for ROS nodes that either:- listen to an LCM topic and republish received messages onto a ROS topic, or
- listen to a ROS topic and republish received messages onto an LCM topic.
The repo contains a test example. If you haven't added any other LCM messages (or even if you have) you should be able to confirm the code is working by:
-
Generate ROS messages for all lcm files in your lcm folder by running (at the root project directory of
ros2lcm
):./rosmsg-gen.sh lcm/*.lcm
This will generate standard LCM hpp message definitions (in the
exlcm
directory), ROS messages (in themsg
directory) and a message definition with an overridden hash value of theexample_type
(in theexlcm_rehash
directory). Feel free to examine (but please don't modify) the ROS message definitions. -
Examine the config file
repub_configs/example_republishers.cfg
. It contains specifications for generating two republishers (one for each non#
commented line). The first will subscribe to the LCM topic example_topic of message typeexlcm/example_type
, and publish messages with the newly-generated ROS message typelcm_to_ros/example_type
onto a ROS topic of the same name (example_topic). The second example does the inverse with topic name other_topic but uses the LCM message type with the overridden hash value (using theexlcm_rehash
package specifier). Generate the ROS republisher code by running:./rosrepub-gen.sh repub_configs/example_republishers.cfg
This will generate CPP republisher code in the
autosrc
folder, and a corresponding launch file in thelaunch
directory. -
Compile the newly-generated code using catkin:
cd ~/catkin_ws catkin_make
-
Confirm that it worked!
- In a new terminal, run the launch file:
roslaunch lcm_to_ros example_republishers.launch
- In a new terminal:
- Run
rostopic list
and confirm that the topics /lcm_to_ros/example_topic and /lcm_to_ros/other_topic exist. - Then, show incoming messages using:
rostopic echo /lcm_to_ros/example_topic
- Run
- Finally, in a third terminal:
rosrun lcm_to_ros example_send_lcm
. This is a small LCM-only (no ROS dependencies) program that publishes a single message onto the LCM topic example_topic - Confirm that a message appears in the
rostopic echo
terminal.
- In a new terminal, run the launch file:
Add lcm messages to the lcm
subdirectory. Some key notes about each lcm file:
- Package name - The package name is set by the
package
specifier on the first line of the lcm file. lcm-gen will generate cpp headers in a folder called PACKAGE_NAME. - Struct name - The message type will be the
struct
name specified in the lcm file. The ROS message generated will reflect this, so name each message type with a unique name, even if they have different package names.
Thus, the sample lcm definition example_type.lcm
in the lcm subdirectory specifies an lcm message type example_type
under the exlcm
package. Also note that the repo .gitignore
is set up to ignore files (except the examples) in the lcm directory, so that your messages will not be committed to the repo. To generate LCM hpp files and ROS msg files, use:
./rosmsg-gen.sh lcm/MY_LCM_MESSAGE.lcm
or, to generate ROS messages for all .lcm files in the lcm directory, use:
./rosmsg-gen.sh -a
For both bash scripts, a help message will be displayed with the -h
flag.
Once you have generated the ROS messages, create a config file to create republishers. A config file is a simple comma-separated text file (where lines starting with #
are assumed to be comments and ignored). I suggest creating them in the repub_configs
directory and using the .cfg
extension. Add one line to the config file for each republisher you want to generate. Each (non-comment) line should contain a list of four comma-separated values (do not use whitespace in field names):
topic_name, package_name, message_type, direction
Where:
- topic_name is the name of the lcm topic (the same name is used for the ROS topic, but can be remapped if required)
- package_name is the name of the package of the lcm message you are using (by default, the rehashed version of the message is generated in original_package_rehash, so you can use that if you want to use the rehashed version of the message, as shown in the example)
- message_type is the message type (the keyword after
struct
in the lcm message definition) - direction is either the string
lcm2ros
orros2lcm
. Note that only one is allowed at a time on the same topic to prevent infinite message bouncing. If you need bidirectional messaging there could be some workarounds you could use to filter the messages such as timestamps, but that is not implemented here.
Use the rosrepub-gen.sh
script to generate republisher node code from your config file:
./rosrepub-gen.sh repub_configs/CONFIG_NAME.cfg
The program will generate cpp code and a CMakeLists.txt
file for these republisher nodes in the autosrc
folder. It will also create a launch file in the launch
folder corresponding to the filename of the config file. After generating the code it will need to be built with catkin_make
.
Once complete, the publishers can be run with:
roslaunch lcm_to_ros CONFIG_NAME.launch
(where CONFIG_NAME
is the name of the config file without file extension). Note that this launch file places all republishers under the namespace \lcm_to_ros
.
Each republisher can also be launched separately with: rosrun lcm_to_ros TOPIC_NAME_republisher
. As usual, output topics can be remapped using standard ROS commands if required.
LCM uses a special fingerprint calculation to identify messages to ensure that they can be properly decoded using the same specification that was used to generate them. In general, this is an excellent idea. However, in some cases, you may want to specify a specific hash value. The rosmsg-gen
tool will attempt to create a version of each message with a user-specified hash value if required. This is not advised, but can be handy when trying to force LCM message types to match for automated decoding. In general I suggest you don't use it, but if you need to, after creating a custom lcm message, add a line at the bottom of the lcm file that specifies a 64-bit fingerprint in the format // HASH 0x0123456789abcdef
(as in the example_type.lcm message). This will create a new folder and hpp file with the package name specified in the lcm file appended with _rehash
. You can proceed to use this message as usual, as shown in one of the example republishers, and it will force the LCM encoding and decoding to use the specified fingerprint value.