如何防止在我的自动驾驶解决方案中过度校正?

Bri*_*eld 3 c++ opencv

我正在使用 C++ 中的 OpenCV 为 Euro Truck Simulator 2 开发自动驾驶解决方案。

这是我们检测道路曲线的地方:

    int bottom_center = 160;
    int sum_centerline = 0;
    int count_centerline = 0;
    int first_centerline = 0;
    int last_centerline = 0;
    double avr_center_to_left = 0;
    double avr_center_to_right = 0;

    //#pragma omp parallel for
    for (int i = 240; i > 30; i--){
        double center_to_right = -1;
        double center_to_left = -1;

        for (int j = 0; j < 150; j++) {
            if (contours.at<uchar>(i, bottom_center + j) == 112 && center_to_right == -1) {
                center_to_right = j;
            }
            if (contours.at<uchar>(i, bottom_center - j) == 112 && center_to_left == -1) {
                center_to_left = j;
            }
        }
        if (center_to_left != -1 && center_to_right != -1){
            int centerline = (center_to_right - center_to_left + 2 * bottom_center) / 2;
            if (first_centerline == 0) {
                first_centerline = centerline;
            }
            cv::circle(outputImg, Point(centerline, i), 1, Scalar(30, 255, 30), 3);
            cv::circle(outputImg, Point(centerline + center_to_right+20, i), 1, Scalar(255, 30, 30) , 3);
            cv::circle(outputImg, Point(centerline - center_to_left+10, i), 1, Scalar(255, 30, 30) , 3);
            sum_centerline += centerline;
            avr_center_to_left = (avr_center_to_left * count_centerline + center_to_left) / count_centerline + 1;
            avr_center_to_right = (avr_center_to_right * count_centerline + center_to_right) / count_centerline + 1;
            last_centerline = centerline;
            count_centerline++;
        }
        else {}
    }
Run Code Online (Sandbox Code Playgroud)

这是我目前的转向解决方案:

int diff = 0;
    if (count_centerline != 0) {
        diff = sum_centerline / count_centerline - bottom_center;
        int degree = atan2(last_centerline - first_centerline, count_centerline) * 180 / PI;
        //diff = (90 - degree);

        int move_mouse_pixel = diff;
        cout << "Steer: " << move_mouse_pixel << "px ";
        if (diff <= 20 || diff >= -20){
            SetCursorPos(pt.x + (move_mouse_pixel / 10), height / 2);
        }
        else{
            SetCursorPos(pt.x + (move_mouse_pixel / 25), height / 2);
        }
    }
Run Code Online (Sandbox Code Playgroud)

最后,这是我的程序目前所做的视频:https : //www.youtube.com/watch?v=rqyvoFuGKKk&feature=youtu.be

我目前遇到的问题是转向没有足够快地居中,导致它不断过度校正,直到它偏离车道。我试图提高游戏中的转向灵敏度,以允许更快或更慢的转弯,但这要么会使卡车失去控制,要么在沿着大弯道行驶时转弯不够。

我目前的方法只是将轻微移动(在 -20px 和 20px 之间)除以 10,将大移动除以 20。我也尝试过反转这一点,但没有解决过度校正的问题。

到目前为止,我发现了两种可能的解决方案:

  1. 我可以逐渐增加我们应用于 move_mouse_pixel 的分隔符,从而减少在小动作之间完成的转向力。

  2. 或者,我可以以某种方式使程序更快地以方向盘为中心。我不确定我将如何实现这一点。

你们有什么感想?

小智 5

我相信 PID 控制器将适合这项任务。 https://en.wikipedia.org/wiki/PID_controller 在您的情况下,它看起来类似于:

            diffOld = diff;
            diff = sum_centerline / count_centerline - bottom_center;
            SetCursorPos(width/2 + Kp* diff + Kd*(diff - diffOld) , height / 2);
Run Code Online (Sandbox Code Playgroud)

不要在这个控制器中使用 if 语句。即使没有纠正错误,您也需要继续转向。我建议跳过积分部分,因为您的对象是积分(当您不直接驾驶时,您积分错误)。您需要通过实验选择 Kp 和 Kd 参数的值,例如使用 Ziegler–Nichols 方法https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method