路径跟随模板
路径跟随模板是深度学习模板的一种替代方案。深度学习模板适用于室内赛道,可以控制光照条件和房间的细节,但在室外环境中,光照条件多变,环境也会发生变化,使用起来可能更加困难。在室外,我们可以使用GPS;路径跟随模板允许您使用GPS接收器记录路径,然后配置一个自动驾驶系统来跟随该路径。
GPS位置通过串口从GPS接收器读取。我们将其作为NMEA句子进行读取,这是大多数GPS接收器默认使用的一种面向行的协议。NMEA句子包括纬度和经度作为位置信息;然后,我们将其转换为以米为单位的本地坐标系。
当我们记录路径时,我们将从GPS接收器获取的每个(x,y)坐标对(每个航点)保存到内存中的数组中。然后,我们可以将其保存到一个CSV文件中,每行一个(x,y)坐标对。稍后,我们可以将这个CSV文件读取回内存中。一旦我们在内存中有了航点,我们就可以进入自动驾驶模式并跟随这些点。
与深度学习模板类似,我们有三种操作模式:
- 在用户驾驶模式下,您可以手动控制汽车。与深度学习模板类似,您可以使用网络控制器和/或游戏控制器来转向、加速和使用按钮选择动作。
- 在自动转向模式下,汽车将尝试跟随记录的航点集,但仅控制转向;您仍然手动控制油门。当按照路径行驶时,这是一个很好的模式,因为您可以通过松开油门来安全停车。它还有助于确定汽车可以可靠地跟随航点的最大速度。
- 在自动驾驶模式下,汽车将尝试通过控制转向和油门来跟随记录的航点集。这是完全自主的。要停止汽车,使用控制器结束用户模式。
路径跟随自动驾驶演示
在我们能够记录或跟随路径之前,我们需要创建一个应用程序并进行一些配置。
创建路径跟随应用程序
您可以像创建深度学习应用程序一样创建路径跟随应用程序;我们只需要告诉它使用path_follow模板而不是默认模板。首先,确保您的DonkeyCar Python环境已激活,然后使用createcar命令创建您的应用程序文件夹。
donkey createcar --template=path_follow --path=~/mycar
当升级到DonkeyCar的新版本时,您可能需要刷新应用程序文件夹。您可以使用相同的命令进行操作,但添加--overwrite
参数,以免删除您的myconfig.py文件。
donkey createcar --template=path_follow --path=~/mycar --overwrite
配置
与深度学习模板类似,我们可以通过编辑mycar文件夹中的myconfig.py文件来更改默认配置值,该文件是使用createcar
命令创建的。
您需要根据校准您的车辆中的描述来校准和配置驱动系统。如果您的汽车配对了游戏控制器,那么您需要按照控制器中的说明进行配置。
配置GPS
在myconfig.py中搜索'gps'部分。确保设置了HAVE_GPS = True
。您需要确定GPS接收器连接的串口和要使用的波特率。如果可能,请将串口设置为115200
波特率以获得良好的吞吐量。
GPS_SERIAL = <serialport>
<serialport>
的值取决于您如何连接GPS接收器(通过USB还是GPIO串口)以及单板计算机(RPi还是Nano)。- 您可以列出所有潜在的串口:
ls /dev/tty*
。请注意,其中大多数实际上是不可用的。 - 如果连接到Nano的USB端口,请使用
/dev/ttyUSB0
。 - 如果连接到RPi的USB端口,请使用
/dev/ttyACM01
。 - 如果连接到默认的RPi GPIO串口(板上引脚8和10),请使用
/dev/ttyAMA0
。 - 如果连接到默认的Jetson Nano GPIO串口(板上引脚8和10),请使用
/dev/ttyTHS1
。
GPS_SERIAL_BAUDRATE = <baudrate>
<baudrate>
的值取决于您的GPS接收器以及是否使用U-Center进行更改。- 当在SBC的USB端口和GPS接收器的USB端口之间连接时,波特率由USB检测到,因此选择115200以获得快速连接。
- ZED-F9P的其他串口默认波特率为38400。
- 廉价的GPS接收器通常默认波特率为9600。
- 观看此视频了解如何使用UBlox的U-Center更改UBlox GPS接收器上的UART波特率。
请注意,RPi和Jetson Nano可能正在使用默认的GPIO串口作为登录控制台(您可以连接一个串行“终端”并登录)。如果使用GPIO串口,您需要禁用登录控制台。有关详细信息,请参阅Writing to a serial port。
这两个设置是与GPS接收器相关的仅需在myconfig.py中设置的设置。大多数GPS接收器还可以直接配置,以更改串口的波特率或将位置估计发送到计算机的速度。理想情况下,位置估计的速率应尽可能快,但不同的接收器具有不同的上限,并且在更新速率和准确性之间存在一些权衡。基于U-Blox的GPS接收器可以使用U-Blox U-Center软件进行配置;请参阅Donkeycar Meets RTK GPS中的U-Center部分获取一些详细信息。其他芯片组制造商也有自己的软件;您需要查看GPS接收器以确定制造商。如果您使用的是RTK高分辨率GPS,则需要在Donkeycar之外进行更多的配置和连接。请参阅Donkeycar meets RTK GPS以详细讨论一种设置RTK GPS接收器供Donkeycar使用的方法。这里有一个相关的视频,介绍了相同的信息。
配置编码器和运动学
编码器设置可以用于估计车辆的速度和位置;这样可以在路径跟随模板中使用编码器代替GPS,因此可以在室内使用。这需要在myconfig.py
中进行一些配置,主要是轮子直径、轴距和轴长的测量值。有关详细信息,请参阅里程计软件设置。
配置按钮操作
您可以使用Web控制器或游戏控制器。您可以通过编辑myconfig.py中的按钮分配来将游戏手柄按钮或Web界面按钮分配给某个操作。游戏手柄按钮的名称取决于您配置的游戏控制器(注意:一个按钮被保留为紧急停止;您可以通过查看使用python manage.py drive
命令启动该汽车时的控制台输出来查看分配的按钮)。可用的5个Web界面按钮的名称为web/w1
到web/w5
。如果将None
操作分配给按钮,则会忽略该按钮。
SAVE_PATH_BTN
是保存内存中路径到文件的按钮。LOAD_PATH_BTN
是从CSV文件中重新加载路径到内存的按钮。RESET_ORIGIN_BTN
是将当前位置设置为原点的按钮。ERASE_PATH_BTN
是从内存中擦除路径并重置原点的按钮。TOGGLE_RECORDING_BTN
是切换录制模式开启或关闭的按钮。请注意,Web界面中有一个预分配的按钮,因此如果您使用Web界面,则无需将此按钮分配给web/w*
按钮之一。INC_PID_D_BTN
是通过PID_D_DELTA增加PID 'D'常数的按钮。DEC_PID_D_BTN
是通过-PID_D_DELTA减少PID 'D'常数的按钮。INC_PID_P_BTN
是通过PID_P_DELTA增加PID 'P'常数的按钮。DEC_PID_P_BTN
是通过-PID_P_DELTA减少PID 'P'常数的按钮。
记录路径
该算法假设我们将以连续的连接路径行驶,使得起点和终点相同。您可以通过编辑myconfig.py中的PATH_MIN_DIST
值来调整记录路径的路径点之间的间距。您可以通过编辑PATH_FILENAME
值来更改保存文件的名称和位置。
记录路径的工作流程如下:
- 使用Web控制器或游戏控制器进入用户驾驶模式。
- 将车辆移动到所需的起点。
- 擦除内存中的路径(这也将重置原点)。
- 切换录制模式开启。
- 手动驾驶汽车绕着赛道行驶,直到再次到达所需的起点。
- 切换录制模式关闭。
- 如果需要,保存路径。
路径将保存为逗号分隔的值(.csv)文件。文件中的每一行包含3个由逗号分隔的数字:x位置、y位置、油门。x和y位置是读取位置时车辆所在的位置,油门是当时生效的油门值。以下是路径文件的一部分示例:
0.0033510593930259347, 7.996719985734671, 0.14
0.11206169077195227, 9.325505392625928, 0.16
0.20344207028392702, 10.525161047000438, 0.18
0.311049185693264, 11.724678185302764, 0.14
0.23874327179510146, 12.75951695209369, 0.13
0.26568955020047724, 14.015127370599657, 0.15
0.35580877534812316, 15.06704786233604, 0.18
0.4303318051388487, 16.192974457982928, 0.15
0.2126157897291705, 17.302927474025637, 0.17
-0.37973403913201764, 18.24986434960738, 0.17
-1.2822835729457438, 18.97783037694171, 0.17
-2.4313870034529828, 19.338536370545626, 0.17
-3.633584696042817, 19.182584955357015, 0.17
-4.694471199880354, 18.471380048431456, 0.25
-5.2241318183369, 17.256997687276453, 0.25
-5.462499356712215, 15.947787401732057, 0.25
-5.5869644057238474, 14.674541235901415, 0.25
由于路径保存在一个简单的.csv文件中,它可以在许多工具中进行可视化。一个简单的工具可以用来可视化您的路径是CSV Plot。使用右上角的按钮(位于主页按钮左侧)使轴的刻度变为正方形。这是一个示例路径(旋转以更好地适应):
路径跟随
当前的自动驾驶系统使用恒定的油门值。您可以通过编辑myconfig.py中的PID_THROTTLE
值来设置它。
以下是路径跟随的工作流程:
- 使用网页控制器或游戏手柄控制器进入用户驾驶模式。
- 将车辆移动到所需的起始点。
- 如果您要跟随保存的路径,则将路径加载到内存中。
- 重置原点(注意:不要删除路径,只是重置原点)。
- 进入自动转向或自动驾驶模式。如果您处于自动转向模式,您需要手动提供油门才能使车辆移动。如果您处于自动驾驶模式,车辆应该完全自动驾驶。
- 再次进入用户模式以停止车辆。
路径跟随算法
我们用于路径跟随的算法非常简单,可以说是路径跟随的入门级算法。
- 获取车辆当前的GPS位置。
- 在路径点列表中找到最近的点;从最近的路径点开始,向上搜索
PATH_SEARCH_LENGTH
个点,并选择最接近当前位置的路径点。 - 选择最接近路径上的点前方
PATH_LOOK_AHEAD
个点的路径点。 - 选择最接近路径上的点后方
PATH_LOOK_BEHIND
个点的路径点。 - 使用前方和后方的路径点创建代表期望轨迹的直线。
- 计算车辆当前位置与期望轨迹之间的横向偏差(cross-track error)。横向偏差是一个带符号的值,表示车辆离轨迹线的距离以及车辆在轨迹线的哪一侧。
- 将横向偏差作为误差输入到控制方向盘的PID控制器中。
- PID控制器输出一个新的转向值。
除了控制方向盘,路径跟随控制器还会将油门设置为与路径上最近的点保存的油门值乘以myconfig.py
文件中的PID_THROTTLE
值的比例。如果在myconfig.py
中设置了USE_CONSTANT_THROTTLE = True
,则可以覆盖该设置,此时将使用PID_THROTTLE
作为恒定的油门值。
配置路径跟随参数
算法使用期望线路与车辆测量位置之间的横向偏差来决定转向的程度和方向。但是我们记录的路径不是简单的一条直线,而是一系列点,通常是一种回路。如上所述,我们使用车辆的当前位置来选择作为期望轨迹的路径的一个短段。每当我们获得新的测量车辆位置时,这个短段就会重新计算。有一些配置参数确定了我们用于计算期望轨迹线的路径上的哪两个点。
PATH_SEARCH_LENGTH = None # 搜索最近点的点数,None表示搜索整个路径
PATH_LOOK_AHEAD = 1 # 最近点之后要包括在横向偏差跟踪中的点数
PATH_LOOK_BEHIND = 1 # 最近点之前要包括在横向偏差跟踪中的点数
一般来说,如果您以很快的速度驾驶,您可能希望前瞻距离比较大,这样您的转向可以预测即将到来的曲线。通过增加结果轨迹线的长度,通过增加后视和/或前瞻距离,还可以作为噪声滤波器;它可以平滑轨迹。这减少了控制器中的抖动量。然而,这必须与路径中真实的曲线相平衡;较长的轨迹段实际上会“拉平”曲线,因此可能导致欠转弯;在曲线上时转向不足。
什么是PID控制器?
PID控制器是一个函数,它接受两个参数:1)要实现的目标值和2)当前测量值。PID函数使用目标值和测量值之间的差异(误差)来计算一个控制值,该控制值可以用于实现目标值(即将期望值与测量值之间的误差驱动到零)。
在我们的情况下,我们希望保持在期望的轨迹上;我们希望横向偏差(期望线路与车辆测量位置之间的距离)为零;输出的控制值是一个转向值,应该将车辆靠近期望线路。因此,我们的PID控制器根据车辆位于线路的哪一侧以及离期望线路有多远来控制转向。
算法使用横向偏差的符号来确定转向的方向。自然地,如果横向偏差表明车辆位于期望轨迹的左侧,则车辆应该向右转以靠近期望轨迹。如果横向偏差表明车辆位于期望轨迹的右侧,则车辆应该向左转以靠近期望轨迹。如果车辆位于期望轨迹上,则转向应该是中性的。
但是我们应该转多少;我们应该只轻微转向还是应该转得很大?PID控制器将输出与横向偏差的大小成比例的转向值。因此,如果我们靠近期望轨迹,它将轻微转向。如果我们偏离期望轨迹很远,它将转得更大。
确定PID系数
PID系数是配置中最重要(也是最耗时)的参数。如果这些参数对于您的车辆不正确,它将无法跟随路径。可以通过编辑myconfig.py文件中的值来更改系数。
PID_P
是比例系数;它与横向偏差相乘。这是最重要的参数;它对输出转向值的贡献最大,在某些情况下可能是跟随线路所需的唯一参数。如果这个值太小,车辆在到达弯道时不会转向足够。如果这个值太大,它会对路径中的小变化过度反应,可能会开始打圈,特别是在到达弯道时。PID_D
是微分系数;它与横向偏差的变化相乘。该参数可用于减小振荡和超调。PID_I
是积分系数;它与累积的横向偏差相乘。这可能有助于减小由累积误差引起的偏移,比如如果一个车轮的直径略小于另一个车轮。
如上面的配置按钮操作部分所述,您还可以将类似INC_PID_P_BTN
或DEC_PID_P_BTN
的函数分配给游戏控制器或Web界面按钮,以实时修改PID参数。这在您确定最佳系数时非常有帮助。按钮功能允许您在不停止车辆、编辑myconfig.py并重新启动车辆的情况下更改值。
确定PID系数可能很困难。一种方法是:
-
首先确定P系数。
- 将D和I系数设为零。
- 使用一种“二进制”搜索的方法,找到一个值,使车辆大致跟随记录的直线;可能会在其周围振荡。它会像受到影响一样来回摆动。
- 为此,记录一段短直线,可能是6米。您可以将车辆置于录制模式,并与车辆一起行走(以便保持油门为零)。一旦记录了短直线,请将车辆置于自动驾驶模式,并站在直线的中间,将车辆与直线平行;车辆的前轮应该保持稳定和直线。现在慢慢将车辆移离直线,保持车辆与直线平行;车辆应该开始朝向直线转向。离线移动的越远,车辆转向的越多。尝试直线的两侧。
- 如果车辆转向远离直线而不是朝向直线,则改变P值的符号。
- 如果车辆转向很小,则增加P值。
- 如果车辆离开直线时转向非常突然,则减小P值。
- 调整P值,直到车辆平稳地回转到直线并与离线距离成比例。
- 现在尝试在自动驾驶模式下实际驾驶直线。车辆可能会在直线上振荡;如果它振荡很多,则减小P值。调整P值,使其能够从一端驱动到另一端的直线。它可能会在直线的末端失控;这是正常的,因为路径不是闭合的。
- 一旦您可以驾驶一段短直线,然后在只设置P值的情况下在自动驾驶模式下驾驶车辆在一个完整的闭合路径上。确保路径中有一个相当紧密的转弯。调整P值,直到获得可接受的性能。一旦您做到了这一点,就可以使用D值进一步优化。
-
接下来,找到一个D系数,以减小直线上的摆动(振荡)。然后记录一个带有紧急转弯的路径。找到一个D系数,以减小转弯时的超调。
-
您可能甚至不需要I值。如果车辆在驾驶一段时间后变得不稳定,那么您可能需要开始设置该值。它可能比其他值小得多。
要耐心。从一个相对较慢的速度开始。逐个更改并测试每个更改;不要一次性进行多个更改。记下什么是有效的。
一旦您有了稳定的PID控制器,那么您可以确定在自动驾驶变得不稳定之前可以以多快的速度行驶。如果您想要更快,那么设置所需的速度,并再次使用上述建议的方法调整值。