LivoxLaser.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #include "LivoxLaser.h"
  2. RegisterLaser(Livox)
  3. CLivoxLaser::DeviceItem CLivoxLaser::g_devices[kMaxLidarCount] = { 0 };
  4. std::map<uint8_t, std::string> CLivoxLaser::g_handle_sn= std::map<uint8_t, std::string>();
  5. std::map<std::string, uint8_t> CLivoxLaser::g_sn_handle = std::map<std::string, uint8_t>();
  6. std::map<std::string, CLivoxLaser*> CLivoxLaser::g_sn_laser= std::map<std::string, CLivoxLaser*>();
  7. CLivoxLaser* CLivoxLaser::g_all_laser[kMaxLidarCount] = { 0 };
  8. unsigned int CLivoxLaser::g_count[kMaxLidarCount] = { 0 };
  9. CLivoxLaser::CLivoxLaser(int id, Laser_proto::laser_parameter laser_param)
  10. :Laser_base(id, laser_param)
  11. {
  12. //设备livox扫描最大帧数
  13. m_frame_maxnum = laser_param.frame_num();
  14. //判断参数类型,
  15. if(laser_param.type()=="Livox")
  16. {
  17. //填充雷达设备的广播码
  18. g_sn_laser.insert(std::make_pair(laser_param.sn(), this));
  19. //初始化livox
  20. InitLivox();
  21. }
  22. }
  23. CLivoxLaser::~CLivoxLaser()
  24. {
  25. }
  26. //雷达链接设备,为3个线程添加线程执行函数。
  27. Error_manager CLivoxLaser::connect_laser()
  28. {
  29. Error_manager t_error;
  30. //设置点云变换矩阵
  31. double matrix[12]={0};
  32. matrix[0]=m_laser_param.mat_r00();
  33. matrix[1]=m_laser_param.mat_r01();
  34. matrix[2]=m_laser_param.mat_r02();
  35. matrix[3]=m_laser_param.mat_r03();
  36. matrix[4]=m_laser_param.mat_r10();
  37. matrix[5]=m_laser_param.mat_r11();
  38. matrix[6]=m_laser_param.mat_r12();
  39. matrix[7]=m_laser_param.mat_r13();
  40. matrix[8]=m_laser_param.mat_r20();
  41. matrix[9]=m_laser_param.mat_r21();
  42. matrix[10]=m_laser_param.mat_r22();
  43. matrix[11]=m_laser_param.mat_r23();
  44. t_error = set_laser_matrix(matrix, 12);
  45. if ( t_error != Error_code::SUCCESS )
  46. {
  47. return t_error;
  48. }
  49. return Laser_base::connect_laser();
  50. }
  51. //雷达断开链接,释放3个线程
  52. Error_manager CLivoxLaser::disconnect_laser()
  53. {
  54. return Laser_base::disconnect_laser();
  55. }
  56. //对外的接口函数,负责接受并处理任务单,
  57. //input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
  58. //注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
  59. Error_manager CLivoxLaser::execute_task(Task_Base* p_laser_task)
  60. {
  61. //LOG(INFO) << " CLivoxLaser::execute_task start "<< this;
  62. Error_manager t_error;
  63. Error_manager t_result;
  64. //检查指针
  65. if (p_laser_task == NULL) {
  66. return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
  67. "Laser_base::porform_task failed, POINTER_IS_NULL");
  68. }
  69. //检查任务类型,
  70. if (p_laser_task->get_task_type() != LASER_BASE_SCAN_TASK)
  71. {
  72. return Error_manager(Error_code::LIVOX_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
  73. "laser task type error != LASER_BASE_SCAN_TASK");
  74. }
  75. //接受任务,并将任务的状态改为TASK_SIGNED已签收
  76. mp_laser_task = (Laser_task *) p_laser_task;
  77. mp_laser_task->set_task_statu(TASK_SIGNED);
  78. //检查消息内容是否正确,
  79. //检查三维点云指针
  80. if (mp_laser_task->get_task_point_cloud()== NULL)
  81. {
  82. t_result.error_manager_reset(Error_code::POINTER_IS_NULL,
  83. Error_level::MINOR_ERROR,
  84. "execute_task mp_task_point_cloud is null");
  85. //将任务的状态改为 TASK_OVER 结束任务
  86. mp_laser_task->set_task_statu(TASK_OVER);
  87. //返回错误码
  88. mp_laser_task->set_task_error_manager(t_result);
  89. return t_result;
  90. }
  91. else
  92. {
  93. m_frame_maxnum=mp_laser_task->get_task_frame_maxnum();
  94. //设置保存文件的路径
  95. std::string save_path = mp_laser_task->get_save_path();
  96. t_error = set_open_save_path(save_path,m_laser_param.is_save_txt());
  97. if ( t_error != Error_code::SUCCESS )
  98. {
  99. //文件保存文件的路径的设置 允许失败。继续后面的动作
  100. t_result.compare_and_cover_error(t_error);
  101. }
  102. //启动雷达扫描
  103. t_error = start_scan();
  104. if ( t_error != Error_code::SUCCESS )
  105. {
  106. t_result.compare_and_cover_error(t_error);
  107. //将任务的状态改为 TASK_OVER 结束任务
  108. mp_laser_task->set_task_statu(TASK_OVER);
  109. //返回错误码
  110. mp_laser_task->set_task_error_manager(t_result);
  111. return t_result;
  112. }
  113. else
  114. {
  115. //将任务的状态改为 TASK_WORKING 处理中
  116. mp_laser_task->set_task_statu(TASK_WORKING);
  117. }
  118. }
  119. //返回错误码
  120. if (t_result != Error_code::SUCCESS)
  121. {
  122. mp_laser_task->set_task_error_manager(t_result);
  123. }
  124. return t_result;
  125. }
  126. //检查雷达状态,是否正常运行
  127. Error_manager CLivoxLaser::check_laser()
  128. {
  129. return Laser_base::check_laser();
  130. }
  131. //雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
  132. Error_manager CLivoxLaser::start_scan()
  133. {
  134. //LOG(INFO) << " livox start :"<<this;
  135. //清空livox子类的队列,
  136. m_queue_livox_data.clear_and_delete();
  137. g_count[m_handle] = 0;
  138. return Laser_base::start_scan();
  139. }
  140. //雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
  141. Error_manager CLivoxLaser::stop_scan()
  142. {
  143. return Laser_base::stop_scan();
  144. }
  145. //结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
  146. Error_manager CLivoxLaser::end_task()
  147. {
  148. return Laser_base::end_task();
  149. }
  150. //判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
  151. //子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
  152. bool CLivoxLaser::is_ready()
  153. {
  154. //livox雷达设备的状态,livox sdk后台线程的状态
  155. if ( m_laser_statu == LASER_READY &&
  156. g_devices[m_handle].device_state != kDeviceStateDisconnect )
  157. {
  158. return true;
  159. }
  160. else
  161. {
  162. return false;
  163. }
  164. }
  165. //接受二进制消息的功能函数,每次只接受一个CBinaryData
  166. // 纯虚函数,必须由子类重载,
  167. bool CLivoxLaser::receive_buf_to_queue(Binary_buf& binary_buf)
  168. {
  169. Binary_buf* tp_livox_buf;
  170. if (m_queue_livox_data.try_pop(tp_livox_buf))
  171. {
  172. binary_buf = *tp_livox_buf;
  173. delete tp_livox_buf;
  174. //std::cout << "huli m_queue_livox_data.try_pop" << std::endl;
  175. return true;
  176. }
  177. return false;
  178. }
  179. //将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
  180. // 纯虚函数,必须由子类重载,
  181. Buf_type CLivoxLaser::transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)
  182. {
  183. if ( p_binary_buf ==NULL )
  184. {
  185. return BUF_UNKNOW;
  186. }
  187. else
  188. {
  189. //livox的二进制数据格式就是三维点坐标。直接强行转化指针类型即可
  190. LivoxRawPoint *tp_Livox_data = (LivoxRawPoint *)p_binary_buf->get_buf();
  191. //计算这一帧数据有多少个三维点。
  192. int t_count = p_binary_buf->get_length() / (sizeof(LivoxRawPoint));
  193. if (t_count <= 0)
  194. {
  195. return BUF_UNKNOW;
  196. }
  197. else
  198. {
  199. //转变三维点格式,并存入vector。
  200. for (int i = 0; i < t_count; ++i)
  201. {
  202. //LivoxRawPoint 转为 CPoint3D
  203. //int32_t 转 double。不要信号强度
  204. LivoxRawPoint t_livox_point = tp_Livox_data[i];
  205. CPoint3D t_point3D;
  206. t_point3D.x = t_livox_point.x;
  207. t_point3D.y = t_livox_point.y;
  208. t_point3D.z = t_livox_point.z;
  209. point3D_cloud.push_back(t_point3D);
  210. // std::cout << "huli points:" << t_point3D.x << " : " << t_point3D.y << " : " << t_point3D.z<< std::endl;
  211. }
  212. return BUF_DATA;
  213. }
  214. }
  215. }
  216. void CLivoxLaser::InitLivox()
  217. {
  218. static bool g_init = false;
  219. if (g_init == false)
  220. {
  221. if (!Init()) {
  222. LOG(INFO) << "livox sdk init failed...";
  223. }
  224. else
  225. {
  226. LivoxSdkVersion _sdkversion;
  227. GetLivoxSdkVersion(&_sdkversion);
  228. char buf[255] = { 0 };
  229. sprintf(buf, "Livox SDK version %d.%d.%d .\n", _sdkversion.major, _sdkversion.minor, _sdkversion.patch);
  230. LOG(INFO) << buf;
  231. SetBroadcastCallback(OnDeviceBroadcast);
  232. SetDeviceStateUpdateCallback(OnDeviceChange);
  233. g_init = true;
  234. }
  235. }
  236. }
  237. bool CLivoxLaser::IsScanComplete()
  238. {
  239. //雷达的采集帧数判断,直接比较任务单里面的帧数最大值
  240. if(mp_laser_task!=NULL)
  241. return g_count[m_handle] >= mp_laser_task->get_task_frame_maxnum();
  242. else
  243. return false;
  244. }
  245. void CLivoxLaser::UpdataHandle()
  246. {
  247. std::string sn = m_laser_param.sn();
  248. if (g_sn_handle.find(sn) != g_sn_handle.end())
  249. {
  250. m_handle = g_sn_handle[sn];
  251. }
  252. }
  253. void CLivoxLaser::OnSampleCallback(livox_status status, uint8_t handle, uint8_t response, void *data) {
  254. CLivoxLaser* laser = (CLivoxLaser*)data;
  255. LOG(INFO)<<"122333-------------------------------";
  256. if (status == kStatusSuccess) {
  257. if (response != 0) {
  258. g_devices[handle].device_state = kDeviceStateConnect;
  259. }
  260. }
  261. else if (status == kStatusTimeout) {
  262. g_devices[handle].device_state = kDeviceStateConnect;
  263. }
  264. }
  265. void CLivoxLaser::OnDeviceChange(const DeviceInfo *info, DeviceEvent type)
  266. {
  267. if (info == NULL) {
  268. return;
  269. }
  270. uint8_t handle = info->handle;
  271. if (handle >= kMaxLidarCount) {
  272. return;
  273. }
  274. /*std::cout<<"-----------------------------------------------------------------"<<std::endl;
  275. std::cout<<" OnDeviceChange handle : "<<info->broadcast_code<<" type : "<<type <<" device_state : "
  276. <<g_devices[handle].device_state<<std::endl;*/
  277. if (type == kEventConnect) {
  278. //QueryDeviceInformation(handle, OnDeviceInformation, NULL);
  279. if (g_devices[handle].device_state == kDeviceStateDisconnect)
  280. {
  281. g_devices[handle].device_state = kDeviceStateConnect;
  282. g_devices[handle].info = *info;
  283. }
  284. }
  285. else if (type == kEventDisconnect) {
  286. g_devices[handle].device_state = kDeviceStateDisconnect;
  287. }
  288. else if (type == kEventStateChange) {
  289. g_devices[handle].info = *info;
  290. }
  291. if (g_devices[handle].device_state == kDeviceStateConnect)
  292. {
  293. if (g_devices[handle].info.state == kLidarStateNormal)
  294. {
  295. if (g_devices[handle].info.type == kDeviceTypeHub)
  296. {
  297. HubStartSampling(OnSampleCallback, NULL);
  298. }
  299. else
  300. {
  301. LidarStartSampling(handle, OnSampleCallback, NULL);
  302. }
  303. g_devices[handle].device_state = kDeviceStateSampling;
  304. }
  305. }
  306. }
  307. void CLivoxLaser::OnDeviceBroadcast(const BroadcastDeviceInfo *info)
  308. {
  309. if (info == NULL) {
  310. return;
  311. }
  312. //printf("Receive Broadcast Code %s\n", info->broadcast_code);
  313. LOG(INFO) << " broadcast sn : " << info->broadcast_code;
  314. bool result = false;
  315. uint8_t handle = 0;
  316. result = AddLidarToConnect(info->broadcast_code, &handle);
  317. if (result == kStatusSuccess) {
  318. /** Set the point cloud data for a specific Livox LiDAR. */
  319. SetDataCallback(handle, LidarDataCallback, NULL);
  320. g_devices[handle].handle = handle;
  321. g_devices[handle].device_state = kDeviceStateDisconnect;
  322. std::string sn = info->broadcast_code;
  323. if (g_handle_sn.find(handle) != g_handle_sn.end())
  324. g_handle_sn[handle] = sn;
  325. else
  326. g_handle_sn.insert(std::make_pair(handle,sn));
  327. if (g_sn_handle.find(sn) != g_sn_handle.end())
  328. g_sn_handle[sn] = handle;
  329. else
  330. g_sn_handle.insert(std::make_pair(sn,handle));
  331. }
  332. }
  333. void CLivoxLaser::LidarDataCallback(uint8_t handle, LivoxEthPacket *data, uint32_t data_num, void *client_data)
  334. {
  335. // std::cout << "huli LidarDataCallback" << std::endl;
  336. CLivoxLaser* livox = g_all_laser[handle];
  337. if (livox == NULL)
  338. {
  339. if (g_handle_sn.find(handle) != g_handle_sn.end())
  340. {
  341. std::string sn = g_handle_sn[handle];
  342. if (g_sn_laser.find(sn) != g_sn_laser.end())
  343. {
  344. livox = g_sn_laser[sn];
  345. g_all_laser[handle] = livox;
  346. if (livox)
  347. livox->UpdataHandle();
  348. }
  349. }
  350. }
  351. // std::cout << "huli LidarDataCallback " << std::endl;
  352. if (data && livox)
  353. {
  354. // std::cout << "huli m_laser_scan_flag = " << livox->m_laser_scan_flag << std::endl;
  355. //判断雷达扫描标志位
  356. if (livox->m_laser_scan_flag)
  357. {
  358. if (livox->IsScanComplete())
  359. {
  360. //std::cout << "huli qwe point count = " << livox->g_count[livox->m_handle] << std::endl;
  361. livox->stop_scan();
  362. return;
  363. }
  364. /*else
  365. {
  366. //std::cout << "huli asd point count = " << livox->g_count[livox->m_handle] << std::endl;
  367. }*/
  368. // std::cout << "huli LidarDataCallback " << std::endl;
  369. if (g_count[handle] >= livox->m_frame_maxnum)
  370. return;
  371. uint64_t cur_timestamp = *((uint64_t *)(data->timestamp));
  372. if(data ->data_type == kCartesian)
  373. {
  374. LivoxRawPoint *p_point_data = (LivoxRawPoint *)data->data;
  375. Binary_buf* data_bin = new Binary_buf((char*)p_point_data, data_num * sizeof(LivoxRawPoint));
  376. livox->m_queue_livox_data.push(data_bin);
  377. }
  378. else if(data ->data_type == kExtendCartesian)
  379. {
  380. LivoxExtendRawPoint *p_point_data = (LivoxExtendRawPoint *)data->data;
  381. Binary_buf* data_bin = new Binary_buf((char*)p_point_data, data_num * sizeof(LivoxExtendRawPoint));
  382. livox->m_queue_livox_data.push(data_bin);
  383. }
  384. else
  385. {
  386. return;
  387. }
  388. g_count[handle]++;
  389. }
  390. livox->m_laser_statu = LASER_READY;
  391. }
  392. /*else
  393. {
  394. //std::cout << "huli 2z error " << "data = "<< data << std::endl;
  395. //std::cout << "huli 2z error " << "livox = "<< livox << std::endl;
  396. }*/
  397. }