底盘和pl程序:
底盘main.cpp中包含RecvFromCAN、RecvFromPL、Process、SendToCAN、RecvFromIMU、AnalysisIMU、SendCarState七个线程。
1.RecvFromCAN线程:
void *RecvFromCAN_pthread(void *arg)
vcu_vstate1_st是一个关于车辆各个信息状态的结构体,先对结构体vcu_vstate1_st和vcu_dstate_st进行memset初始化
memset(&g_vcu_vstate1, 0, sizeof(vcu_vstate1_st));
memset(&g_vcu_dstate, 0, sizeof(vcu_dstate_st));
然后为了获取到vcu_vstate1_st和vcu_dstate_st结构体数据,需要与底盘can口建立通信,所以接下来进行can通信初始化和can数据接受,来填充结构体数据。
将底盘frame.data中的数据传输给g_vcu_vstate1中。
2.RecvFromIMU线程:
这个线程的功能类似于人工采集路径点的过程,思想还是一样,就是提取sv2惯导GPS数据中对自动寻迹有用的数据:经纬度、速度、转向角。
和g_speed
3.SendCarState线程:
这个线程用于将上个线程中提取的经纬度、转向角放到该线程建立的gMC_state、gMC_NAV、gMC_DRIVE三个结构体中。
第一步:先对三个结构体进行初始化。
memset(&gMC_state, 0, sizeof(gMC_state));
memset(&gMC_NAV, 0, sizeof(gMC_NAV));
memset(&gMC_DRIVE, 0, sizeof(gMC_DRIVE));
这边的速度没有采用惯导提取的速度,而是采用的之前can通信传输给vcu_vstate1_st中的speed.并将赋给了gMC_NAV结构体中的Speed_cm_ps,gMC_DRIVE中也有速度。
第二步:接着通过UDP_send_data()函数将底盘和pl(路径规划)之间建立socketUDP通信,将主要的gMC_NAV这个结构体发送给pl程序,发送用的函数是sendto函数。
sendbytes = sendto(brdcFd, &gMC_NAV, sizeof(gMC_NAV), 0, (struct sockaddr *)&Addr, sizeof(struct sockaddr));
4.pl程序中的WRC_UDPRECV线程:
这个线程用于将底盘传输过来的gMC_NAV中的数据进行接受。
创建一个数组buffTEMP,并与底盘建立socketUDP通信。
这个地方pl程序既充当socket的客户端,也充当socket的服务端,ret为一个标志位用来判断是否接收到底盘发过来的数据。-1代表发送失败,0表示发送超时,其他值时说明发送成功,用recvfrom函数将数据存储到buffTEMP中,最后通过线程锁又传给了g_temp_NAV_info.pRecvBuff中。
5.WRC_UDPPROC处理线程:
这个线程用于将传过来的数据进行处理。将NAV(导航)、DRIVE(驱动)、STATE(状态)三者的数据经过一系列的传输,最终传到了pParam中。
6.pl_thread线程:
将保存在gps_load.txt中人工采集的路径点,包括经纬度、速度、转向角传输到g_pMoRoadToPL中,并统计point_num。
第一步:创建g_pMoRoadToPL结构体,并进行初始化
memset(&g_pMoRoadToPL,0,sizeof(WRC_MO_Road_To_PL));
第二步:读取gps_load.txt中保存的经纬度、速度、转向角信息,用mystring这个数组来接受。用lat_s、lon_s、sp_s来分别接受相应位置的经纬度、速度。最后传递给了结构体g_pMoRoadToPL.GPSPointQueue[point_num]中。
7.PL_ProcThread线程:
这个线程是整个寻迹的核心。寻迹的两大关键点(寻找最小路径点和寻找目标点)。
第一步:创建结构体g_PLResultToMC并初始化。
memset(&g_PLResultToMC,0,sizeof(WRC_PL_TO_MC));
第二步:定义了两个求最小路径点和目标点的函数,分别为Road_Planning_Find_Nearest_Point和Road_Planning_Find_Aim_Point。
road_pos = Road_Planning_Find_Nearest_Point(des_pos-5,pParam->g_NavInfo,g_pMoRoadToPL.GPSPointQueue);
des_pos = Road_Planning_Find_Aim_Point(road_pos,5,pParam->g_NavInfo,g_pMoRoadToPL.GPSPointQueue);
首先是求最小路径点的函数:
输入进来的的参数分别指:起始点下标、车辆的实时位置经纬度(一个点)、人工采集的路径点经纬度(所有)。
先求出实时无人车位置坐标与人工采集的第一个点求距离得到(pre_distance),然后从第二个点开始向后遍历人工采集的全部的点,分别求他们的距离(得出aft_distance),然后经过大小比对的算法,最终求得离无人车位置最近的一个人工路径点。并将这个最小路径点的下标进行返回,给到road_pos。这样就找到了最近的路径点。
接着是寻找目标点的函数:
输入的参数分别指:起始点的下标、到达目标点的个数(从起始点向前第5个点的位置设为目标点)、车辆的实时位置经纬度(一个点)、人工采集的路径点经纬度(所有)。
首先定义两个double类型的x_diff、y_diff,表示车辆要到目标点所需要转动的角度(x轴、y轴)。如果起始点加上dest_num没到达采集路径点最后一个点,就让dest_index = start_index+dest_num,寻找到了目标点。如果不满足时,起始点加上dest_num大于最后一个点的下标,就将目标点设为最后一个点的下标。
然后车辆需要想目标点进行行驶。需要求的x_diff、y_diff,用到ntzx_GPS_posit这个函数,来计算得到。最后也得到了des_pos目标点下标。
在寻找到第一个目标点之后,接着寻找第二个目标点。。。。。直到最后。当寻找到最后一个目标点时,赋g_PLResultToMC中的速度为零停车。当不是最后一个点时,就继续赋给结构体g_PLResultToMC(x,y角度和速度)。
8.ThreadToMC线程:
创建了一个PLResultToMC_temp的结构体,并将上述步骤中得到的(x,y)和速度信息传输给这个结构体。
9.RecvFromPL_pthread线程:
回到底盘代码中,首先建立底盘和pl的udp通信,接着将pl那边的数据(包括(x,y)轴的信息、速度信息),最终保存在了gWRC_PL_TO_MC中。
10 Process_thread线程跳转到direction_control、speed_control控制,对方向和速度做优化的处理。
11 最后通过CAN_send.cpp将底盘最终的速度等信息给can的frame.data中,让车动起来。



