用Turtlebot3实现基于深度强化学习的多移动机器人导航避障的仿真训练(附源码)

Do not blindly trust anything I say, try to make your own judgement.


这是我的第一篇CSDN文章,本科四年一直都是白嫖现成的CSDN博客,没有评论也没有做出自己的贡献。直到在做本科毕业论文过程中,我遇到的问题一个接一个,每个问题又引出另一个问题,最终是通过无数次地搜索介绍解决方法的文章和资料,并且尝试了所有可能的解决方法,历经千辛万苦,才解决了所有的问题,完成了毕设。因此,现在毕设已经答辩完毕,我打算在这里写一篇我毕设过程中遇到的所有问题及其解决方案的经验贴,以回馈CSDN社区,感谢社区的每一位伙伴们的热心分享经验。我相信对于用ROS系统做机器人仿真、做深度强化学习训练的伙伴们一定有所帮助。

本人本科双鸭山智工院自动化专业,毕设课题大致是做基于深度强化学习的多移动机器人碰撞避免方法,算法部分因人而异,我用的是DDPG与LSTM结合的网络,以摄像头数据作为主要网络输入。但这里主要是分享我配置ROS环境、在ROS中配置深度强化学习环境、用GPU训练神经网络过程中遇到的问题。

目录

1 配置ROS环境

1.1 注意ROS版本与ubuntu版本要对应

1.2 安装turtlebot3软件包

1.3 使用turtlebot3的软件包做仿真

1.4 自己编写 ROS package并编译执行

1.5 关于获取机器人scan和camera数据的方法

2 配置深度强化学习环境

2.1 显卡驱动安装注意事项

2.2 关于python2.7和3.7版本兼容问题

2.3 OpenCV安装注意事项

2.4 最后强调一点

3 神经网络GPU训练过程

3.1 GPU加速深度强化学习训练的方法

3.2 其他小问题

4 源码

5 结语


1 配置ROS环境

1.1 注意ROS版本与ubuntu版本要对应

我用的是ubuntu18.04系统,因此对应的ROS版本是melodic。一般流程是先安装完ubuntu,然后换源,再用sudo apt-get update 和sudo apt-get upgrade更新源和软件包,最后才按教程安装ROS和turtlebot3各自的库。但安装完ubuntu之后务必注意,不要用sudo apt-get dist-upgrade,因为它会涉及系统内核的升级,导致系统自动更新成了最新版20.04,这样你的ROS系统就要安装20.04对应的版本了,但目前很多教程都还没有20.04版本的说明,因此不建议用最新版,可以用16.04和18.04,这就要注意不要让系统自动升级到新版本了,否则又要重装ubuntu系统。甚至可以换源完直接先安装ROS系统,再更新软件包。

1.2 安装turtlebot3软件包

$ cd ~/catkin_ws/src
$ git clone https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git
$ git clone https://github.com/ROBOTIS-GIT/turtlebot3.git
$ git clone https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
$ git clone https://github.com/ROBOTIS-GIT/turtlebot3_machine_learning.git
$ cd ~/catkin_ws
$ catkin_make

这里用到的都是git clone的方式从github网站上下载的,由于github网站下载代码很多时候速度很慢,因此这里介绍一个从其他博客里找到的有效的加速git clone的方法:

  修改每行命令中的github.com为github.com.cnpmjs.org,以将其改为镜像源。

其他的在hosts文件里加入网站ip地址的方法对我都没用。除了这里用到git,在配置ROS和深度强化学习环境过程中会经常用到git的方式下载软件包,只要速度慢了就可以用这种方式,速度快非常多。

1.3 使用turtlebot3的软件包做仿真

启动仿真结点时有四个地方要注意:

(1)因为turlebot3有Burger和Waffle两个型号,对应不同的仿真模型,因此每个启动结点的roslaunch指令前都要先确认机器人型号:export TURTLEBOT3_MODEL=burger,但这样每次都要输入这条指令非常麻烦,因此可以直接将其加到环境变量中,一劳永逸。

$ echo "export TURTLEBOT3_MODEL=burger" >> ~/.bashrc
$ source ~/.bashrc

但要注意,burger型号是没有摄像头的,只有waffle才有,因此我是用waffle型号的机器人做实验。

(2)如果显示“[turtlebot3_fake.launch] is neither a launch file in package [turtlebot3_fake] nor is [turtlebot3_fake] a launch file name”这样的报错,且该软件包确实存在,则只需要输入下行指令即可让系统识别到该软件包。

$ source ~/catkin_ws/devel/setup.bash

(3)rosrun和roslaunch的区别:

rosrun 运行单个节点;

roslaunch 则同时运行多个节点。

(4)如果启动结点后gazebo软件打开了,但gazebo软件一直卡在加载环境状态,则说明该结点启动的环境中有部分模型未下载,当前正在从网上下载,而这往往是从外网下载,速度非常非常慢,因此需要我们自己先下载模型到本地,再重新启动。具体下载gazebo所有模型的方式如下:

$ cd ~/.gazebo/
$ mkdir -p models
$ cd ~/.gazebo/models/
$ wget http://file.ncnynl.com/ros/gazebo_models.txt
$ wget -i gazebo_models.txt
$ ls model.tar.g* | xargs -n1 tar xzvf

1.4 自己编写 ROS package并编译执行

若没有工作区则先创建工作区,命名为catkin_ws:

$ source /opt/ros/melodic/setup.bash
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/
$ catkin_make  # 生成build, devel文件夹
$ source devel/setup.bash  # 将该工作区路径写到ROS_PACKAGE_PATH环境变量中

在工作区catkin_ws的src路径下使用catkin_create_pkg创建ros package:

$ cd catkin_ws/src/
$ catkin_create_pkg my_pkg std_msgs roscpp # my_pkg是自定义的软件包,其他的是统一用到的包
# 生成my_pkg文件夹,里面包含include, src文件夹和CMakeLists.txt, package.xml文件
$ cd ~/catkin_ws
$ catkin_make
$ source /devel/setup.bash

然后在my_pkg文件夹里创建一个scripts文件夹,在scripts文件夹中创建python文件(python文件一般放在scripts文件夹内, cpp文件放在src文件夹内):

$ mkdir scripts

然后可以先写好python文件再复制进去,也可以直接用指令在文件夹内创建python文件,注意这个文件的权限必须是可读可写可执行(chmod 777),很多人会漏了可执行这个权限导致文件无法执行,尤其是从网上下载下来的代码文件:

$sudo touch test.py
$sudo gedit test.py
$sudo chmod 777 test.py

特别注意:写好的python文件要想让系统识别到,需要对其进行编译,即执行上面所述的catkin_make指令,但实际上,catkin_make所编译的程序目录都在文件夹里的CMakelist.txt中指明了,如果CMakelist.txt中没有指明新加入的python文件,即使执行catkin_make也不会对这个python文件进行编译,因此需要在CMakelist.txt中加上写好的python文件的名字,才能真正编译到该文件。这也是很多时候执行roslaunch或rosrun指令时无法找到软件包的原因。

1.5 关于获取机器人scan和camera数据的方法

一般编写订阅结点可以获取机器人的位置信息、scan、camera数据,但那样太麻烦了,需要额外定义一个回调函数,每当有新数据时就会由回调函数获取并处理数据。所以更常用的方法是用rospy.wait_for_message()函数,在有需要时临时创建一个订阅结点,获取的数据直接作为该函数返回值,然后删除临时结点。具体用法如下:

image = rospy.wait_for_message("/camera/rgb/image_raw", Image, timeout=None) #获取camera数据
scan = rospy.wait_for_message("/scan", LaserScan, timeout=None) #获取scan数据

我遇到有两种情况会导致一直无法获取数据,卡在等待数据的过程,进入死循环:

(1)Image或LaserScan数据类型未import,它不会识别到错误,只会卡在这里没有返回值循环等待,因此程序的开头要写上:

from sensor_msgs.msg import Image,LaserScan

(2)似乎rospy.wait_for_message()函数在一个py文件中只能订阅一个话题,例如我用于它获取camera或scan数据是可以的,但先获取scan数据再获取camera数据就不行,不能用于两个话题消息的获取。我的解决方法是camera数据用rospy.wait_for_message()函数获取,scan数据则用定义订阅结点及其回调函数的方式获取。

2 配置深度强化学习环境

2.1 显卡驱动安装注意事项

跑深度强化学习要用到GPU加速,因此要安装显卡驱动,常用的安装方式如下:

#先把旧驱动卸掉
$ sudo apt-get purge nvidia* 
#添加Graphic Drivers PPA:
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update
#查看合适的驱动版本:
$ ubuntu-drivers devices
#选择带有recommend的版本,我的是nvidia-driver-460
$ sudo apt-get install nvidia-driver-460
$ sudo reboot 

注意:显卡驱动的版本与gcc和g++版本是有关的,最新的显卡驱动需要gcc和g++在第7版本,如果gcc和g++版本过低(如为第5版本),则无法安装成功。这是因为我遇到了这样一个问题,如果你也遇到了,那么可以看看是否是这个原因:

输入nvidia-smi指令显示“NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.”按照网上的方法输入:

  $ sudo apt install dkms
  $ sudo dkms install -m nvidia -v nvidia-driver-460 #填自己显卡驱动版本

仍然报错,显示‘’Bad return status for module build on kernel: ......"

这说明显卡驱动未安装成功,有一种原因(也是我遇到的这种情况)是因为gcc和g++版本过低导致的,将gcc和g++版本调整到版本7即可。

实际上ubuntu系统一般会默认gcc和g++版本为7,那么什么情况下会调整版本呢?就是匹配python2.7时会降低gcc和g++版本。我这里的情况是:因为我最初尝试安装opencv2的库,而python2.7版本下安装opencv2需要将CUDA降低到版本9,同时gcc和g++都要降低到版本5,这时如果再用上述方式安装显卡驱动是安装不了的,需要调整gcc和g++回到版本7安装显卡驱动再降低版本,当然最好是先安装驱动再降低版本。不过,我最后用的是其他方法安装opencv库,也就不需要降低gcc和g++版本了。

2.2 关于python2.7和3.7版本兼容问题

由于neotic以前版本的ROS系统都是用python2.7编写的软件包,而深度强化学习开源库函数大多是以python3.7为编写语言,因此两者无法同时兼容。

# 2023.4.6更新

在ROS1环境中使用python3的解决方法有如下4种方法:

  1. 可以通过指定用python3编译脚本;
  2. 也可以通过创建conda虚拟环境来实现,但前两种方法仍然无法解决python3中import tf和cv_bridge这两个包的问题;
  3. 还有一种办法是装一个docker环境,在docker里安装ROS-noetic,因为noetic版本开始都是ROS2,是用python3编译的,而docker里的ROS2可以与docker外的ROS1自动实现通信,但这种方法需要装docker因此比较麻烦;
  4. 有没有办法既不装docker又能在python3中import tf和cv_bridge呢?tf和cv_bridge原本只在python2中可以用,而ROS1是python2编译的,如果要改到ROS2即python3中使用,则要下载源码自己编译(可参考解决python3无法使用ROS中tf的问题 - 知乎,其中如果遇到No module named em的报错,则尝试pip install empy, pip3 install empy, pip install python-empy, pip3 install python3-empy 这四个命令一定可以解决)。
  5. 但更简单的方法是去https://rospypi.github.io/simple/网址下载whl包,用pip的方式安装ros包,里面的pip包是同时支持py2,py3的,非常方便,很多包都不需要经过ros下载了。 (该方法只能在ROS2环境下安装tf和cv_bridge,在ROS1中安装使用仍会报错,解决办法还是得用上述python3源码编译。)

用conda创建虚拟环境的具体做法是:在虚拟环境中安装python3.7、深度学习框架如pytorch和tensorflow、深度强化学习开源包gym-gazebo,而ROS和turtlebot3的包则安装在常规环境下,这样启动ROS环境时在常规环境中执行指令,启动深度强化学习程序时在conda的虚拟环境中执行指令。conda中虚拟环境的创建等常用操作如下:

$ conda create -n env_name python=3.7 #创建名为env_name的环境,并指定python版本为3.7
$ conda activate env_name #启动env_name虚拟环境
$ conda deactiate env_name #退出env_name虚拟环境

如果实在搞不定python3.7与python2.7版本兼容问题,也可以放弃使用OpenAI开源的gym-gazebo库,直接统一用python2.7版本做实验,我就是用这种方法,非常方便。

具体方法是:直接用turtlebot3_machine_learning里的软件包,里面有很多现成的用turtlebot做DQN训练的程序,在上面的“安装turtlebot3软件包”一小节中已经有安装这个软件包。但这些写好的程序是用tensorflow和keras实现的神经网络,因此需要在conda虚拟环境中安装tensorflow和keras。如果要改成用pytorch也是可以的,同样是要在虚拟环境中安装pytorch库,不要在常规环境中安装。我就是改用的pytorch库实现的神经网络。

2.3 OpenCV安装注意事项

如果要处理机器人摄像头获取的仿真图像,就要安装opencv库。首先一点,python文件中import cv2并不是opencv2!!!opencv3,opencv4都可以,我一开始在python2.7环境中安装opencv2,涉及到降低对应的CUDA、gcc、g++版本问题,好不容易降低版本之后源码安装opencv2时还一堆bug。后来发现只需要sudo pip install opencv-python自动安装opencv即可。然后最后一个支持python2.7的opencv版本是 4.2.0.32,因此:

$ sudo pip install opencv-python==4.2.0.32

千万注意,opencv千万不要源码安装,因为源码里有很多错误,我按照网上的一些说明改了很多地方,但还是编译不了,最后用的pip install 直接自动安装编译完成。

2.4 最后强调一点

显卡驱动、CUDA、cudnn、pytorch或tensorflow、gcc/g++的版本一一对应,python、opencv、CUDA的版本一一对应。因此,以上所有库都是有相互版本对应关系的,不能安装错误的版本。

3 神经网络GPU训练过程

3.1 GPU加速深度强化学习训练的方法

其实GPU加速所有神经网络都是一样的,一是将model转到GPU上,二是将input转到GPU上:

(1)在主程序中只要将model转到GPU上

device = torch.device('cuda:0') #指定用第几号GPU训练网络
agent = agent.to(device) #agent是网络的一个实例

(2)在DDPG网络模型文件:

在choose_action函数中,将网络输入state转为.torch.FloatTensor()之后再.to(device)转到GPU上:

s = torch.unsqueeze(torch.FloatTensor(s),0).to(device)

在对经验池生成的batch进行学习的函数中,将bs,ba,br,bs_全都转为.torch.FloatTensor()类型之后再.to(device)转到GPU上:

 bs = torch.FloatTensor(bs).to(device)
 ba = torch.FloatTensor(ba).to(device)
 br = torch.FloatTensor(br).to(device)
 bs_ = torch.FloatTensor(bs_).to(device)

3.2 其他小问题

(1)训练神经网络的结点必须在conda虚拟环境中用roslaunch启动,gazebo仿真环境在常规环境中启动。自己写的ros结点除了python结点文件以外,还要写好launch文件。

(2)TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.

这是在对神经网络的输出做处理时遇到的报错,因为神经网络都放到了CUDA上运算,这时网络输出的类型也是tensor类型,要想对其做处理,需要将其转换为numpy类型。

output = output.data.cpu().numpy()

(3)RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

该问题是指在默认情况下,网络在反向传播中不允许多个backward()。需要程序中第一次出现的backward设置retain_graph=True

loss.backward()改为loss.backward(retain_graph=True)

4 源码

GitHub - chch9907/turtlebot3-DDPG-LSTM-PER: multi-turtlebot3 collision avoidance and navigation via DDPG-LSTM with Prioritized Experience Replay on ROSmulti-turtlebot3 collision avoidance and navigation via DDPG-LSTM with Prioritized Experience Replay on ROS - GitHub - chch9907/turtlebot3-DDPG-LSTM-PER: multi-turtlebot3 collision avoidance and navigation via DDPG-LSTM with Prioritized Experience Replay on ROShttps://github.com/chch9907/turtlebot3-DDPG-LSTM-PER/tree/main时隔半年,已经读研一学期了,现在决定还是把代码开源了,也方便自己记录一下之前的经历。训练效果不一定理想,因为仅以图像作为输入的状态空间太大,特征信息与训练目标的相关性不够强,加上奖励稀疏(虽然用了PER机制来解决这个问题),因此整体的训练难度很大,但网络结构的代码是严格按照论文实现了DDPG和LSTM的结合以及PER机制,并且实现了基于turtlebot的DRL仿真训练过程,这里相当于是指了个路,等以后有空或恰好做到类似项目了再深入改进一下。

目前上传了单个turtlebot3的仿真训练,多个turtlebot的文件因为之前的仿真环境已经清空所以找不到了,因此只在github里写了multi-turtlebot实现的思路和我能想起来的一些注意点。

(回头看本科时写的代码不规范的地方很多,但现在忙于做研究没空更新代码,有空一定更正代码,望见谅。)


2022.8.29更新:

因为近期不少人联系我问我这篇文章的事情,然后最近我非常碰巧又做回了视觉导航相关的项目,所以我还是在这里说一些建议以免误导了大家。

我这篇文章主要是分享实验过程中的一些工程上的问题的解决方案,虽然我当时通过文献调研了解基于深度学习的视觉导航这个方向还做的不多,但我当时的认识很有限,因此我当时的算法尝试其实是一个很toy的做法,事实上只用image作为state是很难work的(虽然也有position state但我对这个信息的提取不够强),一般还是要结合目标检测或语义分割,或者把target point换成一副图片而不是坐标点。但能不能直接只用image数据训练一个模型来做导航和避障?UC Berkeley就有做这方面的工作。以下两篇论文的主页供大家参考:

(注:可能需要翻墙,如果不能翻墙就直接搜论文名称看论文)

BADGR: An Autonomous Self-Supervised Learning-Based Navigation System

ViNG: Learning Open-World Navigation with Visual Goals

Sim2Real的问题我当时也没调研到有什么好的办法解决,最近才了解到可以用Domain Randomization和迁移学习来解决。

Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World

RetinaGAN: An Object-aware Approach to Sim-to-Real Transfer

5 结语

以上就是我毕设期间遇到绝大部分问题的经验分享,为了解决这些问题真是搜索了各种资料尝试了各种方法,最终我把成功的方法分享给大家。我也是第一次如此深入使用ROS系统,因此希望我的分享对大家有所帮助。虽然我这个课题遇到了如此多的问题,而且算法实现难度很高,预期效果也未知,但我一直坚持我喜欢的事情,不在乎他人如何看待,自己兴趣所在才是最关键的。对于算法部分感兴趣的或配置环境过程中遇到了其他问题,欢迎问我,我如果有遇到过类似问题一定倾力相助,因为我也是请教过其他博客的博主,在前人的帮助下一路走过来的。

  • 35
    点赞
  • 222
    收藏
    觉得还不错? 一键收藏
  • 37
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值