写在前面

为了保证rrt算法能在各种障碍物的情况下运行,因为做的是在非结构化的环境下路径规划,而且还是静态规划,因此要尽可能保证基本的rrt算法实现没有问题。

算法实现结果

黑色:障碍物(可由鼠标绘制);
绿色线段:探索路径;
绿色方块:终点
红色方块:起点
棕色线段:最终路径
点划线:路径探索下边界
绿色圆点:代表算法开始运行

障碍物绘制

首先看一下任意障碍物绘制的效果以及算法效果:

要查看不同障碍物情况下算法的实现效果就需要不同情况下的障碍物,接下来就讲一下实现方法。

绘制障碍物的方法就是点击鼠标右键进行绘制,会有一个固定半径的黑色圆圈跟随鼠标进行运动,从而完成障碍物的绘制,障碍物绘制完毕之后点击鼠标左键即可完成路径规划算法以及路径可视化。

源码如下:

void rrtGraph::init_obs_start_end()
{
/*************************************/
    initgraph(rrt_graph_para->rrt_graph_width, rrt_graph_para->rrt_graph_real_height);
    settextstyle(16, 8, _T("Consolas"));
    setbkcolor(WHITE);
    settextcolor(BLACK);
    setlinestyle(PS_DASHDOT, rrt_graph_para->separating_line);
    setlinecolor(BLACK);
    setfillstyle(BS_SOLID);
    cleardevice();

    setfillcolor(RED);
    solidrectangle(0, 0, rrt_graph_para->block, rrt_graph_para->block);
    setfillcolor(GREEN);
    solidrectangle(rrt_graph_para->rrt_graph_width - rrt_graph_para->block,
        rrt_graph_para->rrt_graph_height - rrt_graph_para->block,
        rrt_graph_para->rrt_graph_width, rrt_graph_para->rrt_graph_height);

    setfillcolor(BLACK);


    line(0, rrt_graph_para->rrt_graph_height + rrt_graph_para->separating_line,
        rrt_graph_para->rrt_graph_width,
        rrt_graph_para->rrt_graph_height + rrt_graph_para->separating_line);

/*************************************/
    bool mouse_down_flag = false;
    ExMessage mse;

    while (1) {
        mse = getmessage(EM_MOUSE | EM_KEY);

        if (mouse_down_flag == false && mse.message == WM_RBUTTONDOWN) {
            mouse_down_flag = true;
            while (1) {
                mse = getmessage(EM_MOUSE);
                if (mse.message == WM_RBUTTONUP) {
                    mouse_down_flag = false;
                    break;
                }
                else {solidcircle(mse.x, mse.y, rrt_graph_para->obstacle_r);}
            }
        }
        else if (mse.message == WM_LBUTTONUP) {
            setfillcolor(GREEN);
            solidcircle(0 + rrt_graph_para->block, rrt_graph_para->rrt_graph_height+block, 
                rrt_graph_para->obstacle_r/4);
            break;
        }
    }


}

在示例程序中,被/*************************************/包起来的部分是easyX相关参数的初始化,跟障碍物绘制的逻辑关系不大,在此不做特殊讲解。

主要逻辑也就是下面这部分:

    bool mouse_down_flag = false;
    ExMessage mse;

    while (1) {
        mse = getmessage(EM_MOUSE | EM_KEY);

        if (mouse_down_flag == false && mse.message == WM_RBUTTONDOWN) {
            mouse_down_flag = true;
            while (1) {
                mse = getmessage(EM_MOUSE);
                if (mse.message == WM_RBUTTONUP) {
                    mouse_down_flag = false;
                    break;
                }
                else {solidcircle(mse.x, mse.y, rrt_graph_para->obstacle_r);}
            }
        }
        else if (mse.message == WM_LBUTTONUP) {
            setfillcolor(GREEN);
            solidcircle(0 + rrt_graph_para->block, rrt_graph_para->rrt_graph_height+block, 
                rrt_graph_para->obstacle_r/4);
            break;
        }
    }

算法用自然语言来描述就是说,首先我们需要获得信息结构体,然后获取鼠标信息,判断鼠标右键是否按下,如果是在按下左键之前按下的鼠标右键,那么就开始画障碍物了,如果此时再松开鼠标右键就是结束这个障碍物的绘制,接下来还可以重复鼠标右键画障碍物的动作。那么如果程序判断到鼠标左键弹起的时候说明障碍物绘制完毕了,要开始算法的执行了,此时设置探索路径为绿色,而且在隔离栏里面绘制小的绿色圆形,表示算法开始运行了。

这里有一个注意的点,消息结构体在获取信息的时候是需要获取鼠标动作的,也就是不按鼠标的时候是没有信息的,而是要按下鼠标的时候才能有信息。那么鼠标按下和弹起状态是成对出现的,因此选择哪个状态做为算法运行的信号都可以,但是鼠标弹起的时候运行算法更能提高用户使用体验感。