EMMC开发环境的搭建与备份

本文讲述在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

常见的组合导航程序,用到了包括OpenCVPCL 在内的众多第三方开发工具库,其中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

OpenCVEigenSophusPCLCeres-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,上述五个第三方库中,OpenCVPCL编译生成的是动态库(*.so),而Ceres-solverSophus安装之后生成的是静态库(*.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 SDKDJI 针对无人机负载设备挂飞所开发的一款工具包。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框架下使用,可参考如下博客:

PSDK的编译与ROS包封装

1.3 源码安装问题

如果严格按照本章开头源码的版本来安装第三方开发库,基本上不会出现编译错误,主要的错误集中在PCL的编译阶段,其解决方法详见如下博客:

Ubuntu20.04安装PCL1.8.0编译错误

同时,在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模块能在接上开发板并上电之后正常开机使用,且开发环境中的相关第三方工具库都可以正常使用。

相关推荐
承渊政道2 小时前
【MySQL数据库学习】MySQL基本查询(上)
linux·数据库·学习·mysql·bash·数据库开发·数据库系统
Benszen2 小时前
云计算基础-4:Linux 进程管理
linux·运维·云计算
人间乄惊鸿客10 小时前
Linux所遇问题自记录
linux
AOwhisky11 小时前
MySQL 学习笔记(第四期):SQL 语言之多表查询
linux·运维·网络·数据库·笔记·学习·mysql
Phantom Void11 小时前
服务器处理客户端请求的设计方法
linux·运维·网络
一段路11 小时前
【虚拟机】Linux常用命令
linux·vim
daad77712 小时前
继续记录无人机SITL的起飞
linux
剑神一笑12 小时前
Linux ls 命令深度解析:从目录遍历到颜色输出的实现原理
linux·服务器·数据库
三千里15 小时前
ZSH的简单配置
linux·zsh·terminal