region_worker.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. //
  2. // Created by zx on 2019/12/9.
  3. //
  4. #include "region_worker.h"
  5. //#include "plc_data.h"
  6. // 测量结果滤波,不影响现有结构
  7. #include "../tool/measure_filter.h"
  8. // 增加车辆停止状态判断
  9. #include "../tool/region_status_checker.h"
  10. Region_worker::Region_worker()
  11. {
  12. m_region_worker_status = E_UNKNOWN;
  13. mp_cloud_collection_mutex = NULL;
  14. mp_cloud_collection = NULL;
  15. m_detect_update_time = std::chrono::system_clock::now() - std::chrono::hours(1);
  16. mp_auto_detect_thread = NULL;
  17. }
  18. /**
  19. * 析构
  20. * */
  21. Region_worker::~Region_worker()
  22. {
  23. if (mp_auto_detect_thread)
  24. {
  25. m_auto_detect_condition.kill_all();
  26. // Close Capturte Thread
  27. if (mp_auto_detect_thread->joinable())
  28. {
  29. mp_auto_detect_thread->join();
  30. delete mp_auto_detect_thread;
  31. mp_auto_detect_thread = nullptr;
  32. }
  33. }
  34. // 将创建的检测器析构
  35. if(mp_detector)
  36. {
  37. delete mp_detector;
  38. mp_detector = nullptr;
  39. }
  40. if(mp_cloud_collection_mutex)
  41. {
  42. delete mp_cloud_collection_mutex;
  43. mp_cloud_collection_mutex = nullptr;
  44. }
  45. }
  46. Error_manager Region_worker::init(wj::Region region)
  47. {
  48. m_region_param = region;
  49. mp_detector = new Region_detector(m_region_param);
  50. mp_cloud_collection_mutex = new std::mutex();
  51. mp_cloud_collection = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>); // = p_cloud_collection;
  52. m_auto_detect_condition.reset(false, false, false);
  53. mp_auto_detect_thread = new std::thread(&Region_worker::auto_detect_thread_fun, this);
  54. m_region_worker_status = E_READY;
  55. return Error_code::SUCCESS;
  56. }
  57. // Error_manager Region_worker::init(Point2D_tool::Point2D_box point2D_box, std::mutex* p_cloud_collection_mutex,
  58. // pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_collection, int index)
  59. // {
  60. // m_index = index;
  61. // return init(point2D_box, p_cloud_collection_mutex, p_cloud_collection);
  62. // }
  63. //开始自动预测的算法线程
  64. Error_manager Region_worker::start_auto_detect()
  65. {
  66. //唤醒一次
  67. m_auto_detect_condition.notify_all(false, true);
  68. return Error_code::SUCCESS;
  69. }
  70. //关闭自动预测的算法线程
  71. Error_manager Region_worker::stop_auto_detect()
  72. {
  73. //唤醒一次
  74. m_auto_detect_condition.notify_all(false);
  75. return Error_code::SUCCESS;
  76. }
  77. // 获得中心点、角度等测量数据
  78. Error_manager Region_worker::detect_wheel_result(std::mutex* p_cloud_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in, Common_data::Car_wheel_information& car_wheel_information)
  79. {
  80. std::lock_guard<std::mutex> lck(*p_cloud_mutex);
  81. double x, y, c, wheelbase, width, front_theta;
  82. auto res = mp_detector->detect(p_cloud_in, x, y, c, front_theta, wheelbase, width, false);
  83. car_wheel_information.car_center_x = x;
  84. car_wheel_information.car_center_y = y;
  85. car_wheel_information.car_angle = c;
  86. car_wheel_information.car_wheel_base = wheelbase;
  87. car_wheel_information.car_wheel_width = width;
  88. car_wheel_information.car_front_theta = front_theta;
  89. if(res == SUCCESS)
  90. {
  91. car_wheel_information.correctness = true;
  92. }else
  93. {
  94. car_wheel_information.correctness = false;
  95. }
  96. return res;
  97. }
  98. // 获得中心点、角度等测量数据, 新算法, 可以测量前轮旋转
  99. Error_manager Region_worker::detect_wheel_result_ex(std::mutex* p_cloud_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in, Common_data::Car_wheel_information& car_wheel_information)
  100. {
  101. return ERROR; //mp_detector->detect_ex(p_cloud_mutex, p_cloud_in, car_wheel_information);
  102. }
  103. //外部调用获取新的车轮定位信息, 获取指令时间之后的车轮定位信息, 如果没有就会等待车轮定位信息刷新, 直到超时, (内置while)
  104. Error_manager Region_worker::get_new_wheel_information_and_wait(Common_data::Car_wheel_information* p_car_wheel_information,
  105. std::chrono::system_clock::time_point command_time, int timeout_ms)
  106. {
  107. if ( p_car_wheel_information == NULL )
  108. {
  109. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  110. " POINTER IS NULL ");
  111. }
  112. //判断是否超时
  113. while (std::chrono::system_clock::now() - command_time < std::chrono::milliseconds(timeout_ms))
  114. {
  115. //获取指令时间之后的信息, 如果没有就会循环
  116. if(m_detect_update_time > command_time )
  117. {
  118. *p_car_wheel_information = m_car_wheel_information;
  119. return Error_code::SUCCESS;
  120. }
  121. //else 等待下一次数据更新
  122. //等1ms
  123. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  124. }
  125. //超时退出就报错
  126. return Error_manager(Error_code::WJ_REGION_EMPTY_NO_WHEEL_INFORMATION, Error_level::MINOR_ERROR,
  127. " Region_worker::get_new_wheel_information_and_wait error ");
  128. }
  129. //外部调用获取当前车轮定位信息, 获取指令时间之后的车轮定位信息, 如果没有就会报错, 不会等待
  130. Error_manager Region_worker::get_current_wheel_information(Common_data::Car_wheel_information* p_car_wheel_information,
  131. std::chrono::system_clock::time_point command_time)
  132. {
  133. if ( p_car_wheel_information == NULL )
  134. {
  135. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  136. " POINTER IS NULL ");
  137. }
  138. //获取指令时间之后的信息, 如果没有就会报错, 不会等待
  139. if( m_detect_update_time > command_time )
  140. {
  141. *p_car_wheel_information = m_car_wheel_information;
  142. return Error_code::SUCCESS;
  143. }
  144. else
  145. {
  146. return Error_manager(Error_code::WJ_REGION_EMPTY_NO_WHEEL_INFORMATION, Error_level::MINOR_ERROR,
  147. " Region_worker::get_current_wheel_information error ");
  148. }
  149. }
  150. //外部调用获取最新的车轮定位信息, 获取指令时间往前一个周期内的车轮定位信息, 如果没有就会报错, 不会等待
  151. Error_manager Region_worker::get_last_wheel_information(Common_data::Car_wheel_information* p_car_wheel_information,
  152. std::chrono::system_clock::time_point command_time)
  153. {
  154. if ( p_car_wheel_information == NULL )
  155. {
  156. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  157. " POINTER IS NULL ");
  158. }
  159. //将指令时间提前一个扫描周期, 然后获取这个时间后面的点云.
  160. //就是说, 在收到指令的时候, 可以使用一个周期以前的数据, 不用获取最新的点云.
  161. if( m_detect_update_time > command_time - std::chrono::milliseconds(REGION_WORKER_DETECT_CYCLE_MS*2) )
  162. {
  163. *p_car_wheel_information = m_car_wheel_information;
  164. return Error_code::SUCCESS;
  165. }
  166. else
  167. {
  168. return Error_manager(Error_code::WJ_REGION_EMPTY_NO_WHEEL_INFORMATION, Error_level::MINOR_ERROR,
  169. " Region_worker::get_last_wheel_information error ");
  170. }
  171. }
  172. std::chrono::system_clock::time_point Region_worker::get_detect_updata_time()
  173. {
  174. return m_detect_update_time;
  175. }
  176. Error_manager Region_worker::update_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
  177. {
  178. // // 点云z转90度,调试用
  179. //Eigen::AngleAxisd rot_z = Eigen::AngleAxisd(M_PI_2, Eigen::Vector3d::UnitZ());
  180. //for (size_t i = 0; i < cloud->size(); i++)
  181. //{
  182. // Eigen::Vector3d t_point(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
  183. // t_point = rot_z.toRotationMatrix() * t_point;
  184. // cloud->points[i].x = t_point.x();
  185. // cloud->points[i].y = t_point.y();
  186. // cloud->points[i].z = t_point.z();
  187. //}
  188. // 限定锁区域,解决因条件变量在析构时无法获得内部mutex导致此互斥锁卡住,造成死锁无法结束程序的问题。
  189. {
  190. std::lock_guard<std::mutex> lck(*mp_cloud_collection_mutex);
  191. mp_cloud_collection = cloud;
  192. // LOG(WARNING) << "update region cloud size: " << mp_cloud_collection->size() << ",,, input size: " << cloud->size();
  193. m_detect_update_time = std::chrono::system_clock::now();
  194. }
  195. m_auto_detect_condition.notify_one(false, true);
  196. // std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  197. // std::chrono::duration<double> time_used_update = std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0);
  198. // std::cout << "update cloud time: " << time_used_update.count() << std::endl;
  199. return SUCCESS;
  200. }
  201. cv::RotatedRect Region_worker::create_rotate_rect(float length,float width,float angle,float cx,float cy)
  202. {
  203. const double C_PI=3.14159265;
  204. float theta=C_PI*(angle/180.0);
  205. float a00=cos(theta);
  206. float a01=-sin(theta);
  207. float a10=sin(theta);
  208. float a11=cos(theta);
  209. cv::Point2f point[4];
  210. point[0].x=-length/2.0;
  211. point[0].y=-width/2.0;
  212. point[1].x=-length/2.0;
  213. point[1].y=width/2.0;
  214. point[2].x=length/2.0;
  215. point[2].y=-width/2.0;
  216. point[3].x=length/2.0;
  217. point[3].y=width/2.0;
  218. std::vector<cv::Point2f> point_vec;
  219. for(int i=0;i<4;++i)
  220. {
  221. float x=point[i].x*a00+point[i].y*a01+cx;
  222. float y=point[i].x*a10+point[i].y*a11+cy;
  223. point_vec.push_back(cv::Point2f(x,y));
  224. }
  225. return cv::minAreaRect(point_vec);
  226. }
  227. int Region_worker::outOfRangeDetection(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double plate_cx, double plate_cy, double theta)
  228. {
  229. if(cloud->size() <= 0)
  230. return Range_status_wj::Range_correct;
  231. int res = Range_status_wj::Range_correct;
  232. // 计算转盘旋转后点云坐标
  233. double theta_rad = theta * M_PI / 180.0;
  234. pcl::PointCloud<pcl::PointXYZ> t_cloud;
  235. for (size_t i = 0; i < cloud->size(); i++)
  236. {
  237. Eigen::Vector2d t_point(cloud->points[i].x - plate_cx, cloud->points[i].y - plate_cy);
  238. pcl::PointXYZ t_pcl_point;
  239. t_pcl_point.x = (t_point.x() * cos(theta_rad) - t_point.y() * sin(theta_rad)) + plate_cx;
  240. t_pcl_point.y = (t_point.x() * sin(theta_rad) + t_point.y() * cos(theta_rad)) + plate_cy;
  241. t_pcl_point.z = cloud->points[i].z;
  242. t_cloud.push_back(t_pcl_point);
  243. }
  244. pcl::PointXYZ min_p, max_p;
  245. pcl::getMinMax3D(t_cloud, min_p, max_p);
  246. // 判断左右超界情况
  247. if(min_p.x < m_region_param.border_minx())
  248. res |= Range_status_wj::Range_left;
  249. if(max_p.x > m_region_param.border_maxx())
  250. res |= Range_status_wj::Range_right;
  251. // LOG_IF(WARNING, m_region_param.region_id() == 4)<< "border minmax x: "<< min_p.x<<", "<<max_p.x<<", res: "<<res;
  252. return res;
  253. }
  254. int Region_worker::outOfRangeDetection(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, Common_data::Car_wheel_information measure_result, double plate_cx, double plate_cy, double theta)
  255. {
  256. int res = Range_status_wj::Range_correct;
  257. if(cloud->size() <= 0)
  258. return res;
  259. // 计算转盘旋转后车辆中心点坐标
  260. Eigen::Vector2d car_center(measure_result.car_center_x, measure_result.car_center_y);
  261. Eigen::Vector2d car_uniform_center;
  262. double theta_rad = theta * M_PI / 180.0;
  263. car_uniform_center.x() = car_center.x() * cos(theta_rad) - car_center.y() * sin(theta_rad);
  264. car_uniform_center.y() = car_center.x() * sin(theta_rad) + car_center.y() * cos(theta_rad);
  265. // 车位位于y负方向,判断后轮超界情况
  266. double rear_wheel_y = car_uniform_center.y() + m_region_param.plc_offsety() - 0.5 * measure_result.car_wheel_base;
  267. if(rear_wheel_y < m_region_param.plc_border_miny())
  268. {
  269. res |= Range_status_wj::Range_back;
  270. }
  271. // 判断车辆宽度超界情况
  272. if (measure_result.car_wheel_width < m_region_param.car_min_width() || measure_result.car_wheel_width > m_region_param.car_max_width())
  273. {
  274. res |= Range_status_wj::Range_car_width;
  275. }
  276. // 判断车辆轴距超界情况
  277. if (measure_result.car_wheel_base < m_region_param.car_min_wheelbase() || measure_result.car_wheel_base > m_region_param.car_max_wheelbase())
  278. {
  279. res |= Range_status_wj::Range_car_wheelbase;
  280. }
  281. // 判断车辆旋转角超界情况
  282. double dtheta = 90-measure_result.car_angle;
  283. if (dtheta > m_region_param.turnplate_angle_limit_anti_clockwise())
  284. {
  285. res |= Range_status_wj::Range_angle_clock;
  286. }
  287. if (dtheta < -m_region_param.turnplate_angle_limit_clockwise())
  288. {
  289. res |= Range_status_wj::Range_angle_anti_clock;
  290. }
  291. // // 判断车辆前轮角回正情况
  292. // if (fabs(measure_result.car_front_theta) > 8.0)
  293. // {
  294. // res |= Range_status_wj::Range_steering_wheel_nozero;
  295. // }
  296. res |= outOfRangeDetection(cloud, plate_cx, plate_cy, theta);
  297. return res;
  298. }
  299. //自动预测的线程函数
  300. void Region_worker::auto_detect_thread_fun()
  301. {
  302. LOG(INFO) << " Wanji_manager::collect_cloud_thread_fun() start "<< this;
  303. Error_manager t_error;
  304. Error_manager t_result;
  305. while (m_auto_detect_condition.is_alive())
  306. {
  307. //暂时固定为一个扫描周期, 就循环一次
  308. //后期可以根据每个小雷达的刷新情况, 实时更改总点云.....
  309. m_auto_detect_condition.wait();
  310. if ( m_auto_detect_condition.is_alive() )
  311. {
  312. // auto start = std::chrono::system_clock::now();
  313. t_error = detect_wheel_result(mp_cloud_collection_mutex, mp_cloud_collection, m_car_wheel_information);
  314. // auto end = std::chrono::system_clock::now();
  315. // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  316. // std::cout << "花费了"
  317. // << double(duration.count()*1000) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den << "毫秒" << std::endl;
  318. // if ( t_error == SUCCESS )
  319. // {
  320. // std::unique_lock<std::mutex> t_lock(*mp_cloud_collection_mutex);
  321. // m_car_wheel_information.correctness = true;
  322. // }
  323. // else
  324. // {
  325. // std::unique_lock<std::mutex> t_lock(*mp_cloud_collection_mutex);
  326. // m_car_wheel_information.correctness = false;
  327. // }
  328. // //无论结果如何,都要刷新时间, 表示这次定位已经执行了.
  329. // m_detect_update_time = std::chrono::system_clock::now();
  330. // // 测量正确,更新到滤波器
  331. // if(m_car_wheel_information.correctness)
  332. // {
  333. // Common_data::Car_wheel_information_stamped t_wheel_info_stamped;
  334. // t_wheel_info_stamped.wheel_data = m_car_wheel_information;
  335. // t_wheel_info_stamped.measure_time = m_detect_update_time;
  336. // Measure_filter::get_instance_references().update_data(get_terminal_id(), t_wheel_info_stamped);
  337. // }
  338. std::lock_guard<std::mutex> lck(*mp_cloud_collection_mutex);
  339. m_detect_update_time = std::chrono::system_clock::now();
  340. // 增加滤波轴距
  341. Common_data::Car_wheel_information_stamped t_wheel_info_stamped;
  342. // 车辆移动检测
  343. Common_data::Car_wheel_information_stamped t_wheel_info_stamped_for_car_move;
  344. if (t_error == SUCCESS)
  345. {
  346. m_car_wheel_information.correctness = true;
  347. m_car_wheel_information.theta_uniform(m_region_param.turnplate_cx(), m_region_param.turnplate_cy());
  348. // 超界校验
  349. {
  350. int res = outOfRangeDetection(mp_cloud_collection, m_car_wheel_information, m_region_param.turnplate_cx(), m_region_param.turnplate_cy(), 90.0 - m_car_wheel_information.car_angle);
  351. m_car_wheel_information.range_status = res;
  352. }
  353. // 添加plc偏移
  354. m_car_wheel_information.car_center_x += m_region_param.plc_offsetx();
  355. m_car_wheel_information.car_center_y += m_region_param.plc_offsety();
  356. m_car_wheel_information.uniform_car_x += m_region_param.plc_offsetx();
  357. m_car_wheel_information.uniform_car_y += m_region_param.plc_offsety();
  358. m_car_wheel_information.car_angle += m_region_param.plc_offset_degree();
  359. t_wheel_info_stamped.wheel_data = m_car_wheel_information;
  360. t_wheel_info_stamped.measure_time = m_detect_update_time;
  361. Measure_filter::get_instance_references().update_data(m_region_param.region_id(), t_wheel_info_stamped);
  362. // 20211228 added by yct, car movement checking, human and door detection
  363. t_wheel_info_stamped_for_car_move = t_wheel_info_stamped;
  364. t_wheel_info_stamped_for_car_move.wheel_data.car_center_x -= m_region_param.plc_offsetx();
  365. t_wheel_info_stamped_for_car_move.wheel_data.car_center_y -= m_region_param.plc_offsety();
  366. t_wheel_info_stamped_for_car_move.wheel_data.uniform_car_x -= m_region_param.plc_offsetx();
  367. t_wheel_info_stamped_for_car_move.wheel_data.uniform_car_y -= m_region_param.plc_offsety();
  368. t_wheel_info_stamped_for_car_move.wheel_data.car_angle -= m_region_param.plc_offset_degree();
  369. // // wj don't test if statble
  370. // Error_manager car_status_res = Region_status_checker::get_instance_references().get_region_parking_status(m_region_param.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_collection);
  371. // // success means car stable
  372. // if(car_status_res == SUCCESS)
  373. // {
  374. // m_car_wheel_information.range_status &= ~((int)Range_status_wj::Range_car_moving);
  375. // }
  376. // else{
  377. // m_car_wheel_information.range_status |= Range_status_wj::Range_car_moving;
  378. // if(m_region_param.region_id()==4){
  379. // LOG(WARNING)<<"success: "<<car_status_res.to_string()<<std::endl;
  380. // }
  381. // }
  382. // Region_status_checker::get_instance_references().add_measure_data(m_region_param.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_collection);
  383. t_error = Measure_filter::get_instance_references().get_filtered_wheel_information(m_region_param.region_id(), t_wheel_info_stamped.wheel_data);
  384. if (t_error == SUCCESS)
  385. {
  386. m_car_wheel_information.car_wheel_base = t_wheel_info_stamped.wheel_data.car_wheel_base;
  387. m_car_wheel_information.car_front_theta = t_wheel_info_stamped.wheel_data.car_front_theta;
  388. // 临时添加,滤波后前轮超界
  389. if(fabs(m_car_wheel_information.car_front_theta)>8.0)
  390. {
  391. m_car_wheel_information.range_status |= Range_status_wj::Range_steering_wheel_nozero;
  392. }
  393. }
  394. // else{
  395. // std::cout<<t_error.to_string()<<std::endl;
  396. // }
  397. // LOG_IF(INFO, m_region_param.region_id() == 4 || m_region_param.region_id() == 5) << m_car_wheel_information.to_string();
  398. }
  399. else
  400. {
  401. m_car_wheel_information.correctness = false;
  402. // LOG_IF(ERROR, m_region_param.region_id() == 4 || m_region_param.region_id() == 5) <<t_error<<", "<< m_car_wheel_information.to_string();
  403. // 20211228 added by yct, car movement checking, human and door detection
  404. // wj don't test if statble
  405. // Error_manager car_status_res = Region_status_checker::get_instance_references().get_region_parking_status(m_region_param.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_collection);
  406. // // success means car stable
  407. // if(car_status_res == SUCCESS)
  408. // {
  409. // m_car_wheel_information.range_status &= ~((int)Range_status_wj::Range_car_moving);
  410. // }else
  411. // {
  412. // m_car_wheel_information.range_status |= Range_status_wj::Range_car_moving;
  413. // // if(m_region_param.region_id()==4){
  414. // // std::cout<<"failed: "<<car_status_res.to_string()<<std::endl;
  415. // // }
  416. // }
  417. }
  418. }
  419. }
  420. LOG(INFO) << " Wanji_manager::collect_cloud_thread_fun() end "<< this;
  421. return;
  422. }