前面的几篇文章我们简单介绍了ROS的一些基本操作和数据获取的实现。下面,我们将更深入地研究ROS的数据传递,因为这关系到能不能真正把ROS用于实际的工程项目中。

 

如果工程只用ROS搭建,那么是不需要用到命题所说的LCM的。但如果ROS只是整体系统的一部分,则需要利用内存共享或者网络传输等方式与其他程序进行数据交互,这时候LCM就是一种比较简单的选择(如果不清楚什么是LCM,可以参考这篇文章)。

 

下面,我们将逐步介绍如何在ROS系统中使用LCM。

 

联系前面,我们已经知道ROS归根结底是一个多进程的管理工具,因此我们可以把上面的工作分成两步。

 

第一步:在Ubuntu下把LCM搭建起来,可以直接发送和接收数据。

 

第二步:把上面做完的用LCM发送和接收的代码移植到ROS中。

 

下面我们来做第一步(这里只用C++实现,其他版本类似):

先安装编译LCM会用到的依赖项:

 
sudo apt-get install build-essential autoconf automake autopoint libglib2.0-dev libtool openjdk-8-jdk python-dev
 

github上下载源码包,这里本人下的是"lcm-1.4.0.zip"

 

下完后直接解压缩,然后cd进去解压后的文件夹:

 
mkdir build
cd build
cmake ..
make
 

等待编译完成(意外的快),然后安装:

 
sudo make install
 

完成这一步就算搞定了,但这个时候系统不知道lib的库在哪里,因此需要告诉它。

 

为lcm创建一个ld.so.conf文件:

 
export LCM_INSTALL_DIR=/usr/local/lib
sudo sh -c "echo $LCM_INSTALL_DIR > /etc/ld.so.conf.d/lcm.conf"
 

更新

 
sudo ldconfig
 

配置pkgconfig来查找lcm.pc

 
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$LCM_INSTALL_DIR/pkgconfig
 

做完上面的步骤,则LCM就全部安装配置完成了。接着我们可以写一个客户端和服务器测试下。

 

首先写服务器,LCM_Client.cpp:

 
#include <iostream>
#include "lcm/lcm-cpp.hpp"
 
int main()
{
	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);//第一个参数是通道名,第二个参数是数据指针,第三个参数是长度
	std::cout << "发送成功!";
	return 0;
}
 

然后编译+链接:

 
g++ `pkg-config --cflags lcm` -I. -o Client.o -c LCM_Client.cpp
g++ -o Client Client.o `pkg-config --libs lcm`
 

其次写客户端,LCM_Server.cpp:

 
#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() {
	lcm::LCM lcm;
	MyMessageHandler handler;
	lcm.subscribe("EXAMPLE", &MyMessageHandler::onMessage, &handler);
	while (true)
		lcm.handle();
	return 0;
}
 

同样编译+链接:

 
g++ `pkg-config --cflags lcm` -I. -o Server.o -c LCM_Server.cpp
g++ -o Server Server.o `pkg-config --libs lcm`
 

这样我们就得到了LCM的服务器和客户端,运行效果如下:

  微信图片_20210120162337   微信图片_20210120162347  

接下来我们看看怎么把LCM放到ROS里面跑。

 

在我们前面文章创建的rosOpenCV包下新建两个文件,分别为“LCM_Client.cpp”、“LCM_Server.cpp”,内容如下:

 

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);//第一个参数是通道名,第二个参数是数据指针,第三个参数是长度
  std::cout << "发送成功!";
 
  ros::spinOnce();
}
 

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

接着修改“CmakeLists.txt”,主要内容如下:

 
include_directories(${catkin_INCLUDE_DIRS})
add_executable(LCM_Client /home/weixin/桌面/lcmdemo/src/printHelloRosPK/src/LCM_Client.cpp)
target_link_libraries(LCM_Client lcm)
target_link_libraries(LCM_Client ${catkin_LIBRARIES})
 
add_executable(LCM_Server /home/weixin/HelloRos/src/rosOpenCV/src/LCM_Server.cpp)
target_link_libraries(LCM_Server lcm)
target_link_libraries(LCM_Server ${catkin_LIBRARIES})
 

最后编译运行一下即可。