本文讲述在RK3588 开发板上搭建组合导航开发环境的方法,以及备份EMMC中开发环境的方法。
文章目录
- [1 开发环境介绍与搭建](#1 开发环境介绍与搭建)
-
- [1.1 源码安装方法](#1.1 源码安装方法)
- [1.2 其他开发库的安装](#1.2 其他开发库的安装)
- [1.3 源码安装问题](#1.3 源码安装问题)
- [2 EMMC 开发环境的复制](#2 EMMC 开发环境的复制)
-
- [2.1 镜像的制作](#2.1 镜像的制作)
- [2.2 新EMMC的烧写](#2.2 新EMMC的烧写)
- 后记
1 开发环境介绍与搭建
OrangePi 5Max 是一款以瑞芯微RK3588 为主控芯片而设计的开发板,其可使用SD卡 、2280型固态硬盘 或EMMC模块 作为系统硬盘。本文则使用Orangepi系列中可插拔的EMMC模块来作为系统硬盘,该模块中的EMMC容量为256GB。
常见的组合导航程序,用到了包括OpenCV 和PCL 在内的众多第三方开发工具库,其中OpenCV主要用于图像的处理与计算,PCL主要用于激光雷达点云的处理与计算。本文以OpenVINS这一带有视觉里程计的组合导航程序为例,来搭建其开发环境。
经过大量实验验证,最切合的第三方开发库以及其对应版本如下:
- OpenCV:4.2.0,非CUDA版本;
- Eigen:3.4.0;
- Sophus:1.24.6;
- PCL:1.8.1;
- Ceres-solver:2.2.0
1.1 源码安装方法
在进行源码安装前,需要预先安装编译工具:
shell
sudo apt-get install cmake git g++ libgflags-dev
OpenCV、Eigen、Sophus、PCL与Ceres-solver源码的安装方法是相似的,其主要命令为:
shell
git clone <src_url>
cd <src_dir>
mkdir build && cd build
cmake ..
make -j10
sudo make install
这也是绝大多数第三方开发工具库的源码安装流程。首先,通过从一个Git仓库中获得源码,再在源码根目录下创建build目录,再在build目录下通过cmake配置编译选项,之后再经过make工具编译并安装,就完成了整个源码安装流程。
第三方开发库在经过make编译并安装之后,其所默认存放的路径为/usr/local/lib,上述五个第三方库中,OpenCV、PCL编译生成的是动态库(*.so),而Ceres-solver 和Sophus安装之后生成的是静态库(*.a),Eigen安装之后只有相应的头文件(*.h),不生成库文件。
1.2 其他开发库的安装
如果需要使用特定的传感器,也就需要使用到其对应的开发工具库,这里以Livox激光雷达 和DJI GPS信号接收机为例,讲述其开发工具库的安装方法。
- Livox SDK
Livox SDK需要在PCL成功安装之后才能进行源码编译安装,其有在ROS1和ROS2两个平台上使用的版本,在ROS2上使用的版本叫Livox-SDK2。与其他第三方库安装的方法类似,其安装步骤为:
shell
git clone https://github.com/Livox-SDK/Livox-SDK.git
cd Livox-SDK
mkdir build && cd build
cmake ..
sudo make install
编译生成的工具库liblivox_sdk_static.a是静态库,同样也默认存放在/usr/local/lib下。
- Payload SDk
Payload SDK是DJI 针对无人机负载设备挂飞所开发的一款工具包。DJI大型无人机上有包括GPS接收机、气压高度计在内的众多传感器,挂飞的负载设备上Payload SDK负责采集这些数据,在经过二次开发,能实现将数据通过ROS的话题机制进行发布,从而供其他进程使用。
Payload SDK的源码涉及OpenCV函数的应用,因此安装前需预先安装OpenCV。在安装OpenCV之后,便可通过下列命令进行Payload SDK的安装:
shell
git clone https://github.com/dji-sdk/Payload-SDK
cd Payload-SDK
mkdir build && cd build
cmake ..
sudo make install
其安装步骤大体也和其他源码安装方式一致。编译生成的libPayload_sdk.a是静态库,默认存放于路径/usr/local/lib下。有关Payload SDK如何在ROS框架下使用,可参考如下博客:
1.3 源码安装问题
如果严格按照本章开头源码的版本来安装第三方开发库,基本上不会出现编译错误,主要的错误集中在PCL的编译阶段,其解决方法详见如下博客:
同时,在PCL源码安装之前,请先安装下列库,否则在cmake配置阶段会报错:
shell
sudo apt install libvtk7-dev libflann-dev libpcap-dev libboost-all-dev
PCL库的代码规模极其庞大,即使在CPU性能较高的机器上也需要至少10分钟完成编译。因此,源码编译期间请耐心等待。
2 EMMC 开发环境的复制
从零开始手动搭建一个VINS开发平台是繁琐而极其耗时的,替代手动搭建开发环境的最好方法就是镜像备份 。所谓镜像备份,是指对一个存储设备的内容进行完整的复制,最终生成克隆文件(镜像文件)的过程,镜像文件的后缀名主要为.iso(常见于Windows系统)或.img。
复制一个EMMC开发环境所需要的条件如下:
- 一个带有USB接口的EMMC读卡器;
- 待复制的EMMC模块;
- 空的EMMC模块;
- 高性能大容量的Ubuntu系统的主机
对于ARM架构的Linux系统来说,一个完整可用的系统镜像文件包括对boot分区 、rootfs(根文件系统)和bootloader的克隆。
制作镜像的过程也是读取EMMC存储空间的过程,对于已经集成的EMMC模块的读写,则需要对应的转接器,这就是EMMC读卡器。本文使用带有USB TypeA型的读卡器,讲述用其读写EMMC的方法。
将待拷贝的EMMC模块安装上EMMC读卡器,然后接入一个装有Ubuntu系统的主机上,随后,在该Ubuntu主机上通过Linux命令来实现镜像的制作和新EMMC模块的读写。
2.1 镜像的制作
为了弄清楚boot分区和rootfs分区分别是什么类型的文件系统,我们可以用lsblk 命令查看:
shell
XXX@YYY:~$ lsblk -f
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
loop0 squashfs 0 100% /snap/bare/5
loop1 squashfs 0 100% /snap/code/233
loop2 squashfs 0 100% /snap/gnome-3-38-2004/143
loop3 squashfs 0 100% /snap/gnome-3-38-2004/119
loop4 squashfs 0 100% /snap/snapd/26382
loop5 squashfs 0 100% /snap/gtk-common-themes/1535
loop6 squashfs 0 100% /snap/snapd/25935
loop7 squashfs 0 100% /snap/core20/2717
loop8 squashfs 0 100% /snap/core20/2686
loop9 squashfs 0 100% /snap/snap-store/1216
loop10 squashfs 0 100% /snap/gnome-42-2204/247
loop11 squashfs 0 100% /snap/snap-store/638
loop12 squashfs 0 100% /snap/code/237
loop13 squashfs 0 100% /snap/core22/2411
loop14 squashfs 0 100% /snap/core22/2339
sda ext4 d87e9732-5e99-48a9-9d8c-20aad9ae5af1 6.8T 1% /media/DISK
sdb
├─sdb1 vfat opi_boot F123-B06C 1G 0 part
└─sdb2 ext4 opi_root 7791cc74-4309-4a07-a8ce-efed07698e80 229.6G 0 part
nvme0n1
├─nvme0n1p1 vfat 7C66-0F35 504.9M 1% /boot/efi
└─nvme0n1p2 ext4 73262acb-0a6c-4eda-bcb8-97d38617f9fe 1.6T 4% /
可以看到,EMMC所对应的设备名为/dev/sdb,该设备有两个分区,其中一个分区为vfat文件系统,另一个是ext4文件系统,为了进一步确认这两个分区哪一个是boot分区,哪一个是rootfs分区,我们可以使用blkid(block id)来查看:
shell
XXX@YYY:~$ sudo blkid /dev/sdb1
LABEL_FATBOOT="opi_boot" LABEL="opi_boot" UUID="F123-B06C" TYPE="vfat" PARTLABEL="bootfs" PARTUUID="845450d3-6819-4b47-bce9-69ace106cfc3"
XXX@YYY:~$ sudo blkid /dev/sdb2
LABEL="opi_root" UUID="7791cc74-4309-4a07-a8ce-efed07698e80" TYPE="ext4" PARTUUID="b7f709c2-510e-8c4c-8a2e-5ce1e3d5efbe"
以上的结果加上先前lsblk命令的执行结果已经很明了了,/dev/sdb1是boot分区的设备名称,/dev/sdb2是rootfs分区的设备名称,接下来就可以根据分区来生成镜像了。
在制作镜像前,必须先将设备解挂载:
shell
XXX@YYY:~$ sudo umount /dev/sdb
此时再查看整个系统中的块设备,可以发现/dev/sdb已经不再被挂载:
shell
XXX@YYY:~$ df -h
文件系统 容量 已用 可用 已用% 挂载点
udev 126G 0 126G 0% /dev
tmpfs 26G 43M 26G 1% /run
/dev/nvme0n1p2 1.8T 68G 1.7T 4% /
tmpfs 126G 0 126G 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 126G 0 126G 0% /sys/fs/cgroup
/dev/loop0 128K 128K 0 100% /snap/bare/5
/dev/loop1 362M 362M 0 100% /snap/code/233
/dev/loop2 350M 350M 0 100% /snap/gnome-3-38-2004/143
/dev/loop3 347M 347M 0 100% /snap/gnome-3-38-2004/119
/dev/loop4 49M 49M 0 100% /snap/snapd/26382
/dev/loop5 92M 92M 0 100% /snap/gtk-common-themes/1535
/dev/loop6 49M 49M 0 100% /snap/snapd/25935
/dev/loop7 64M 64M 0 100% /snap/core20/2717
/dev/loop8 64M 64M 0 100% /snap/core20/2686
/dev/loop9 13M 13M 0 100% /snap/snap-store/1216
/dev/loop11 46M 46M 0 100% /snap/snap-store/638
/dev/loop12 381M 381M 0 100% /snap/code/237
/dev/loop10 532M 532M 0 100% /snap/gnome-42-2204/247
/dev/loop13 74M 74M 0 100% /snap/core22/2411
/dev/loop14 74M 74M 0 100% /snap/core22/2339
/dev/nvme0n1p1 511M 6.1M 505M 2% /boot/efi
tmpfs 26G 20K 26G 1% /run/user/29999
bootloader的数据来自于boot分区开头的一段内容,对于RK系列的芯片来说,其bootloader包括uboot.bin在内的多种组件,其总大小在56MB左右,为了能使整个bootloader全部包含,本文将生成的镜像大小设置为64MB。生成bootloader.img的命令为:
shell
sudo dd if=/dev/sdb of=bootloader.img bs=1M count=64 status=progress
以下是执行结果:
shell
41943040字节(42 MB,40 MiB)已复制,1 s,41.9 MB/s
记录了64+0 的读入
记录了64+0 的写出
67108864字节(67 MB,64 MiB)已复制,1.60969 s,41.7 MB/s
此步骤生成了bootloader.img文件。
接下来制作的是boot分区的镜像,因为boot分区的内容全在设备/dev/sdb1上,所以,直接将整个块设备上的内容分块制作为镜像文件即可:
shell
sudo dd if=/dev/sdb1 of=boot.img bs=4M status=progress
以下是执行结果:
shell
1073741824字节(1.1 GB,1.0 GiB)已复制,29 s,37.0 MB/s
记录了256+0 的读入
记录了256+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,29.1 s,36.9 MB/s
此步骤生成了boot.img文件,其大小为1.1GB。
最后制作的是rootfs分区的镜像。dd命令用于定量拷贝数据,其单个块大小和镜像总大小是需要手动设置的,在不了解数据的分布和具体大小的情况下,容易出现数据冗余拷贝或数据拷贝缺失的问题,因此不适合在rootfs分区镜像的制作中使用。
本文使用partclone命令来制作rootfs分区的镜像,该命令可灵活制作数据,仅拷贝有效数据块,而未被写入的数据块不会包含在生成的镜像里。制作rootfs分区的镜像的命令为:
shell
sudo partclone.ext4 -c -s /dev/sdb2 -o rootfs.img
此条命令执行的时间取决于EMMC中存储的具体数据大小,数据量越大,制作时间越长。当终端输出Cloned successfully.的字样时,说明rootfs.img镜像制作完成。
此时,便可以使用命令弹出读卡器:
shell
sudo udisksctl power-off -b /dev/sdb
接下来,就可以开始将新EMMC接在读卡器上,开启新EMMC的烧写工作了。
2.2 新EMMC的烧写
EMMC的烧写实际上是镜像制作的反过程,即将.img文件中的内容输出到对应的设备上。
首先需要确定新EMMC的设备名,同理,使用lsblk命令实现,可以发现,即使更换新EMMC的情况下,设备名依然不变,仍然为/dev/sdb。
烧写EMMC可以使用如下脚本,执行时,请将此脚本文件放在三镜像文件的目录下:
shell
#!/bin/bash
DISK=/dev/sdb
echo "[1/4] Checking files..."
echo ""
FILES=(
"bootloader.img"
"boot.img"
"rootfs.img"
)
for f in "${FILES[@]}"
do
if [ ! -f "$f" ]; then
echo "ERROR: Missing $f"
exit 1
fi
done
echo "All files exist."
echo ""
echo "[2/4] Restoring bootloader..."
sudo dd if=bootloader.img of=$DISK bs=1M count=64 status=progress
sync
echo ""
echo "[3/4] Restoring boot partition..."
sudo dd if=boot.img of=${DISK}1 bs=4M status=progress
sync
echo ""
echo "[4/4] Restoring root filesystem..."
sudo partclone.ext4 -r -s rootfs.img -o ${DISK}2
sync
echo ""
echo " Restore Completed Successfully "
echo ""
当脚本执行完成之后,原EMMC开发环境已经写入了新EMMC中,随后仍使用udisksctl命令来弹出读卡器。
后记
经过实际测试,新EMMC模块能在接上开发板并上电之后正常开机使用,且开发环境中的相关第三方工具库都可以正常使用。