// // Created by YY on 2019/10/23. // // // 0 ____________________________________7 // // // 1 _____________2 5_________________6 // 8| |9 // | | // | | // | | // 3--------4 // #include "park_bottom.h" #include "../common/apptimer.h" #include "../test_common/Geometry.h" #include "../native-lib.h" #include "../jni_log.h" #include "../driver_test.h" #include "../utils/xconvert.h" #include "../master/comm_if.h" #include "area_exam.h" #include "../test_common/car_sensor.h" #include "../test_common/odo_graph.h" #include #include #define DEBUG(fmt, args...) LOGD(" <%s>: " fmt, __func__, ##args) using namespace std; enum { NONE, FIRST_TOUCH_CTRL_LINE, FIRST_PARK, SECOND_TOUCH_CTRL_LINE, SECOND_PARK, THIRD_TOUCH_CTRL_LINE }; enum { TESTING, TEST_FAIL, // 因触发某些规则,在车身未完全立场情况下,提前终止部分测试 TEST_FINISH }; typedef enum { NONE_CTRL_LINE, LEFT_CTRL_LINE, RIGHT_CTRL_LINE } ctrl_line_t; static bool reverseCar = false; const uint32_t CHECK_PARK_DELAY = 400; static uint32_t stopTimepoint; static int prevMoveDirect; static bool occurCrashRedLine; static uint32_t firstReverseTimepoint; static int parkCount; static char carray[3]; static int darray[3]; static int parkStatus[3]; static int gearAtStop; static int currGear; static ctrl_line_t prevCrossedCtrlLine; static double odo; static ctrl_line_t CrossCtrlLine(prime_t &prime); static bool EnterParking(prime_t &prime); static bool CrashRedLine(prime_t &prime); void StartParkBottom(prime_t &prime) { DEBUG("StartParkBottom"); reverseCar = false; memset(carray, 0, sizeof(carray)); memset(darray, 0, sizeof(darray)); memset(parkStatus, 0, sizeof(parkStatus)); prevMoveDirect = prime.pMotion->move; firstReverseTimepoint = 0; parkCount = 0; occurCrashRedLine = false; currGear = ReadCarStatus(GEAR); prevCrossedCtrlLine = NONE_CTRL_LINE; stopTimepoint = 0; odo = ReadOdo(); PlayTTS("您已进入倒车入库区域", NULL); } void TestParkBottom(prime_t &prime) { ctrl_line_t crossCtrlLine = NONE_CTRL_LINE; uint32_t tp = AppTimer_GetTickCount(); vector dtox; vector line_set; Line distance_line; bool gear_change = false; int gear = ReadCarStatus(GEAR); if (gear == GEAR_R) { if (currGear != GEAR_R) { gear_change = true; currGear = GEAR_R; } } else if (currGear == GEAR_R) { gear_change = true; currGear = gear; } if (gear_change) { // 检查上一次挡位的行驶距离,过小就放弃,避开学员原地挂挡重试 double run_distance = ReadOdo() - odo; DEBUG("2次挡位运行距离 %f", run_distance); if (run_distance < 1) { gear_change = false; DEBUG("2次挡位运行距离过小,忽略"); } odo = ReadOdo(); } if (gear_change) { if (currGear == GEAR_R) { // 挂倒挡,检测是否过控制线 DEBUG("开始挂倒挡"); if (!reverseCar) { DEBUG("开始首轮入库"); reverseCar = true; MA_EnterMap(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].id, MAP_TYPE_PARK_BUTTOM, 1); firstReverseTimepoint = tp; // 开始210秒计时 } crossCtrlLine = CrossCtrlLine(prime); if (parkCount >= 2) { DEBUG("开始次轮入库"); parkCount = 0; MA_EnterMap(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].id, MAP_TYPE_PARK_BUTTOM, 1); firstReverseTimepoint = tp; // 开始210秒计时 } if (crossCtrlLine == NONE_CTRL_LINE) { // 倒车前,前轮未驶过控制线 AddExamFault(20104); DEBUG("倒车前,前轮未驶过控制线"); } else if (crossCtrlLine == prevCrossedCtrlLine) { // 重复跨越同一控制线,不按规定线路,顺序形式,不合格 AddExamFault(20101); DEBUG("不按规定线路,顺序形式, 同 %c 侧", prevCrossedCtrlLine); } else { prevCrossedCtrlLine = crossCtrlLine; DEBUG("开始 %c 侧 倒库", prevCrossedCtrlLine); } } else { // 从倒挡移出,检测是否入库 DEBUG("从倒挡移出"); parkCount++; DEBUG("库位检查次数 = %d", parkCount); if (EnterParking(prime)) { DEBUG("倒库成功"); } else { AddExamFault(20103); DEBUG("倒库不入"); } } } if (ExitParkArea(prime)) { // 离开场地 DEBUG("离开场地"); if (parkCount < 2) { AddExamFault(10103); DEBUG("直接驶离测试区,不按考试员指令驾驶"); } prime.curr_exam_map.type = 0; goto TEST_END; } if (BodyCollidingLine(prime) >= 0) { if (!occurCrashRedLine) { occurCrashRedLine = true; // 车身出线,不合格 AddExamFault(10116); DEBUG("车身出线"); } } else { occurCrashRedLine = false; } if (prime.pMotion->move != prevMoveDirect) { if (prime.pMotion->move == STOP) { stopTimepoint = tp; gearAtStop = (currGear == GEAR_R ? 1 : 0); DEBUG("停车了"); DEBUG("停车时挡位 = %d", gearAtStop); } else if (prevMoveDirect == STOP && stopTimepoint > 0) { DEBUG("继续行驶"); DEBUG("停车时间 %ld", tp - stopTimepoint); DEBUG("再次移动时挡位 = %d", currGear == GEAR_R ? 1 : 0); if (tp - stopTimepoint >= CorrectPauseCriteria(examParam.park_bottom_pause_criteria) && gearAtStop == (currGear == GEAR_R ? 1 : 0)) { // 停车超2秒,每次扣5分 AddExamFault(20106); DEBUG("中途停车"); } } prevMoveDirect = prime.pMotion->move; } TEST_END: DEBUG("倒库结束"); MA_EnterMap(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].id, MAP_TYPE_PARK_BUTTOM, 0); } static int BodyCollidingLine(prime_t &prime) { vector lines; Polygon car_body; car_body.num = prime.pModel->body.size(); car_body.point = new PointF[car_body.num]; for (int i = 0; i < car_body.num; ++i) { car_body.point[i] = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->body[i]]; } Line line; MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[0], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[7]); lines.push_back(line); MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[1], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[2]); lines.push_back(line); MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[2], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[3]); lines.push_back(line); MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[3], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[4]); lines.push_back(line); MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[4], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[5]); lines.push_back(line); MAKE_LINE(line, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[5], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[6]); lines.push_back(line); int idx = 0; for (auto line: lines) { if (IntersectionOf(line, &car_body) != GM_None) { break; } idx++; } delete []car_body.point; return idx < lines.size()? idx : -1; } // 检测2前轮是否正向越过左右控制线 static ctrl_line_t CrossCtrlLine(prime_t &prime) { // 过右控制线 Line left_trace, right_trace; Line left_ctrl, right_ctrl; MAKE_LINE(left_trace, prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]], prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_rear_tire[TIRE_OUTSIDE]]); MAKE_LINE(right_trace, prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]], prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_rear_tire[TIRE_OUTSIDE]]); MAKE_LINE(left_ctrl, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[1], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[0]); MAKE_LINE(right_ctrl, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[6], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[7]); if (IntersectionOf(left_trace, left_ctrl) == GM_Intersection && IntersectionOf(right_trace, left_ctrl) == GM_Intersection && IntersectionOfLine(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]], left_ctrl) == RELATION_LEFT) { return LEFT_CTRL_LINE; } if (IntersectionOf(left_trace, right_ctrl) == GM_Intersection && IntersectionOf(right_trace, right_ctrl) == GM_Intersection && IntersectionOfLine(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]], right_ctrl) == RELATION_RIGHT) { return RIGHT_CTRL_LINE; } return NONE_CTRL_LINE; } // 需要库入口线宽计算在内 static bool EnterParking(prime_t &prime) { bool succ = false; Polygon park_area; Polygon car_body; car_body.num = prime.pModel->body.size(); car_body.point = new PointF[car_body.num]; for (int i = 0; i < car_body.num; ++i) { car_body.point[i] = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->body[i]]; } PointF p8 = PointExtend(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[2], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].line_width, YawOf(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[2], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[3])); PointF p9 = PointExtend(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[5], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].line_width, YawOf(prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[5], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[4])); MakePolygon(&park_area, {p8, prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[3], prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[4], p9}); if (IntersectionOf(&car_body, &park_area) == GM_Containment) { succ = true; } CleanPolygon(&park_area); free(car_body.point); DEBUG("检查倒库状态 %s", succ ? "成功" : "失败"); return succ; } // 4个车轮和车头点不在场地中 bool ExitParkArea(prime_t &prime) { Polygon polygon; polygon.num = prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map.size(); polygon.point = new PointF[polygon.num]; for (int i = 0; i < polygon.num; ++i) { polygon.point[i] = prime.pMap->park_button_map[prime.curr_exam_map.map_idx].map[i]; } int num = 0; if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]], &polygon) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]], &polygon) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_rear_tire[TIRE_OUTSIDE]], &polygon) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_rear_tire[TIRE_OUTSIDE]], &polygon) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->body[prime.pModel->axial[AXIAL_FRONT]]], &polygon) == GM_None) { num++; } delete []polygon.point; return num == 5? true : false; }