方法1:
交叉编译环境搭建流程
- 交叉编译环境搭建的主要思路是利用catkin提供的rostoolchain脚本设置相应的交叉编译工具、lib库地址等,中间遇到问题再针对性解决。
基础环境:
- 目标运行环境
- arm64 cpu
- Ubuntu 16.04
- ros kinetic for arm
- 编译环境
- x86_64 cpu
- Ubuntu Kylin(16.04)
- ros kinetic for amd64
环境设置流程:
1 ARM ubuntu环境上安装arm-indigo版本,后面需要将这个arm版本copy到交叉编译环境上
2 x86环境上安装docker(ubuntu)
3 下载docker-ros(ubuntu)镜像, 加载启动docker-ros(ubuntu+ROS)镜像
4 安装 sudo apt-get install g++-arm-linux-gnueabihf
5 将docker环境中中x86版本的indigo替换成arm版本的indigo,
替换之前需要备份x86版本indigo的lib,因为这些库文件在运行ros时是需要的。
将x86版本indigo的lib保存到localpath目录下,设置export LD_LIBRARY_PATH=localpath,
实现运行ros命令时使用x86的lib库。
6 将arm环境下的库文件/头文件 copy到docker环境中,目录可以自己设定比如:/$ENV{HOME}/cross-compiling/ubuntu-rootfs
7 配置rostoolchain.cmake文件
8 修改/opt/ros/indigo/share/catkin/cmake/tools/rt.cmake
该文件的第34行
9 个人理解cmake交叉编译过程就是修改cmake搜索链接库文件位置的过程,正常编译会搜索x86库文件做在位置,
交叉编译需要将搜索位置切换到目标架构需要的库文件存放位置,比如/$ENV{HOME}/cross-compiling/ubuntu-rootfs
实现方法:
修改catkin_INCLUDE_DIRS catkin_LIBRARY_DIRS,将这两个变量中指向x86系统的位置,修改为指向交叉编译依赖文件存放位置
这个文件末增加如下处理:
10 编译命令
编译
- 命令
验证编译产出
- 将devel产出拷贝到px2的workspace中,启动roscore之后,进入devel/lib/hdmap_interface,运行./hdmap_interface_node
tip:参考了https://zhuanlan.zhihu.com/p/183819313的相关操作,并清晰阐释了该流程。
方法2:
ros开源了一套编译库,直接通过python即可得到交叉编译的结果。
这个包安装ros_cross_compile命令后,使用以下指令即可实现交叉。命令的第一个参数是指向ROS工作区的路径。
下面是一个标准工作流的简单调用
python -m ros_cross_compile /path/to/my/workspace --arch aarch64 --os ubuntu --rosdistro dashing
关于脚本的其他参数说明,执行”python -m ros_cross_compile -h“获得。
tips:python后面需要加 -m 来实现模块当作脚本来启动,作者发现文章举的例子较为详细,因此作为采用,来阐述此处为何需要python -m
python xxx.py
与python -m xxx
。
这是两种加载py文件的方式:
前者叫做直接运行,此时脚本的__name__
为'main'
;
后者把模块当作脚本来启动,相当于import
,此时脚本的__name__
为'xxx'
。这种启动方式时最好不要带后缀.py
。
不同的加载py文件的方式,主要是影响sys.path
这个属性。sys.path
是一个list,是当前Python解析器运行的环境,Python解析器会在这些目录下去寻找依赖库。python导入文件或模块时默认会先在sys.path
里找其的路径。
# 直接启动:python run.py
test_import_project git:(master) ✗ python run.py
['/Users/sx/Documents/note/test_py/test_import_project',
'/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
...]
# 以模块方式启动:python -m run
test_import_project git:(master) ✗ python -m run
['',
'/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
对比一下就可以发现,-m
运行比直接运行仅是多了一个’’,也就是当前所在的目录。
直接启动:把run.py
文件所在的目录放到了sys.path
属性中。
模块启动:把也就是当前路径放到了sys.path
属性中
在实际场景中,对于多个启动目录的程序效果明显
# 目录结构如下
package/
__init__.py
mod1.py
package2/
__init__.py
run.py
# run.py 内容如下
import sys
from package import mod1
print(sys.path)
现在就尝试以两种不同的方法启动run.py
文件。
# 直接启动(失败)
➜ test_import_project git:(master) ✗ python package2/run.py
Traceback (most recent call last):
File "package2/run.py", line 2, in <module>
from package import mod1
ImportError: No module named package
# 以模块方式启动(成功)
➜ test_import_project git:(master) ✗ python -m package2.run
['',
'/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
...]
接下来分析一下原因。
需要注意的是,当需要启动的py文件引用了一个模块,在启动的时候需要考虑sys.path中有没有import的模块的路径。这个时候,到底是使用直接启动,还是以模块的启动?目的就是把import的那个模块的路径放到sys.path中。
导入一个模块时,解释器先在当前目录中搜索它。如果没有找到的话,就会到 sys.path变量中给出的目录列表中查找。
我们要启动package2文件夹下的run.py,所需模块在package目录中。因此当我们直接执行run.py时,只是把run.py文件所在的目录放到了sys.path属性中,sys.path并没有把package目录收录。故会报错。
当我们使用-m参数时,把当前路径放到了sys.path属性中。当前路径包含了package目录与package2目录,故均在sys.path中。运行成功。
因此此处使用python -m
能够有效地去管理交叉编译的问题,可以使ROS环境包与交叉编译包能够同处于一个目录下,方便编译。
同时为了进一步方便代码的debug,本文还提供了pycharm如何设置.py作为脚本启动,即带-m参数运行
首先是如何以python xxx.py
方式直接运行:Edit Configurations
选项中,选择的是Script path
。输入框是run.py
的绝对路径。
如何以python -m xxx方式运行,将xxx.py作为模块运行(感谢stackoverflow):
Edit Configurations选项中,点击Script path输入框左侧的倒三角,选择Module name,右边输入框输入xxx,即模块的名字,不带.py后缀。然后就可以在Parameters设置任何参数。这种方法不需要在任何地方包含 -m 参数。
通过该类方法能够有效地去管理代码的读取与存储,当然不同的芯片有可能具有不同的使用方法,目前该方法二仍然只适用于ubuntu与Debain系统,如果以传统的ARM系统,有可能仍然需要使用方法1来保证安全稳定。此处提供一个古月的交叉编译博客,而RK3308等RK系列也得到了众多开发者的支持。而树莓派等虽然存在编译界面,但是由于性能等问题,很多人还是尝试将其进行交叉编译以及移植。由于本人最近才接触交叉编译,有些不合适的地方请各位批评指正。