LCM通信模塊簡介
LCM(Lightweight Communications and Marshalling)是一套用於消息傳遞和數據編組的庫和工具的集合,旨在為實時系統提供高帶寬和低延遲的消息傳遞的能力。它提供了一個發布/訂閱消息傳遞模型以及為各種編程語言的應用程序自動生成編/解組代碼。
LCM允許多個進程以安全和高性能地方式進行消息的交換。消息是LCM通信的基本單元,開發者可將消息定義為與編程語言無關的數據結構,然後使用LCM提供的lcm-gen工具將自定義的數據結構編譯為特定語言的代碼。lcm-gen支持C、C++、Java、Python等編程語言,關於lcm-gen的使用可以參考官方文檔。
2. LCM通信模塊使用方法
本節旨在介紹基於C編程語言進行LCM通信的使用方法。在此之前,用戶需要使用lcm-gen工具將自定義的數據結構編譯為LCM能夠處理的消息格式。
開發者使用LCM進行消息交換時需要完成以下三個主要步驟:
1)初始化LCM;
2)發布一個消息;
3)訂閱及接收消息。
2.1 初始化
LCM的初始化代碼如下所示。
#include <stdio.h> #include <lcm/lcm.h> int main(int argc, char **argv) { lcm_t *lcm = lcm_create(NULL); if(!lcm) { return (PX_ERROR); } /* * 用戶應用程序代碼 */ lcm_destroy(lcm); return (ERROR_NONE); }
函數lcm_create主要完成lcm_t實例的分配與初始化,該實例表示與LCM網絡的連接。其入參為NULL表示使用默認設置來初始化LCM。初始化的默認值適合於本地計算機上的其他LCM應用程序進行通信,也可以指定底層網絡通信機制的字符串。
完成之後,調用lcm_destroy來清理LCM使用的資源。
2.2 發布消息
假定用戶已使用lcm-gen生成了“exlcm_example_t.h”和“exlcm_example_t.c”兩個文件,其中用戶定義的數據結構被lcm-gen編譯並保存在“exlcm_example_t.h”中,假設生成的消息結構如下所示。
typedef struct _exlcm_example_t exlcm_example_t; struct _exlcm_example_t { int64_t timestamp; double position[3]; double orientation[4]; int32_t num_ranges; int16_t ranges; char name; int8_t enabled; };
接下來我們將按照消息結構實例化一些數據並進行發布,如下所示。
#include <stdio.h>
#include <lcm/lcm.h>
#include "exlcm_example_t.h"
int main(int argc, char **argv)
{
int i;
int16_t ranges[15];
lcm_t *lcm = lcm_create(NULL);
if(!lcm) {
return (PX_ERROR);
}
exlcm_example_t lcmData = {
.timestamp = 0,
.position = { 1, 2, 3 },
.orientation = { 1, 0, 0, 0 },
};
for(i = 0; i < 15; i++) {
ranges[i] = i;
}
lcmData.num_ranges = 15;
lcmData.ranges = ranges;
lcmData.name = "example string";
lcmData.enabled = 1;
exlcm_example_t_publish(lcm, "EXAMPLE", &lcmData);
lcm_destroy(lcm);
return (ERROR_NONE);
}
函數exlcm_example_t_publish將數據串行化為字節流,並使用LCM將數據包發送給接收器,“EXAMPLE”在這裏表示通道名,是與數據包一起進行傳輸的字符串,用於向接收方標識內容。接收這使用該標識符訂閱不同的通道,從而可以快速有效的丟棄無關的數據。
2.3 訂閱消息
如2.2節所描述,每個LCM消息都以相關聯的通道名發送,用戶可以根據通道名決定應用程序接收哪些已訂閱的消息。發布者與接收者必須就每種消息類型達成使用的通道名的一致性。
消息訂閱示例代碼如下所示。
#include <stdio.h>
#include <inttypes.h>
#include <sys/select.h>
#include <lcm/lcm.h>
#include "exlcm_example_t.h"
static void my_handler (const lcm_recv_buf_t *rbuf,
const char *channel,
const exlcm_example_t *msg,
void *user)
{
printf("Received message on channel %s:\n", channel);
}
int main(int argc, char ** argv)
{
int status
lcm_t *lcm;
lcm = lcm_create(NULL);
if(!lcm) {
return (PX_ERROR);
}
exlcm_example_t_subscription_t *sub =
exlcm_example_t_subscribe(lcm, "EXAMPLE", &my_handler, NULL);
while(1) {
fd_set fds;
int lcm_fd = lcm_get_fileno(lcm);
FD_ZERO(&fds);
FD_SET(lcm_fd, &fds);
struct timeval timeout = {
1,
0
};
status = select(lcm_fd + 1, &fds, 0, 0, &timeout);
if(ERROR_NONE == status) {
printf("waiting for message\n");
} else if(FD_ISSET(lcm_fd, &fds)) {
lcm_handle(lcm);
}
}
exlcm_example_t_unsubscribe(lcm, sub);
lcm_destroy(lcm);
return (ERROR_NONE);
}
本示例代碼首先創建了一個LCM實例,然後向“EXAMPL”通道添加訂閱,當該通道接收到消息,將會調用my_handler將該通道打印出來。其中my_handler是在lcm_handle函數內被調用的。如果其他通道上有消息傳輸,則該示例程序不會接收到,因為該程序只訂閱了“EXAMPL”通道。通常一個特定的LCM實例可能具有若幹數量的訂閱。
3. 最後
SylixOS基於LCM通信模塊開發了一套板間通信機制。該機制主要完成了對LCM庫的進一步封裝。詳細內容參見文檔《SylixOS板間通信框架開發手冊》。
LCM通信模塊簡介