最近组里想在诸如NVIDIA TX2之类的硬件上搞自动驾驶,用以研究自动驾驶框架和算法性能。真车是真的搞不起,因为购置和维护成本太高,场地搭建不现实,测试安全性风险也太高,只能用软件模拟搭个沙盘才能过得了生活。自动驾驶模拟器自然应该在服务器上跑,自动驾驶软件又应该在板子上跑;模拟器就相当是个赛车游戏,板子就是个车手。问题来了:如何将一个硬件接入模拟器?鉴于机器人项目一般使用ROS作为中间件,而ROS本身是分布式的,只要模拟器和自动驾驶框架支持ROS或者有ROS的转接口就可以了。
自动驾驶软件方面,在目前开源的两大框架Apollo和autoware之中,由于阿波罗太过沉重,板子上跑不动,我选择用autoware。autoware按使用的中间件不同分两版本,其中autoware.ai使用老版的ROS1,autoware.auto使用新的ROS2;由于后者还需要大量折腾,我选择旧版autoware。
模拟器方面,目前流行的开源方案有lgsvl和carla,它们功能都相当强大:可以模拟自然环境、道路建筑、交通信号、行人车辆、各种天气情况等,还有诸如GPS、IMU、摄像头、激光雷达等传感器,并提供ROS接口供软件接入。
- lgsvl是LG开源的模拟器,使用unity引擎,有许多官方企业合作,图形界面做的很完整,自带有一键傻瓜式的连接Apollo或者autoware的例程,自带了一个几条道路的小地图;
- carla是开源社区开发的,使用Unreal4引擎,没啥界面,基本上需要用python调它API才能操作,例程比较充分,自带了七八个小村镇的地图模型。
个人感觉二者功能都可比,不过lgsvl太官方了,不够自由,开放的模型和地图没carla多,所以我选择用carla模拟器。
实验设置:
- 局域网:千兆以太网。
- 服务器:CPU选用i7-6700,内存32GB;至于显卡,我最开始用P106-100矿卡,性能略低于1060,结果无论是单独跑模拟器还是驾驶软件都非常勉强,还严重连累了图形界面的响应速度;后来升级到泰坦X(12GB)之后模拟器和自动驾驶都可以同时实时跑。
- 操作系统:服务器上Ubuntu 18.04或者20.04都亲测能跑,嵌入式端最好用Ubuntu 18.04。
- 嵌入式:我首先试了4G内存版的树莓派4,它启动autoware时候直接爆内存;又尝试TX2,8GB内存加开zram swap之后惊险地跑起来了,但是目测处理速度只有一两帧每秒,经常因为localization模块处理不过来而撞车;最后我升级到NVIDIA AGX Xavier,32GB内存,相传它比TX2高20倍的算力;但是最后发现网络通信成了瓶颈。
carla提供了一个carla-autoware的仿真组合,使用docker一键编译和部署,在本机上开carla,而在docker上开autoware。这就好办了,把它docker构建过程依葫芦画瓢在嵌入式端部署一遍就好了。
carla模拟器搭建
直接参考carla quick start guide。由于国内git访问速度相当糟糕,我尽量选择下载release压缩包。
安装
先安装一些依赖包:
# ubuntu20.04已经没有python-pip包了。。
sudo apt install -y python3-pip
pip3 install --user pygame numpy
从release中下载CARLA_xx.tar.gz
(或者CARLA_xx_RSS.tar.gz
,二选一),还有AdditionalMaps_xx.tar.gz
。推荐使用最新的0.9.11版本。将CARLA解压,再将AdditionalMaps解压到Import
目录中:
mkdir carla-simulator
tar xf CARLA_0.9.11.tar.gz -C carla-simulator
tar xf AdditionalMaps_0.9.11.tar.gz -C carla-simulator/Import
然后一键启动carla:
cd carla-simulator
./CarlaUE4.sh
等上一会儿就会启动carla的world视图,在这里可以用WASD和鼠标来游玩。
配置操作
对carla的操作全凭它的python API。。可以在另外的电脑上对它操作,不过得把carla-simulator下的PythonAPI
文件夹拷贝过去,然后使用PythonAPI/util
和PythonAPI/examples
里面的例程,它们在import carla
时候会引用PythonAPI/carla/dist/
的egg包,默认只提供了python2.7和3.7的版本,如果python版本不对还会报错。这时可以做一些hack:如果你用ubuntu18.04自带的python3.6,就需要将carla-0.9.11-py3.7-linux-x86_64.egg
拷贝一份为carla-0.9.11-py3.6-linux-x86_64.egg
;或者你用的是ubuntu20.04的python3.8,就将它拷贝为carla-0.9.11-py3.8-linux-x86_64.egg
,以此类推。
还需要注意,跑这些例程时候得先cd到它们的目录中。。下面列举一些常用操作:
PythonAPI/util/test_connection.py
用于测试模拟器的连接情况。需要使用--host
指明服务器IP:
$ python3 ./test_connection.py --host 192.168.xxx.xxx
CARLA 61caeef4 connected at 192.168.xxx.xxx:2000.
PythonAPI/util/config.py
对carla进行操作。首先使用-l
列举天气和地图的配置:
$ python3 ./config.py --host 192.168.xxx.xxx -l
weather presets:
ClearNoon, ClearSunset, CloudyNoon, CloudySunset, Default,
HardRainNoon, HardRainSunset, MidRainSunset, MidRainyNoon,
SoftRainNoon, SoftRainSunset, WetCloudyNoon, WetCloudySunset,
WetNoon, WetSunset.
available maps:
Town01, Town01_Opt, Town02, Town02_Opt, Town03, Town03_Opt,
Town04, Town04_Opt, Town05, Town05_Opt.
随后可以使用--weather
换天气,或者--map
换地图。参考自带的地图配置。目前默认地图Town03。
开车
在PythonAPI/examples
下面有manual_control.py
和manual_control_steeringwheel.py
可供玩耍。前者是鼠标键盘控制,后者用pygame接口,可以用手柄控制。玩手柄的时候,需要在本文件夹下面新建wheel_config.ini
文件映射键位,配置诸如方向盘、油门、刹车的按键编号。可以使用jstest-gtk
来确认按键配置:
安排好按键之后,可以写如下配置文件:
[G29 Racing Wheel]
steering_wheel = 3
throttle = 2
brake = 5
reverse = 0
handbrake = 1
然后就可以愉快的玩耍了。
嵌入式端
刷机,安装依赖包
刷机工具问题:在主机上,用NVIDIA sdkmanager来给板子刷机。目前(2021-1)这个刷机工具拒绝在Ubuntu 20.04上运行,如果要强行运行,就要欺骗它:将/etc/os-release
改为Ubuntu 18.04的!当然这可能会给别的工具造成一些困扰,到时候再改回去即可。。以下是一个例子:
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
Jetpack版本问题:目前autoware工程里面定死CUDA版本要小于等于10.0,凡是10.1、10.2通通报错,如果想省点心的话就给板子刷Jetpack 4.3
,它带的是CUDA 10.0。
添加SSD:工程代码体积很大,板子自带的32GB闪存根本不够用。我给AGX Xavier加了个512G的SN750,不过测试读写速度只有1500MB左右,看样子其实可以用更低档次的SSD。可以将整个rootfs都移到SSD上,参考https://github.com/jetsonhacks/rootOnNVMe
,这个代码的原理是先从32G的闪存上启动(uboot和内核都没动),然后利用一个systemd service将文件系统chroot到SSD上。首先对SSD分区:可以用fdisk、gparted等,分一个区就行了;接着格式化为ext4文件系统,可以用mkfs.ext4等工具;这两步可以在板子上做,也可以先弄好再装到板子上;然后依次运行这个代码里的copy-rootfs-ssd.sh
和setup-service.sh
;最后重启即可。
改为国内软件源:刷机完成之后,将/etc/apt/sources.list
里面的URL改为国内的源,推荐清华源:https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/
,注意Ubuntu的非x86的源的URL一般是xxxxx/ubuntu-ports/
,而不是xxxxx/ubuntu/
。
OpenCV版本问题:nvidia的jetson源里面画蛇添足地提供了opencv-4.1.1的包(而且这个包都没开cuda),然而ubuntu源是opencv-3.2.0,而且ros里面很多包都依赖这个版本的opencv。opencv3到4之间有大量接口更改,比如有很多CV_xxx
宏定义改成了cv::xxx
,又比如配置文件读写通通只认流式接口而不认以前的节点对象;而autoware代码用的是opencv3,要编译通过就有两种选择:改代码(亲测,修完接口之后没问题),不想改代码就降级opencv:
首先使用apt-cache policy libopencv-dev
查看都有哪些版本的包:
$ apt-cache policy libopencv-dev
libopencv-dev:
Installed: 3.2.0+dfsg-4ubuntu0.1
Candidate: 4.1.1-2-gd5a58aa75
Version table:
*** 4.1.1-2-gd5a58aa75 500
500 https://repo.download.nvidia.com/jetson/common r32/main arm64 Packages
3.2.0+dfsg-4ubuntu0.1 500
500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports bionic-updates/universe arm64 Packages
500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports bionic-security/universe arm64 Packages
100 /var/lib/dpkg/status
3.2.0+dfsg-4build2 500
500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports bionic/universe arm64 Packages
这里我选择3.2.0+dfsg-4ubuntu0.1
版本的,重新安装libopencv-dev
,并且用apt-mark hold
锁死它:
sudo apt install --reinstall libopencv-dev=3.2.0+dfsg-4ubuntu0.1
sudo apt-mark hold libopencv-dev
然后安装ros,参考ros ubuntu安装文档。这里我还是选用清华源:
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
sudo apt update
sudo apt install ros-melodic-desktop-full
用rosdep
初始化ROS依赖项。注意国内访问github raw可能会出问题,因此最好买一个梯子。可以使用proxychains4
进行代理:
source /opt/ros/melodic/setup.sh
sudo rosdep init
rosdep update
# 这两步会访问https://raw.githubusercontent.com/,可能需要代理:
# sudo apt install proxychains4
# 装完之后记得修改/etc/proxychains4.conf配置代理,记得要开启quiet_mode
# 然后使用proxychains4代理这两个操作:
# sudo proxychains4 rosdep init
# proxychains4 rosdep update
接着就可以开始部署autoware了。
编译autoware和bridge
玩嵌入式端之前,先在主机上搭建carla-autoware的docker,确认能跑通了,再将里面的程序从docker里面拷贝出来到板子上部署。在主机上我没碰到什么问题,只是国内访问github相当慢,最好搭个代理;编译也要花上一段时间,耐心等待。
在板子上,为了加快编译速度,我将板子CPU性能拉到最高(8核@2.265GHz),并且开风扇散热:
sudo nvpmodel -m 0
sudo sh -c 'echo 100 > /sys/devices/pwm-fan/target_pwm'
在板子上,先建立工程目录,并启动ROS环境:
mkdir ~/autoware.ai/src -p
source /opt/ros/melodic/setup.sh
在主机上,将carla-autoware的docker里面~/Autoware/src
打包出来,拷贝到板子的~/autoware.ai/src
里。
以下配置均在板子上操作,参考autoware源码编译和carla-autoware docker例程。
安装依赖项:
sudo apt install -y python-catkin-pkg python-rosdep \
ros-$ROS_DISTRO-catkin python3-pip \
python3-colcon-common-extensions \
python3-setuptools python3-vcstool
pip3 install -U setuptools
升级eigen库以支持cuda:
cd && wget http://bitbucket.org/eigen/eigen/get/3.3.7.tar.gz #Download Eigen
mkdir eigen && tar xf 3.3.7.tar.gz -C eigen #Decompress
cd eigen && mkdir build && cd build && cmake .. && make && make install #Build and install
cd && rm -rf 3.3.7.tar.gz && rm -rf eigen #Remove downloaded and temporary files
安装autoware的依赖库:
cd ~/autoware.ai
rosdep install -y --from-paths src --ignore-src --rosdistro $ROS_DISTRO
最后开始编译:
AUTOWARE_COMPILE_WITH_CUDA=1 colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
编译carla的PythonAPI
板子作为client,还需要carla的python包以和carla服务器交互,这需要在板子上编译carla的client部分。参考carla的linux编译流程,首先下载完整的源代码。我们新建文件夹carla-0.9.11
并将代码解压进去。
安装依赖项:
sudo apt install build-essential \
clang-8 lld-8 g++-7 cmake \
ninja-build libvulkan1 python \
python-pip python-wheel python-dev \
python3-dev python3-pip libpng-dev \
libtiff5-dev libjpeg-dev tzdata sed \
curl unzip autoconf libtool rsync \
libxml2-dev ros-melodic-ackermann-msgs \
ros-melodic-derived-object-msgs
pip2 install --user distro
pip3 install --user distro
然后将clang-8拷贝为clang,否则后面会找不到clang:
cd /usr/bin/
sudo ln -s clang-8 clang
sudo ln -s clang++-8 clang++
cd - # cd空格减号回车:切换回到原来的目录
接着修改Util/BuildTools/Setup.sh
,将CARLA_VERSION
直接定义为"0.9.11"
而不是通过git去找,因为这是release代码包,并没有git仓库:
@@ -465,7 +465,8 @@
# -- Generate Version.h --------------------------------------------------------
# ==============================================================================
-CARLA_VERSION=$(get_git_repository_version)
+#CARLA_VERSION=$(get_git_repository_version)
+CARLA_VERSION="0.9.11"
log "CARLA version ${CARLA_VERSION}."
随后开始编译。编译时会下载一堆东西导致很慢,耐心等待。。。
# 编译python2,因为carla-autoware例程只用python2
make PythonAPI ARGS="--python-version=2"
最后在PythonAPI/carla/dist/
下就会生成aarch64
的python egg包。将它们拷贝出来,比方说放在~/PythonAPI/
目录下面,那么就要将PYTHONPATH
环境变量指向那里。可以在~/.bashrc
里面添加:
export PYTHONPATH=$PYTHONPATH:~/PythonAPI/carla-0.9.11-py2.7-linux-aarch64.egg
编译carla ros bridge
首先安装依赖项:
sudo apt install python-pip python-wheel \
ros-melodic-ackermann-msgs \
ros-melodic-derived-object-msgs \
libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev \
libsdl2-mixer-dev libsdl2-gfx-dev \
libsdl2-net-dev libportmidi-dev
pip install simple-pid pygame networkx==2.2
下载代码,姑且放在~/
目录:
cd
# bridge代码
git clone -b '0.9.10.1' --recurse-submodules https://github.com/carla-simulator/ros-bridge.git
# 地图配置和点云数据,2.4G,git仓库另占有2.4G
git clone --recurse-submodules https://github.com/carla-simulator/carla-autoware
# 以上两步可以直接从docker里面拷出来,反正它们都已经下载过了。注意它们的.git目录就不需要拷贝了
建立ros工作目录为~/carla_ws
:
mkdir -p ~/carla_ws/src
cd ~/carla_ws/src
ln -s ~/ros-bridge
ln -s ~/carla-autoware/carla-autoware-agent
编译它:
cd ~/carla_ws
source /opt/ros/melodic/setup.bash
catkin_make
最后在~/.bashrc
最后追加设置CARLA_AUTOWARE_CONTENTS
环境变量,指向地图目录:
export CARLA_AUTOWARE_CONTENTS=~/carla-autoware/autoware-contents
运行
先在服务器上启动carla,即运行CarlaUE4.sh
。然后用python API切换地图,详见上文。假设切为Town01。
在板子的图形界面里打开一个终端,初始化autoware环境:
source ~/carla_ws/devel/setup.bash
source ~/autoware.ai/install/setup.bash
最后开始运行例程,需要设置town
和host
参数:
roslaunch carla_autoware_agent carla_autoware_agent.launch town:=Town01 host:=192.168.xxx.xxx
它启动了一个rviz界面,可以通过它进行操作:
看上去可以跑了,然而在AGX Xavier板子上运行仍未达到实时,转弯之后还是撞车了;CPU和内存利用率都还好,但是千兆网络下行速度80MBps左右,考虑到给板子scp大文件时候也基本上这个速度,可以认为网络IO已经跑满了。想必瓶颈就在ros以及跟服务器的网络通信上了,这将是以后需要优化的目标,可选的方案:数据压缩、减少连接个数、RDMA。