// // Created by YY on 2020/4/3. // #include #include #include #include "area_exam.h" #include "../test_common/car_sensor.h" #include "../driver_test.h" #include "../jni_log.h" #include "park_bottom.h" #include "uphill.h" #include "park_edge.h" #include "driving_curve.h" #include "right_corner.h" #include "../utils/xconvert.h" #include "../common/apptimer.h" #include "../test_common/odo_graph.h" #include "../test_common/Geometry.h" #include "../common/observer.h" #include "../native-lib.h" #define DEBUG(fmt, args...) LOGD(" <%s>: " fmt, __func__, ##args) enum class ProximityStatus { Near, Bounce, Far }; ilovers::Observer> CarMoveEvent; ilovers::Observer> ShiftEvent; static void CheckProximity(prime_t &prime, Line &base_line, Line &line, int this_id); static bool CrossingStartLine(Line &trace, Line &start_line); static void ProximityReminders(prime_t &prime); static void DetectCarMove(prime_t &prime); static void DetectShift(prime_t &prime); static void EnterMap(prime_t &prime); static void ExitMap(prime_t &prime); void AreaExam(prime_t &prime) { if (prime.prev_modeling_index == -1 || prime.curr_modeling_index == -1) { return; } DEBUG("--------------> %d", __LINE__); DetectShift(prime); DEBUG("--------------> %d", __LINE__); DetectCarMove(prime); DEBUG("--------------> %d", __LINE__); ProximityReminders(prime); DEBUG("--------------> %d", __LINE__); EnterMap(prime); DEBUG("--------------> %d", __LINE__); TestDrivingCurve(prime); DEBUG("--------------> %d", __LINE__); TestParkBottom(prime); DEBUG("--------------> %d", __LINE__); TestParkEdge(prime); DEBUG("--------------> %d", __LINE__); TestUphill(prime); DEBUG("--------------> %d", __LINE__); TestRightCorner(prime); DEBUG("--------------> %d", __LINE__); ExitMap(prime); DEBUG("--------------> %d", __LINE__); } // 检查换挡,如停车入库、倒车开始等动作,需要在挡位变换时检测,同时需考虑驾驶员一次换挡不进,停在原地再次操作的情况 static void DetectShift(prime_t &prime) { static int prevGear = prime.sensor.gear; static double odo = prime.odo; // 记录这个挡位下行驶的距离 if (prime.sensor.gear != prevGear) { if (prime.odo - odo > 1) { } ShiftEvent.Notify(prime.sensor.gear, prevGear, prime.odo - odo); prevGear = prime.sensor.gear; odo = prime.odo; } } static bool stopTimeout = false; static void StoppedTimeout(apptimer_var_t val) { stopTimeout = true; } // 处理各个项目的超时停车(停下时和再次启动时,挡位是一致的) static void DetectCarMove(prime_t &prime) { static double odo = prime.odo; static int gearWhenStop = GEAR_N; static move_status_t prevMove = prime.pMotion->move; if (prime.pMotion->move != prevMove) { // Notify DEBUG("行驶状态改变 %d", prime.pMotion->move); CarMoveEvent.Notify(prime.pMotion->move, prevMove, prime.odo - odo); AppTimer_delete(StoppedTimeout); if (prime.pMotion->move == STOP) { gearWhenStop = prime.sensor.gear; switch (prime.examing_area.type) { case MAP_TYPE_PARK_BUTTOM: AppTimer_add(StoppedTimeout, prime.examParam.park_bottom_pause_criteria); break; case MAP_TYPE_PARK_EDGE: AppTimer_add(StoppedTimeout, prime.examParam.park_edge_pause_criteria); break; case MAP_TYPE_RIGHT_CORNER: AppTimer_add(StoppedTimeout, prime.examParam.turn_a90_pause_criteria); break; case MAP_TYPE_CURVE: AppTimer_add(StoppedTimeout, prime.examParam.curve_pause_criteria); break; case MAP_TYPE_UPHILL: break; default:break; } } else { if (stopTimeout && ((prime.sensor.gear == GEAR_R) == (gearWhenStop == GEAR_R))) { // 停车超时 switch (prime.examing_area.type) { case MAP_TYPE_PARK_BUTTOM: // 停车超2秒,每次扣5分 AddExamFault(20106); break; case MAP_TYPE_PARK_EDGE: AddExamFault(20406); break; case MAP_TYPE_RIGHT_CORNER: AddExamFault(20703); break; case MAP_TYPE_CURVE: // 停车超2秒,不合格 AddExamFault(20602); break; case MAP_TYPE_UPHILL: break; default:break; } } } stopTimeout = false; prevMove = prime.pMotion->move; odo = prime.odo; } } int RegisterCarMoveObserver(std::function ob) { return CarMoveEvent.Connect(ob); } void UnregisterCarMoveObserver(int handle) { CarMoveEvent.Disconnect(handle); } int RegisterShiftObserver(std::function ob) { return ShiftEvent.Connect(ob); } void UnregisterShiftObserver(int handle) { ShiftEvent.Disconnect(handle); } static void EnterMap(prime_t &prime) { if (prime.examing_area.type != 0) { return; } DEBUG("--------------> %d", __LINE__); DEBUG("1. %d", prime.pModeling[prime.curr_modeling_index].points.size()); DEBUG("2. %d", prime.pModeling[prime.prev_modeling_index].points.size()); DEBUG("3. %d", prime.pModel->left_front_tire[TIRE_OUTSIDE]); DEBUG("4. %d", prime.pModel->right_front_tire[TIRE_OUTSIDE]); PointF lp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]]; PointF lp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]]; PointF rp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]]; PointF rp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]]; Line left_trace, right_trace; DEBUG("--------------> %d", __LINE__); MAKE_LINE(left_trace, lp1, lp2); MAKE_LINE(right_trace, rp1, rp2); Line start_line; DEBUG("倒库> %d", std::get(prime.maps).size()); for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[1], std::get(prime.maps)[i].points[0]); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_PARK_BUTTOM; prime.examing_area.idx = i; StartParkBottom(prime); return; } MAKE_LINE(start_line, std::get(prime.maps)[i].points[7], std::get(prime.maps)[i].points[6]); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_PARK_BUTTOM; prime.examing_area.idx = i; StartParkBottom(prime); return; } } DEBUG("侧方> %d", std::get(prime.maps).size()); for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[1], std::get(prime.maps)[i].points[0]); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_PARK_EDGE; prime.examing_area.idx = i; StartParkEdge(prime); return; } } DEBUG("上坡> %d", std::get(prime.maps).size()); for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[0], std::get(prime.maps)[i].points[10]); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_UPHILL; prime.examing_area.idx = i; StartUphill(prime); return; } } DEBUG("曲线> %d", std::get(prime.maps).size()); for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].right_start_point, std::get(prime.maps)[i].left_start_point); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_CURVE; prime.examing_area.idx = i; StartDrivingCurve(prime); return; } } DEBUG("直角> %d", std::get(prime.maps).size()); for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[0], std::get(prime.maps)[i].points[1]); if (CrossingStartLine(left_trace, start_line)) { prime.examing_area.type = MAP_TYPE_RIGHT_CORNER; prime.examing_area.idx = i; StartRightCorner(prime); return; } } } /**************************************** * 退出场地:条件是车头和四轮都不在场地中 * 如果当前测试项目未完成,要报不合格 * @param prime */ static void ExitMap(prime_t &prime) { if (prime.examing_area.type == MAP_TYPE_NONE) { return; } if (prime.examing_area.type == MAP_TYPE_CURVE) { // 车的后轮是否越过结束线或是车辆不在2个大圆范围内 PointF lp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]]; PointF lp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]]; PointF rp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]]; PointF rp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]]; Line left_trace, right_trace; MAKE_LINE(left_trace, lp1, lp2); MAKE_LINE(right_trace, rp1, rp2); Line end_line; MAKE_LINE(end_line, std::get(prime.maps)[prime.examing_area.idx].right_end_point, std::get(prime.maps)[prime.examing_area.idx].left_end_point); if (CrossingStartLine(left_trace, end_line)) { // 离开区域 StopDrivingCurve(prime); } if (DistanceOf(prime.pModeling[prime.curr_modeling_index].base_point, std::get(prime.maps)[prime.examing_area.idx].front_half_big_circle_centre) > std::get(prime.maps)[prime.examing_area.idx].front_half_big_circle_radius && DistanceOf(prime.pModeling[prime.curr_modeling_index].base_point, std::get(prime.maps)[prime.examing_area.idx].back_half_big_circle_centre) > std::get(prime.maps)[prime.examing_area.idx].back_half_big_circle_radius) { // 离开区域 StopDrivingCurve(prime); } } else { MakePolygon area({}); DEBUG("------------> %d", __LINE__); switch (prime.examing_area.type) { case MAP_TYPE_PARK_BUTTOM: area.AddPoints({std::get(prime.maps)[prime.examing_area.idx].points[0], std::get(prime.maps)[prime.examing_area.idx].points[1], std::get(prime.maps)[prime.examing_area.idx].points[2], std::get(prime.maps)[prime.examing_area.idx].points[3], std::get(prime.maps)[prime.examing_area.idx].points[4], std::get(prime.maps)[prime.examing_area.idx].points[5], std::get(prime.maps)[prime.examing_area.idx].points[6], std::get(prime.maps)[prime.examing_area.idx].points[7]}); break; case MAP_TYPE_PARK_EDGE: area.AddPoints({std::get(prime.maps)[prime.examing_area.idx].points[0], std::get(prime.maps)[prime.examing_area.idx].points[1], std::get(prime.maps)[prime.examing_area.idx].points[2], std::get(prime.maps)[prime.examing_area.idx].points[3], std::get(prime.maps)[prime.examing_area.idx].points[4], std::get(prime.maps)[prime.examing_area.idx].points[5], std::get(prime.maps)[prime.examing_area.idx].points[6], std::get(prime.maps)[prime.examing_area.idx].points[7]}); break; case MAP_TYPE_UPHILL: area.AddPoints({std::get(prime.maps)[prime.examing_area.idx].points[0], std::get(prime.maps)[prime.examing_area.idx].points[9], std::get(prime.maps)[prime.examing_area.idx].points[11], std::get(prime.maps)[prime.examing_area.idx].points[10]}); break; case MAP_TYPE_RIGHT_CORNER: area.AddPoints({std::get(prime.maps)[prime.examing_area.idx].points[0], std::get(prime.maps)[prime.examing_area.idx].points[1], std::get(prime.maps)[prime.examing_area.idx].points[2], std::get(prime.maps)[prime.examing_area.idx].points[3], std::get(prime.maps)[prime.examing_area.idx].points[4], std::get(prime.maps)[prime.examing_area.idx].points[5]}); break; default: break; } DEBUG("------------> %d", __LINE__); int num = 0; if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]], area.GetPolygon()) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]], area.GetPolygon()) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_rear_tire[TIRE_OUTSIDE]], area.GetPolygon()) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_rear_tire[TIRE_OUTSIDE]], area.GetPolygon()) == GM_None) { num++; } if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->body[prime.pModel->axial[AXIAL_FRONT]]], area.GetPolygon()) == GM_None) { num++; } DEBUG("------------> %d", __LINE__); if (num == 5) { // 离开区域 StopDrivingCurve(prime); StopParkBottom(prime); StopRightCorner(prime); StopUphill(prime); StopParkEdge(prime); } DEBUG("------------> %d", __LINE__); } } // 车轮驶过线,且车头位于右侧 static bool CrossingStartLine(Line &trace, Line &start_line) { PointF head = trace.p1; if (IntersectionOf(trace, start_line) == GM_Intersection && IntersectionOfLine(head, start_line) == REL_POS_RIGHT) { return true; } return false; } static void ProximityReminders(prime_t &prime) { if (prime.examing_area.type != MAP_TYPE_NONE) return; DEBUG("----------------> %d", __LINE__); DEBUG("test %d",std::get(prime.maps).size()); DEBUG("test %d",std::get(prime.maps)[0].points.size()); DEBUG("test %f,%f",std::get(prime.maps)[0].points[1].X, std::get(prime.maps)[0].points[1].Y); { Line test; MAKE_LINE(test, std::get(prime.maps)[0].points[1], std::get(prime.maps)[0].points[0]); DEBUG("test %f,%f - %f,%f",test.p1.X, test.p1.Y, test.p2.X, test.p2.Y); } DEBUG("----------------> %d", __LINE__); PointF car_head = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->axial[AXIAL_FRONT]]; PointF car_head_trend = PointExtend(car_head, 8, prime.pModeling->yaw); DEBUG("----------------> %d", __LINE__); Line car_head_line; MAKE_LINE(car_head_line, car_head, car_head_trend); DEBUG("----------------> %d", __LINE__); Line start_line; for (int i = 0; i < std::get(prime.maps).size(); ++i) { // 左右2条控制线都可作为入口 MAKE_LINE(start_line, std::get(prime.maps)[i].points[1], std::get(prime.maps)[i].points[0]); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); MAKE_LINE(start_line, std::get(prime.maps)[i].points[7], std::get(prime.maps)[i].points[6]); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); } for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[1], std::get(prime.maps)[i].points[0]); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); } for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[0], std::get(prime.maps)[i].points[10]); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); } for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].right_start_point, std::get(prime.maps)[i].left_start_point); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); } for (int i = 0; i < std::get(prime.maps).size(); ++i) { MAKE_LINE(start_line, std::get(prime.maps)[i].points[0], std::get(prime.maps)[i].points[1]); CheckProximity(prime, car_head_line, start_line, std::get(prime.maps)[i].id); } } // 判断是否接近场地的起始线 // 车头趋势线是否和入口线相交 static void CheckProximity(prime_t &prime, Line &base_line, Line &line, int this_id) { ProximityStatus status; if (CrossingStartLine(base_line, line)) { PointF p1 = base_line.p1; PointF p2 = base_line.p2; // 增加距离,用于消除测量误差带来的不稳定 if (DistanceOf(p1, line) > 0.5 && DistanceOf(p2, line) > 0.5) { status = ProximityStatus::Near; } else { status = ProximityStatus::Bounce; } } else { status = ProximityStatus::Far; } if (status == ProximityStatus::Near && prime.arriving_map != this_id) { prime.arriving_map = this_id; // 报语音提示 PlayTTS("即将考试", nullptr); } else if (status == ProximityStatus::Far && prime.arriving_map == this_id) { prime.arriving_map = -1; } } void TerminateAreaExam(void) { } void InitAreaExam(void) { ResetOdo(); }