文章目录
一、LCM中间件简介
LCM(Lightweight Communications and Marshalling)是一款轻量级通信与编组中间件,专为实时系统设计,尤其适用于机器人、自动驾驶、航空航天等对低延迟、高可靠性有要求的领域。其核心优势在于轻量化设计(无集中式服务器)、高效数据传输(基于UDP组播)和跨语言支持(C/C++、Python、Java等),能轻松实现多进程/多设备间的实时数据交互。
二、基本工作原理与核心概念
通信模型
LCM采用发布-订阅(Publish-Subscribe)模式:- 发布者(Publisher):向指定“通道(Channel)”发送消息。
- 订阅者(Subscriber):监听感兴趣的“通道”,接收并处理消息。
- 通道(Channel):字符串标识的消息传输路径(类似“话题”),用于区分不同类型的消息。
数据编组(Marshalling)
LCM通过自定义消息类型实现跨平台数据传输。用户需定义.lcm
格式的消息结构,工具会自动生成对应语言的编解码代码,解决不同设备/语言间的数据格式差异(如大小端、数据类型长度)。传输机制
基于UDP组播实现消息广播,支持同一网络内的多节点通信,无需中心节点转发,减少延迟。同时支持单播模式,适用于点对点通信。
三、Ubuntu下安装LCM
通过包管理器安装(推荐)
适用于Ubuntu 18.04及以上版本:sudo apt update sudo apt install liblcm-dev
源码编译安装
若需最新版本,可从源码编译:# 安装依赖 sudo apt install build-essential cmake libglib2.0-dev # 克隆源码 git clone https://github.com/lcm-proj/lcm.git cd lcm # 编译安装 mkdir build && cd build cmake .. make -j4 sudo make install
验证安装
执行以下命令,若输出版本信息则安装成功:lcm-gen --version
四、C++使用示例
以下通过“温度传感器数据传输”案例,展示LCM的完整使用流程。
1. 定义消息类型(.lcm
文件)
创建temperature.lcm
,定义温度消息结构:
package example; // 消息包名
struct Temperature {
int64_t timestamp; // 时间戳(毫秒)
float value; // 温度值(摄氏度)
string sensor_id; // 传感器ID
}
2. 生成C++代码
使用lcm-gen
工具将.lcm
文件转换为C++代码:
lcm-gen -x temperature.lcm # -x 表示生成C++代码
执行后会生成example/Temperature.hpp
文件,包含消息的结构体定义和编解码逻辑。
3. 发布者代码(publisher.cpp)
#include <lcm/lcm-cpp.hpp>
#include "example/Temperature.hpp"
#include <chrono>
#include <thread>
int main() {
// 创建LCM实例(自动绑定网络)
lcm::LCM lcm;
if (!lcm.good()) {
std::cerr << "LCM初始化失败!" << std::endl;
return 1;
}
// 构造消息
example::Temperature msg;
msg.timestamp = 0;
msg.sensor_id = "sensor_001";
// 循环发布消息(模拟传感器数据)
while (true) {
msg.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
msg.value = 25.0 + (rand() % 100) / 10.0; // 随机温度值(25.0~35.0℃)
// 向通道"THERMOMETER"发布消息
lcm.publish("THERMOMETER", &msg);
std::cout << "发布温度: " << msg.value << "℃(时间戳: " << msg.timestamp << ")" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // 每秒发布一次
}
return 0;
}
4. 订阅者代码(subscriber.cpp)
#include <lcm/lcm-cpp.hpp>
#include "example/Temperature.hpp"
#include <iostream>
// 消息处理类(继承自消息对应的Listener)
class TemperatureHandler {
public:
// 回调函数:接收消息时自动调用
void handleMessage(const lcm::ReceiveBuffer* rbuf,
const std::string& channel,
const example::Temperature* msg) {
std::cout << "\n收到通道 [" << channel << "] 的消息:" << std::endl;
std::cout << "传感器ID: " << msg->sensor_id << std::endl;
std::cout << "温度值: " << msg->value << "℃" << std::endl;
std::cout << "时间戳: " << msg->timestamp << "ms" << std::endl;
}
};
int main() {
lcm::LCM lcm;
if (!lcm.good()) {
std::cerr << "LCM初始化失败!" << std::endl;
return 1;
}
// 创建消息处理器并订阅通道"THERMOMETER"
TemperatureHandler handler;
lcm.subscribe("THERMOMETER", &TemperatureHandler::handleMessage, &handler);
std::cout << "等待接收温度数据..." << std::endl;
while (true) {
lcm.handle(); // 阻塞等待消息,收到后调用回调函数
}
return 0;
}
5. 编译与运行
创建CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(lcm_example)
# -------------------------- 手动指定 LCM 路径 --------------------------
# 替换为你的 LCM 头文件实际路径(根据上面的查询结果修改)
set(LCM_INCLUDE_DIR "/usr/include/lcm") # 包管理器安装
# set(LCM_INCLUDE_DIR "/usr/local/include/lcm") # 源码安装
# 替换为你的 LCM 库文件实际路径(根据上面的查询结果修改)
set(LCM_LIB_DIR "/usr/lib/x86_64-linux-gnu") # 包管理器安装
# set(LCM_LIB_DIR "/usr/local/lib") # 源码安装
# 指定 LCM 库文件名(通常是 liblcm.so,去掉前缀 "lib" 和后缀 ".so" 即为库名)
set(LCM_LIB "lcm")
# ----------------------------------------------------------------------
# 引入 LCM 头文件
include_directories(${LCM_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
# 引入 LCM 库文件路径
link_directories(${LCM_LIB_DIR})
# 编译发布者和订阅者,并链接 LCM 库
add_executable(publisher publisher.cpp example/Temperature.hpp)
target_link_libraries(publisher ${LCM_LIB})
add_executable(subscriber subscriber.cpp example/Temperature.hpp)
target_link_libraries(subscriber ${LCM_LIB})
编译并运行:
# 编译
mkdir build && cd build
cmake ..
make
# 打开两个终端,分别运行
./subscriber # 订阅者
./publisher # 发布者
运行后,订阅者会实时接收并打印发布者发送的温度数据。
五、总结
LCM凭借轻量化、低延迟的特性,在实时系统通信中占据重要地位。其核心是通过发布-订阅模式和自定义消息类型,实现跨进程/跨设备的高效数据交互。在Ubuntu环境下,通过简单的安装和代码生成流程,即可快速集成到C++项目中,特别适合机器人、无人机等领域的实时数据传输需求。