LivoxLaser.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #include "LivoxLaser.h"
  2. #include "livox_driver.h"
  3. RegisterLaser(Livox)
  4. CLivoxLaser::CLivoxLaser(int id, Laser_proto::laser_parameter laser_param)
  5. :Laser_base(id, laser_param)
  6. {
  7. Error_manager t_error;
  8. m_frame_count = 0;
  9. m_frame_maxnum = laser_param.frame_num();//初始化从外部参数导入,实际运行前从任务单导入.
  10. //默认handle为-1,切记不能初始化为0.因为0表示0号雷达,是有效的.....
  11. m_livox_device.handle = -1;
  12. //判断参数类型,
  13. if(laser_param.type()=="Livox")
  14. {
  15. //填充雷达设备的广播码
  16. t_error = Livox_driver::get_instance_references().Livox_insert_sn_laser(laser_param.sn(), this);
  17. //此时不进行驱动层的初始化,在所有雷达创建完成之后,在laser_manager统一初始化.
  18. if ( t_error != SUCCESS)
  19. {
  20. //如果sn码不规范,或者sn码重复都会引发错误,
  21. //故障处理,
  22. // 方案一:回退.取消创建雷达的操作.释放雷达内存.
  23. //方案二:允许创建雷达,但是状态改为故障.禁用后续的功能.
  24. //以后再写.
  25. ;
  26. }
  27. }
  28. }
  29. CLivoxLaser::~CLivoxLaser()
  30. {
  31. //清空队列
  32. m_queue_livox_data.clear_and_delete();
  33. }
  34. //雷达链接设备,为3个线程添加线程执行函数。
  35. Error_manager CLivoxLaser::connect_laser()
  36. {
  37. return Laser_base::connect_laser();
  38. }
  39. //雷达断开链接,释放3个线程
  40. Error_manager CLivoxLaser::disconnect_laser()
  41. {
  42. return Laser_base::disconnect_laser();
  43. }
  44. //对外的接口函数,负责接受并处理任务单,
  45. //input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
  46. //注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
  47. Error_manager CLivoxLaser::execute_task(Task_Base* p_laser_task)
  48. {
  49. LOG(INFO) << " ---CLivoxLaser::execute_task run ---"<< this;
  50. Error_manager t_error;
  51. Error_manager t_result;
  52. //检查指针
  53. if (p_laser_task == NULL) {
  54. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  55. "Laser_base::execute_task failed, POINTER_IS_NULL");
  56. }
  57. //检查任务类型,
  58. if (p_laser_task->get_task_type() != LASER_BASE_SCAN_TASK)
  59. {
  60. return Error_manager(Error_code::LIVOX_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
  61. "laser task type error != LASER_BASE_SCAN_TASK");
  62. }
  63. //检查雷达状态
  64. t_error = check_status();
  65. if ( t_error != SUCCESS )
  66. {
  67. t_result.compare_and_cover_error(t_error);
  68. }
  69. else
  70. {
  71. //接受任务,并将任务的状态改为TASK_SIGNED已签收
  72. mp_laser_task = (Laser_task *) p_laser_task;
  73. mp_laser_task->set_task_statu(TASK_SIGNED);
  74. //检查消息内容是否正确,
  75. //检查三维点云指针
  76. if (mp_laser_task->get_task_point_cloud().get() == NULL)
  77. {
  78. t_error.error_manager_reset(Error_code::POINTER_IS_NULL,
  79. Error_level::MINOR_ERROR,
  80. "execute_task mp_task_point_cloud is null");
  81. t_result.compare_and_cover_error(t_error);
  82. }
  83. else if (mp_laser_task->get_task_cloud_lock() == NULL)
  84. {
  85. t_error.error_manager_reset(Error_code::POINTER_IS_NULL,
  86. Error_level::MINOR_ERROR,
  87. "execute_task mp_task_cloud_lock is null");
  88. t_result.compare_and_cover_error(t_error);
  89. }
  90. else
  91. {
  92. //扫描最大帧数,从任务单导入.
  93. m_frame_maxnum = mp_laser_task->get_task_frame_maxnum();
  94. //设置保存文件的路径
  95. t_error = set_open_save_path(mp_laser_task->get_task_save_path(), mp_laser_task->get_task_save_flag());
  96. if (t_error != Error_code::SUCCESS)
  97. {
  98. //文件保存文件的路径的设置 允许失败。继续后面的动作
  99. t_result.compare_and_cover_error(t_error);
  100. }
  101. //启动雷达扫描
  102. t_error = start_scan();
  103. if (t_error != Error_code::SUCCESS)
  104. {
  105. t_result.compare_and_cover_error(t_error);
  106. }
  107. else
  108. {
  109. //将任务的状态改为 TASK_WORKING 处理中
  110. mp_laser_task->set_task_statu(TASK_WORKING);
  111. }
  112. }
  113. //return 之前要填充任务单里面的错误码.
  114. if (t_result != Error_code::SUCCESS)
  115. {
  116. //忽略轻微故障
  117. if ( t_result.get_error_level() >= Error_level::MINOR_ERROR)
  118. {
  119. //将任务的状态改为 TASK_ERROR 结束错误
  120. mp_laser_task->set_task_statu(TASK_ERROR);
  121. }
  122. //返回错误码
  123. mp_laser_task->compare_and_cover_task_error_manager(t_result);
  124. }
  125. }
  126. return t_result;
  127. }
  128. //检查雷达状态,是否正常运行
  129. Error_manager CLivoxLaser::check_status()
  130. {
  131. if ( get_laser_statu() == LASER_READY && m_livox_device.device_state == K_DEVICE_STATE_CONNECT )
  132. {
  133. return Error_code::SUCCESS;
  134. }
  135. else if ( get_laser_statu() == LASER_BUSY && m_livox_device.device_state == K_DEVICE_STATE_SAMPLING )
  136. {
  137. return Error_manager(Error_code::lIVOX_STATUS_BUSY, Error_level::MINOR_ERROR,
  138. " CLivoxLaser::check_status error ");
  139. }
  140. else
  141. {
  142. return Error_manager(Error_code::lIVOX_STATUS_ERROR, Error_level::MINOR_ERROR,
  143. " CLivoxLaser::check_status error ");
  144. }
  145. return Error_code::SUCCESS;
  146. }
  147. //雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
  148. Error_manager CLivoxLaser::start_scan()
  149. {
  150. LOG(INFO) << " ---CLivoxLaser::start_scan() ---:"<<this;
  151. if ( is_ready() )
  152. {
  153. //清空livox子类的队列,
  154. m_queue_livox_data.clear_and_delete();
  155. m_frame_count = 0;
  156. Livox_driver::get_instance_references().Livox_driver_start_sample(m_livox_device.handle);
  157. return Laser_base::start_scan();
  158. }
  159. else
  160. {
  161. return Error_manager(Error_code::LIVOX_START_FAILE, Error_level::MINOR_ERROR,
  162. "Laser_base::start_scan() is not ready ");
  163. }
  164. return Error_code::SUCCESS;
  165. }
  166. //雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
  167. Error_manager CLivoxLaser::stop_scan()
  168. {
  169. //防止多次调用
  170. if ( m_laser_scan_flag )
  171. {
  172. LOG(INFO) << " ---CLivoxLaser::stop_scan() ---:"<<this;
  173. Livox_driver::get_instance_references().Livox_driver_stop_sample(m_livox_device.handle);
  174. return Laser_base::stop_scan();
  175. }
  176. return Error_code::SUCCESS;
  177. }
  178. //结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
  179. Error_manager CLivoxLaser::end_task()
  180. {
  181. stop_scan();
  182. m_frame_count = 0;
  183. m_queue_livox_data.clear_and_delete();
  184. return Laser_base::end_task();
  185. }
  186. //判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
  187. //子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
  188. bool CLivoxLaser::is_ready()
  189. {
  190. //livox雷达设备的状态,livox sdk后台线程的状态
  191. if ( m_laser_statu == LASER_READY && m_livox_device.device_state == K_DEVICE_STATE_CONNECT )
  192. {
  193. true;
  194. }
  195. else
  196. {
  197. false;
  198. }
  199. }
  200. //判断是否扫描完成
  201. bool CLivoxLaser::is_scan_complete()
  202. {
  203. //雷达的采集帧数判断,直接比较 扫描当前帧数 扫描最大帧数
  204. return m_frame_count >= m_frame_maxnum;
  205. }
  206. //往数据缓存里面添加雷达数据,
  207. Error_manager CLivoxLaser::push_livox_data(Binary_buf* p_binary_buf)
  208. {
  209. if(m_queue_livox_data.push(p_binary_buf))
  210. {
  211. return Error_code::SUCCESS;
  212. }
  213. else
  214. {
  215. return Error_manager(Error_code::lIVOX_CANNOT_PUSH_DATA, Error_level::MINOR_ERROR,
  216. " CLivoxLaser::push_livox_data error ");
  217. }
  218. return Error_code::SUCCESS;
  219. }
  220. //雷达帧数计数增加
  221. Error_manager CLivoxLaser::add_livox_frame(int add_count)
  222. {
  223. m_frame_count += add_count;
  224. return Error_code::SUCCESS;
  225. }
  226. void CLivoxLaser::set_livox_device(uint8_t handle, DeviceState device_state , DeviceInfo info )
  227. {
  228. m_livox_device.handle = handle;
  229. m_livox_device.device_state = device_state;
  230. m_livox_device.info = info;
  231. }
  232. void CLivoxLaser::set_handle(uint8_t handle)
  233. {
  234. m_livox_device.handle = handle;
  235. }
  236. void CLivoxLaser::set_device_state(DeviceState device_state)
  237. {
  238. m_livox_device.device_state = device_state;
  239. }
  240. CLivoxLaser::DeviceState CLivoxLaser::get_device_state()
  241. {
  242. return m_livox_device.device_state;
  243. }
  244. void CLivoxLaser::set_device_info(DeviceInfo info)
  245. {
  246. m_livox_device.info = info;
  247. }
  248. //接受二进制消息的功能函数,并将其存入 m_queue_laser_data, 每次只转化一个CBinaryData,
  249. // 纯虚函数,必须由子类重载,
  250. Error_manager CLivoxLaser::receive_buf_to_queue()
  251. {
  252. Binary_buf* tp_livox_buf = NULL;
  253. if (m_queue_livox_data.try_pop(tp_livox_buf))
  254. {
  255. //tp_livox_buf此时是有内存的, 是 livox_data_callback 里面new出来的
  256. //Binary_buf 内存的管理权限 从 m_queue_livox_data 直接进入到 m_queue_laser_data,
  257. //数据最终在 Laser_base::thread_transform() transform_buf_to_points 释放.
  258. if(m_queue_laser_data.push(tp_livox_buf))
  259. {
  260. return Error_code::SUCCESS;
  261. }
  262. else
  263. {
  264. //这里要销毁 tp_livox_buf 的内存
  265. delete(tp_livox_buf);
  266. return Error_manager(Error_code::LASER_QUEUE_ERROR, Error_level::MINOR_ERROR,
  267. " CLivoxLaser::receive_buf_to_queue() error ");
  268. }
  269. }
  270. else
  271. {
  272. return NO_DATA;// m_queue_livox_data 没有数据并不意味着程序就出错了,
  273. }
  274. return Error_code::SUCCESS;
  275. }
  276. //将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
  277. // 纯虚函数,必须由子类重载,
  278. Error_manager CLivoxLaser::transform_buf_to_points()
  279. {
  280. Error_manager t_error;
  281. Binary_buf* tp_binaty_buf=NULL;
  282. //从队列中取出缓存。 tp_binaty_buf的内存 从链表取出时,就自带内存了。需要手动释放。
  283. if(m_queue_laser_data.try_pop(tp_binaty_buf))
  284. {
  285. //livox的二进制数据格式就是三维点坐标。直接强行转化指针类型即可
  286. LivoxRawPoint *tp_Livox_data = (LivoxRawPoint *)tp_binaty_buf->get_buf();
  287. //计算这一帧数据有多少个三维点。
  288. int t_count = tp_binaty_buf->get_length() / (sizeof(LivoxRawPoint));
  289. //转变三维点格式,并存入vector。
  290. for (int i = 0; i < t_count; ++i)
  291. {
  292. //三维点的坐标变换,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
  293. CPoint3D point_source;
  294. point_source.x = tp_Livox_data[i].x;
  295. point_source.y = tp_Livox_data[i].y;
  296. point_source.z = tp_Livox_data[i].z;
  297. CPoint3D point_destination = transform_by_matrix(point_source);
  298. //保存雷达扫描 三维点云的最终结果。
  299. if(m_save_flag)
  300. {
  301. char buf[64] = {0};
  302. sprintf(buf, "%f %f %f\n", point_destination.x, point_destination.y, point_destination.z);
  303. m_points_log_tool.write(buf, strlen(buf));
  304. }
  305. //LivoxRawPoint 转为 pcl::PointXYZ
  306. //int32_t 转 double。不要信号强度
  307. pcl::PointXYZ pointXYZ;
  308. pointXYZ.x = point_destination.x/1000.0;
  309. pointXYZ.y = point_destination.y/1000.0;
  310. pointXYZ.z = point_destination.z/1000.0;
  311. //注:单位毫米转为米, 最终数据单位统一为米.....
  312. t_error = mp_laser_task->task_push_point(&pointXYZ);
  313. if ( t_error != Error_code::SUCCESS )
  314. {
  315. delete tp_binaty_buf;
  316. return t_error;
  317. }
  318. }
  319. //统计扫描点个数。
  320. m_points_count += t_count;
  321. delete tp_binaty_buf;
  322. }
  323. else
  324. {
  325. return NO_DATA;// m_queue_laser_data 没有数据并不意味着程序就出错了,
  326. }
  327. return Error_code::SUCCESS;
  328. }