Laser.puml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. @startuml
  2. skinparam classAttributeIconSize 0
  3. title Laser_base 雷达的基类
  4. enum Laser_statu
  5. {
  6. //雷达工作状态,基类三线程的状态
  7. //connect_laser 和 disconnect_laser 中要切换状态 LASER_DISCONNECT <===> LASER_READY
  8. //start_scan 和 stop_scan 和 end_task 中要切换状态 LASER_READY <===> LASER_BUSY
  9. //默认值 LASER_DISCONNECT =0
  10. LASER_DISCONNECT =0, //雷达断连
  11. LASER_READY =1, //雷达正常待机,空闲
  12. LASER_BUSY =2, //雷达正在工作,正忙
  13. LASER_FAULT =3, //雷达错误
  14. }
  15. class Laser_base
  16. {
  17. //雷达的基类,不能直接使用,必须子类继承
  18. ==public:==
  19. Laser_base() = delete;
  20. Laser_base(const Laser_base& other) = delete;
  21. ..
  22. //唯一的构造函数,按照设备名称和雷达参数来创建实例。
  23. //input:id: 雷达设备的id,(唯一索引)
  24. //input:laser_param:雷达的参数,
  25. //注:利用protobuf创建 laser_parameter 类,然后从文件读取参数
  26. Laser_base(int laser_id,Laser_proto::laser_parameter laser_param);
  27. //析构函数
  28. ~Laser_base();
  29. ..
  30. //雷达链接设备,为3个线程添加线程执行函数。
  31. virtual Error_manager connect_laser();
  32. //雷达断开链接,释放3个线程
  33. virtual Error_manager disconnect_laser();
  34. //对外的接口函数,负责接受并处理任务单,
  35. //input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
  36. //注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
  37. virtual Error_manager execute_task(Task_Base* p_laser_task);
  38. //检查雷达状态,是否正常运行
  39. virtual Error_manager check_laser();
  40. //雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
  41. virtual Error_manager start_scan();
  42. //雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
  43. virtual Error_manager stop_scan();
  44. //结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
  45. virtual Error_manager end_task();
  46. ==public:==
  47. //设置保存文件的路径,并打开文件,
  48. Error_manager set_open_save_path(std::string save_path,bool is_save=true);
  49. //关闭保存文件,推出前一定要执行
  50. Error_manager close_save_path();
  51. //判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
  52. //子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
  53. virtual bool is_ready();
  54. //获取雷达id
  55. int get_laser_id();
  56. ==protected:==
  57. //接受二进制消息的功能函数,每次只接受一个CBinaryData
  58. // 纯虚函数,必须由子类重载,
  59. virtual bool receive_buf_to_queue(Binary_buf& binary_buf) = 0;
  60. //线程执行函数,将二进制消息存入队列缓存,
  61. void thread_receive();
  62. ..
  63. //将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
  64. // 纯虚函数,必须由子类重载,
  65. virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)=0;
  66. //线程执行函数,转化并处理三维点云。
  67. void thread_transform();
  68. ..
  69. //公开发布雷达信息的功能函数,
  70. Error_manager publish_laser_to_message();
  71. //线程执行函数,公开发布雷达的相关信息,用作上位机的监视。
  72. static void thread_publish(Laser_base* p_laser);
  73. ..
  74. //获取雷达状态
  75. Laser_statu get_laser_statu();
  76. ==protected:==
  77. //初始化变换矩阵,设置默认值
  78. Error_manager init_laser_matrix();
  79. //设置变换矩阵,用作三维点的坐标变换,
  80. Error_manager set_laser_matrix(double* p_matrix, int size);
  81. ..
  82. //三维点的坐标变换的功能函数,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
  83. virtual CPoint3D transform_by_matrix(CPoint3D point);
  84. ==protected:==
  85. //为了保证多线程的数据安全,修改共享数据必须加锁。 atomic 和 安全队列 可以不加锁进行读写
  86. //建议:判断标志位使用 atomic, 容器要封装并使用 安全容器,
  87. std::mutex m_laser_lock; //雷达数据锁
  88. ..
  89. std::atomic<int> m_laser_id; //雷达设备id
  90. Laser_proto::laser_parameter m_laser_param; //雷达的配置参数
  91. //雷达变换矩阵,三维点的坐标变换的矩阵,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
  92. //必须在set_laser_matrix之后,才能使用。(connect时,从雷达的配置参数导入)
  93. double mp_laser_matrix[LASER_MATRIX_ARRAY_SIZE]; //雷达变换矩阵
  94. //雷达扫描事件的标志位,受start和stop控制,然后其他线程判断m_scan_flag标准位,来进行启停。
  95. std::atomic<bool> m_laser_scan_flag; //雷达扫描的使能标志位
  96. //雷达状态和任务状态同步,m_scan_flag停止之后,还要等任务执行完成,才会切回 ready。
  97. std::atomic<Laser_statu> m_laser_statu; //雷达工作状态,基类三线程的状态
  98. //注:m_laser_statu是基类的三线程的状态,和livox sdk后台线程状态没有任何关系。
  99. //子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
  100. ..
  101. std::atomic<int> m_points_count; //雷达采集点的计数
  102. Thread_safe_queue<Binary_buf*> m_queue_laser_data; //二进制缓存的队列容器
  103. Binary_buf m_last_data; //上一个二进制缓存,用作数据拼接
  104. ..
  105. std::atomic<bool> m_save_flag; //雷达保存文件的使能标志位
  106. std::string m_save_path; //雷达保存文件的保存路径
  107. CLogFile m_binary_log_tool; //二进制缓存的日志工具
  108. CLogFile m_points_log_tool; //三维点云的日志工具
  109. ..
  110. //线程指针的内存管理,由Connect和Disconnect进行分配和释放。
  111. std::thread* mp_thread_receive; //接受缓存的线程指针
  112. Thread_condition m_condition_receive; //接受缓存的条件变量
  113. std::thread* mp_thread_transform; //转化数据的线程指针
  114. Thread_condition m_condition_transform; //转化数据的条件变量
  115. std::thread* mp_thread_publish; //发布信息的线程指针
  116. Thread_condition m_condition_publish; //发布信息的条件变量
  117. ..
  118. //任务单的指针,实际内存由应用层管理,
  119. //接受任务后,指向新的任务单
  120. Laser_task * mp_laser_task; //任务单的指针
  121. }
  122. class CPoint3D
  123. {
  124. //三维点
  125. double x, y, z;
  126. }
  127. class CLogFile
  128. {
  129. //日志文件
  130. void open(const char *_Filename, bool binary = false);
  131. void write(const char *_Str, streamsize _Count);
  132. void close();
  133. fstream m_file;
  134. std::mutex m_lock;
  135. }
  136. class laser_parameter
  137. {
  138. //雷达参数
  139. }
  140. class Laser_task
  141. {
  142. //雷达模块的任务指令,从Task_Base继承,
  143. //补充了雷达专属的数据输入和输出
  144. ==public:==
  145. //初始化任务单,必须初始化之后才可以使用,(必选参数)
  146. Error_manager task_init(Task_statu task_statu,
  147. pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
  148. std::mutex* p_task_cloud_lock);
  149. ..
  150. //初始化任务单,必须初始化之后才可以使用,(可选参数)
  151. Error_manager task_init(Task_statu task_statu,
  152. std::string & task_statu_information,
  153. unsigned int task_frame_maxnum,
  154. pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
  155. std::mutex* p_task_cloud_lock);
  156. ..
  157. //push点云,把 point_xyz 添加到 p_task_point_cloud 里面。
  158. Error_manager task_push_point(pcl::PointXYZ point_xyz);
  159. ==protected:==
  160. //点云的采集帧数最大值,任务输入
  161. unsigned int m_task_frame_maxnum;
  162. //点云保存文件的路径,任务输入
  163. std::string m_task_save_path;
  164. //三维点云的数据保护锁,任务输入
  165. std::mutex* mp_task_cloud_lock;
  166. //采集结果,三维点云容器的智能指针,任务输出
  167. //这里只是指针,实际内存由应用层管理,初始化时必须保证内存有效。
  168. pcl::PointCloud<pcl::PointXYZ>::Ptr mp_task_point_cloud;
  169. }
  170. class Task_Base
  171. {
  172. //任务单基类
  173. ==public:==
  174. //初始化任务单,初始任务单类型为 UNKONW_TASK
  175. virtual Error_manager init();
  176. //更新任务单
  177. Error_manager update_statu(Task_statu task_statu,std::string statu_information="");
  178. //获取任务类型
  179. Task_type get_task_type();
  180. ==protected:==
  181. Task_type m_task_type; //任务类型
  182. Task_statu m_task_statu; //任务状态
  183. std::string m_task_statu_information; //任务状态说明
  184. Error_manager m_task_error_manager;//错误码,任务故障信息,任务输出
  185. }
  186. Laser_task <-- Task_Base : inherit
  187. class Error_manager
  188. {
  189. //错误码管理
  190. }
  191. class Binary_buf
  192. {
  193. //二进制缓存,
  194. //比较前面部分的buf是否相等,使用 other.m_length 为标准
  195. bool is_equal_front(const Binary_buf& other);
  196. //比较前面部分的buf是否相等,len为0时,使用strlen(buf)为标准,不比较结束符'\0'
  197. bool is_equal_front(const char* p_buf, int len = 0);
  198. ..
  199. char* get_buf()const;
  200. int get_length()const;
  201. --
  202. char* mp_buf; //二进制缓存指针
  203. int m_length; //二进制缓存长度
  204. }
  205. class Thread_condition
  206. {
  207. bool wait();
  208. //等待一定的时间(默认时间单位:毫秒ms),由 is_pass_wait 决定是否阻塞。
  209. bool wait_for_millisecond(unsigned int millisecond);
  210. //唤醒已经阻塞的线程,唤醒一个线程
  211. void notify_one(bool pass_ever, bool pass_once = false);
  212. //唤醒已经阻塞的线程,唤醒全部线程
  213. void notify_all(bool pass_ever, bool pass_once = false);
  214. //杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
  215. void kill_all();
  216. //判断是否或者,return !m_kill_flag
  217. bool is_alive();
  218. ==protected:==
  219. static bool is_pass_wait(Thread_condition * other);
  220. ..
  221. std::atomic<bool> m_kill_flag; //是否杀死线程,让线程强制退出,
  222. std::atomic<bool> m_pass_ever; //线程能否直接通过等待,对后面的线程也生效。
  223. std::atomic<bool> m_pass_once; //线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
  224. std::mutex m_mutex; //线程的锁
  225. std::condition_variable m_condition_variable; //线程的条件变量
  226. }
  227. class Thread_safe_queue << template<class T> >>
  228. {
  229. //等待并弹出数据,成功弹出则返回true
  230. bool wait_and_pop(T& value);
  231. //尝试弹出数据,成功弹出则返回true
  232. bool try_pop(T& value);
  233. //等待并弹出数据,成功弹出则返回true
  234. std::shared_ptr<T> wait_and_pop();
  235. //尝试弹出数据,成功弹出则返回true
  236. std::shared_ptr<T> try_pop();
  237. //插入一项,并唤醒一个线程,
  238. bool push(T new_value);
  239. //清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
  240. bool clear();
  241. //清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
  242. bool clear_and_delete();
  243. ==public:==
  244. //判空
  245. bool empty();
  246. //获取队列大小
  247. size_t size();
  248. //设置队列为退出状态。并唤醒所有的线程,使其通过wait
  249. void termination_queue();
  250. //唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
  251. void wake_queue();
  252. //获取退出状态
  253. bool get_termination_flag();
  254. //判断是否可以直接通过wait, m_data_queue不为空或者m_termination终止时都可以通过等待。
  255. bool is_pass();
  256. ==protected:==
  257. std::mutex m_mutex; //队列的锁
  258. std::queue<std::shared_ptr<T>> m_data_queue; //队列数据,使用智能指针shared_ptr
  259. std::condition_variable m_data_cond; //条件变量
  260. std::atomic<bool> m_termination_flag; //终止标志位
  261. }
  262. Laser_base <-- Laser_statu : include
  263. Laser_base <-- CPoint3D : include
  264. Laser_base <-- CLogFile : include
  265. Laser_base <-- laser_parameter : include
  266. Laser_base <-- Laser_task : include
  267. Laser_base <-- Error_manager : include
  268. Laser_base <-- Binary_buf : include
  269. Laser_base <-- Thread_condition : include
  270. Laser_base <-- Thread_safe_queue : include
  271. @enduml