wj_716_lidar_protocol.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. #include "wj_716_lidar_protocol.h"
  2. #include <iostream>
  3. //#include "../tool/proto_tool.h"
  4. Wj_716_lidar_protocol::Wj_716_lidar_protocol()
  5. {
  6. m_wanji_lidar_protocol_status = E_UNKNOWN;
  7. mp_communication_data_queue = NULL;
  8. memset(m_scan_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  9. memset(m_scan_point_intensity, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  10. memset(m_two_echo_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  11. m_current_frame_number = 0;
  12. mp_scan_points = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  13. mp_two_echo_points = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  14. mp_thread_analysis = NULL;
  15. // 设置初始时间为昨天,以避免第一次点云更新前获取到空点云
  16. m_scan_cloud_time = std::chrono::system_clock::now() - std::chrono::duration<int, std::ratio<60 * 60 * 24>>(1);
  17. m_two_echo_cloud_time =
  18. std::chrono::system_clock::now() - std::chrono::duration<int, std::ratio<60 * 60 * 24>>(1);
  19. memset(&m_polar_coordinates_box, 0, sizeof(Point2D_tool::Polar_coordinates_box));
  20. memset(&m_point2D_box, 0, sizeof(Point2D_tool::Point2D_box));
  21. memset(&m_point2D_transform, 0, sizeof(Point2D_tool::Point2D_transform));
  22. mp_thread_analysis = NULL;
  23. }
  24. Wj_716_lidar_protocol::~Wj_716_lidar_protocol()
  25. {
  26. uninit();
  27. }
  28. // 初始化
  29. Error_manager Wj_716_lidar_protocol::init(Thread_safe_queue<Binary_buf *> *p_communication_data_queue,
  30. Point2D_tool::Polar_coordinates_box polar_coordinates_box,
  31. Point2D_tool::Point2D_box point2D_box,
  32. Point2D_tool::Point2D_transform point2D_transform)
  33. {
  34. if (p_communication_data_queue == NULL)
  35. {
  36. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  37. " POINTER IS NULL ");
  38. }
  39. mp_communication_data_queue = p_communication_data_queue;
  40. m_polar_coordinates_box = polar_coordinates_box;
  41. m_point2D_box = point2D_box;
  42. m_point2D_transform = point2D_transform;
  43. //接受线程, 默认开启循环, 在内部的wait_and_pop进行等待
  44. m_condition_analysis.reset(false, true, false);
  45. mp_thread_analysis = new std::thread(&Wj_716_lidar_protocol::thread_analysis, this);
  46. m_wanji_lidar_protocol_status = E_READY;
  47. return Error_code::SUCCESS;
  48. }
  49. //反初始化
  50. Error_manager Wj_716_lidar_protocol::uninit()
  51. {
  52. LOG(INFO) << " ---Wj_716_lidar_protocol uninit --- "<< this;
  53. if ( mp_communication_data_queue )
  54. {
  55. //终止队列,防止 wait_and_pop 阻塞线程。
  56. mp_communication_data_queue->termination_queue();
  57. }
  58. //关闭线程
  59. if (mp_thread_analysis)
  60. {
  61. m_condition_analysis.kill_all();
  62. }
  63. //回收线程的资源
  64. if (mp_thread_analysis)
  65. {
  66. mp_thread_analysis->join();
  67. delete mp_thread_analysis;
  68. mp_thread_analysis = NULL;
  69. }
  70. if ( mp_communication_data_queue )
  71. {
  72. //清空队列
  73. mp_communication_data_queue->clear_and_delete();
  74. }
  75. //队列的内存由上级管理, 这里写空就好了.
  76. mp_communication_data_queue = NULL;
  77. if ( m_wanji_lidar_protocol_status != E_FAULT )
  78. {
  79. m_wanji_lidar_protocol_status = E_UNKNOWN;
  80. }
  81. return Error_code::SUCCESS;
  82. }
  83. //检查状态
  84. Error_manager Wj_716_lidar_protocol::check_status()
  85. {
  86. if ( m_wanji_lidar_protocol_status == E_READY )
  87. {
  88. return Error_code::SUCCESS;
  89. }
  90. else
  91. {
  92. return Error_manager(Error_code::WJ_PROTOCOL_STATUS_ERROR, Error_level::MINOR_ERROR,
  93. " Wj_716_lidar_protocol::check_status() error ");
  94. }
  95. }
  96. //判断是否为待机,如果已经准备好,则可以执行任务。
  97. bool Wj_716_lidar_protocol::is_ready()
  98. {
  99. if ( m_wanji_lidar_protocol_status == E_READY )
  100. {
  101. return true;
  102. }
  103. else
  104. {
  105. return false;
  106. }
  107. }
  108. //获取状态
  109. Wj_716_lidar_protocol::Wanji_lidar_protocol_status Wj_716_lidar_protocol::get_status()
  110. {
  111. return m_wanji_lidar_protocol_status;
  112. }
  113. //获取扫描周期
  114. int Wj_716_lidar_protocol::get_scan_cycle()
  115. {
  116. return WANJI_FRAME_SCAN_CYCLE_MS;
  117. }
  118. //获取扫描点云
  119. Error_manager Wj_716_lidar_protocol::get_scan_points(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_out)
  120. {
  121. if ( p_cloud_out.get() == NULL )
  122. {
  123. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  124. " Wj_716_lidar_protocol::get_scan_points POINTER IS NULL ");
  125. }
  126. std::unique_lock<std::mutex> lck(m_scan_mutex);
  127. //将扫描点云追加到p_cloud_out后面, 不要清除p_cloud_out原有的数据
  128. (*p_cloud_out)+=(*mp_scan_points);
  129. return Error_code::SUCCESS;
  130. }
  131. //获取二次回波点云
  132. Error_manager Wj_716_lidar_protocol::get_two_echo_points(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_out)
  133. {
  134. if ( p_cloud_out.get() == NULL )
  135. {
  136. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  137. " Wj_716_lidar_protocol::get_two_echo_points POINTER IS NULL ");
  138. }
  139. std::unique_lock<std::mutex> lck(m_two_echo_mutex);
  140. //将扫描点云追加到p_cloud_out后面, 不要清除p_cloud_out原有的数据
  141. (*p_cloud_out)+=(*mp_two_echo_points);
  142. return Error_code::SUCCESS;
  143. }
  144. /**
  145. * 获取更新扫描点云时间
  146. * */
  147. std::chrono::system_clock::time_point Wj_716_lidar_protocol::get_scan_time()
  148. {
  149. std::unique_lock<std::mutex> lck(m_scan_mutex);
  150. return m_scan_cloud_time;
  151. }
  152. /**
  153. * 获取更新二次回波时间
  154. * */
  155. std::chrono::system_clock::time_point Wj_716_lidar_protocol::get_two_echo_time()
  156. {
  157. std::unique_lock<std::mutex> lck(m_two_echo_mutex);
  158. return m_two_echo_cloud_time;
  159. }
  160. //解析线程函数
  161. void Wj_716_lidar_protocol::thread_analysis()
  162. {
  163. LOG(INFO) << " ---Wj_716_lidar_protocol::thread_analysis start ---" << this;
  164. Error_manager t_error;
  165. //接受雷达消息,包括连接,重连和接受数据
  166. while (m_condition_analysis.is_alive())
  167. {
  168. m_condition_analysis.wait();
  169. if (m_condition_analysis.is_alive())
  170. {
  171. std::this_thread::yield();
  172. if (mp_communication_data_queue == NULL)
  173. {
  174. m_wanji_lidar_protocol_status = E_FAULT;
  175. }
  176. else
  177. {
  178. Binary_buf *tp_binary_buf = NULL;
  179. bool is_pop = mp_communication_data_queue->wait_and_pop(tp_binary_buf);
  180. if (is_pop == true && tp_binary_buf != NULL)
  181. {
  182. //检查数据头和长度,
  183. if (check_head_and_length(tp_binary_buf))
  184. {
  185. // 消息完整性检查, 检查末尾的校验码,
  186. if (check_xor(tp_binary_buf))
  187. {
  188. //至此, 我们确认消息已经被正常的接受, 后续错误就不可
  189. // 万集通信协议, 解析数据, 转化为点云
  190. t_error = data_protocol_analysis(tp_binary_buf);
  191. //暂时不管错误
  192. }
  193. //else 错误不管, 当做无效消息处理
  194. }
  195. //else 错误不管, 当做无效消息处理
  196. delete(tp_binary_buf);
  197. }
  198. }
  199. }
  200. }
  201. LOG(INFO) << " -Wj_716_lidar_protocol::thread_analysis end :" << this;
  202. return;
  203. }
  204. //检查数据头和长度, 注:返回失败只是表示消息格式不对不是需要处理的消息, 忽略就好了
  205. bool Wj_716_lidar_protocol::check_head_and_length(Binary_buf *p_binary_buf)
  206. {
  207. //检查总长度, 716固定为898byte
  208. if (p_binary_buf->get_length() != WANJI_FRAME_LENGTH_716)
  209. {
  210. return false;
  211. }
  212. char *tp_data = p_binary_buf->get_buf();
  213. //检查数据头, 716的前4个字节固定为0x02020202
  214. if (tp_data[0] == 0x02 && tp_data[1] == 0x02 && tp_data[2] == 0x02 && tp_data[3] == 0x02)
  215. {
  216. //4~7字节合并为32位的int, 是数据消息里面的长度值, 不包括数据头(4byte) 长度(4byte) 尾部校验码(1byte)
  217. unsigned int l_u32reallen = (tp_data[4] << 24) |
  218. (tp_data[5] << 16) |
  219. (tp_data[6] << 8) |
  220. (tp_data[7] << 0);
  221. if (l_u32reallen + 9 == WANJI_FRAME_LENGTH_716)
  222. {
  223. return true;
  224. }
  225. else
  226. {
  227. return false;
  228. }
  229. }
  230. else
  231. {
  232. return false;
  233. }
  234. }
  235. // 消息完整性检查, 检查末尾的校验码, 注:返回失败只是表示消息格式不对不是需要处理的消息, 忽略就好了
  236. bool Wj_716_lidar_protocol::check_xor(Binary_buf *p_binary_buf)
  237. {
  238. int i = 0;
  239. char check = 0;
  240. //校验码的运算, 就是把中间所有的数据异或, 不包括数据头(4byte) 长度(4byte) 尾部校验码(1byte)
  241. char *tp_data = p_binary_buf->get_buf() + 8;
  242. int t_length = p_binary_buf->get_length() - 9;
  243. for (i = 0; i < t_length; i++)
  244. {
  245. check ^= *tp_data++;
  246. //后++, tp_data在最后 还会右移一个
  247. }
  248. if (check == *tp_data)
  249. {
  250. return true;
  251. }
  252. else
  253. {
  254. return false;
  255. }
  256. }
  257. // 万集通信协议, 解析数据, 转化为点云
  258. Error_manager Wj_716_lidar_protocol::data_protocol_analysis(Binary_buf *p_binary_buf)
  259. {
  260. Error_manager t_error;
  261. char *data = p_binary_buf->get_buf();
  262. int len = p_binary_buf->get_length();
  263. //消息指令类型判断, data[8] == 0x73 为数据类型, data[9] == 0x52||0x53 为传输方向(发送或接受)
  264. if ((data[8] == 0x73 && data[9] == 0x52) ||
  265. (data[8] == 0x73 && data[9] == 0x53)) //command type:0x73(s) 0x52/0X53(R/S)
  266. {
  267. //716雷达扫描的数据量很大, 一次完整的扫描信息分成了6条消息分开发送,
  268. //数据的包号l_n32PackageNo, 实际为1~6, 无限循环, 循环完毕后,6条加起来就是一个完整的雷达扫描数据
  269. //奇数包发送前面的405个点的数据, 偶数包发送后面406个点的数据
  270. int l_n32PackageNo = (data[50] << 8) + data[51];
  271. //数据的帧号l_u32FrameNo, 实际为0~2^32, 相同帧号的6条消息表示这6条是雷达一次扫描的完整消息,
  272. unsigned int l_u32FrameNo = (data[46] << 24) + (data[47] << 16) + (data[48] << 8) + data[49];
  273. //1~2包为扫描点到雷达的距离, 405+406 = 811,
  274. if (l_n32PackageNo == 1)
  275. {
  276. //重置当前的帧号, 清空数据, 防止出错后复用上一次的数据.
  277. m_current_frame_number = l_u32FrameNo;
  278. memset(m_scan_point_intensity, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  279. memset(m_scan_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  280. memset(m_two_echo_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL);
  281. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i)
  282. {
  283. m_scan_point_distance[i] =
  284. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  285. m_scan_point_distance[i] /= 1000.0;//毫米->米
  286. //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据)
  287. if (m_scan_point_distance[i] >= 25 || m_scan_point_distance[i] == 0)
  288. {
  289. m_scan_point_distance[i] = NAN;
  290. }
  291. }
  292. }
  293. else if (l_n32PackageNo == 2)
  294. {
  295. //检查帧号的一致性
  296. if (m_current_frame_number == l_u32FrameNo)
  297. {
  298. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i)
  299. {
  300. m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] =
  301. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  302. m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] /= 1000.0;//毫米->米
  303. //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据)
  304. if (m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] >= 25 ||
  305. m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] == 0)
  306. {
  307. m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = NAN;
  308. }
  309. }
  310. //至此就得到了扫描点到雷达的距离, 如有需要, 可以再此使用
  311. //数据加锁的范围
  312. {
  313. std::unique_lock<std::mutex> lck(m_scan_mutex);
  314. mp_scan_points->clear();
  315. // 把点到雷达的距离, 转化为标准坐标下的点云
  316. t_error = polar_coordinates_transform_cloud(m_scan_point_distance,
  317. WANJI_SCAN_POINT_NUMBER_TOTAL, mp_scan_points);
  318. m_scan_cloud_time = std::chrono::system_clock::now();
  319. }
  320. }
  321. else
  322. {
  323. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  324. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  325. }
  326. }
  327. //1~2包为扫描点的光强, 405+406 = 811,
  328. else if (l_n32PackageNo == 3)
  329. {
  330. //检查帧号的一致性
  331. if (m_current_frame_number == l_u32FrameNo)
  332. {
  333. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i)
  334. {
  335. m_scan_point_intensity[i] =
  336. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  337. }
  338. }
  339. else
  340. {
  341. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  342. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  343. }
  344. }
  345. else if (l_n32PackageNo == 4)
  346. {
  347. //检查帧号的一致性
  348. if (m_current_frame_number == l_u32FrameNo)
  349. {
  350. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i)
  351. {
  352. m_scan_point_intensity[WANJI_SCAN_POINT_NUMBER_FORMER + i] =
  353. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  354. }
  355. //至此就得到了扫描点的光强, 如有需要, 可以再此使用
  356. }
  357. else
  358. {
  359. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  360. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  361. }
  362. }
  363. else if (l_n32PackageNo == 5)
  364. {
  365. //检查帧号的一致性
  366. if (m_current_frame_number == l_u32FrameNo)
  367. {
  368. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i)
  369. {
  370. m_two_echo_point_distance[i] =
  371. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  372. m_two_echo_point_distance[i] /= 1000.0;//毫米->米
  373. //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据)
  374. if (m_two_echo_point_distance[i] >= 25 || m_two_echo_point_distance[i] == 0)
  375. {
  376. m_two_echo_point_distance[i] = NAN;
  377. }
  378. }
  379. }
  380. else
  381. {
  382. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  383. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  384. }
  385. }
  386. else if (l_n32PackageNo == 6)
  387. {
  388. //检查帧号的一致性
  389. if (m_current_frame_number == l_u32FrameNo)
  390. {
  391. for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i)
  392. {
  393. m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] =
  394. (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]);
  395. m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] /= 1000.0;//毫米->米
  396. //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据)
  397. if (m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] >= 25 ||
  398. m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] == 0)
  399. {
  400. m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = NAN;
  401. }
  402. }
  403. //至此就得到了二次反射的扫描点到雷达的距离, 如有需要, 可以再此使用
  404. //数据加锁的范围
  405. {
  406. std::unique_lock<std::mutex> lck(m_two_echo_mutex);
  407. mp_two_echo_points->clear();
  408. // 把点到雷达的距离, 转化为标准坐标下的点云
  409. t_error = polar_coordinates_transform_cloud(m_two_echo_point_distance,
  410. WANJI_SCAN_POINT_NUMBER_TOTAL, mp_two_echo_points);
  411. m_two_echo_cloud_time = std::chrono::system_clock::now();
  412. }
  413. }
  414. else
  415. {
  416. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  417. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  418. }
  419. }
  420. return Error_manager(Error_code::SUCCESS);
  421. }
  422. else
  423. {
  424. return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR,
  425. " Wj_716_lidar_protocol::data_protocol_analysis parse failed ");
  426. }
  427. return Error_code::SUCCESS;
  428. }
  429. // 把点到雷达的距离, 转化为标准坐标下的点云
  430. Error_manager Wj_716_lidar_protocol::polar_coordinates_transform_cloud(float *p_point_distance, int number,
  431. pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_out)
  432. {
  433. if (p_point_distance == NULL || p_cloud_out.get() == NULL)
  434. {
  435. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  436. " POINTER IS NULL ");
  437. }
  438. else
  439. {
  440. pcl::PointXYZ point;
  441. for (int i = 0; i < number; ++i)
  442. {
  443. float angle = WANJI_SCAN_POINT_ANGLE_MIN + i * WANJI_SCAN_POINT_ANGLE_INCREMENT;
  444. //判断极坐标点是否在限制范围
  445. if (Point2D_tool::limit_with_polar_coordinates_box(p_point_distance[i], angle,
  446. &m_polar_coordinates_box))
  447. {
  448. //极坐标 -> 平面坐标
  449. float x = p_point_distance[i] * cos(angle);
  450. float y = p_point_distance[i] * sin(angle);
  451. //判断平面坐标点是否在限制范围
  452. if (Point2D_tool::limit_with_point2D_box(x, y, &m_point2D_box))
  453. {
  454. //平面坐标的转换, 可以进行旋转和平移, 不能缩放
  455. point.x = x * m_point2D_transform.m00 + y * m_point2D_transform.m01 + m_point2D_transform.m02;
  456. point.y = x * m_point2D_transform.m10 + y * m_point2D_transform.m11 + m_point2D_transform.m12;
  457. //添加到最终点云
  458. p_cloud_out->push_back(point);
  459. }
  460. //else直接忽略
  461. }
  462. //else直接忽略
  463. }
  464. }
  465. return Error_code::SUCCESS;
  466. }