[学习LCM]lcm教程与实例(C++ API)

背景

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

以上文件可以在这里下载.

其他文章:
lcm实例(Python API)
lcm安装c++和python版本,不同编程语言之间相互通信

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值