问题
raspberry pi zero w 的系统目前树莓派官方推出的镜像是armv6hf debian 11,而ROS2官方只支持ubuntu debian aarch64,不支持arm32,所以要在raspberry pi zero w上使用ROS2必须从源码构建。那么问题就在于如果直接在zero w上编译,显然因为硬件的原因(cpu: 1 core, memory: 512M),编译将会极其缓慢,我也尝试使用armhf交叉编译工具链在aarch64系统上编译ROS源码,但是会出现系统库缺失问题。同时我还考虑到后续的开发环境和zero w原始系统环境的一致性问题,我决定采用zero w的原生debian 11 armhf系统做为rootfs,制作docker image,然后运行在aarch64系统上(比如树莓派4,jetson agx),这样编译出来的ros2直接可以运行在zero w上,并且运行环境和编译环境都是保持一致的,这样对后续的调优以及debug处理都会非常方便。
兼容性
raspberry pi zero w 使用的是cpu arm1176jzf-s,armv6版本,raspberry pi 4 使用的是 ARM Cortex-A72 ARMv8-A版本,我们可以从Cortex-A72文档中看出AArch32 for full backward compatibility with Armv7,也就是armv8 aarch32指令集兼容armv7 aarch32,同时armv7指令集兼容armv6,那么也就意味着armv6的二进制文件是可以直接在raspberry pi 4 aarch64上运行,反之aarch64 binary当然无法在armv6系统上运行,这样思路一下子清晰了,我们可以将armhf的根文件系统制作成docker image,运行在aarch64系统上,然后编译ros2,最后将编译产物拷贝到zero w上直接运行。
解决问题
command line run on raspberry pi 4 ubuntu 20.04 aarch64 os
-
donwload rpi zero w image (raspios-bullseye-armhf-lite)
-
mount img file and copy all root partition files to /mnt
sudo losetup /dev/loop0 ./2023-05-03-raspios-bullseye-armhf-lite.img -P
sudo mount /dev/loop0p2 /mnt
sudo rsync -avz -P -p /mnt/ /opt/armv6-rpi-rootfs/
- build Docker image
Dockerfile
FROM scratch
ADD . /
docker build -t armhf-rootfs .
- ros2 compile environment prepare
docker run -ti –rm armhf-rootfs bash
# install build dependencies (also need run on rpi zero w)
apt install \
bison \
cmake \
curl \
libasio-dev \
libbullet-dev \
libcunit1-dev \
libcurl4-openssl-dev \
libeigen3-dev \
liblog4cxx-dev \
libopencv-dev \
libtinyxml2-dev \
python3-dev \
python3-netifaces \
python3-numpy \
python3-setuptools \
python3-yaml \
python3-pip \
libcppunit-dev python3-sip-dev python3-psutil python3-future
pip3 install rosinstall_generator colcon-common-extensions vcstool lark-parser packaging rosdep
# download ros2 humble source code
vcs import --input ros2.repos src
- patch files
# don't build this unnecessary packages
touch src/ros-visualization/COLCON_IGNORE
touch src/ros/ros_tutorials/turtlesim/COLCON_IGNORE
touch src/ros2/demos/image_tools/COLCON_IGNORE
touch src/ros2/demos/intra_process_demo/COLCON_IGNORE
touch src/ros2/rviz/COLCON_IGNORE
src/ros-tooling/keyboard_handler/keyboard_handler/CMakeLists.txt
error case: libkeyboard_handler.so: undefined reference to `__atomic_fetch_add_8'
@@ -52,9 +52,8 @@
# TODO(sloretz) stop exporting old-style CMake variables in the future
ament_export_include_directories("include/${PROJECT_NAME}")
ament_export_libraries(${PROJECT_NAME})
-
ament_export_targets(export_${PROJECT_NAME})
-
+target_link_libraries(${PROJECT_NAME} -latomic)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
find_package(ament_cmake_gtest)
src/ros2/rcutils/CMakeLists.txt
error case: librcutils.so: undefined reference to `__atomic_load_8'
@@ -130,7 +130,7 @@
target_compile_definitions(${PROJECT_NAME} PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
endif()
-target_link_libraries(${PROJECT_NAME} ${CMAKE_DL_LIBS})
+target_link_libraries(${PROJECT_NAME} ${CMAKE_DL_LIBS} -latomic)
# Needed if pthread is used for thread local storage.
if(IOS AND IOS_SDK_VERSION LESS 10.0)
- compile
create toolchain.cmake,force cmake project build into cross compiling model
/opt/toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_LIBRARY_ARCHITECTURE arm-linux-gnueabihf)
set(CMAKE_CROSSCOMPILING 1)
set(CMAKE_CXX_FLAGS "-latomic")
colcon build --merge-install --cmake-force-configure --cmake-args -DCMAKE_TOOLCHAIN_FILE=/opt/toolchain.cmake
- upload ros2 install binary folder to rpi zero w and test
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener