ground_region.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. //
  2. // Created by zx on 2021/5/20.
  3. //
  4. #include "ground_region.h"
  5. #include <pcl/common/transforms.h>
  6. #include <pcl/filters/statistical_outlier_removal.h>
  7. #include <pcl/filters/voxel_grid.h>
  8. #include <pcl/segmentation/extract_clusters.h>
  9. #include <fcntl.h>
  10. #include "../tool/point_tool.h"
  11. // 测量结果滤波,不影响现有结构
  12. #include "../tool/measure_filter.h"
  13. // 增加车辆停止状态判断
  14. #include "../tool/region_status_checker.h"
  15. #include "../system/system_communication_mq.h"
  16. //欧式聚类*******************************************************
  17. std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> Ground_region::segmentation(pcl::PointCloud<pcl::PointXYZ>::Ptr sor_cloud)
  18. {
  19. std::vector<pcl::PointIndices> ece_inlier;
  20. pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
  21. pcl::EuclideanClusterExtraction<pcl::PointXYZ> ece;
  22. ece.setInputCloud(sor_cloud);
  23. ece.setClusterTolerance(0.07);
  24. ece.setMinClusterSize(20);
  25. ece.setMaxClusterSize(20000);
  26. ece.setSearchMethod(tree);
  27. ece.extract(ece_inlier);
  28. std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> segmentation_clouds;
  29. for (int i = 0; i < ece_inlier.size(); i++)
  30. {
  31. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_copy(new pcl::PointCloud<pcl::PointXYZ>);
  32. std::vector<int> ece_inlier_ext = ece_inlier[i].indices;
  33. copyPointCloud(*sor_cloud, ece_inlier_ext, *cloud_copy); //按照索引提取点云数据
  34. segmentation_clouds.push_back(cloud_copy);
  35. }
  36. return segmentation_clouds;
  37. }
  38. // /**
  39. // * @description: distance between two points
  40. // * @param {Point2f} p1
  41. // * @param {Point2f} p2
  42. // * @return the distance
  43. // */
  44. // double Ground_region::distance(cv::Point2f p1, cv::Point2f p2)
  45. // {
  46. // return sqrt(pow(p1.x - p2.x, 2.0) + pow(p1.y - p2.y, 2.0));
  47. // }
  48. /**
  49. * @description: point rectangle detect
  50. * @param points detect if points obey the rectangle rule
  51. * @return wether forms a rectangle
  52. */
  53. bool Ground_region::isRect(std::vector<cv::Point2f> &points)
  54. {
  55. if (points.size() == 4)
  56. {
  57. double L[3] = {0.0};
  58. L[0] = distance(points[0], points[1]);
  59. L[1] = distance(points[1], points[2]);
  60. L[2] = distance(points[0], points[2]);
  61. double max_l = L[0];
  62. double l1 = L[1];
  63. double l2 = L[2];
  64. cv::Point2f ps = points[0], pt = points[1];
  65. cv::Point2f pc = points[2];
  66. for (int i = 1; i < 3; ++i)
  67. {
  68. if (L[i] > max_l)
  69. {
  70. max_l = L[i];
  71. l1 = L[abs(i + 1) % 3];
  72. l2 = L[abs(i + 2) % 3];
  73. ps = points[i % 3];
  74. pt = points[(i + 1) % 3];
  75. pc = points[(i + 2) % 3];
  76. }
  77. }
  78. //直角边与坐标轴的夹角 <20°
  79. float thresh = 20.0 * M_PI / 180.0;
  80. cv::Point2f vct(pt.x - pc.x, pt.y - pc.y);
  81. float angle = atan2(vct.y, vct.x);
  82. if (!(fabs(angle) < thresh || (M_PI_2 - fabs(angle) < thresh)))
  83. {
  84. //std::cout<<" 4 wheel axis angle : "<<angle<<std::endl;
  85. return false;
  86. }
  87. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  88. if (fabs(cosa) >= 0.15)
  89. {
  90. /*char description[255]={0};
  91. sprintf(description,"angle cos value(%.2f) >0.13 ",cosa);
  92. std::cout<<description<<std::endl;*/
  93. return false;
  94. }
  95. float width = std::min(l1, l2);
  96. float length = std::max(l1, l2);
  97. if (width < 1.400 || width > 1.900 || length > 3.300 || length < 2.200)
  98. {
  99. /*char description[255]={0};
  100. sprintf(description,"width<1400 || width >1900 || length >3300 ||length < 2200 l:%.1f,w:%.1f",length,width);
  101. std::cout<<description<<std::endl;*/
  102. return false;
  103. }
  104. double d = distance(pc, points[3]);
  105. cv::Point2f center1 = (ps + pt) * 0.5;
  106. cv::Point2f center2 = (pc + points[3]) * 0.5;
  107. if (fabs(d - max_l) > max_l * 0.1 || distance(center1, center2) > 0.150)
  108. {
  109. /*std::cout << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2<<std::endl;
  110. char description[255]={0};
  111. sprintf(description,"Verify failed-4 fabs(d - max_l) > max_l * 0.1 || distance(center1, center2) > 0.150 ");
  112. std::cout<<description<<std::endl;*/
  113. return false;
  114. }
  115. //std::cout << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2<<std::endl;
  116. return true;
  117. }
  118. else if (points.size() == 3)
  119. {
  120. double L[3] = {0.0};
  121. L[0] = distance(points[0], points[1]);
  122. L[1] = distance(points[1], points[2]);
  123. L[2] = distance(points[0], points[2]);
  124. double max_l = L[0];
  125. double l1 = L[1];
  126. double l2 = L[2];
  127. int max_index = 0;
  128. cv::Point2f ps = points[0], pt = points[1];
  129. cv::Point2f pc = points[2];
  130. for (int i = 1; i < 3; ++i)
  131. {
  132. if (L[i] > max_l)
  133. {
  134. max_index = i;
  135. max_l = L[i];
  136. l1 = L[abs(i + 1) % 3];
  137. l2 = L[abs(i + 2) % 3];
  138. ps = points[i % 3];
  139. pt = points[(i + 1) % 3];
  140. pc = points[(i + 2) % 3];
  141. }
  142. }
  143. //直角边与坐标轴的夹角 <20°
  144. float thresh = 20.0 * M_PI / 180.0;
  145. cv::Point2f vct(pt.x - pc.x, pt.y - pc.y);
  146. float angle = atan2(vct.y, vct.x);
  147. if (!(fabs(angle) < thresh || (M_PI_2 - fabs(angle) < thresh)))
  148. {
  149. //std::cout<<" 4 wheel axis angle : "<<angle<<std::endl;
  150. return false;
  151. }
  152. double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
  153. if (fabs(cosa) >= 0.15)
  154. {
  155. /*char description[255]={0};
  156. sprintf(description,"3 wheels angle cos value(%.2f) >0.13 ",cosa);
  157. std::cout<<description<<std::endl;*/
  158. return false;
  159. }
  160. double l = std::max(l1, l2);
  161. double w = std::min(l1, l2);
  162. if (l > 2.100 && l < 3.300 && w > 1.400 && w < 2.100)
  163. {
  164. //生成第四个点
  165. cv::Point2f vec1 = ps - pc;
  166. cv::Point2f vec2 = pt - pc;
  167. cv::Point2f point4 = (vec1 + vec2) + pc;
  168. points.push_back(point4);
  169. /*char description[255]={0};
  170. sprintf(description,"3 wheels rectangle cos angle=%.2f,L=%.1f, w=%.1f",cosa,l,w);
  171. std::cout<<description<<std::endl;*/
  172. return true;
  173. }
  174. else
  175. {
  176. /*char description[255]={0};
  177. sprintf(description,"3 wheels rectangle verify Failed cos angle=%.2f,L=%.1f, w=%.1f",cosa,l,w);
  178. std::cout<<description<<std::endl;*/
  179. return false;
  180. }
  181. }
  182. //std::cout<<" default false"<<std::endl;
  183. return false;
  184. }
  185. /**
  186. * @description: 3d wheel detect core func
  187. * @param cloud input cloud for measure
  188. * @param thresh_z z value to cut wheel
  189. * @param result detect result
  190. * @return wether successfully detected
  191. */
  192. bool Ground_region::classify_ceres_detect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double thresh_z,
  193. detect_wheel_ceres3d::Detect_result &result)
  194. {
  195. if (m_detector == nullptr)
  196. return false;
  197. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
  198. for (int i = 0; i < cloud->size(); ++i)
  199. {
  200. pcl::PointXYZ pt = cloud->points[i];
  201. if (pt.z < thresh_z)
  202. {
  203. cloud_filtered->push_back(pt);
  204. }
  205. }
  206. //下采样
  207. pcl::VoxelGrid<pcl::PointXYZ> vox; //创建滤波对象
  208. vox.setInputCloud(cloud_filtered); //设置需要过滤的点云给滤波对象
  209. vox.setLeafSize(0.01f, 0.01f, 0.01f); //设置滤波时创建的体素体积为1cm的立方体
  210. vox.filter(*cloud_filtered); //执行滤波处理,存储输出
  211. if (cloud_filtered->size() == 0)
  212. {
  213. return false;
  214. }
  215. pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; //创建滤波器对象
  216. sor.setInputCloud(cloud_filtered); //设置待滤波的点云
  217. sor.setMeanK(5); //设置在进行统计时考虑的临近点个数
  218. sor.setStddevMulThresh(3.0); //设置判断是否为离群点的阀值,用来倍乘标准差,也就是上面的std_mul
  219. sor.filter(*cloud_filtered); //滤波结果存储到cloud_filtered
  220. if (cloud_filtered->size() == 0)
  221. {
  222. return false;
  223. }
  224. std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> seg_clouds;
  225. seg_clouds = segmentation(cloud_filtered);
  226. if (!(seg_clouds.size() == 4 || seg_clouds.size() == 3))
  227. {
  228. return false;
  229. }
  230. std::vector<cv::Point2f> centers;
  231. cv::Point2f temp_centers(0,0);
  232. for (int i = 0; i < seg_clouds.size(); ++i)
  233. {
  234. Eigen::Vector4f centroid;
  235. pcl::compute3DCentroid(*seg_clouds[i], centroid);
  236. centers.push_back(cv::Point2f(centroid[0], centroid[1]));
  237. temp_centers += cv::Point2f(centroid[0], centroid[1]);
  238. }
  239. temp_centers /= 4.0f;
  240. bool ret = isRect(centers);
  241. if (ret)
  242. {
  243. std::string error_str;
  244. // LOG(WARNING) << "region id: "<< m_region.region_id();
  245. if (m_detector->detect(seg_clouds, result, error_str))
  246. {
  247. return true;
  248. }
  249. else
  250. {
  251. // LOG(WARNING) << error_str;
  252. return false;
  253. }
  254. }
  255. return ret;
  256. }
  257. // constructor
  258. Ground_region::Ground_region()
  259. {
  260. m_region_status = E_UNKNOWN;
  261. m_detector = nullptr;
  262. m_measure_thread = nullptr;
  263. }
  264. // deconstructor
  265. Ground_region::~Ground_region()
  266. {
  267. // LOG(WARNING) << "start deconstruct ground region";
  268. if (m_measure_thread)
  269. {
  270. m_measure_condition.kill_all();
  271. // Close Capturte Thread
  272. if (m_measure_thread->joinable())
  273. {
  274. m_measure_thread->join();
  275. delete m_measure_thread;
  276. m_measure_thread = nullptr;
  277. }
  278. }
  279. // LOG(WARNING) << "thread released";
  280. // 将创建的检测器析构
  281. if(m_detector)
  282. {
  283. delete m_detector;
  284. m_detector = nullptr;
  285. }
  286. Region_status_checker::get_instance_references().Region_status_checker_uninit();
  287. // LOG(WARNING) << "detector released";
  288. }
  289. Error_manager Ground_region::init(velodyne::Region region, pcl::PointCloud<pcl::PointXYZ>::Ptr left_model, pcl::PointCloud<pcl::PointXYZ>::Ptr right_model)
  290. {
  291. m_range_status_last = 0;
  292. Region_status_checker::get_instance_references().Region_status_checker_init();
  293. m_region = region;
  294. m_detector = new detect_wheel_ceres3d(left_model,right_model);
  295. mp_cloud_collection = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  296. mp_cloud_filtered = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  297. mp_cloud_detect_z = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  298. m_measure_thread = new std::thread(&Ground_region::thread_measure_func, this);
  299. m_measure_condition.reset();
  300. m_region_status = E_READY;
  301. return SUCCESS;
  302. }
  303. // 计算均方误差
  304. bool computer_var(std::vector<double> data, double &var)
  305. {
  306. if (data.size() == 0)
  307. return false;
  308. Eigen::VectorXd dis_vec(data.size());
  309. for (int i = 0; i < data.size(); ++i)
  310. {
  311. dis_vec[i] = data[i];
  312. }
  313. double mean = dis_vec.mean();
  314. Eigen::VectorXd mean_vec(data.size());
  315. Eigen::VectorXd mat = dis_vec - (mean_vec.setOnes() * mean);
  316. Eigen::MatrixXd result = (mat.transpose()) * mat;
  317. var = sqrt(result(0) / double(data.size()));
  318. return true;
  319. }
  320. Error_manager Ground_region::detect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, detect_wheel_ceres3d::Detect_result &last_result)
  321. {
  322. // 1.*********点云合法性检验*********
  323. if (cloud->size() == 0){
  324. // 更新过滤点
  325. m_filtered_cloud_mutex.lock();
  326. mp_cloud_filtered->clear();
  327. m_filtered_cloud_mutex.unlock();
  328. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NEGLIGIBLE_ERROR, "no input point");
  329. }
  330. // 2.*********点云预处理*********
  331. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  332. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cut(new pcl::PointCloud<pcl::PointXYZ>);
  333. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_clean(new pcl::PointCloud<pcl::PointXYZ>);
  334. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
  335. for (int i = 0; i < cloud->size(); ++i)
  336. {
  337. pcl::PointXYZ pt = cloud->points[i];
  338. if (pt.x > m_region.minx() && pt.x < m_region.maxx() && pt.y > m_region.miny() && pt.y < m_region.maxy() && pt.z > m_region.minz() && pt.z < m_region.maxz())
  339. {
  340. cloud_cut->push_back(pt);
  341. }
  342. }
  343. if(cloud_cut->size() <= 0)
  344. {
  345. // 更新过滤点
  346. m_filtered_cloud_mutex.lock();
  347. mp_cloud_filtered->clear();
  348. m_filtered_cloud_mutex.unlock();
  349. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NEGLIGIBLE_ERROR, "cut no point");
  350. }
  351. //下采样
  352. pcl::VoxelGrid<pcl::PointXYZ> vox; //创建滤波对象
  353. vox.setInputCloud(cloud_cut); //设置需要过滤的点云给滤波对象
  354. vox.setLeafSize(0.02f, 0.02f, 0.02f); //设置滤波时创建的体素体积为1cm的立方体
  355. vox.filter(*cloud_clean); //执行滤波处理,存储输出
  356. // cloud_filtered = cloud_clean;
  357. if (cloud_clean->size() == 0){
  358. // 更新过滤点
  359. m_filtered_cloud_mutex.lock();
  360. mp_cloud_filtered->clear();
  361. m_filtered_cloud_mutex.unlock();
  362. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NEGLIGIBLE_ERROR, "ApproximateVoxelGrid no point");
  363. }
  364. //离群点过滤
  365. pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
  366. sor.setInputCloud(cloud_clean);
  367. sor.setMeanK(5); //K近邻搜索点个数
  368. sor.setStddevMulThresh(3.0); //标准差倍数
  369. sor.setNegative(false); //保留未滤波点(内点)
  370. sor.filter(*cloud_filtered); //保存滤波结果到cloud_filter
  371. // 20221211 changed by yct, 10 point threshold
  372. if (cloud_filtered->size() <= 10){
  373. // 更新过滤点
  374. m_filtered_cloud_mutex.lock();
  375. mp_cloud_filtered->clear();
  376. m_filtered_cloud_mutex.unlock();
  377. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NEGLIGIBLE_ERROR, "StatisticalOutlierRemoval no point");
  378. }
  379. // 更新过滤点
  380. m_filtered_cloud_mutex.lock();
  381. mp_cloud_filtered->clear();
  382. mp_cloud_filtered->operator+=(*cloud_filtered);
  383. m_filtered_cloud_mutex.unlock();
  384. // 3.*********位姿优化,获取中心xy与角度*********
  385. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_detect_z(new pcl::PointCloud<pcl::PointXYZ>);
  386. double car_pose_x, car_pose_y, car_pose_theta, car_pose_width, z_value=0.2;
  387. // if(!Car_pose_detector::get_instance_references().detect_pose(cloud_filtered, cloud_detect_z, car_pose_x, car_pose_y, car_pose_theta, car_pose_width, z_value, false))
  388. if(!Car_pose_detector::get_instance_references().detect_pose_mat(cloud_filtered, cloud_detect_z, car_pose_x, car_pose_y, car_pose_theta, false))
  389. {
  390. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NEGLIGIBLE_ERROR, "find general car pose value failed.");
  391. }
  392. // 20230112 added by yct for rough angle border detection
  393. if(fabs(car_pose_theta * 180.0 / M_PI) > 8)
  394. {
  395. last_result.cx = car_pose_x;
  396. last_result.cy = car_pose_y;
  397. last_result.theta = - car_pose_theta * 180.0 / M_PI;
  398. return Error_manager(VELODYNE_REGION_ANGLE_PRECHECK_FAILED, NEGLIGIBLE_ERROR, "find general car pose value failed.");
  399. }
  400. // LOG_IF(INFO, m_region.region_id() == 0) << "car pose :::: cx: " << car_pose_x+m_region.plc_offsetx() << ", cy: " << car_pose_y+m_region.plc_offsety() << ", theta: " << car_pose_theta*180.0/M_PI << std::endl;
  401. std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
  402. std::chrono::duration<double> time_used_bowl = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
  403. // 4.*********xoz优化获取底盘高度*********
  404. // 重新取包含地面点的点云,用于底盘优化
  405. double z_solver_x = car_pose_x;
  406. double z_solver_y = car_pose_y;
  407. double z_solver_theta = car_pose_theta;
  408. double z_solver_width = 1.0;
  409. chassis_ceres_solver t_solver;
  410. // !!!重新筛选地面点并滤波,融入第一步位姿使用的滤波后点云,传入第二步获取底盘高度
  411. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_z_solver(new pcl::PointCloud<pcl::PointXYZ>);
  412. for (int i = 0; i < cloud->size(); ++i)
  413. {
  414. pcl::PointXYZ pt = cloud->points[i];
  415. if (pt.x > m_region.minx() && pt.x < m_region.maxx() && pt.y > m_region.miny() && pt.y < m_region.maxy() && pt.z <= m_region.minz())
  416. {
  417. cloud_z_solver->push_back(pt);
  418. }
  419. }
  420. if (cloud_z_solver->size() == 0){
  421. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NEGLIGIBLE_ERROR, "cloud z no point for outlier removal");
  422. }
  423. //离群点过滤
  424. sor.setInputCloud(cloud_z_solver);
  425. sor.setMeanK(5); //K近邻搜索点个数
  426. sor.setStddevMulThresh(3.0); //标准差倍数
  427. sor.setNegative(false); //保留未滤波点(内点)
  428. sor.filter(*cloud_z_solver); //保存滤波结果到cloud_filter
  429. // 补上车身与车轮点
  430. cloud_z_solver->operator+=(*mp_cloud_filtered);
  431. // 去中心,角度调正
  432. Car_pose_detector::get_instance_references().inv_trans_cloud(cloud_z_solver, z_solver_x, z_solver_y, z_solver_theta);
  433. if (cloud_z_solver->size() == 0)
  434. return Error_manager(VELODYNE_REGION_EMPTY_CLOUD, NORMAL, "z solver no point");
  435. // 给予底盘z中心与高度初值
  436. double mid_z = 0.05, height = 0.08;
  437. z_solver_x = 0.0;
  438. // Error_manager ec = t_solver.solve(cloud_z_solver, z_solver_x, mid_z, z_solver_width, height);
  439. Error_manager ec = t_solver.solve_mat(cloud_z_solver, z_solver_x, mid_z, z_solver_width, height, false);
  440. // 切除大于height高度以外点,并显示width直线
  441. // 根据z值切原始点云
  442. // std::cout<<"before clip: "<<cloud_z_solver->size()<<std::endl;
  443. pcl::PassThrough<pcl::PointXYZ> pass;
  444. pass.setInputCloud(cloud_z_solver);
  445. pass.setFilterFieldName("z");
  446. pass.setFilterLimits(m_region.minz(), mid_z + height / 2.0);
  447. pass.setFilterLimitsNegative(false);
  448. pass.filter(*cloud_z_solver);
  449. // std::cout<<"after clip: "<<cloud_z_solver->size()<<std::endl;
  450. // // 车宽方向画线
  451. // for (double i = -3.0; i < 3.0; i+=0.02)
  452. // {
  453. // cloud_z_solver->push_back(pcl::PointXYZ(-width/2.0, i, 0));
  454. // cloud_z_solver->push_back(pcl::PointXYZ(width/2.0, i, 0));
  455. // }
  456. // std::cout << "\n------------------------------------ chassis z1: " << mid_z + height / 2.0 << ", mid z: "<< mid_z << std::endl;
  457. if(ec != SUCCESS)
  458. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NORMAL, "failed to find chassis z value.");
  459. std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now();
  460. std::chrono::duration<double> time_used_block = std::chrono::duration_cast<std::chrono::duration<double>>(t3 - t2);
  461. // 更新z中间点
  462. m_detect_z_cloud_mutex.lock();
  463. mp_cloud_detect_z->clear();
  464. mp_cloud_detect_z->operator+=(*cloud_z_solver);
  465. m_detect_z_cloud_mutex.unlock();
  466. // 二分法存在错误弃用!!!直接使用底盘z值
  467. std::vector<detect_wheel_ceres3d::Detect_result> results;
  468. detect_wheel_ceres3d::Detect_result result;
  469. double chassis_z = mid_z + height / 2.0; // + 0.02;
  470. if(chassis_z > m_region.maxz() || chassis_z < m_region.minz())
  471. {
  472. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NEGLIGIBLE_ERROR, (std::string("optimized chassis z value out of range: ")+std::to_string(chassis_z)).c_str());
  473. }
  474. bool ret = false;
  475. while (chassis_z > (mid_z - height / 2.0))
  476. {
  477. // LOG_IF(WARNING, m_region.region_id() == 0) << "chassis z: " << chassis_z << ", midz: " << mid_z - height / 2.0;
  478. // 初值中x使用第一步优化的值
  479. result.cx = car_pose_x;
  480. // 传入整车角度,用于准确判断轮宽,此处需要的是点云的角度,通常逆时针90度到x轴
  481. result.theta = -(M_PI_2 - car_pose_theta);
  482. ret = classify_ceres_detect(cloud_filtered, chassis_z, result);
  483. // changed by yct, 根据底盘z识别,失败则向下移动直至成功或超过底盘内空中点
  484. if(ret)
  485. {
  486. results.push_back(result);
  487. break;
  488. }else{
  489. chassis_z -= 0.01;
  490. }
  491. }
  492. // } while (fabs(center_z - last_center_z) > 0.01);
  493. std::chrono::steady_clock::time_point t4 = std::chrono::steady_clock::now();
  494. std::chrono::duration<double> time_used_div = std::chrono::duration_cast<std::chrono::duration<double>>(t4 - t3);
  495. // std::cout << "\n------------------------------------------------------------ " << std::to_string(time_used_bowl.count()) << " " << std::to_string(time_used_block.count()) << " " << std::to_string(time_used_div.count())<<" || "<< std::to_string(time_used_bowl.count()+time_used_block.count()+time_used_div.count())<< std::endl;
  496. if (results.size() == 0)
  497. {
  498. // std::cout << "\n-------- no result: " << std::endl;
  499. //LOG_IF(INFO, m_region.region_id() == 4) << "failed with midz, currz: " << mid_z << ", " << chassis_z;
  500. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NEGLIGIBLE_ERROR, "3d wheel detect failed.");
  501. }
  502. else
  503. {
  504. // // 20201010, may lead to problem in chutian, uncomment in debug only
  505. // // changed by yct, save 3d wheel detect result.
  506. // static int save_debug = 0;
  507. // if (m_region.region_id() == 0 && save_debug++ == 5)
  508. // m_detector->save_debug_data("/home/zx/yct/chutian_measure_2021/build");
  509. // LOG_IF(INFO, m_region.region_id() == 4) << "detected with suitable z value: " << chassis_z;
  510. }
  511. /// to be
  512. float min_mean_loss = 1.0;
  513. for (int i = 0; i < results.size(); ++i)
  514. {
  515. detect_wheel_ceres3d::Detect_result result = results[i];
  516. std::vector<double> loss;
  517. loss.push_back(result.loss.lf_loss);
  518. loss.push_back(result.loss.rf_loss);
  519. loss.push_back(result.loss.lb_loss);
  520. loss.push_back(result.loss.rb_loss);
  521. double mean = (result.loss.lf_loss + result.loss.rf_loss + result.loss.lb_loss + result.loss.rb_loss) / 4.0;
  522. double var = -1.;
  523. computer_var(loss, var);
  524. if (mean < min_mean_loss)
  525. {
  526. last_result = result;
  527. min_mean_loss = mean;
  528. }
  529. }
  530. // printf("z : %.3f angle : %.3f front : %.3f wheel_base:%.3f,width:%.3f, mean:%.5f\n",
  531. // center_z, last_result.theta, last_result.front_theta, last_result.wheel_base, last_result.width,
  532. // min_mean_loss);
  533. // std::cout << "\n-------- final z: " << chassis_z << std::endl;
  534. // std::cout << "cx: " << last_result.cx << ", cy: " << last_result.cy << ", theta: " << last_result.theta
  535. // << ", front: " << last_result.front_theta << ", wheelbase: " << last_result.wheel_base << ", width: " << last_result.width << std::endl << std::endl;
  536. // last_result.cx -= x;
  537. // last_result.cy -= y;
  538. // last_result.theta -= theta;
  539. // 角度校验,理论上car pose检测使用车身点云,应与车轮点云识别得到的车身 x偏移(0.035)与角度(<1°)一致
  540. double car_pose_theta_deg = 90 - car_pose_theta * 180.0 / M_PI;
  541. if (fabs(car_pose_x - last_result.cx) > 0.035 || fabs(car_pose_theta_deg - last_result.theta) > 1)
  542. {
  543. char valid_info[255];
  544. sprintf(valid_info, "validation failed for x and theta, carpose: (%.3f, %.3f), result: (%.3f, %.3f)", car_pose_x, car_pose_theta_deg, last_result.cx, last_result.theta);
  545. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NEGLIGIBLE_ERROR, valid_info);
  546. }
  547. // 车宽精度优化
  548. {
  549. pcl::PointCloud<pcl::PointXYZ>::Ptr t_width_rough_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  550. pcl::PointCloud<pcl::PointXYZ>::Ptr t_width_extract_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  551. t_width_rough_cloud->operator+=(*mp_cloud_filtered);
  552. t_width_extract_cloud->operator+=(m_detector->m_left_front_cloud);
  553. t_width_extract_cloud->operator+=(m_detector->m_right_front_cloud);
  554. t_width_extract_cloud->operator+=(m_detector->m_left_rear_cloud);
  555. t_width_extract_cloud->operator+=(m_detector->m_right_rear_cloud);
  556. pcl::PointXYZ t_rough_min_p, t_rough_max_p;
  557. // rough width for human detect
  558. {
  559. //离群点过滤
  560. sor.setInputCloud(t_width_rough_cloud);
  561. sor.setMeanK(5); //K近邻搜索点个数
  562. sor.setStddevMulThresh(1.0); //标准差倍数
  563. sor.setNegative(false); //保留未滤波点(内点)
  564. sor.filter(*t_width_rough_cloud); //保存滤波结果到cloud_filter
  565. Eigen::Affine3d t_affine = Eigen::Affine3d::Identity();
  566. t_affine.prerotate(Eigen::AngleAxisd((90 - last_result.theta) * M_PI / 180.0, Eigen::Vector3d::UnitZ()));
  567. pcl::transformPointCloud(*t_width_rough_cloud, *t_width_rough_cloud, t_affine.matrix());
  568. // 车宽重计算,并赋值到当前车宽
  569. pcl::getMinMax3D(*t_width_rough_cloud, t_rough_min_p, t_rough_max_p);
  570. }
  571. double rough_width = t_rough_max_p.x - t_rough_min_p.x;
  572. //离群点过滤
  573. sor.setInputCloud(t_width_extract_cloud);
  574. sor.setMeanK(5); //K近邻搜索点个数
  575. sor.setStddevMulThresh(1.0); //标准差倍数
  576. sor.setNegative(false); //保留未滤波点(内点)
  577. sor.filter(*t_width_extract_cloud); //保存滤波结果到cloud_filter
  578. Eigen::Affine3d t_affine = Eigen::Affine3d::Identity();
  579. t_affine.prerotate(Eigen::AngleAxisd((90 - last_result.theta) * M_PI / 180.0, Eigen::Vector3d::UnitZ()));
  580. pcl::transformPointCloud(*t_width_extract_cloud, *t_width_extract_cloud, t_affine.matrix());
  581. // 车宽重计算,并赋值到当前车宽
  582. pcl::PointXYZ t_min_p, t_max_p;
  583. pcl::getMinMax3D(*t_width_extract_cloud, t_min_p, t_max_p);
  584. double accurate_width = t_max_p.x - t_min_p.x;
  585. last_result.width = accurate_width;
  586. if(fabs(rough_width - accurate_width) > 0.08)
  587. {
  588. std::string disp_str = std::string("width difference too large, assume noise situation, ")+std::to_string(rough_width)+", "+std::to_string(accurate_width);
  589. LOG(WARNING) << disp_str;
  590. return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, MINOR_ERROR, disp_str.c_str());
  591. }
  592. // !!!暂时不限制宽度数据
  593. // char valid_info[255];
  594. // sprintf(valid_info, "validation for car width, origin/accurate: (%.3f, %.3f)", last_result.width, accurate_width);
  595. // // 允许一边5cm误差,且保证车宽应比车轮识别计算出的大,否则为错误宽度数据
  596. // if (accurate_width - last_result.width > 0.1 || accurate_width < last_result.width)
  597. // {
  598. // return Error_manager(VELODYNE_REGION_CERES_SOLVE_ERROR, NEGLIGIBLE_ERROR, valid_info);
  599. // }
  600. // if (m_region.region_id() == 0 || m_region.region_id() == 4)
  601. // {
  602. // LOG(WARNING) << valid_info;
  603. // // 保存车宽数据,统计用
  604. // if (m_file_out.is_open())
  605. // m_file_out << std::setprecision(5) << std::to_string(1.883) << "," << last_result.width << "," << accurate_width << std::endl;
  606. // }
  607. }
  608. // LOG_IF(INFO, m_region.region_id() == 4) << last_result.to_string();
  609. return SUCCESS;
  610. }
  611. int Ground_region::outOfRangeDetection(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double cx, double cy, double plate_cx, double plate_cy, double theta)
  612. {
  613. // LOG(WARNING) << m_range_status_last;
  614. if(cloud->size() <= 0)
  615. return Range_status::Range_correct;
  616. int res = Range_status::Range_correct;
  617. // 计算转盘旋转后点云坐标
  618. double theta_rad = theta * M_PI / 180.0;
  619. pcl::PointCloud<pcl::PointXYZ> t_cloud;
  620. for (size_t i = 0; i < cloud->size(); i++)
  621. {
  622. Eigen::Vector2d t_point(cloud->points[i].x - plate_cx, cloud->points[i].y - plate_cy);
  623. pcl::PointXYZ t_pcl_point;
  624. t_pcl_point.x = (t_point.x() * cos(theta_rad) - t_point.y() * sin(theta_rad)) + plate_cx;
  625. t_pcl_point.y = (t_point.x() * sin(theta_rad) + t_point.y() * cos(theta_rad)) + plate_cy;
  626. t_pcl_point.z = cloud->points[i].z;
  627. t_cloud.push_back(t_pcl_point);
  628. }
  629. pcl::PointXYZ min_p, max_p;
  630. pcl::getMinMax3D(t_cloud, min_p, max_p);
  631. #ifndef ANTI_SHAKE
  632. // 判断左右超界情况
  633. if(min_p.x < m_region.border_minx())
  634. res |= Range_status::Range_left;
  635. if(max_p.x > m_region.border_maxx())
  636. res |= Range_status::Range_right;
  637. // LOG_IF(WARNING, m_region.region_id() == 4)<< "border minmax x: "<< min_p.x<<", "<<max_p.x<<", res: "<<res;
  638. return res;
  639. #else
  640. /*
  641. if(min_p.x < m_region.border_minx()-0.000)
  642. {
  643. m_range_status_last |= Range_status::Range_left;
  644. }
  645. else if(min_p.x > m_region.border_minx()+0.010)
  646. {
  647. int t = Range_status::Range_left;
  648. m_range_status_last &= (~t);
  649. }
  650. //else m_range_status_last no change
  651. if(max_p.x > m_region.border_maxx()+0.000)
  652. {
  653. m_range_status_last |= Range_status::Range_right;
  654. }
  655. else if(max_p.x < m_region.border_maxx()-0.010)
  656. {
  657. int t = Range_status::Range_right;
  658. m_range_status_last &= (~t);
  659. }
  660. //else m_range_status_last no change
  661. */
  662. //huli 不再使用汽车左右边界来判断,直接使用中心点x值判断左右超界。
  663. //plc坐标,1 3 5入口x为-1.8左右, 2 4 6入口为1.8左右
  664. //要求x取值范围,1650~2150左右
  665. float t_center_x = cx + m_region.plc_offsetx();
  666. if(t_center_x < m_region.border_minx()-0.000)
  667. {
  668. m_range_status_last |= Range_status::Range_left;
  669. }
  670. else if(t_center_x > m_region.border_minx()+0.010)
  671. {
  672. int t = Range_status::Range_left;
  673. m_range_status_last &= (~t);
  674. }
  675. //else m_range_status_last no change
  676. if(t_center_x > m_region.border_maxx()+0.000)
  677. {
  678. m_range_status_last |= Range_status::Range_right;
  679. }
  680. else if(t_center_x < m_region.border_maxx()-0.010)
  681. {
  682. int t = Range_status::Range_right;
  683. m_range_status_last &= (~t);
  684. }
  685. //else m_range_status_last no change
  686. // LOG(WARNING) << "-------------------------------------------------------" <<std::endl;
  687. // LOG(WARNING) << "min_p.x = " << min_p.x <<std::endl;
  688. // LOG(WARNING) << "max_p.x = " << max_p.x <<std::endl;
  689. // LOG(WARNING) << "t_center_x = " << t_center_x <<std::endl;
  690. // LOG(WARNING) << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" <<std::endl;
  691. return m_range_status_last;
  692. #endif //ANTI_SHAKE
  693. }
  694. int Ground_region::outOfRangeDetection(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, Common_data::Car_wheel_information measure_result, double plate_cx, double plate_cy, double theta)
  695. {
  696. // int res = Range_status::Range_correct;
  697. if(cloud->size() <= 0)
  698. return Range_status::Range_correct;
  699. // 计算转盘旋转后车辆中心点坐标
  700. Eigen::Vector2d car_center(measure_result.car_center_x, measure_result.car_center_y);
  701. Eigen::Vector2d car_uniform_center;
  702. double theta_rad = theta * M_PI / 180.0;
  703. car_uniform_center.x() = car_center.x() * cos(theta_rad) - car_center.y() * sin(theta_rad);
  704. car_uniform_center.y() = car_center.x() * sin(theta_rad) + car_center.y() * cos(theta_rad);
  705. #ifndef ANTI_SHAKE
  706. // 车位位于y负方向,判断后轮超界情况
  707. //yct old program 20221101
  708. // double rear_wheel_y = car_uniform_center.y() + m_region.plc_offsety() - 0.5 * measure_result.car_wheel_base;
  709. // if(rear_wheel_y < m_region.plc_border_miny())
  710. // {
  711. // res |= Range_status::Range_back;
  712. // }
  713. //huli new program 20221101
  714. double t_center_y = 0.0 - (car_uniform_center.y() + m_region.plc_offsety()); // 汽车中心y, 参照plc坐标,并且进行偏移, 绝对值。结果大约为 5~6左右
  715. if( t_center_y - 4.88 + 0.5*(measure_result.car_wheel_base - 2.7) < m_region.plc_border_maxy() &&
  716. t_center_y - 4.88 - 0.5*(measure_result.car_wheel_base - 2.7) < m_region.plc_border_miny() )
  717. {
  718. //normal
  719. } else
  720. {
  721. res |= Range_status::Range_back;
  722. }
  723. // 判断车辆宽度超界情况
  724. if (measure_result.car_wheel_width < m_region.car_min_width() || measure_result.car_wheel_width > m_region.car_max_width())
  725. {
  726. res |= Range_status::Range_car_width;
  727. }
  728. // 判断车辆轴距超界情况
  729. if (measure_result.car_wheel_base < m_region.car_min_wheelbase() || measure_result.car_wheel_base > m_region.car_max_wheelbase())
  730. {
  731. res |= Range_status::Range_car_wheelbase;
  732. }
  733. //yct old program 20221103 , 使用 velodyne_manager.prototxt 里面的 turnplate_angle_limit 来做边界判断
  734. // 判断车辆旋转角超界情况
  735. // double dtheta = 90-measure_result.car_angle;
  736. // if (dtheta > m_region.turnplate_angle_limit_anti_clockwise())
  737. // {
  738. // res |= Range_status::Range_angle_clock;
  739. // }
  740. // if (dtheta < -m_region.turnplate_angle_limit_clockwise())
  741. // {
  742. // res |= Range_status::Range_angle_anti_clock;
  743. // }
  744. //huli new program 20221103, 使用 plc dispatch_1_statu_port 里面的 来做边界判断
  745. // double t_dtheta = 90-measure_result.car_angle; // 车身的旋转角, 修正到正负5度,
  746. double t_dtheta = measure_result.car_angle + m_region.plc_offset_degree(); // 车身的旋转角, 修正到正5度, (m_region.plc_offset_degree():-89)
  747. int t_terminal_id = m_region.region_id() +1; //region_id:0~5, terminal_id:1~6
  748. //turnplate_angle_min = -5, turnplate_angle_max = 5,
  749. if (t_dtheta > System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_max())
  750. {
  751. res |= Range_status::Range_angle_anti_clock;
  752. }
  753. if (t_dtheta < System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_min())
  754. {
  755. res |= Range_status::Range_angle_clock;
  756. }
  757. // // 判断车辆前轮角回正情况
  758. // if (fabs(measure_result.car_front_theta) > 8.0)
  759. // {
  760. // res |= Range_status::Range_steering_wheel_nozero;
  761. // }
  762. res |= outOfRangeDetection(cloud, plate_cx, plate_cy, theta);
  763. return res;
  764. #else
  765. // LOG(WARNING) << m_range_status_last;
  766. // 车位位于y负方向,判断后轮超界情况
  767. double t_center_y = 0.0 - (car_uniform_center.y() + m_region.plc_offsety()); // 汽车中心y, 参照plc坐标,并且进行偏移, 绝对值。结果大约为 5~6左右
  768. if( t_center_y - 4.88 + 0.5*(measure_result.car_wheel_base - 2.7) < m_region.plc_border_maxy()-0.000 &&
  769. t_center_y - 4.88 - 0.5*(measure_result.car_wheel_base - 2.7) < m_region.plc_border_miny()-0.000 )
  770. {
  771. int t = Range_status::Range_back;
  772. m_range_status_last &= (~t);
  773. }
  774. else if( t_center_y - 4.88 + 0.5*(measure_result.car_wheel_base - 2.7) > m_region.plc_border_maxy()+0.010 ||
  775. t_center_y - 4.88 - 0.5*(measure_result.car_wheel_base - 2.7) > m_region.plc_border_miny()+0.010 )
  776. {
  777. m_range_status_last |= Range_status::Range_back;
  778. }
  779. //else m_range_status_last no change
  780. // LOG(WARNING) << m_range_status_last;
  781. // 判断车辆宽度超界情况
  782. if (measure_result.car_wheel_width < m_region.car_min_width()-0.000 ||
  783. measure_result.car_wheel_width > m_region.car_max_width()+0.000)
  784. {
  785. m_range_status_last |= Range_status::Range_car_width;
  786. }
  787. else if (measure_result.car_wheel_width > m_region.car_min_width()+0.010 &&
  788. measure_result.car_wheel_width < m_region.car_max_width()-0.010)
  789. {
  790. int t = Range_status::Range_car_width;
  791. m_range_status_last &= (~t);
  792. }
  793. //else m_range_status_last no change
  794. // LOG(WARNING) << m_range_status_last;
  795. // 判断车辆轴距超界情况
  796. if (measure_result.car_wheel_base < m_region.car_min_wheelbase()-0.000 ||
  797. measure_result.car_wheel_base > m_region.car_max_wheelbase()+0.000)
  798. {
  799. m_range_status_last |= Range_status::Range_car_wheelbase;
  800. }
  801. else if (measure_result.car_wheel_base > m_region.car_min_wheelbase()+0.010 ||
  802. measure_result.car_wheel_base < m_region.car_max_wheelbase()-0.010)
  803. {
  804. int t = Range_status::Range_car_wheelbase;
  805. m_range_status_last &= (~t);
  806. }
  807. //else m_range_status_last no change
  808. // LOG_IF(INFO, m_region.region_id() == 4) << m_range_status_last;
  809. // 判断车辆旋转角超界情况
  810. //huli new program 20221103, 使用 plc dispatch_1_statu_port 里面的 来做边界判断
  811. // double t_dtheta = 90-measure_result.car_angle; // 车身的旋转角, 修正到正负5度,
  812. double t_dtheta = measure_result.car_angle + m_region.plc_offset_degree(); // 车身的旋转角, 修正到正5度, (m_region.plc_offset_degree():-89)
  813. int t_terminal_id = m_region.region_id() +1; //region_id:0~5, terminal_id:1~6
  814. //turnplate_angle_min = -5, turnplate_angle_max = 5,
  815. if (t_dtheta > System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_max()+0.00)
  816. {
  817. m_range_status_last |= Range_status::Range_angle_anti_clock;
  818. }
  819. else if (t_dtheta < System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_max()-0.10)
  820. {
  821. int t = Range_status::Range_angle_anti_clock;
  822. m_range_status_last &= (~t);
  823. }
  824. // LOG_IF(INFO, m_region.region_id() == 4) << m_range_status_last;
  825. //else m_range_status_last no change
  826. if (t_dtheta < System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_min()-0.00)
  827. {
  828. m_range_status_last |= Range_status::Range_angle_clock;
  829. }
  830. else if (t_dtheta > System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_min()+0.10)
  831. {
  832. int t = Range_status::Range_angle_clock;
  833. m_range_status_last &= (~t);
  834. }
  835. // LOG_IF(INFO, m_region.region_id() == 4) << m_range_status_last <<", t_dtheta "<<t_dtheta<<", minmax: "<<System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_min()<<", "<<System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_max();
  836. // LOG(INFO) << t_dtheta<<", "<<System_communication_mq::get_instance_references().dispatch_region_info_map[t_terminal_id].turnplate_angle_min()<<std::endl;
  837. //else m_range_status_last no change
  838. m_range_status_last |= outOfRangeDetection(cloud, measure_result.car_center_x, measure_result.car_center_y, plate_cx, plate_cy, theta);
  839. return m_range_status_last;
  840. #endif
  841. }
  842. //外部调用获取当前车轮定位信息, 获取指令时间之后的车轮定位信息, 如果没有就会报错, 不会等待
  843. Error_manager Ground_region::get_current_wheel_information(Common_data::Car_wheel_information *p_car_wheel_information, std::chrono::system_clock::time_point command_time)
  844. {
  845. if ( p_car_wheel_information == NULL )
  846. {
  847. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  848. " POINTER IS NULL ");
  849. }
  850. //获取指令时间之后的信息, 如果没有就会报错, 不会等待
  851. if( m_detect_update_time > command_time )
  852. {
  853. std::lock_guard<std::mutex> lck(m_car_result_mutex);
  854. *p_car_wheel_information = m_car_wheel_information;
  855. if(m_car_wheel_information.correctness)
  856. return Error_code::SUCCESS;
  857. else
  858. return Error_manager(Error_code::VELODYNE_REGION_CERES_SOLVE_ERROR, Error_level::MINOR_ERROR, " Ground_region detect error");
  859. }
  860. else
  861. {
  862. return Error_manager(Error_code::VELODYNE_REGION_EMPTY_NO_WHEEL_INFORMATION, Error_level::MINOR_ERROR,
  863. " Ground_region::get_current_wheel_information error ");
  864. }
  865. }
  866. //外部调用获取最新的车轮定位信息, 获取指令时间往前一个周期内的车轮定位信息, 如果没有就会报错, 不会等待
  867. Error_manager Ground_region::get_last_wheel_information(Common_data::Car_wheel_information *p_car_wheel_information, std::chrono::system_clock::time_point command_time)
  868. {
  869. if ( p_car_wheel_information == NULL )
  870. {
  871. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  872. " POINTER IS NULL ");
  873. }
  874. //获取指令时间之后的信息, 如果没有就会报错, 不会等待
  875. // LOG(WARNING) << std::chrono::duration_cast<std::chrono::milliseconds>(command_time-m_detect_update_time).count()/1000.0 <<", "
  876. // <<std::chrono::duration_cast<std::chrono::milliseconds>(command_time-m_cloud_collection_time).count()/1000.0;
  877. if( m_detect_update_time > command_time - std::chrono::milliseconds(GROUND_REGION_DETECT_CYCLE_MS))
  878. {
  879. std::lock_guard<std::mutex> lck(m_car_result_mutex);
  880. *p_car_wheel_information = m_car_wheel_information;
  881. if(m_car_wheel_information.correctness)
  882. return Error_code::SUCCESS;
  883. else
  884. return Error_manager(Error_code::VELODYNE_REGION_CERES_SOLVE_ERROR, Error_level::MINOR_ERROR, " Ground_region detect error");
  885. }
  886. else
  887. {
  888. return Error_manager(Error_code::VELODYNE_REGION_EMPTY_NO_WHEEL_INFORMATION, Error_level::MINOR_ERROR,
  889. " Ground_region::get_current_wheel_information error ");
  890. }
  891. }
  892. Error_manager Ground_region::update_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
  893. {
  894. // // 点云z转90度,调试用
  895. //Eigen::AngleAxisd rot_z = Eigen::AngleAxisd(M_PI_2, Eigen::Vector3d::UnitZ());
  896. //for (size_t i = 0; i < cloud->size(); i++)
  897. //{
  898. // Eigen::Vector3d t_point(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
  899. // t_point = rot_z.toRotationMatrix() * t_point;
  900. // cloud->points[i].x = t_point.x();
  901. // cloud->points[i].y = t_point.y();
  902. // cloud->points[i].z = t_point.z();
  903. //}
  904. // 限定锁区域,解决因条件变量在析构时无法获得内部mutex导致此互斥锁卡住,造成死锁无法结束程序的问题。
  905. {
  906. std::lock_guard<std::mutex> lck(m_cloud_collection_mutex);
  907. mp_cloud_collection = cloud;
  908. // LOG(WARNING) << "update region cloud size: " << mp_cloud_collection->size() << ",,, input size: " << cloud->size();
  909. m_cloud_collection_time = std::chrono::system_clock::now();
  910. }
  911. m_measure_condition.notify_one(false, true);
  912. // std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  913. // std::chrono::duration<double> time_used_update = std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0);
  914. // std::cout << "update cloud time: " << time_used_update.count() << std::endl;
  915. return SUCCESS;
  916. }
  917. void Ground_region::thread_measure_func()
  918. {
  919. LOG(INFO) << " Ground_region::thread_measure_func() start " << this;
  920. while (m_measure_condition.is_alive())
  921. {
  922. m_measure_condition.wait();
  923. if (m_measure_condition.is_alive())
  924. {
  925. m_region_status = E_BUSY;
  926. detect_wheel_ceres3d::Detect_result t_result;
  927. Error_manager ec = detect(mp_cloud_collection, t_result);
  928. std::lock_guard<std::mutex> lck(m_car_result_mutex);
  929. m_detect_update_time = std::chrono::system_clock::now();
  930. // 增加滤波轴距
  931. Common_data::Car_wheel_information_stamped t_wheel_info_stamped;
  932. // 车辆移动检测
  933. Common_data::Car_wheel_information_stamped t_wheel_info_stamped_for_car_move;
  934. if (ec == SUCCESS)
  935. {
  936. m_car_wheel_information.correctness = true;
  937. m_car_wheel_information.car_center_x = t_result.cx;
  938. m_car_wheel_information.car_center_y = t_result.cy;
  939. m_car_wheel_information.car_angle = t_result.theta;
  940. m_car_wheel_information.car_wheel_base = t_result.wheel_base;
  941. m_car_wheel_information.car_wheel_width = t_result.width;
  942. m_car_wheel_information.car_front_theta = t_result.front_theta;
  943. // 220110 added by yct, single wheel width filtering
  944. m_car_wheel_information.single_wheel_width = t_result.single_wheel_width;
  945. m_car_wheel_information.single_wheel_length = t_result.single_wheel_length;
  946. m_car_wheel_information.theta_uniform(m_region.turnplate_cx(), m_region.turnplate_cy());
  947. // 超界校验
  948. {
  949. std::lock_guard<std::mutex> lck(m_filtered_cloud_mutex);
  950. int res = outOfRangeDetection(mp_cloud_filtered, m_car_wheel_information, m_region.turnplate_cx(), m_region.turnplate_cy(), 90.0 - t_result.theta);
  951. m_car_wheel_information.range_status = res;
  952. // LOG_IF(INFO, m_region.region_id() == 4) << res;
  953. }
  954. // 添加plc偏移
  955. m_car_wheel_information.car_center_x += m_region.plc_offsetx();
  956. m_car_wheel_information.car_center_y += m_region.plc_offsety();
  957. m_car_wheel_information.uniform_car_x += m_region.plc_offsetx();
  958. m_car_wheel_information.uniform_car_y += m_region.plc_offsety();
  959. m_car_wheel_information.car_angle += m_region.plc_offset_degree();
  960. // LOG(INFO) << "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy t_result.theta = " << t_result.theta << " ";
  961. // LOG(INFO) << "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy m_region.plc_offset_degree() = " << m_region.plc_offset_degree() << " ";
  962. // LOG(INFO) << "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy m_car_wheel_information.car_angle= " << m_car_wheel_information.car_angle << " ";
  963. t_wheel_info_stamped.wheel_data = m_car_wheel_information;
  964. t_wheel_info_stamped.measure_time = m_detect_update_time;
  965. Measure_filter::get_instance_references().update_data(m_region.region_id(), t_wheel_info_stamped);
  966. // 20211228 added by yct, car movement checking, human and door detection
  967. t_wheel_info_stamped_for_car_move = t_wheel_info_stamped;
  968. t_wheel_info_stamped_for_car_move.wheel_data.car_center_x -= m_region.plc_offsetx();
  969. t_wheel_info_stamped_for_car_move.wheel_data.car_center_y -= m_region.plc_offsety();
  970. t_wheel_info_stamped_for_car_move.wheel_data.uniform_car_x -= m_region.plc_offsetx();
  971. t_wheel_info_stamped_for_car_move.wheel_data.uniform_car_y -= m_region.plc_offsety();
  972. t_wheel_info_stamped_for_car_move.wheel_data.car_angle -= m_region.plc_offset_degree();
  973. Error_manager car_status_res = Region_status_checker::get_instance_references().get_region_parking_status(m_region.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_filtered);
  974. // success means car stable
  975. if(car_status_res == SUCCESS)
  976. {
  977. m_car_wheel_information.range_status &= ~((int)Range_status::Range_car_moving);
  978. }else
  979. {
  980. m_car_wheel_information.range_status |= Range_status::Range_car_moving;
  981. // if(m_region.region_id()==4){
  982. // std::cout<<"success: "<<car_status_res.to_string()<<std::endl;
  983. // }
  984. }
  985. Region_status_checker::get_instance_references().add_measure_data(m_region.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_filtered);
  986. ec = Measure_filter::get_instance_references().get_filtered_wheel_information(m_region.region_id(), t_wheel_info_stamped.wheel_data);
  987. if (ec == SUCCESS)
  988. {
  989. // 20221208 added by yct, use avg car angle and width data.
  990. // LOG(WARNING)<<m_region.region_id()<<" angles: "<<m_car_wheel_information.car_angle<<", "<<t_wheel_info_stamped.wheel_data.car_angle;
  991. // LOG(WARNING)<<m_region.region_id()<<" filter res: "<<t_wheel_info_stamped.wheel_data.to_string()<<std::endl;
  992. // m_car_wheel_information.car_angle = t_wheel_info_stamped.wheel_data.car_angle;
  993. // m_car_wheel_information.car_wheel_width = t_wheel_info_stamped.wheel_data.car_wheel_width;
  994. m_car_wheel_information.car_wheel_base = t_wheel_info_stamped.wheel_data.car_wheel_base;
  995. m_car_wheel_information.car_front_theta = t_wheel_info_stamped.wheel_data.car_front_theta;
  996. // 临时添加,滤波后前轮超界
  997. if(fabs(m_car_wheel_information.car_front_theta)>8.0)
  998. {
  999. m_car_wheel_information.range_status |= Range_status::Range_steering_wheel_nozero;
  1000. }
  1001. }
  1002. // else{
  1003. // std::cout<<ec.to_string()<<std::endl;
  1004. // }
  1005. // LOG_IF(INFO, m_region.region_id() == 4) << m_car_wheel_information.to_string();
  1006. }
  1007. // rough angle too large, display for pre-movement
  1008. else if(ec.get_error_code() == VELODYNE_REGION_ANGLE_PRECHECK_FAILED)
  1009. {
  1010. m_car_wheel_information.correctness = false;
  1011. m_car_wheel_information.car_center_x = t_result.cx;
  1012. m_car_wheel_information.car_center_y = t_result.cy;
  1013. m_car_wheel_information.car_angle = t_result.theta;
  1014. m_car_wheel_information.car_wheel_base = 0.0;
  1015. m_car_wheel_information.car_wheel_width = 0.0;
  1016. m_car_wheel_information.car_front_theta = 0.0;
  1017. // 220110 added by yct, single wheel width filtering
  1018. m_car_wheel_information.single_wheel_width = 0.0;
  1019. m_car_wheel_information.single_wheel_length = 0.0;
  1020. // 添加plc偏移
  1021. m_car_wheel_information.car_center_x += m_region.plc_offsetx();
  1022. m_car_wheel_information.car_center_y += m_region.plc_offsety();
  1023. m_car_wheel_information.uniform_car_x += m_region.plc_offsetx();
  1024. m_car_wheel_information.uniform_car_y += m_region.plc_offsety();
  1025. m_car_wheel_information.theta_uniform(m_region.turnplate_cx(), m_region.turnplate_cy());
  1026. m_car_wheel_information.range_status |= m_car_wheel_information.car_angle<0?Range_status::Range_angle_clock:Range_status::Range_angle_anti_clock;
  1027. }
  1028. else
  1029. {
  1030. m_car_wheel_information.correctness = false;
  1031. // LOG_IF(ERROR, m_region.region_id() == 1) << ec.to_string();
  1032. // 20211228 added by yct, car movement checking, human and door detection
  1033. Error_manager car_status_res = Region_status_checker::get_instance_references().get_region_parking_status(m_region.region_id(), t_wheel_info_stamped_for_car_move, *mp_cloud_filtered);
  1034. // success means car stable
  1035. if(car_status_res == SUCCESS)
  1036. {
  1037. m_car_wheel_information.range_status &= ~((int)Range_status::Range_car_moving);
  1038. }else
  1039. {
  1040. m_car_wheel_information.range_status |= Range_status::Range_car_moving;
  1041. // if(m_region.region_id()==1){
  1042. // std::cout<<"failed: "<<car_status_res.to_string()<<std::endl;
  1043. // }
  1044. }
  1045. }
  1046. }
  1047. m_region_status = E_READY;
  1048. }
  1049. LOG(INFO) << " Ground_region::thread_measure_func() end " << this;
  1050. }