ROS學(xué)習(xí)(四)ROS系統(tǒng)下LCM通信

如果工程只用ROS搭建霹陡,那么是不需要用到LCM的歪玲。但如果ROS只是整體系統(tǒng)的一部分赚抡,則需要利用內(nèi)存共享或者網(wǎng)絡(luò)傳輸?shù)确绞脚c其他程序進(jìn)行數(shù)據(jù)交互吝沫,這時(shí)候LCM就是一種比較簡(jiǎn)單的選擇呻澜,例如自動(dòng)駕駛中車內(nèi)利用ROS進(jìn)行數(shù)據(jù)流處理控制,車間利用LCM通信惨险。

1. LCM的介紹與安裝

(1)LCM 簡(jiǎn)介

自動(dòng)駕駛領(lǐng)域有很多進(jìn)程間通信的方式羹幸,如ROS、Apollo的Cyber RT以及一些自動(dòng)駕駛初創(chuàng)公司對(duì)ROS進(jìn)行改進(jìn)的通信協(xié)議平道,今天介紹一種適用于高速自動(dòng)駕駛場(chǎng)景的LCM通信協(xié)議睹欲,其特點(diǎn)是輕量化、傳輸速度快一屋,易封裝窘疮。

LCM(Lightweight Communications and Marshalling)是一組用于消息傳遞和數(shù)據(jù)編組的庫和工具,其基于UDP傳輸?shù)膶傩约侥瑐鬏斔俣容^快闸衫,其目標(biāo)是高帶寬和低延遲的實(shí)時(shí)系統(tǒng)。它提供了一種發(fā)布/訂閱消息傳遞模型以及帶有各種編程語言C++诽嘉、Java蔚出、python等應(yīng)用程序綁定的自動(dòng)編組/解組代碼生成,LCM通過將消息封裝在不同的Channel中進(jìn)行通信虫腋,這點(diǎn)類似于ROS中的Topic骄酗。

(2)LCM安裝

Releases · lcm-proj/lcm · GitHub下載源碼包,本文下載的是lcm-1.4.0.zip悦冀。打開terminal并cd到解壓后的文件夾趋翻,依次執(zhí)行:

mkdir build

cd build

cmake ..

make

編譯完成后執(zhí)行:

sudo make install

完成LCM的安裝。然后告訴系統(tǒng)lib的庫所在位置:

export LCM_INSTALL_DIR=/usr/local/lib

sudo sh -c "echo$LCM_INSTALL_DIR> /etc/ld.so.conf.d/lcm.conf"

sudo ldconfig

配置pkgconfig:

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$LCM_INSTALL_DIR/pkgconfig

至此LCM安裝配置完成盒蟆。

2. LCM 通信示例

LCM可以將數(shù)據(jù)進(jìn)行封裝和發(fā)送踏烙,使用UDP組播的方式發(fā)送出去师骗。首先我們需要有我們自己的數(shù)據(jù)。LCM給我們提供了一個(gè)程序讨惩,可以很簡(jiǎn)單的將我們的結(jié)構(gòu)體轉(zhuǎn)變?yōu)長(zhǎng)CM需要的格式(這里必須轉(zhuǎn)變辟癌,否則LCM將無法發(fā)送或封裝),這個(gè)程序就是lcm-gen荐捻。

新建文件夾lcm_example用于存放LCM工程黍少,進(jìn)入lcm_example文件夾,新建example_t.lcm空白文檔來定義一個(gè)我們自己想要的結(jié)構(gòu)體:

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;

}

執(zhí)行:?lcm-gen -x example_t.lcm

生成一個(gè)文件夾exlcm处面,并包含一個(gè)文件example_t.hpp仍侥,到這里lcm結(jié)構(gòu)體定義完成。

接下來我們建立收發(fā)此結(jié)構(gòu)體類型message的LCM收發(fā)機(jī)鸳君。

(1)建立publisher

在lcm_example目錄下农渊,新建send_message.cpp復(fù)制以下內(nèi)容:

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

}

(2)建立subscriber

在lcm_example目錄下,新建listener.cpp復(fù)制以下內(nèi)容:

#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());

? ? return 0;

}

(3)編輯CMakeLists.txt文件

在lcm_example目錄下或颊,新建CMakeLists.txt文件:

project(lcm_test)

set(CMAKE_CXX_STANDARD 11)

add_executable(send_message send_message.cpp)

target_link_libraries(send_message lcm)

add_executable(listener listener.cpp)

target_link_libraries(listener lcm)

編譯CMakeLists.txt文件成功后砸紊,生成可執(zhí)行文件send_message和listener。

分別在兩個(gè)terminal中cd到可執(zhí)行文件所在位置囱挑,分別運(yùn)行:

./listener

./send_message

便可在listerner窗口中看見由send_message發(fā)送的信息醉顽。

3. ROS系統(tǒng)下LCM通信示例

接下來把LCM連接到ROS系統(tǒng)中使用。

(1)建立LCM_Client.cpp文件

#include <ros/ros.h>

#include <iostream>

#include "lcm/lcm-cpp.hpp"

int main(int argc, char** argv)

{

? ros::init(argc, argv, "image_publisher");

? ros::NodeHandle nh;

? lcm::LCM lcm;

? if (!lcm.good())

? {

? ? return 1;

? }

? char data[5];

? data[0] = 1;

? data[1] = 5;

? data[2] = 1;

? data[3] = 2;

? data[4] = 1;

? lcm.publish("EXAMPLE", data,5);//第一個(gè)參數(shù)是通道名平挑,第二個(gè)參數(shù)是數(shù)據(jù)指針游添,第三個(gè)參數(shù)是長(zhǎng)度

? std::cout << "發(fā)送成功!";

? ros::spinOnce();

}

(2)建立LCM_Server.cpp文件

#include <ros/ros.h>

#include <iostream>

#include "lcm/lcm-cpp.hpp"

class MyMessageHandler

{

public:

? void onMessage(const lcm::ReceiveBuffer* rbuf, const std::string& channel)

? {

? ? std::cout << (int)((unsigned char*)rbuf->data)[0] << std::endl;

? ? std::cout << (int)((unsigned char*)rbuf->data)[1] << std::endl;

? ? std::cout << (int)((unsigned char*)rbuf->data)[2] << std::endl;

? ? std::cout << (int)((unsigned char*)rbuf->data)[3] << std::endl;

? ? std::cout << (int)((unsigned char*)rbuf->data)[4] << std::endl;

? ? std::cout << "接收成功!";

? }

};

int main(int argc, char** argv)

{

? ros::init(argc, argv, "image_publisher");

? ros::NodeHandle nh;

? lcm::LCM lcm;

? MyMessageHandler handler;

? lcm.subscribe("EXAMPLE", &MyMessageHandler::onMessage, &handler);

? while (true)

? ? lcm.handle();

? ros::spin();

}

(3)修改CmakeLists.txt文件

include_directories(${catkin_INCLUDE_DIRS})

add_executable(LCM_Client src/LCM_Client.cpp)

target_link_libraries(LCM_Client lcm)

target_link_libraries(LCM_Client ${catkin_LIBRARIES})

add_executable(LCM_Server src/LCM_Server.cpp)

target_link_libraries(LCM_Server lcm) //necessary for lcm message transmission

target_link_libraries(LCM_Server ${catkin_LIBRARIES}

編譯運(yùn)行即可。簡(jiǎn)單來說通熄,在ROS中使用LCM唆涝,需要將lcm相應(yīng)頭文件include進(jìn)來,并且生成lcm變量唇辨,使用lcm.publish和lcm.subscribe即可廊酣。

如有問題歡迎聯(lián)系討論。

參考文檔:自動(dòng)駕駛消息傳輸機(jī)制LCM的安裝與使用_python_snail_zcx的博客-CSDN博客ROS系統(tǒng)學(xué)習(xí)7---LCM數(shù)據(jù)的發(fā)送和接收_matlab_weixinhum-CSDN博客

下一篇:ROS學(xué)習(xí)(五)問題小結(jié) - 簡(jiǎn)書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赏枚,一起剝皮案震驚了整個(gè)濱河市亡驰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饿幅,老刑警劉巖凡辱,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異栗恩,居然都是意外死亡透乾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來续徽,“玉大人,你說我怎么就攤上這事亲澡∏张ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵床绪,是天一觀的道長(zhǎng)客情。 經(jīng)常有香客問我,道長(zhǎng)癞己,這世上最難降的妖魔是什么膀斋? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮痹雅,結(jié)果婚禮上仰担,老公的妹妹穿的比我還像新娘。我一直安慰自己绩社,他們只是感情好摔蓝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著愉耙,像睡著了一般贮尉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朴沿,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天猜谚,我揣著相機(jī)與錄音,去河邊找鬼赌渣。 笑死魏铅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坚芜。 我是一名探鬼主播沦零,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼货岭!你這毒婦竟也來了路操?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤千贯,失蹤者是張志新(化名)和其女友劉穎屯仗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搔谴,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魁袜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峰弹。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡店量,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞠呈,到底是詐尸還是另有隱情融师,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布蚁吝,位于F島的核電站旱爆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窘茁。R本人自食惡果不足惜怀伦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望山林。 院中可真熱鬧房待,春花似錦、人聲如沸驼抹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砂蔽。三九已至洼怔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間左驾,已是汗流浹背镣隶。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诡右,地道東北人安岂。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像帆吻,于是被迫代替她去往敵國和親域那。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355