在Microzed上移植ROS—基于linaro

最近想玩玩智能小车,就想在吃灰已久的Microzed上面运行ROS以实现一些比较好玩的功能。第一个拦路虎就是如何把ROS移植到系统上面。Microzed目前支持比较好的Linux系统是Linaro,而ROS官方的Ubuntu ARM install of ROS Indigo(http://wiki.ros.org/indigo/Installation/UbuntuARM)并不合适,试了很多次,踩了很多坑始终无法解决依赖。本文记录一下踩过的坑,方便以后查看。

在Microzed上移植ROS—基于linaro

背景

最近想玩玩智能小车,就想在吃灰已久的Microzed上面运行ROS以实现一些比较好玩的功能。第一个拦路虎就是如何把ROS移植到系统上面。Microzed目前支持比较好的Linux系统是Linaro,而ROS官方的Ubuntu ARM install of ROS Indigo(http://wiki.ros.org/indigo/Installation/UbuntuARM)并不合适,试了很多次,踩了很多坑始终无法解决依赖。本文记录一下踩过的坑,方便以后查看。

第一步:安装好合适的linux

这一步直接参考官方教程:Installing Linux on the MicroZed(https://github.com/SDU-Embedded/linux_zynq/wiki/Installing-Linux-on-the-MicroZed).

编译环境如下:

  1. 主机:Windows 10 x64
  2. 虚拟机:ubuntu 16.04 LTS
  3. 开发环境:Vivado 2018.1/SDK(运行在虚拟机里,webpack版本)

按照链接的教程生产BOOT.bin

  1. 生成devicetree.dtb的指令有两个”O”,但绝对不是0

dtc -I dts -O dtb -o devicetree.dtb devicetree.dts

BOOT部分生成之后下载Linaro的最新版本,解压到ROOT_FS内即可

http://releases.linaro.org/debian/images/developer-armhf/latest/

第二步:让Linaro运行起来

给mirozed通电,Windows上用putty 通过串口连接,运行Linaro

注意要插上网线,dhcp模式自动获取到IP并连接到网络

运行一次:

    $ apt-get update
  1. 如何在Windows和Mirozed板子之间传输文件?

推荐使用WinS C P连接并传输文件

  1. Linaro默认不允许root登陆ssh

SCP协议是基于SSH的,当Microzed获取到IP之后就可以通过WinSCP去连接板子了,但问题是此时板子上的SSH还不允许root用户登陆,

需要做如下操作:

sudo
                        vi /etc/ssh/sshd_config

修改ssh服务配置文件,两种情况:

调整PermitRootLogin参数值为yes,如下图:



同时做如下修改:

1) 将PermitEmptyPasswords yes前面的#号去掉

2) 将PermitEmptyPasswords 参数值修改为yes

保存后执行:

service sshd restart  # 或者

重启sshd服务即可通过WinSCP连接(使用SCP)

第三步:在Linaro上安装ROS

经过多次调试确认,ROS的ubuntu ARM的Wiki(http://wiki.ros.org/indigo/Installation/UbuntuARM)只适用于Ubuntu 14.04 armhf版本,并不适用与其他发行版,因此需要想办法从源码安装,这里直接用microzed自己编译了源码,费时较长,感兴趣的小伙伴可以试试交叉编译。

按照官网的Installing from source(http://wiki.ros.org/Installation/Source)来实现移植。

由于Linaro是基于Debian的,因此按照Debian的教程来就可以了。

  1. 依赖项

Bootstrap依赖

apt-get install python-rosdep python-rosinstall-generator python-wstool python-rosinstall build-essential

初始化Rosdep

$ sudo rosdep init
$ rosdep update
  1. 安装

创建catkin 工作目录

$ mkdir ~/ros_catkin_ws

$ cd ~/ros_catkin_ws

安装ROS-Comm: (Bare Bones),无GUI版本

$ rosinstall_generator ros_comm --rosdistro melodic --deps --tar > melodic-ros_comm.rosinstall
$ wstool init -j8 src melodic-ros_comm.rosinstall

解析依赖并安装

$ rosdep install --from-paths src --ignore-src --rosdistro melodic -y

Build catkin workspace

$ ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release

取决于网络快慢和运行速度,这个过程大概在2个小时。

编译完成后执行:

$ source ~/ros_catkin_ws/install_isolated/setup.bash

此时ROS已经完成了安装

如何验证ROS?

  1. Hello world—第一个Talker和listener实例

参考博文:https://blog.csdn.net/eliot_shao/article/details/73730373

  1. 创建一个工作区(workspace)

工作区可以作为一个独立的项目进行编译,存放ROS程序的源文件、编译文件和执行文件。建立工作区的方法如下:

[plain] view plain copy

  1. $ mkdir -p ~/catkin_ws/src  
  2. $ cd ~/catkin_ws/src  
  3. $ catkin_init_workspace  

虽然这时候工作区是空的,但是我们依然可以进行编译:

[plain] view plain copy

  1. $ cd ~/catkin_ws/  
  2. $ catkin_make  

这时候,会在当前文件夹下生成devel,build这两个子文件夹,在devel文件夹下能看到几个setup.*sh文件。

接下来把工作区在bash中注册

[plain] view plain copy

  1. $ source devel/setup.bash  
  1. 创建一个ROS工程包(Package)

在一个工作区内,可能会包含多个ROS工程包。而最基本ROS工程包中会包括CmakeLists.txt和Package.xml这两个文件,其中Package.xml中主要包含本项目信息和各种依赖(depends),而CmakeLists.txt中包含了如何编译和安装代码的信息。

首先切换到工作区:

[plain] view plain copy

  1. $ cd ~/catkin_ws/src  

现在可以使用catkin_create_pkg命令去创建一个叫beginner_tutorials的包,这个包依靠std_msgs、roscpp、rospy。

[plain] view plain copy

  1. $ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp  

接下来在工作区编译这个工程包。

[plain] view plain copy

  1. $ cd ~/catkin_ws  
  2. $ catkin_make  

beginner_tutorials/src下放入两个cpp文件:talker.cpp/listener.cpp

内容如下:

Talker.cpp

  1. #include “ros/ros.h”  
  2. #include “std_msgs/String.h”  
  3. #include <sstream>  
  4. int main(int argc, char **argv)  
  5. {  
  6.   /** 
  7.    * The ros::init() function needs to see argc and argv so that it can perform 
  8.    * any ROS arguments and name remapping that were provided at the command line. For programmatic 
  9.    * remappings you can use a different version of init() which takes remappings 
  10.    * directly, but for most command-line programs, passing argc and argv is the easiest 
  11.    * way to do it.  The third argument to init() is the name of the node. 
  12.    * 
  13.    * You must call one of the versions of ros::init() before using any other 
  14.    * part of the ROS system. 
  15.    */  
  16.   ros::init(argc, argv, “talker”);  
  17.   /** 
  18.    * NodeHandle is the main access point to communications with the ROS system. 
  19.    * The first NodeHandle constructed will fully initialize this node, and the last 
  20.    * NodeHandle destructed will close down the node. 
  21.    */  
  22.   ros::NodeHandle n;  
  23.   /** 
  24.    * The advertise() function is how you tell ROS that you want to 
  25.    * publish on a given topic name. This invokes a call to the ROS 
  26.    * master node, which keeps a registry of who is publishing and who 
  27.    * is subscribing. After this advertise() call is made, the master 
  28.    * node will notify anyone who is trying to subscribe to this topic name, 
  29.    * and they will in turn negotiate a peer-to-peer connection with this 
  30.    * node.  advertise() returns a Publisher object which allows you to 
  31.    * publish messages on that topic through a call to publish().  Once 
  32.    * all copies of the returned Publisher object are destroyed, the topic 
  33.    * will be automatically unadvertised. 
  34.    * 
  35.    * The second parameter to advertise() is the size of the message queue 
  36.    * used for publishing messages.  If messages are published more quickly 
  37.    * than we can send them, the number here specifies how many messages to 
  38.    * buffer up before throwing some away. 
  39.    */  
  40.   ros::Publisher chatter_pub = n.advertise<std_msgs::String>(“chatter”, 1000);  
  41.   ros::Rate loop_rate(10);  
  42.   /** 
  43.    * A count of how many messages we have sent. This is used to create 
  44.    * a unique string for each message. 
  45.    */  
  46.   int count = 0;  
  47.   while (ros::ok())  
  48.   {  
  49.     /** 
  50.      * This is a message object. You stuff it with data, and then publish it. 
  51.      */  
  52.     std_msgs::String msg;  
  53.     std::stringstream ss;  
  54.     ss << “hello world “ << count;  
  55.     msg.data = ss.str();  
  56.     ROS_INFO(“%s”, msg.data.c_str());  
  57.     /** 
  58.      * The publish() function is how you send messages. The parameter 
  59.      * is the message object. The type of this object must agree with the type 
  60.      * given as a template parameter to the advertise<>() call, as was done 
  61.      * in the constructor above. 
  62.      */  
  63.     chatter_pub.publish(msg);  
  64.     ros::spinOnce();  
  65.     loop_rate.sleep();  
  66.     ++count;  
  67.   }  
  68.   return 0;  
  69. }  

Listener.cpp

  1. #include “ros/ros.h”  
  2. #include “std_msgs/String.h”  
  3. /** 
  4.  * This tutorial demonstrates simple receipt of messages over the ROS system. 
  5.  */  
  6. void chatterCallback(const std_msgs::String::ConstPtr& msg)  
  7. {  
  8.   ROS_INFO(“I heard: [%s]”, msg->data.c_str());  
  9. }  
  10. int main(int argc, char **argv)  
  11. {  
  12.   /** 
  13.    * The ros::init() function needs to see argc and argv so that it can perform 
  14.    * any ROS arguments and name remapping that were provided at the command line. For programmatic 
  15.    * remappings you can use a different version of init() which takes remappings 
  16.    * directly, but for most command-line programs, passing argc and argv is the easiest 
  17.    * way to do it.  The third argument to init() is the name of the node. 
  18.    * 
  19.    * You must call one of the versions of ros::init() before using any other 
  20.    * part of the ROS system. 
  21.    */  
  22.   ros::init(argc, argv, “listener”);  
  23.   /** 
  24.    * NodeHandle is the main access point to communications with the ROS system. 
  25.    * The first NodeHandle constructed will fully initialize this node, and the last 
  26.    * NodeHandle destructed will close down the node. 
  27.    */  
  28.   ros::NodeHandle n;  
  29.   /** 
  30.    * The subscribe() call is how you tell ROS that you want to receive messages 
  31.    * on a given topic.  This invokes a call to the ROS 
  32.    * master node, which keeps a registry of who is publishing and who 
  33.    * is subscribing.  Messages are passed to a callback function, here 
  34.    * called chatterCallback.  subscribe() returns a Subscriber object that you 
  35.    * must hold on to until you want to unsubscribe.  When all copies of the Subscriber 
  36.    * object go out of scope, this callback will automatically be unsubscribed from 
  37.    * this topic. 
  38.    * 
  39.    * The second parameter to the subscribe() function is the size of the message 
  40.    * queue.  If messages are arriving faster than they are being processed, this 
  41.    * is the number of messages that will be buffered up before beginning to throw 
  42.    * away the oldest ones. 
  43.    */  
  44.   ros::Subscriber sub = n.subscribe(“chatter”, 1000, chatterCallback);  
  45.   /** 
  46.    * ros::spin() will enter a loop, pumping callbacks.  With this version, all 
  47.    * callbacks will be called from within this thread (the main one).  ros::spin() 
  48.    * will exit when Ctrl-C is pressed, or the node is shutdown by the master. 
  49.    */  
  50.   ros::spin();  
  51.   return 0;  
  52. }  

在CMakeLists.txt中加入信息,告诉编译器需要编译的文件以及依赖,在文件末尾处添加以下信息:

  1. include_directories(include ${catkin_INCLUDE_DIRS})  
  2. add_executable(talker src/talker.cpp)  
  3. target_link_libraries(talker ${catkin_LIBRARIES})  
  4. add_dependencies(talker beginner_tutorials_generate_messages_cpp)  
  5. add_executable(listener src/listener.cpp)  
  6. target_link_libraries(listener ${catkin_LIBRARIES})  
  7. add_dependencies(listener beginner_tutorials_generate_messages_cpp)  

将目录切换到工作区目录,并执行catkin_make运行命令:

  1. $ cd ~/catkin_ws  
  2. $ catkin_make  

正常情况下应该编译完成

  1. 验证程序正常运行

后台启动roscore

分别开两个terminal运行:

  1. $ cd ~/catkin_ws  
  2. $ source ./devel/setup.bash  
  3. $ rosrun beginner_tutorials talker   
  4. $ rosrun beginner_tutorials listener 

效果如下:

Listener:

Talker:

ROScore:

至此大功告成

2 回复

发表评论

Want to join the discussion?
Feel free to contribute!

黑糯进行回复 取消回复

邮箱地址不会被公开。 必填项已用*标注