天天看点

横向自动控制方法:Purepursuit, Stanley, MPC对比

刚刚学习了cousera上的自动驾驶课程第一课,在CarLa模拟器上跑了三种不同横向控制方法的表现(纵向用的PID)。在这记录下他们各自的表现,并从理论上找下原因。

PurePursuit

这种方法最大的特点是有lookahead distance: ld, 这个距离与前进速度成比例kdd,速度越快需要往前看的更远。这种方法的好处是因为看的远,汽车行驶时非常robust,即使参考曲线时不连续的,而是waypoints形式的,也不会造成很大影响,而且不会对速度,弯道弧度的瞬间变化过度敏感。然而缺点就是cutting corner: 在转弯处,因为转向角度一直是根据前面的位置状态决定的,所以它通常超前拐弯,不能很好的贴合设计的弯道线路,而且可以从公式上看到,这种方式并没有考虑cross track error: e,因此在转弯时偏离预设道路的问题没法很好解决。

横向自动控制方法:Purepursuit, Stanley, MPC对比

下图能够直观的看到弯道处cutting corner的现象:绿色为预设线路,橙色为汽车在PurePursuit控制下真实行驶线路

横向自动控制方法:Purepursuit, Stanley, MPC对比

因此这种方式虽然比较robust但不太适合在弯道比较多,精度要求比较高的场景下使用

Stanley

这种方式综合考虑了heading error 和 cross track error两个问题

横向自动控制方法:Purepursuit, Stanley, MPC对比
横向自动控制方法:Purepursuit, Stanley, MPC对比

这种方式的优点很明显,相对比Purepursuit而言,这种方式不会出现cutting corner的现象,因为它并没有视野提前量,而且对cross track error很敏感,所以能够很好的贴合预定线路。

横向自动控制方法:Purepursuit, Stanley, MPC对比

但是缺点就是,因为它不会向前看,只关注现在的状态,所以对外界的刺激很敏感,不像PurePursuit那样robust,这种现象在waypoints这种不连续的预定线路下很明显。车在行驶的时候晃来晃去的,反映在数据上就是steering angle的变化非常的reckless,像是酒驾的司机。

横向自动控制方法:Purepursuit, Stanley, MPC对比

因此这种方式适合用在normal operation下,给定的曲线信息也要是连续的。

MPC

这种方式就很高级,能够在着眼未来的同时脚踏实地。首先这种方式会往前看,确保自己不短视,能够有一定的抗干扰能力。之后根据自己现阶段的状态,预测采用不同的策略(不同的steering angle)时,t秒后自己状态是怎么样的。然后指定一种(表现指标)performance index判定不同策略的好坏,选择在这种指标下最好的结果。在trace track的场景下就可以把表现指标设为t秒后,到达我现在视野内前方的某个位置。根据这个选择最好的steering angle。这样的话看起来和PurePursuit有点像。但关键在于MPC在一步步根据自己目前的状态的做预测然后控制汽车一步步往前走, 而PurePursuit只往前看,不管自己怎么移动过去的,也不会预测。

还有一点就是MPC有一个horizon time, 做预测的整体时间Ttotal,假设为20s。那MPC就会根据现在的状态预测之后每一秒的状态直到20s后,然后再根据自己每一秒移动后的状态更新之后20s每一步的预测。像是在下棋,每一步都挑最优解,同时根据每一步之后的变化谋划未来。

这种方法当然非常好,能够非常精确的规划运动,但是每步都用到了最优化求解所以很考验计算能力。在模拟中效果也很好,没有cutting corner,steering angle的变化也很稳定。

横向自动控制方法:Purepursuit, Stanley, MPC对比
横向自动控制方法:Purepursuit, Stanley, MPC对比

MPC-实现代码

elif self._control_method == 'MPC':
            steering_list = self.vars.steering_previous+self._steering_diff*self._pi/180
            #how far we predict, how we predict
            #meaning of last_waypoint from module_7.py:
            #Find closet distance and index in whole waypoints
            # return the path that has 1 waypoint behind and X waypoints ahead, where X is the index
            # that has a lookahead distance specified by INTERP_LOOKAHEAD_DISTANCE

            # waypoints 是整体waypoints.txt里的子集,(closest_point-1, X)插值后的集合
            # Use the first and last waypoint subset indices into the hash
            # table to obtain the first and last indicies for the interpolated
            # list. Update the interpolated waypoints to the controller
            # for the next controller update.

            #在这里 kmpc取得越大,last_waypoint看的就越远
            last_waypoint = [waypoints[int(self._Kmpc*len(waypoints))][0],waypoints[int(self._Kmpc*len(waypoints))][1]]
            min_dis = float("inf")
            steering = self.vars.steering_previous
            for i in range(len(steering_list)):
                #possible concequences after steering at different degree
                predicted_wheel_location = self.get_predicted_wheel_location(x,y,steering_list[i],yaw,v)
                #performance index:
                # measurement the concequences(how far the vehicle is away from the last_waypoint it is heading for)
                dis_to_last_waypoint = self.get_distance(predicted_wheel_location[0],predicted_wheel_location[1],last_waypoint[0],last_waypoint[1])
                #decision based on the measured concequences:
                # steer to make the vehicle as close as possible to the last_waypoint ahead
                if dis_to_last_waypoint<min_dis:
                    min_dis  = dis_to_last_waypoint
                    steering = steering_list[i]
            return steering
           

总结

观察了这些横向控制方法的特点后,明白了自动驾驶汽车领域为什么都用MPC了,只要够精确,效果好,在安全是第一需求的前提下,多点计算量又算神🐎。

继续阅读