// // Created by YY on 2019/10/21. // Units note: distance - metre // speed - metre per second // angle - DEGREES // #include #include #include #include #include #include #include "driver_test.h" #include "defs.h" #include "Geometry.h" #include "common/apptimer.h" #include "jni_log.h" #include "test_items/park_edge.h" #include "native-lib.h" #include "test_items/park_bottom.h" #include "test_items/park_edge.h" #include "test_items/error_list.h" #include "test_items/turn_a90.h" #include "test_items/driving_curve.h" #include "test_items/stop_and_start.h" #include "master/comm_if.h" #include "utils/xconvert.h" #define DEBUG(fmt, args...) LOGD(" <%s>: " fmt, __func__, ##args) using namespace std; #define MAP_TYPE_PARK_BUTTOM 1 #define MAP_TYPE_STOP_START 2 #define MAP_TYPE_PART_EDGE 3 #define MAP_TYPE_CURVE 4 #define MAP_TYPE_TURN_90 5 #define RTK_INVALID 0 #define RTK_SINGLE_POINT 1 #define RTK_DIFF 2 #define RTK_FIX 3 #define RTK_FLOAT 4 #define CAR_MODEL_POINT_NUM 32 #define MAP_LIST_SIZE 32 enum { TEST_NONE, TEST_PARK_EDGE, TEST_PARK_BOTTOM, TEST_TUNE_90, TEST_S_CURVE, TEST_SLOPE, TEST_SIMPLE, TEST_END }; static bool TestStart = false; static int CarInArea = 0; int errs = 0; vector ErrorList; vector ExamFaultList; static int examFaultIndex = 0; static struct map_list { int id; int type; Polygon map; Polygon map2; } MapList[MAP_LIST_SIZE]; static int MapNum = 0; static int CurrExamMapId = -1; static int CurrExamStatus = 0; // 1 测试完成 0 测试中 -1 测试错误退出 static car_model *CarModel = NULL; static car_model *CarModelPrev = NULL; #define MOV_AVG_SIZE 1 #define RTK_BUFFER_SIZE 100 #define CAR_MODEL_CACHE_SIZE 10 static rtk_info *RtkBuffer = NULL; static int RtkBufferNum = 0, RtkBufferIn = 0; static uint32_t CalcTimeDiff(const rtk_info *a, const rtk_info *b); static void ReadDriverExamPrimerTimeout(union sigval sig); static void UpdateCarBodyCoord(double azimuth, PointF main_ant, car_model *carModel); static bool UpdateCarCoord(double &spd, int &mov, int &idx); static bool FrontTireEnterArea(const Polygon *car, const Polygon *map); static int EnterMap(const car_model *car, const struct map_list *mapList, int mapNum); static bool ExitMap(const car_model *car, int mapId, const struct map_list *mapList, int mapNum); static int GetMapType(int id, const struct map_list *mapList, int mapNum); void DriverTestInit(void) { TestStart = false; memset(&MapList, 0, sizeof(MapList)); MapNum = 0; CarModel = NULL; CarModelPrev = NULL; RtkBuffer = (rtk_info *) malloc(RTK_BUFFER_SIZE * sizeof(rtk_info)); RtkBufferNum = RtkBufferIn = 0; } static void ReadDriverExamPrimerTimeout(union sigval sig) { AppTimer_delete(ReadDriverExamPrimerTimeout); AppTimer_add(ReadDriverExamPrimerTimeout, D_SEC(2)); ReadDriverExamPrimer(); } void ReadDriverExamPrimer(void) { MA_ReadMap(); MA_ReadCar(); MA_ReadSensor(); } void ClearMap(void) { if (TestStart) return; for (int i = 0; i < MapNum; ++i) { if (MapList[i].map.point != NULL) free(MapList[i].map.point); if (MapList[i].map2.point != NULL) free(MapList[i].map2.point); } memset(&MapList, 0, sizeof(MapList)); MapNum = 0; } void AddMap(int id, int type, const double (*map)[2], int pointNum, const double (*map2)[2], int pointNum2) { DEBUG("加入地图信息 id %d type %d pointNum %d point2Num %d", id, type, pointNum, pointNum2); AppTimer_delete(ReadDriverExamPrimerTimeout); if (map == NULL || pointNum == 0 || TestStart) return; MapList[MapNum].id = id; MapList[MapNum].type = type; MapList[MapNum].map.num = pointNum; if (pointNum > 0) { MapList[MapNum].map.point = (PointF *)malloc(sizeof(PointF) * pointNum); for (int i = 0; i < pointNum; ++i) { MapList[MapNum].map.point[i].X = map[i][0]; MapList[MapNum].map.point[i].Y = map[i][1]; } } MapList[MapNum].map2.num = pointNum2; if (pointNum2 > 0 && map2 != NULL) { MapList[MapNum].map2.point = (PointF *)malloc(sizeof(PointF) * pointNum2); for (int i = 0; i < pointNum2; ++i) { MapList[MapNum].map2.point[i].X = map2[i][0]; MapList[MapNum].map2.point[i].Y = map2[i][1]; } } MapNum++; DEBUG("AddMap num %d", MapNum); } void SetCarMeasurePoint(double *basePoint, int *axial, int *left_front_tire, int *right_front_tire, int *left_rear_tire, int *right_rear_tire, int *body, int bodyNum,double (*point)[2], int pointNum) { DEBUG("加入车辆信息 pointNum %d", pointNum); if (point == NULL || pointNum == 0 || TestStart) return; if (CarModel != NULL) { if (CarModel->body != NULL) free(CarModel->body); if (CarModel->carDesc != NULL) free(CarModel->carDesc); if (CarModel->carXY != NULL) free(CarModel->carXY); free(CarModel); CarModel = NULL; } if (CarModelPrev != NULL) { if (CarModelPrev->body != NULL) free(CarModelPrev->body); if (CarModelPrev->carDesc != NULL) free(CarModelPrev->carDesc); if (CarModelPrev->carXY != NULL) free(CarModelPrev->carXY); free(CarModelPrev); CarModelPrev = NULL; } CarModelPrev = (car_model *)malloc(sizeof(car_model)); CarModelPrev->body = NULL; CarModelPrev->carDesc = NULL; CarModelPrev->pointNum = 0; CarModelPrev->carXY = (PointF *) malloc(sizeof(PointF) * pointNum); CarModel = (car_model *)malloc(sizeof(car_model)); CarModel->basePoint.X = basePoint[0]; CarModel->basePoint.Y = basePoint[1]; CarModel->axial[0] = axial[0]; CarModel->axial[1] = axial[1]; CarModel->left_front_tire[0] = left_front_tire[0]; CarModel->left_front_tire[1] = left_front_tire[1]; CarModel->right_front_tire[0] = right_front_tire[0]; CarModel->right_front_tire[1] = right_front_tire[1]; CarModel->left_rear_tire[0] = left_rear_tire[0]; CarModel->left_rear_tire[1] = left_rear_tire[1]; CarModel->right_rear_tire[0] = right_rear_tire[0]; CarModel->right_rear_tire[1] = right_rear_tire[1]; CarModel->bodyNum = bodyNum; if (bodyNum == 0 || body == NULL) { CarModel->bodyNum = 6; CarModel->body = (int *) malloc(sizeof(int) * 6); for (int i = 0; i < 6; ++i) { CarModel->body[i] = i; } } else { CarModel->body = (int *) malloc(sizeof(int) * CarModel->bodyNum); for (int i = 0; i < CarModel->bodyNum; ++i) { CarModel->body[i] = body[i]; } } CarModel->pointNum = pointNum; CarModel->carDesc = (struct car_desc_ *)malloc(sizeof(struct car_desc_) * pointNum); CarModel->carXY = (PointF *) malloc(sizeof(PointF) * pointNum); // 测量坐标转换为距离-角度形式 double C02 = (point[0][0]-basePoint[0])*(point[0][0]-basePoint[0]) + (point[0][1]-basePoint[1])*(point[0][1]-basePoint[1]); double C0 = sqrt(C02); CarModel->carDesc[0].distance = sqrt(C02); CarModel->carDesc[0].angle = 0.0; for (int i = 1; i < pointNum; ++i) { double dis2 = (point[i][0]-basePoint[0])*(point[i][0]-basePoint[0]) + (point[i][1]-basePoint[1])*(point[i][1]-basePoint[1]); double dis = sqrt(dis2); CarModel->carDesc[i].distance = dis; CarModel->carDesc[i].angle = 180 * acos((dis2 + C02 - ((point[i][0]-point[0][0])*(point[i][0]-point[0][0]) + (point[i][1]-point[0][1])*(point[i][1]-point[0][1])))/(2*C0*dis)) / M_PI; if (i > axial[1]) CarModel->carDesc[i].angle = 360.0 - CarModel->carDesc[i].angle; DEBUG("加入点<%d> 距离 %f 角度 %f", i, CarModel->carDesc[i].distance, CarModel->carDesc[i].angle); } CarModel->carDesc[0].distance = 0.2465; CarModel->carDesc[0].angle = 0; CarModel->carDesc[1].distance = 0.2635; CarModel->carDesc[1].angle = 20.7; CarModel->carDesc[2].distance = 0.14; CarModel->carDesc[2].angle = 138.9; CarModel->carDesc[3].distance = 0.1055; CarModel->carDesc[3].angle = 180.0; CarModel->carDesc[4].distance = 0.14; CarModel->carDesc[4].angle = 221.1; CarModel->carDesc[5].distance = 0.2635; CarModel->carDesc[5].angle = 339.3; DEBUG("SetCarMeasurePoint Calc Over"); } void SetSensorCfg(int (*sensor)[2], int sensorNum) { DEBUG("SetSensorCfg sensorNum %d", sensorNum); } void StartDriverExam(int start) { bool err = false; DEBUG("StartDriverExam %d", start); if (MapNum == 0) { err = true; MA_SendExamStatus(0, -1); } if (CarModel == NULL) { err = true; MA_SendExamStatus(0, -2); } if (!err) { if (!TestStart) { ExamFaultList.clear(); examFaultIndex = 0; TestStart = true; } MA_SendExamStatus(1, 0); } } void UpdateRTKInfo(const rtk_info *s) { if (s->qf > 0) { RtkBuffer[RtkBufferIn] = *s; RtkBufferIn = (RtkBufferIn + 1) % RTK_BUFFER_SIZE; if (RtkBufferNum < RTK_BUFFER_SIZE) RtkBufferNum++; } else { return; } double speed; int move; int index; if (UpdateCarCoord(speed, move, index)) { struct carBrief brief; sprintf(brief.utc, "%04d%02d%02d%02d%02d%02d.%02d", 2000 + RtkBuffer[index].YY, RtkBuffer[index].MM, RtkBuffer[index].DD, RtkBuffer[index].hh, RtkBuffer[index].mm, RtkBuffer[index].ss, RtkBuffer[index].dss); brief.qf = RtkBuffer[index].qf; brief.map_id = 863;//CurrExamMapId; brief.move = move; brief.speed = speed * 3.6; brief.heading = RtkBuffer[index].heading; brief.main_ant[0] = RtkBuffer[index].x; brief.main_ant[1] = RtkBuffer[index].y; brief.axial[0] = CarModel->axial[0]; brief.axial[1] = CarModel->axial[1]; brief.left_front_tire[0] = CarModel->left_front_tire[0]; brief.left_front_tire[1] = CarModel->left_front_tire[1]; brief.right_front_tire[0] = CarModel->right_front_tire[0]; brief.right_front_tire[1] = CarModel->right_front_tire[1]; brief.left_rear_tire[0] = CarModel->left_rear_tire[0]; brief.left_rear_tire[1] = CarModel->left_rear_tire[1]; brief.right_rear_tire[0] = CarModel->right_rear_tire[0]; brief.right_rear_tire[1] = CarModel->right_rear_tire[1]; brief.bodyNum = CarModel->bodyNum; brief.body = (int *) malloc(sizeof(int) * CarModel->bodyNum); for (int i = 0; i < CarModel->bodyNum; ++i) { brief.body[i] = CarModel->body[i]; } brief.pointNum = CarModel->pointNum; brief.point = (double *) malloc(CarModel->pointNum * 2 * sizeof(double)); for (int i = 0, j = 0; i < CarModel->pointNum; ++i) { brief.point[j++] = CarModel->carXY[i].X; brief.point[j++] = CarModel->carXY[i].Y; } MA_SendCarPosition(&brief); free(brief.body); free(brief.point); if (TestStart) { if (CurrExamMapId < 0) { CurrExamMapId = EnterMap(CarModel, MapList, MapNum); int mtype = GetMapType(CurrExamMapId, MapList, MapNum); DEBUG("CurrExamMapId %d mtype %d", CurrExamMapId, mtype); switch (mtype) { case MAP_TYPE_PARK_BUTTOM: DEBUG("进入倒车入库场地"); MA_SendDebugInfo("进入倒车入库场地 %d", CurrExamMapId); StartParkBottom(); CurrExamStatus = 0; break; case MAP_TYPE_STOP_START: break; case MAP_TYPE_PART_EDGE: break; case MAP_TYPE_CURVE: break; case MAP_TYPE_TURN_90: break; default:break; } } } struct RtkTime rtkTime; rtkTime.YY = RtkBuffer[index].YY; rtkTime.MM = RtkBuffer[index].MM; rtkTime.DD = RtkBuffer[index].DD; rtkTime.hh = RtkBuffer[index].hh; rtkTime.mm = RtkBuffer[index].mm; rtkTime.ss = RtkBuffer[index].ss; rtkTime.mss = RtkBuffer[index].dss; if (CurrExamMapId >= 0) { if (CurrExamStatus == 0) { int mtype = GetMapType(CurrExamMapId, MapList, MapNum); switch (mtype) { case MAP_TYPE_PARK_BUTTOM: CurrExamStatus = TestParkBottom(ErrorList, &MapList[CurrExamMapId].map, CarModel, CarModelPrev, speed, move, &rtkTime); break; case MAP_TYPE_STOP_START: break; case MAP_TYPE_PART_EDGE: break; case MAP_TYPE_CURVE: break; case MAP_TYPE_TURN_90: break; default: break; } } if (CurrExamStatus != 0) { if (ExitMap(CarModel, CurrExamMapId, MapList, MapNum)) { DEBUG("退出场地 %d", CurrExamMapId); MA_SendDebugInfo("退出场地 %d", CurrExamMapId); CurrExamMapId = -1; } } } } } /************************************************* * 2次采样相差的时间 * @param a * @param b * @return ms */ static uint32_t CalcTimeDiff(const rtk_info *a, const rtk_info *b) { return ABS(TimeMakeComposite(2000 + a->YY, a->MM, a->DD, a->hh, a->mm, a->ss) * 1000 + a->dss*10 - (TimeMakeComposite(2000 + b->YY, b->MM, b->DD, b->hh, b->mm, b->ss) * 1000 + b->dss*10)); } static bool UpdateCarCoord(double &spd, int &mov, int &idx) { if (CarModel == NULL) return false; if (RtkBufferNum < 3) return false; int p1 = ((RtkBufferIn-1)+RTK_BUFFER_SIZE)%RTK_BUFFER_SIZE; int p2 = ((RtkBufferIn-2)+RTK_BUFFER_SIZE)%RTK_BUFFER_SIZE; int p3 = ((RtkBufferIn-3)+RTK_BUFFER_SIZE)%RTK_BUFFER_SIZE; // 如果一定的时间都没有有效定位,删除之前的值 uint32_t tmDiff = CalcTimeDiff(&RtkBuffer[p1], &RtkBuffer[p2]); DEBUG("tmDiff = %ld, p1 = %d p2 = %d dss = %d dss2 = %d", tmDiff, p1, p2, RtkBuffer[p1].dss, RtkBuffer[p2].dss); if (tmDiff > D_SEC(5)) { if (p1 != 0) RtkBuffer[0] = RtkBuffer[p1]; RtkBufferIn = RtkBufferNum = 1; return false; } // 计算车辆轮廓点 PointF main_ant_coord; main_ant_coord.X = RtkBuffer[p1].x; main_ant_coord.Y = RtkBuffer[p1].y; // 保存上一个车身轮廓点 if (CarModelPrev->pointNum > 0) { CarModelPrev->pointNum = CarModel->pointNum; CarModelPrev->basePoint = CarModel->basePoint; for (int i = 0; i < CarModel->pointNum; ++i) { CarModelPrev->carXY[i] = CarModel->carXY[i]; } } UpdateCarBodyCoord(RtkBuffer[p1].heading, main_ant_coord, CarModel); if (CarModelPrev->pointNum == 0) { CarModelPrev->pointNum = CarModel->pointNum; CarModelPrev->basePoint = CarModel->basePoint; for (int i = 0; i < CarModel->pointNum; ++i) { CarModelPrev->carXY[i] = CarModel->carXY[i]; } } // 计算速度(米/秒)、前进后退 double speed = sqrt(pow(RtkBuffer[p1].x - RtkBuffer[p2].x, 2) + pow(RtkBuffer[p1].y - RtkBuffer[p2].y, 2)) * 1000 / (double)(tmDiff); int move = 0; double deg = 0.0; if (speed < 0.05) { // 停车 move = 0; } else { // 判断前进还是后退 if (fabs(RtkBuffer[p1].y - RtkBuffer[p2].y) <= GLB_EPSILON) { if (RtkBuffer[p1].x > RtkBuffer[p2].x) { deg = 90; } else { deg = 270; } } else if (fabs(RtkBuffer[p1].x - RtkBuffer[p2].x) <= GLB_EPSILON) { if (RtkBuffer[p1].y > RtkBuffer[p2].y) { deg = 0; } else { deg = 180; } } else { deg = atan(fabs(RtkBuffer[p1].x - RtkBuffer[p2].x) / fabs(RtkBuffer[p1].y - RtkBuffer[p2].y)); deg = toDegree(deg); if (RtkBuffer[p1].x > RtkBuffer[p2].x && RtkBuffer[p1].y > RtkBuffer[p2].y) { } else if (RtkBuffer[p1].x < RtkBuffer[p2].x && RtkBuffer[p1].y > RtkBuffer[p2].y) { deg = 360 - deg; } else if (RtkBuffer[p1].x < RtkBuffer[p2].x && RtkBuffer[p1].y < RtkBuffer[p2].y) { deg = 180 + deg; } else if (RtkBuffer[p1].x > RtkBuffer[p2].x && RtkBuffer[p1].y < RtkBuffer[p2].y) { deg = 180 - deg; } } deg = fabs(RtkBuffer[p1].heading - deg); if (deg > 180) { deg = 360 - deg; } if (deg < 90) { // 前进 move = 1; } else { // 后退 move = -1; } } spd = speed; mov = move; idx = p1; DEBUG("speed = %f m/Sec move = %d", speed, move); return true; /* if (!TestStart) return; if (CarInArea == 0) { // if (FrontTireEnterArea(&py, &theParkEdgeMap)) { // CarInArea = TEST_PARK_BOTTOM; // TestItem = TEST_PARK_BOTTOM; // StartParkBottom(); // } CarInArea = TEST_SLOPE; TestItem = TEST_SLOPE; StartSAS(); } switch (TestItem) { case TEST_NONE: { break; } case TEST_PARK_BOTTOM: { errs = TestParkBottom(ErrorList, &theParkEdgeMap, GetCarModelCache(0), currSpeed, currDirect); if (errs != 0) { StopParkBottom(); TestItem = TEST_NONE; } break; } case TEST_PARK_EDGE: { errs = TestParkEdge(ErrorList, &theParkEdgeMap, GetCarModelCache(0), currSpeed, currDirect); if (errs != 0) { StopParkEdge(); TestItem = TEST_NONE; } break; } case TEST_TUNE_90: { errs = TestTurnA90(ErrorList, &theTurn90Map, GetCarModelCache(0), currSpeed, currDirect, currAzimuth); if (errs != 0) { StopTurnA90(); TestItem = TEST_NONE; } break; } case TEST_SLOPE: { errs = TestSAS(ErrorList, &theSSMap, GetCarModelCache(0), currSpeed, currDirect); if (errs != 0) { StopSAS(); TestItem = TEST_NONE; } break; } default: break; } if (ErrorList.size() > 0) { vector::iterator it = ErrorList.end(); it--; error_list_t list = GetErrorList(*it); int scr = 0; for (vector::iterator it1 = ErrorList.begin(); it1 != ErrorList.end(); ++it1) { error_list_t list = GetErrorList(*it1); scr += list.dec_score; } char buff[256]; sprintf(buff, "%s, 总计扣分 %d", list.text_desc, scr); TextOsd(1, buff); }*/ } static int EnterMap(const car_model *car, const struct map_list *mapList, int mapNum) { // 车的最前点是否进入地图 for (int i = 0; i < mapNum && car != NULL; ++i) { if (mapList[i].type == MAP_TYPE_STOP_START) { } else if (mapList[i].type == MAP_TYPE_CURVE) { } else if (mapList[i].type == MAP_TYPE_PARK_BUTTOM) { if (IntersectionOf(car->carXY[ car->axial[AXIAL_FRONT] ], &mapList[i].map) == GM_Containment) { Line enterLine1, enterLine2; MakeLine(&enterLine1, &(mapList[i].map.point[0]), &(mapList[i].map.point[1])); MakeLine(&enterLine2, &(mapList[i].map.point[6]), &(mapList[i].map.point[7])); if (DistanceOf(car->carXY[car->axial[AXIAL_FRONT]], enterLine1) > 0.1 && DistanceOf(car->carXY[car->axial[AXIAL_FRONT]], enterLine2) > 0.1) return mapList[i].id; } } } return -1; } static bool ExitMap(const car_model *car, int mapId, const struct map_list *mapList, int mapNum) { // 车的最后点是否进入地图 for (int i = 0; i < mapNum && car != NULL; ++i) { if (mapList[i].id == mapId) { if (mapList[i].type == MAP_TYPE_PARK_BUTTOM) { if (IntersectionOf(car->carXY[ car->axial[AXIAL_REAR] ], &mapList[i].map) == GM_None) { Line enterLine1, enterLine2; MakeLine(&enterLine1, &(mapList[i].map.point[0]), &(mapList[i].map.point[1])); MakeLine(&enterLine2, &(mapList[i].map.point[6]), &(mapList[i].map.point[7])); if (DistanceOf(car->carXY[car->axial[AXIAL_REAR]], enterLine1) > 0.1 && DistanceOf(car->carXY[car->axial[AXIAL_REAR]], enterLine2) > 0.1) return true; } } return false; } } return true; } static int GetMapType(int id, const struct map_list *mapList, int mapNum) { for (int i = 0; i < mapNum && id >= 0; ++i) { if (mapList[i].id == id) return mapList[i].type; } return -1; } void AddExamFault(int wrong, const struct RtkTime *rtkTime) { struct ExamFault fault; fault.sn = examFaultIndex++; sprintf(fault.utc, "%04d%02d%02d%02d%02d%02d.%02d", 2000 + rtkTime->YY, rtkTime->MM, rtkTime->DD, rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss); fault.wrong_id = wrong; DEBUG("考试发生错误 %d %s", wrong, fault.utc); ExamFaultList.push_back(fault); MA_SendExamWrong(ExamFaultList); ExamFaultList.clear(); } car_model_cache_t *GetCarModelCache(int node) { return NULL; } /******************************************************************* * @brief 由主天线坐标计算车身点坐标 * @param azimuth * @param coord */ static void UpdateCarBodyCoord(double azimuth, PointF main_ant, car_model *carModel) { carModel->basePoint = main_ant; for (int i = 0; i < carModel->pointNum; ++i) { double tx = main_ant.X + carModel->carDesc[i].distance*sin(toRadians(azimuth)); double ty = main_ant.Y + carModel->carDesc[i].distance*cos(toRadians(azimuth)); carModel->carXY[i].X = (tx-main_ant.X)*cos(toRadians(carModel->carDesc[i].angle)) - (ty-main_ant.Y)*sin(toRadians(carModel->carDesc[i].angle)) + main_ant.X; carModel->carXY[i].Y = (tx-main_ant.X)*sin(toRadians(carModel->carDesc[i].angle)) + (ty-main_ant.Y)*cos(toRadians(carModel->carDesc[i].angle)) + main_ant.Y; } } static bool FrontTireEnterArea(const Polygon *car, const Polygon *map) { if (IntersectionOf(car->point[0], map) == GM_Containment) { return true; } return false; }