背景
Ubuntu 16.04
C++ API
lcm 1.30
1. 安装
版本: 1.3.0, 下载
安装 autoconf :
$ sudo apt-get install autoconf
解压, 编译, 在LCM目录下执行:
$ autoreconf -i
$ ./configure
$ make -j8 -l8
$ sudo make install
安装位置:/usr/local/:
在/usr/local/bin目录下安装lcm-gen, lcm-logger, lcm-logplayer, lcm-logplayer-gui, lcm-spy可执行程序
在/usr/local/lib目录下安装liblcm.la, liblcm.so, liblcm.so.1, liblcm.so.1.3.3库文件
在/usr/local/include目录下安装eventlog.h, lcm_coretypes.h, lcm-cpp.hpp, lcm-cpp-impl.hpp, lcm.h头文件配置头文件, 在home/igs/.profile中添加以下内容后, 重启:
#glib c++
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/include/glib-2.0:/usr/lib/x86_64-linux-gnu/glib-2.0/include
#lcm
#export CLASSPATH=.:$CLASSPATH:/program/3rd/lcm/lcm-1.2.1/lcm-java/build/lcm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
#glib c
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/include/glib-2.0:/usr/lib/x86_64-linux-gnu/glib-2.0/include
2. 介绍
LCM(Lightweight Communications and Marshalling)是一套用于消息传递和数据编组的库和工具,针对高带宽和低延迟至关重要的实时系统。 它提供了一个发布/订阅消息传递模型和自动编组/解组代码生成,并为各种编程语言的应用程序提供绑定。
C++ API 提供了三个类两个结构体封装LCM:
class lcm::LCM
struct lcm::ReceiveBuffer
class lcm::Subscription
struct lcm::LogEvent
class lcm::LogFile
3. 教程
该教程介绍了如何使用C++ API交换LCM信息(LCM 提供了多种语言的API, 这里只以C++ 为例). 教程包含以下几部分:
3.1 创建类型定义(type definition)
由于类型定义与编程语言类型无关,故第一步对所有编程语言都一样; 类型规则的定义与C语言非常像, 下面是一个名为example_t的示例类型, 创建一个名为 example_t.lcm 的文件.
package exlcm;
struct example_t
{
int64_t timestamp;
double position[3];
double orientation[4];
int32_t num_ranges;
int16_t ranges[num_ranges];
string name;
boolean enabled;
}
更多类型规范,下表是基本类型规范:
type Description
int8_t 8-bit signed integer
int16_t 16-bit signed integer
int32_t 32-bit signed integer
int64_t 64-bit signed integer
float 32-bit IEEE floating point value
double 64-bit IEEE floating point value
string UTF-8 string
boolean true/false logical value
byte 8-bit value
除此之外还可以定义数组;
生成特定编程语言的绑定(bindings):
lcm-gen -x example_t.lcm
如果你用的不是C++, 运行lcm-gen -h 获取命令行帮助;
运行之后,会在当前文件夹生成一个exlcm/example_t.hpp 的文件, 它包含了之前定义类型的同名类:
class example_t
{
public:
int64_t timestamp;
double position[3];
double orientation[4];
int32_t num_ranges;
std::vector< int16_t > ranges;
std::string name;
int8_t enabled;
3.2 初始化LCM
任何使用LCM的应用程序第一步就是初始化LCM库, 下面是一个例子:
#include <lcm/lcm-cpp.hpp>
int main(int argc, char ** argv)
{
lcm::LCM lcm;
if(!lcm.good())
return 1;
// Your application goes here
return 0;
}
3.3 发布(publish)一个消息
// send_message.cpp
#include <lcm/lcm-cpp.hpp>
#include "exlcm/example_t.hpp"
int main(int argc, char **argv)
{
lcm::LCM lcm;
if (!lcm.good())
return 1;
exlcm::example_t my_data;
my_data.timestamp = 0;
my_data.position[0] = 1;
my_data.position[1] = 2;
my_data.position[2] = 3;
my_data.orientation[0] = 1;
my_data.orientation[1] = 0;
my_data.orientation[2] = 0;
my_data.orientation[3] = 0;
my_data.num_ranges = 15;
my_data.ranges.resize(my_data.num_ranges);
for (int i = 0; i < my_data.num_ranges; i++)
my_data.ranges[i] = i;
my_data.name = "example string";
my_data.enabled = true;
lcm.publish("EXAMPLE", &my_data);
return 0;
}
lcm::LCM::publish() 会将数据序列化为字节流,并使用LCM将数据包传输到任何感兴趣的接收者, 字符串 EXAMPLE 是频道名称, 是随每个数据包一起发送的字符串.
3.4 订阅和接收(subscribe and receive)一个消息
下面是一个接收 EXAMPLE 的例子:
// listener.cpp
#include <stdio.h>
#include <lcm/lcm-cpp.hpp>
#include "exlcm/example_t.hpp"
class Handler {
public:
~Handler() {}
void handleMessage(const lcm::ReceiveBuffer *rbuf, const std::string &chan,
const exlcm::example_t *msg)
{
int i;
printf("Received message on channel \"%s\":\n", chan.c_str());
printf(" timestamp = %lld\n", (long long) msg->timestamp);
printf(" position = (%f, %f, %f)\n", msg->position[0], msg->position[1],
msg->position[2]);
printf(" orientation = (%f, %f, %f, %f)\n", msg->orientation[0], msg->orientation[1],
msg->orientation[2], msg->orientation[3]);
printf(" ranges:");
for (i = 0; i < msg->num_ranges; i++)
printf(" %d", msg->ranges[i]);
printf("\n");
printf(" name = '%s'\n", msg->name.c_str());
printf(" enabled = %d\n", msg->enabled);
}
};
int main(int argc, char **argv)
{
lcm::LCM lcm;
if (!lcm.good())
return 1;
Handler handlerObject;
lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject);
while (0 == lcm.handle()) {
// Do nothing
}
return 0;
}
3.5 运行
文件夹结构如下:
example_t.lcm
listener.cpp
Makefile
read_log.cpp
send_message.cpp
将 Makefile 28 行修改为 lcm-gen -x *.lcm;
在当前文件夹运行 make, 会出现三个可执行文件:listener, read_log, send_message;
运行 ./listener 再开一个窗口运行 ./send_message 可以看到 listener 窗口接收到信息:
Received message on channel "EXAMPLE":
timestamp = 0
position = (1.000000, 2.000000, 3.000000)
orientation = (1.000000, 0.000000, 0.000000, 0.000000)
ranges: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
name = 'example string'
enabled = 1
以上文件可以在这里下载.