wanji_lidar_device.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. #include "wanji_lidar_device.h"
  2. // 万集雷达封装类构造函数
  3. Wanji_lidar_device::Wanji_lidar_device()
  4. {
  5. m_wanji_lidar_device_status = E_UNKNOWN;
  6. mp_wanji_lidar_scan_task = NULL;
  7. }
  8. // 万集雷达封装类析构函数
  9. Wanji_lidar_device::~Wanji_lidar_device()
  10. {
  11. uninit();
  12. }
  13. // 初始化
  14. Error_manager Wanji_lidar_device::init(wj::wjLidarParams params)
  15. {
  16. Error_manager t_error;
  17. LOG(INFO) << " Wanji_lidar_device::init "<< this;
  18. //唤醒队列
  19. m_communication_data_queue.wake_queue();
  20. //控制参数
  21. Point2D_tool::Polar_coordinates_box t_polar_coordinates_box; //极坐标的限定范围
  22. Point2D_tool::Point2D_box t_point2D_box; //平面坐标的限定范围
  23. Point2D_tool::Point2D_transform t_point2D_transform; //平面坐标的转换矩阵
  24. t_polar_coordinates_box.angle_min = params.angle_min();
  25. t_polar_coordinates_box.angle_max = params.angle_max();
  26. t_polar_coordinates_box.distance_min = params.range_min();
  27. t_polar_coordinates_box.distance_max = params.range_max();
  28. t_point2D_box.x_min = params.scan_limit().minx();
  29. t_point2D_box.x_max = params.scan_limit().maxx();
  30. t_point2D_box.y_min = params.scan_limit().miny();
  31. t_point2D_box.y_max = params.scan_limit().maxy();
  32. t_point2D_transform.m00 = params.transform().m00();
  33. t_point2D_transform.m01 = params.transform().m01();
  34. t_point2D_transform.m02 = params.transform().m02();
  35. t_point2D_transform.m10 = params.transform().m10();
  36. t_point2D_transform.m11 = params.transform().m11();
  37. t_point2D_transform.m12 = params.transform().m12();
  38. //初始化通信协议
  39. t_error = m_protocol.init(&m_communication_data_queue, t_polar_coordinates_box, t_point2D_box, t_point2D_transform);
  40. if (t_error != SUCCESS)
  41. {
  42. return t_error;
  43. }
  44. //初始化雷达通信模块
  45. std::string t_ip = params.net_config().ip_address();
  46. int t_port = params.net_config().port();
  47. t_error = m_async_client.init(t_ip, t_port, &m_communication_data_queue);
  48. if ( t_error != SUCCESS )
  49. {
  50. return t_error;
  51. }
  52. //启动 内部线程。默认wait。
  53. m_execute_condition.reset(false, false, false);
  54. mp_execute_thread = new std::thread(&Wanji_lidar_device::execute_thread_fun, this);
  55. m_wanji_lidar_device_status = E_READY;
  56. return t_error;
  57. }
  58. //反初始化
  59. Error_manager Wanji_lidar_device::uninit()
  60. {
  61. //终止队列,防止 wait_and_pop 阻塞线程。
  62. m_communication_data_queue.termination_queue();
  63. //关闭线程
  64. if (mp_execute_thread)
  65. {
  66. m_execute_condition.kill_all();
  67. }
  68. //回收线程的资源
  69. if (mp_execute_thread)
  70. {
  71. mp_execute_thread->join();
  72. delete mp_execute_thread;
  73. mp_execute_thread = NULL;
  74. }
  75. m_async_client.uninit();
  76. m_protocol.uninit();
  77. //清空队列
  78. m_communication_data_queue.clear_and_delete();
  79. if ( m_wanji_lidar_device_status != E_FAULT )
  80. {
  81. m_wanji_lidar_device_status = E_UNKNOWN;
  82. }
  83. return Error_code::SUCCESS;
  84. }
  85. //对外的接口函数,负责接受并处理任务单,
  86. Error_manager Wanji_lidar_device::execute_task(Task_Base* p_wanji_lidar_scan_task)
  87. {
  88. LOG(INFO) << " ---Laser_manager::execute_task run--- "<< this;
  89. Error_manager t_error;
  90. Error_manager t_result;
  91. //检查指针
  92. if (p_wanji_lidar_scan_task == NULL) {
  93. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  94. "Wanji_lidar_device::execute_task failed, POINTER_IS_NULL");
  95. }
  96. //检查任务类型,
  97. if (p_wanji_lidar_scan_task->get_task_type() != WANJI_LIDAR_SCAN)
  98. {
  99. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
  100. " task type error != WANJI_LIDAR_SCAN ");
  101. }
  102. //检查接收方的状态
  103. t_error = check_status();
  104. if ( t_error != SUCCESS )
  105. {
  106. t_result.compare_and_cover_error(t_error);
  107. }
  108. else
  109. {
  110. //接受任务,并将任务的状态改为TASK_SIGNED已签收
  111. mp_wanji_lidar_scan_task = (Wanji_lidar_scan_task *) p_wanji_lidar_scan_task;
  112. mp_wanji_lidar_scan_task->set_task_statu(TASK_SIGNED);
  113. //检查消息内容是否正确,
  114. //检查三维点云指针
  115. if (mp_wanji_lidar_scan_task->get_task_point_cloud().get() == NULL)
  116. {
  117. t_error.error_manager_reset(Error_code::POINTER_IS_NULL,
  118. Error_level::MINOR_ERROR,
  119. "execute_task mp_task_point_cloud is null");
  120. t_result.compare_and_cover_error(t_error);
  121. }
  122. else if ( mp_wanji_lidar_scan_task->get_task_cloud_lock() == NULL )
  123. {
  124. t_error.error_manager_reset(Error_code::POINTER_IS_NULL,
  125. Error_level::MINOR_ERROR,
  126. "execute_task mp_task_cloud_lock is null");
  127. t_result.compare_and_cover_error(t_error);
  128. }
  129. else
  130. {
  131. m_wanji_lidar_device_status = E_BUSY;
  132. //启动雷达管理模块,的核心工作线程
  133. m_execute_condition.notify_all(true);
  134. //通知 thread_work 子线程启动。
  135. //将任务的状态改为 TASK_WORKING 处理中
  136. mp_wanji_lidar_scan_task->set_task_statu(TASK_WORKING);
  137. }
  138. //return 之前要填充任务单里面的错误码.
  139. if (t_result != Error_code::SUCCESS)
  140. {
  141. //忽略轻微故障
  142. if ( t_result.get_error_level() >= Error_level::MINOR_ERROR)
  143. {
  144. //将任务的状态改为 TASK_ERROR 结束错误
  145. mp_wanji_lidar_scan_task->set_task_statu(TASK_ERROR);
  146. }
  147. //返回错误码
  148. mp_wanji_lidar_scan_task->compare_and_cover_task_error_manager(t_result);
  149. }
  150. }
  151. return t_result;
  152. }
  153. //检查雷达状态,是否正常运行
  154. Error_manager Wanji_lidar_device::check_status()
  155. {
  156. updata_status();
  157. if ( m_wanji_lidar_device_status == E_READY )
  158. {
  159. return Error_code::SUCCESS;
  160. }
  161. else if(m_wanji_lidar_device_status == E_BUSY)
  162. {
  163. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
  164. " Wanji_lidar_device::check_status() error ");
  165. }
  166. else
  167. {
  168. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_STATUS_ERROR, Error_level::MINOR_ERROR,
  169. " Wanji_lidar_device::check_status() error ");
  170. }
  171. return Error_code::SUCCESS;
  172. }
  173. //结束任务单,里面会根据任务的故障等级修正雷达管理模块的状态和任务单的状态
  174. Error_manager Wanji_lidar_device::end_task()
  175. {
  176. m_execute_condition.notify_all(false);
  177. if ( m_wanji_lidar_device_status == E_BUSY)
  178. {
  179. m_wanji_lidar_device_status = E_READY;
  180. }
  181. //else 状态不变
  182. //在结束任务单时,将雷达任务状态改为 TASK_OVER 已结束
  183. if(mp_wanji_lidar_scan_task !=NULL)
  184. {
  185. //判断任务单的错误等级,
  186. if ( mp_wanji_lidar_scan_task->get_task_error_manager().get_error_level() < Error_level::MINOR_ERROR)
  187. {
  188. //强制改为TASK_OVER,不管它当前在做什么。
  189. mp_wanji_lidar_scan_task->set_task_statu(TASK_OVER);
  190. }
  191. else
  192. {
  193. //强制改为 TASK_ERROR,不管它当前在做什么。
  194. mp_wanji_lidar_scan_task->set_task_statu(TASK_ERROR);
  195. }
  196. }
  197. return Error_code::SUCCESS;
  198. }
  199. //取消任务单,由发送方提前取消任务单
  200. Error_manager Wanji_lidar_device::cancel_task(Task_Base* p_wanji_lidar_scan_task)
  201. {
  202. if ( p_wanji_lidar_scan_task == mp_wanji_lidar_scan_task )
  203. {
  204. m_execute_condition.notify_all(false);
  205. if ( m_wanji_lidar_device_status == E_BUSY)
  206. {
  207. m_wanji_lidar_device_status = E_READY;
  208. }
  209. //else 状态不变
  210. //强制改为 TASK_DEAD,不管它当前在做什么。
  211. mp_wanji_lidar_scan_task->set_task_statu(TASK_DEAD);
  212. return Error_code::SUCCESS;
  213. }
  214. else
  215. {
  216. return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR,
  217. " Wanji_lidar_device::cancel_task PARAMRTER ERROR ");
  218. }
  219. }
  220. //判断是否为待机,如果已经准备好,则可以执行任务。
  221. bool Wanji_lidar_device::is_ready()
  222. {
  223. updata_status();
  224. return m_wanji_lidar_device_status == E_READY;
  225. }
  226. //外部调用获取新的点云, 获取指令时间之后的点云, 如果没有就会等待点云刷新, 直到超时, (内置while)
  227. Error_manager Wanji_lidar_device::get_new_cloud_and_wait(std::mutex* p_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud,
  228. std::chrono::system_clock::time_point command_time, int timeout_ms)
  229. {
  230. if ( p_mutex == NULL || p_cloud.get() == NULL )
  231. {
  232. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  233. " POINTER IS NULL ");
  234. }
  235. //判断是否超时
  236. while (std::chrono::system_clock::now() - command_time < std::chrono::milliseconds(timeout_ms))
  237. {
  238. //获取指令时间之后的点云, 如果没有就会循环
  239. if( m_protocol.get_scan_time() > command_time )
  240. {
  241. std::unique_lock<std::mutex> lck(*p_mutex);
  242. Error_manager code = m_protocol.get_scan_points(p_cloud);
  243. return code;
  244. }
  245. //else 等待下一次数据更新
  246. //等1ms
  247. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  248. }
  249. //超时退出就报错
  250. return Error_manager(Error_code::WJ_LIDAR_GET_CLOUD_TIMEOUT, Error_level::MINOR_ERROR,
  251. " Wanji_lidar_device::get_new_cloud_and_wait error ");
  252. }
  253. //外部调用获取当前点云, 获取指令时间之后的点云, 如果没有就会报错, 不会等待
  254. Error_manager Wanji_lidar_device::get_current_cloud(std::mutex* p_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud,
  255. std::chrono::system_clock::time_point command_time)
  256. {
  257. if ( p_mutex == NULL || p_cloud.get() == NULL )
  258. {
  259. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  260. " POINTER IS NULL ");
  261. }
  262. //获取指令时间之后的点云, 如果没有就会报错, 不会等待
  263. if( m_protocol.get_scan_time() > command_time )
  264. {
  265. std::unique_lock<std::mutex> lck(*p_mutex);
  266. Error_manager code = m_protocol.get_scan_points(p_cloud);
  267. return code;
  268. }
  269. else
  270. {
  271. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_NO_CLOUD, Error_level::MINOR_ERROR,
  272. " Wanji_lidar_device::get_current_cloud error ");
  273. }
  274. }
  275. //外部调用获取最新的点云, 获取指令时间往前一个周期内的点云, 如果没有就会报错, 不会等待
  276. Error_manager Wanji_lidar_device::get_last_cloud(std::mutex* p_mutex, pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud,
  277. std::chrono::system_clock::time_point command_time)
  278. {
  279. if ( p_mutex == NULL || p_cloud.get() == NULL )
  280. {
  281. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  282. " POINTER IS NULL ");
  283. }
  284. int t_scan_cycle_ms = m_protocol.get_scan_cycle();
  285. //将指令时间提前一个扫描周期, 然后获取这个时间后面的点云.
  286. //就是说, 在收到指令的时候, 可以使用一个周期以前的数据, 不用获取最新的点云.
  287. if( m_protocol.get_scan_time() > command_time - std::chrono::milliseconds(t_scan_cycle_ms) )
  288. {
  289. std::unique_lock<std::mutex> lck(*p_mutex);
  290. Error_manager code = m_protocol.get_scan_points(p_cloud);
  291. return code;
  292. }
  293. else
  294. {
  295. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_NO_CLOUD, Error_level::MINOR_ERROR,
  296. " Wanji_lidar_device::get_last_cloud error ");
  297. }
  298. }
  299. //外部调用获取最新的点云, 获取指令时间往前一个周期内的点云, 如果没有就会报错, 不会等待
  300. //注:函数内部不加锁, 由外部统一加锁.
  301. Error_manager Wanji_lidar_device::get_last_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud,
  302. std::chrono::system_clock::time_point command_time)
  303. {
  304. if ( p_cloud.get() == NULL )
  305. {
  306. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  307. " POINTER IS NULL ");
  308. }
  309. int t_scan_cycle_ms = m_protocol.get_scan_cycle();
  310. //将指令时间提前一个扫描周期, 然后获取这个时间后面的点云.
  311. //就是说, 在收到指令的时候, 可以使用一个周期以前的数据, 不用获取最新的点云.
  312. if( m_protocol.get_scan_time() > command_time - std::chrono::milliseconds(t_scan_cycle_ms) )
  313. {
  314. Error_manager code = m_protocol.get_scan_points(p_cloud);
  315. // LOG(WARNING) << p_cloud->size();
  316. return code;
  317. }
  318. else
  319. {
  320. // LOG(WARNING) << "get cloud failed.....";
  321. return Error_manager(Error_code::WANJI_LIDAR_DEVICE_NO_CLOUD, Error_level::MINOR_ERROR,
  322. " Wanji_lidar_device::get_last_cloud error ");
  323. }
  324. }
  325. Wanji_lidar_device::Wanji_lidar_device_status Wanji_lidar_device::get_status()
  326. {
  327. updata_status();
  328. return m_wanji_lidar_device_status;
  329. }
  330. void Wanji_lidar_device::updata_status()
  331. {
  332. Async_Client::Communication_status communication_status = m_async_client.get_status();
  333. Wj_716_lidar_protocol::Wanji_lidar_protocol_status wanji_lidar_protocol_status = m_protocol.get_status();
  334. if ( communication_status == Async_Client::Communication_status::E_FAULT ||
  335. wanji_lidar_protocol_status == Wj_716_lidar_protocol::Wanji_lidar_protocol_status::E_FAULT)
  336. {
  337. m_wanji_lidar_device_status = E_FAULT;
  338. }
  339. if ( communication_status == Async_Client::Communication_status::E_DISCONNECT )
  340. {
  341. m_wanji_lidar_device_status = E_DISCONNECT;
  342. }
  343. else if ( communication_status == Async_Client::Communication_status::E_READY &&
  344. wanji_lidar_protocol_status == Wj_716_lidar_protocol::Wanji_lidar_protocol_status::E_READY )
  345. {
  346. if ( m_execute_condition.get_pass_ever() )
  347. {
  348. m_wanji_lidar_device_status = E_BUSY;
  349. }
  350. else
  351. {
  352. m_wanji_lidar_device_status = E_READY;
  353. }
  354. }
  355. else
  356. {
  357. m_wanji_lidar_device_status = E_UNKNOWN;
  358. }
  359. }
  360. //mp_laser_manager_thread 线程执行函数,
  361. //thread_work 内部线程负责获取点云结果
  362. void Wanji_lidar_device::execute_thread_fun()
  363. {
  364. LOG(INFO) << " Wanji_lidar_device::execute_thread_fun() start "<< this;
  365. Error_manager t_error;
  366. //雷达管理的独立线程,负责控制管理所有的雷达。
  367. while (m_execute_condition.is_alive())
  368. {
  369. m_execute_condition.wait();
  370. if ( m_execute_condition.is_alive() )
  371. {
  372. std::this_thread::yield();
  373. if ( mp_wanji_lidar_scan_task == NULL )
  374. {
  375. //没有任务就忽略, 直接关闭线程
  376. m_wanji_lidar_device_status = E_READY;
  377. m_execute_condition.notify_all(false);
  378. }
  379. else
  380. {
  381. if ( mp_wanji_lidar_scan_task->is_over_time() )
  382. {
  383. t_error.error_manager_reset(TASK_TIMEOVER, MINOR_ERROR, "Wanji_lidar_device::get_cloud_thread() TASK_TIMEOVER");
  384. mp_wanji_lidar_scan_task->compare_and_cover_task_error_manager(t_error);
  385. //故障结束任务
  386. end_task();
  387. }
  388. else
  389. {
  390. //将指令时间提前一个扫描周期, 然后获取这个时间后面的点云.
  391. //就是说, 在收到指令的时候, 可以使用一个周期以前的数据, 不用获取最新的点云.
  392. if( m_protocol.get_scan_time() >
  393. mp_wanji_lidar_scan_task->get_command_time() - std::chrono::milliseconds(m_protocol.get_scan_cycle()) )
  394. {
  395. std::mutex *tp_mutex = mp_wanji_lidar_scan_task->get_task_cloud_lock();
  396. pcl::PointCloud<pcl::PointXYZ>::Ptr tp_cloud = mp_wanji_lidar_scan_task->get_task_point_cloud();
  397. {
  398. std::unique_lock<std::mutex> lck(*tp_mutex);
  399. t_error = m_protocol.get_scan_points(tp_cloud);
  400. }
  401. mp_wanji_lidar_scan_task->compare_and_cover_task_error_manager(t_error);
  402. //正常结束任务
  403. end_task();
  404. }
  405. else
  406. {
  407. //等1ms
  408. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  409. }
  410. }
  411. }
  412. }
  413. }
  414. LOG(INFO) << " Wanji_lidar_device::execute_thread_fun() end :"<<this;
  415. return;
  416. }