LCM-发、收

  • 这几天写了lcm发、收、录、读的小工具,之前都用过发和收,这次主要还是录和读,就是把接收到的lcm消息保存下来,再通过另外一个读的程序把数据读出来,用于离线分析等。
  • LCM(Lightweight Communications and
    Marshalling)在实时系统的数据传递中经常被使用。它具有高带宽、低延迟的特点,支持多种编程语言,API使用方便。官方文档提供了基本的使用说明,以及函数的具体代表。

发送消息

step1:定义结构体

1、将要发送的数据,定义在一个结构体中,写在以 .lcm 结尾的文件中。比如:

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;
}

其中,数据类型需要使用lcm支持的类型,如下:
在这里插入图片描述
定义好数据结构后,生成对应语言使用的头文件。使用如下指令:
在这里插入图片描述
没有问题的话就会生成example_t.hpp,这个文件是不允许修改的。

step2:LCM初始化

数据结构的头文件生成后,在主程序代码里#include进来

#include <lcm/lcm-cpp.hpp>
#include “example_t.hpp"

定义lcm的对象并初始化

lcm::LCM lcm;
 if(!lcm.good())
	return 1;

初始化干了什么呢?我们进去看一下:

inline bool
LCM::good() const
{
    return this->lcm != NULL;
}

好像也没干什么?

step3:赋值并发送

在程序中定义一个数据结构的对象,并在相应的位置进行赋值

example_t   my_data;
my_data.timestamp = 0;
my_data.position[0] = 1;
my_data.position[1] = 2;
my_data.position[2] = 3;

发送

lcm.publish("EXAMPLE", &my_data);

其中"EXAMPLE"为通道名,可以自由定义,接收的时候也要指定,二者保持一致才能收到。
发送的数据较多时,可以定义多个数据结构,相应会有多个lcm生成的头文件。用不同的通道名来区分他们。发送时也可灵活选择对哪些通道的数据进行发送。

至此,lcm发送的方式就结束了,还是很简洁的。整个发送代码如下:

 	  #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;
    
    
        lcm.publish("EXAMPLE", &my_data);
    
        return 0;
    }

接收消息

消息接收主要利用lcm.subscribe()函数,函数定义如下:

LCM::subscribe(const std::string& channel,
    void (MessageHandlerClass::*handlerMethod)(const ReceiveBuffer* rbuf, const std::string& channel, const MessageType* msg),
    MessageHandlerClass* handler)

上面需要3个参数,分别是(通道名、回调函数、句柄对象)。
subscribe()还有另一种重载形式,其中回调函数只要2个参数,不用绑定具体的类对象。

LCM::subscribe(const std::string& channel,
    void (MessageHandlerClass::*handlerMethod)(const ReceiveBuffer* rbuf, const std::string& channel),
    MessageHandlerClass* handler)

step1:LCM初始化

 #include <stdio.h>
 #include <lcm/lcm-cpp.hpp>
#include "exlcm/example_t.hpp"

int main(int argc, char** argv)
	 {
        lcm::LCM lcm;
        if(!lcm.good())
            return 1;
      }

step2:定义句柄及回调函数

句柄类可以如下定义,其中handleMessage即为subscribe时使用的回调函数:

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("\n");
            }
    };

上面代码将接收到的内容打印出来,可以看到,使用了之前定义的消息类型example_t

step3:接收消息

定义句柄对象,调用subscribe()函数接收。其中lcm.handle()

Handler handlerObject;
lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject);

while(0 == lcm.handle());

LCM自动解码消息,再传给回调函数,回调函数可以识别消息类型。因为回调函数在lcm.handle()方法中调度,所以不需要并发执行,这些都在一个单线程中完成。
调用lcm.handle()非常重要,函数会保持阻塞直到有任务需要做。

完整的接收代码如下,代码只会接收通道名为”EXAMPLE"的消息。

	1 #include <stdio.h>
    2 #include <lcm/lcm-cpp.hpp>
    3 #include "exlcm/example_t.hpp"
    4 
    5 class Handler 
    6 {
    7     public:
    8         ~Handler() {}
    9 
   10         void handleMessage(const lcm::ReceiveBuffer* rbuf,
   11                 const std::string& chan, 
   12                 const exlcm::example_t* msg)
   13         {
   14             int i;
   15             printf("Received message on channel \"%s\":\n", chan.c_str());
   16             printf("  timestamp   = %lld\n", (long long)msg->timestamp);
   17             printf("  position    = (%f, %f, %f)\n",
   18                     msg->position[0], msg->position[1], msg->position[2]);
   28         }
   29 };
   30 
   31 int main(int argc, char** argv)
   32 {
   33     lcm::LCM lcm;
   34     if(!lcm.good())
   35         return 1;
   36 
   37     Handler handlerObject;
   38     lcm.subscribe("EXAMPLE", &Handler::handleMessage, &handlerObject);
   39 
   40     while(0 == lcm.handle());
   41 
   42     return 0;
   43 }

一个lcm对象可以有无限个接收器,如果有多个通道的消息需要接收,可以

lcm.subscribe("AAAA", &Handler::handleMessage, &handlerObject);
lcm.subscribe("BBBB", &Handler::handleMessage, &handlerObject);

或者用下面方式接收所有通道

lcm.subscribe(".*", &Handler::handleMessage, &handlerObject);
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值