基于视觉演示学习的自动驾驶小车

作者:郭传鈜,文章来源:XILINX开发者社区微信公众号

本文作者:郭传鈜
华南理工大学计算机科学与工程学院2021级硕士研究生,“Self-driving Car Based on Learning from Vision Demonstration”项目开发人员之一,该项目获得2021赛灵思自适应计算挑战赛边缘计算组三等奖。

此外,他还曾获得全国大学生计算机系统能力大赛编译系统设计赛二等奖、华为云人工智能大会无人车挑战杯大赛三等奖。

在诸如自动巡逻等许多应用场景中,自动驾驶小车只需要按照一条固定路线行走即可。在传统自动驾驶框架中,小车的驾驶是使用激光雷达等设备完成的,这种方案需要预先完成地图建立、路径点设置以及大量其它参数设置,十分繁琐。

我们从其它工业机器人的示教学习方案中得到启发,在ROS机器人框架下设计了一套基于视觉信息和神经网络的小车自动驾驶程序,并部署在KV260平台上。

使用这个方案,在新场景中,我们只需要人工驾驶小车在所需固定路线中行走若干次,收集摄像头图像和驾驶角度数据,利用这些数据训练一个输出驾驶角度的神经网络,小车在后续应用中就只需要获取摄像头图像输入网络,根据神经网络输出的驾驶角度驾驶,就能按照原有路线行走。

本项目中的所有源代码都可以在这里下载:

https://bitbucket.org/981213/kv260_car

也可以点击访问如下链接在比赛原始项目页面的Code部分中查看包含代码注释的版本:

https://www.hackster.io/gch981213/self-driving-car-based-on-learning-fro...

1. 训练数据收集

我们的方案属于有监督学习的方案,这一方案必不可少的部分是带标签的训练数据。在这一步中,我们将利用ROS框架自带的rosbag工具。首先启动rosbag录制,然后人工驾驶小车并录制640x480分辨率的图像数据和对应的驾驶角度标签。

我们使用的小车本身自带一块类似于树莓派的RK3399开发板,因此我们可以先使用这一开发板完成数据收集工作,也可以选择先完成第三部分后在KV260上完成本步骤。

1. ROS工作区准备

为了完成数据收集工作,我们需要在ROS下准备好小车驱动、摄像头程序和键盘驾驶小车的程序。首先创建工作区目录:

mkdir -p ~/ros_ws/src

cd ~/ros_ws/src

然后添加上面提到的相关节点。小车的驱动由小车的厂商提供,使用scp或者其它工具复制程序到ros_ws/src下即可。

我们使用的小车接受ROS标准的AckermannDriveStamped消息作为控制指令,所以我们需要下载下面这个项目控制小车:

git clone

https://github.com/gkouros/ackermann-drive-teleop ackermann_drive_teleop

ROS官方提供了一个USB摄像头节点。如果你们使用基于Ubuntu的开发板完成这一工作,可以用下面这个命令安装:

sudo apt update && sudo apt install ros-noetic-usb-cam

如果是按照第三部分配置的KV260镜像,那么镜像中已经包含了摄像头节点,不需要这一步。

准备好源代码后即可构建工作区:

source /opt/ros/noetic/setup.bash

cd ~/ros_ws

catkin_make

2. 采集数据

我们使用一张带有车道线的地毯作为示例场景:

在ROS中,驱动、控制程序等被称作节点,节点之间使用消息进行通信。

rosbag工具可以把所有节点之间的消息录制下来供后续使用。

我们通过ssh打开四个终端连接小车,分别启动如下节点:

第一个终端启动ROS小车驱动,具体的启动命令根据小车的不同有所不同,可以参考小车的说明书:

cd ~/ros_ws

source ./devel/setup.bash

roslaunch base_control base_control.launch

第二个终端启动USB摄像头节点:

cd ~/ros_ws

source ./devel/setup.bash

roslaunch usb_cam usb_cam-test.launch

第三个终端启动rosbag:

cd ~/ros_ws

source ./devel/setup.bash

rosbag record

最后一个终端启动键盘控制节点:

cd ~/ros_ws

source ./devel/setup.bash

rosrun ackermann_drive_teleop keyop.py

现在,我们驾驶小车在场景中行走若干轮录制数据:

结束后,按Ctrl+C终止第三个终端中的rosbag程序,我们就可以在ros_ws下看到一个以日期时间命名的.bag文件。把这个文件复制到电脑上,然后我们可以暂时关闭小车。

3. 提取数据和标签

我们在装有Ubuntu 20.04的PC上使用一个Python脚本解压图片,并使用当前最新的驾驶角度数据作为标签。

安装ROS后,创建一个工作区:

source /opt/ros/noetic/setup.bash

mkdir -p ~/ros_ws/src

cd ~/ros_ws/src

复制代码包中提供的1-data-collection/data_extractor目录到该工作区下,然后构建:

source /opt/ros/noetic/setup.bash

cd ~/ros_ws

catkin_make

source ./devel/setup.bash

复制rosbag文件到ros_ws中,运行脚本解压数据:

mkdir dataset

rosrun data_extractor extractor.py labels.csv {date}-{time}.bag dataset

运行完成后,dataset目录中就会包含所有解压的图片以及一个包含图片标签的csv文件。

2. 训练神经网络

这里,我们使用PyTorch构建一个简单的CNN网络用于车道线场景。读者可以选择其它Vitis-AI支持的深度学习框架并按照Xilinx官方教程https://github.com/Xilinx/Vitis-AI-Tutorials 生成量化后的模型。

1. 构建Vitis-AI docker容器

由于GPU容器太大,Xilinx官方不提供构建好的镜像。如果需要使用GPU进行训练,我们首先需要构建Docker容器。

下载Vitis-AI 2.0源代码:

git clone --recurse-submodules https://github.com/Xilinx/Vitis-AI

cd Vitis-AI

git checkout v2.0

运行命令创建容器:

cd setup/docker

./docker_build_gpu.sh

2. 构建并训练网络

这里使用的网路是基于PyTorch官方CIFAR10教程制作的,数据加载器也是按照PyTorch官方的数据加载教程编写的。这里我们只展示提供代码的运行流程,如果读者希望了解代码细节,可以阅读如下两篇教程进行学习:

https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

https://pytorch.org/tutorials/beginner/data_loading_tutorial.html

本步骤中编写的三个脚本如下:

dataset.py: 数据加载器

model_reg.py: 神经网络模型

train.py: 神经网络训练脚本

首先进入Vitis-AI容器中:

cd Vitis-AI

./docker_run.sh xilinx/vitis-ai-gpu:latest

就可以看到这一界面:

激活PyTorch环境并开始训练:

conda activate vitis-ai-pytorch

python3 training/train_reg.py

训练完成后,脚本会生成state_dict_rgb.pth文件保存网络训练结果。

3. 量化网络

Vitis-AI使用int8类型完成推理,而我们在训练网络的时候使用的数据类型是浮点数,因此我们需要使用Vitis-AI容器中的转换工具完成模型量化。我们基于Xilinx的例程:

https://github.com/Xilinx/Vitis-AI-Tutorials/blob/master/Design_Tutorial...

编写了量化脚本training/quantize_xlnx.py。执行如下脚本生成量化模型:

python3 training/quantize_xlnx.py calib

python3 training/quantize_xlnx.py test


量化后的模型会被保存在quantize_result/Net_int.xmodel中。这个模型还需要使用工具编译后才能部署到KV260上。这个工作将在第四部分进行。

3. KV260镜像准备

这部分中,我们将使用Xilinx提供的tcl脚本为KV260编译包含DPU和ROS的PetaLinux系统镜像。

1. 硬件部分

在硬件部分中,我们需要创建基础硬件平台并构建FPGA bitstream。Xilinx官方提供了详细的教程,可以参考如下三个教程完成这一工作:

https://xilinx.github.io/kria-apps-docs/main/build/html/docs/build_vivad...

https://xilinx.github.io/kria-apps-docs/main/build/html/docs/build_vitis...

https://xilinx.github.io/kria-apps-docs/main/build/html/docs/build_accel...

由于我们使用的小车需要UART通信,我们在这个过程中还修改基础硬件平台增加了一个UART接口。这部分工作与项目本身关系不大,因此这里不再赘述,感兴趣的读者可以阅读原始比赛项目。

完成构建后,我们会得到arch.json、dpu.xclbin和kv260_ispMipiRx_vcu_DP_wrapper.bit三个文件。arch.json是DPU的型号文件,在后续编译模型时需要使用。其余两个文件在后续PetaLinux构建时创建bitstream overlay包时使用。

2. 系统部分

首先,从Xilinx官方下载页面下载PetaLinux 2021.1 、K26 Starter Kit BSP:

https://www.xilinx.com/support/download/index.html/content/xilinx/en/dow...

完成安装PetaLinux后,创建基础项目:

source {your_petalinux_install}/PetaLinux/2021.1/settings.sh

# 安装kv260相关的petalinux更新

petalinux-upgrade-u http://petalinux.xilinx.com/sswreleases/rel-v2021/sdkupdate/2021.1_update1/ -p "aarch64" --wget-args "--wait 1 -nH --cut-dirs=4"

petalinux-create -t project -s //xilinx-k26-starterkit-v2021.1-final.bsp -n xilinx-k26-starterkit-2021.1

cd xilinx-k26-starterkit-2021.1

# 导入硬件部分创建基础硬件平台得到的xsa文件

petalinux-config --get-hw-description /path/to/xsa

# 先构建一次系统

petalinux-build

# 设置开发板类型为KV260

echo 'BOARD_VARIANT = "kv"' >> project-spec/meta-user/conf/petalinuxbsp.conf

按照:

https://xilinx.github.io/kria-apps-docs/main/build/html/docs/build_petal... 创建FPGA overlay软件包。(为了方便区分文件,硬件部分创建的相关文件在这里已经全部重命名成vai20-2uart.*)

petalinux-create -t apps --template fpgamanager -n user-firmware --enable --srcuri "vai20-2uart.bit vai20-2uart.dtsi vai20-2uart.xclbin shell.json"

按照:

https://www.hackster.io/jlamperez10/ros-2-in-kria-kv260-with-petalinux-2... 给系统增加ROS。我们使用的是ROS Noetic而不是ROS2,所以原教程第二步中,我们需要增加如下laters:

${PROOT}/project-spec/meta-ros/meta-ros-backports-hardknott

${PROOT}/project-spec/meta-ros/meta-ros-common

${PROOT}/project-spec/meta-ros/meta-ros2

${PROOT}/project-spec/meta-ros/meta-ros2-rolling

原教程第三步中,我们创建project-spec/meta-user/recipes-core/images/petalinux-image-minimal.bbappend:

inherit ros_distro_${ROS_DISTRO}

inherit ${ROS_DISTRO_TYPE}_image

接下来我们需要增加所使用的ROS相关包到project-spec/meta-user/conf/user-rootfsconfig中:

CONFIG_ros-core

CONFIG_usb-cam

CONFIG_ackermann-msgs

CONFIG_cv-bridge

CONFIG_cv-bridge-dev

CONFIG_catkin-dev

CONFIG_ackermann-msgs-dev

CONFIG_sensor-msgs-dev

CONFIG_roscpp-dev

CONFIG_vai20-2uart

CONFIG_tf2

CONFIG_tf2-dev

最后按照:

https://github.com/Xilinx/Vitis-AI/tree/master/tools/Vitis-AI-Recipes#ho...增加Vitis-AI 2.0的库文件,所有源代码的修改就完成了。

运行PetaLinux配置:

petalinux-config -c rootfs

在user packages菜单中选择我们需要的软件包:

由于我们后续将在PetaLinux中编译软件,我们需要安装开发相关的-dev软件包以及Petalinux Package Groups中的packagegroup-petalinux-self-hosted包。

构建系统:

# 编译文件

petalinux-build

# 打包 BOOT.BIN

petalinux-package --boot --u-boot --dtb images/linux/u-boot.dtb

# 打包SD卡镜像

petalinux-package --wic --bootfiles "ramdisk.cpio.gz.u-boot boot.scr Image system.dtb

最后烧写SD卡镜像并根据https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/1641152513/Kria+K2... 更新BOOT.BIN即可。

4. 模型部署

1. 编译模型

把第二部分的Net_int.xmodel和第三部分的arch.json到Vitis-AI目录中,并进入Vitis-AI容器:

cd Vitis-AI

./docker_run.sh xilinx/vitis-ai-gpu:latest

conda activate vitis-ai-pytorch

执行下面的命令编译模型:

vai_c_xir-x/PATH/TO/quantized.xmodel-a /PATH/TO/arch.json -o /OUTPUTPATH -n netname

编译后得到上图中的几个文件。

2. 编写部署代码

先按照教程开头的部分在KV260系统上创建包含小车驱动的ROS工作区,然后创建一个ROS软件包用于部署代码:

cd ~/ros_ws/src

source ./devel/setup.bash

# create our package

catkin_create_pkg lane_dl_xlnx std_msgs ackermann_msgs cv_bridge roscpp

cd lane_dl_xlnx

mkdir launch model

然后我们需要编写模型部署代码。这里,我们使用Xilinx VART API编写相关代码,Xilinx的官方例程如下:

https://github.com/Xilinx/Vitis-AI/blob/master/demo/VART/resnet50_ext/re...

我们参考这个代码,增加了OpenCV摄像头读取和ROS小车速度指令发布的功能。完整代码可以参考提供源码中的4-deployment/lane_dl_xlnx/src/main.cpp.

在软件包中我们还需要修改CMakeLists.txt增加源码路径、增加launch文件启动节点,并把编译好的模型复制到model下。完整ROS包为提供源码的4-deployment/lane_dl_xlnx目录。

最后,编译工作区:

cd ~/ros_ws

catkin_make

然后就可以尝试运行了。把小车放在采集数据的场景中,打开两个ssh终端。第一个终端中加载FPGA bitstream并启动神经网络的ROS节点:

# 移除默认的比特流

sudo xmutil unloadapp

# 加载我们创建的比特流

sudo xmutil loadapp vai20-2uart

# 启动节点

cd ~/ros_ws

source ./devel/setup.bash

roslaunch lane_dl_xlnx lane_dl_xlnx.launch

在第二个终端中启动小车驱动。具体命令请参考读者所使用的小车的说明文档。

cd ~/ros_ws

source ./devel/setup.bash

roslaunch base_control base_control.launch

启动后,小车就会根据神经网络输出的驾驶角度在场景中行走了。运行效果视频:

最新文章