#include "wj_716_lidar_protocol.h" #include //#include "../tool/proto_tool.h" Wj_716_lidar_protocol::Wj_716_lidar_protocol() { m_wanji_lidar_protocol_status = E_UNKNOWN; mp_communication_data_queue = NULL; memset(m_scan_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); memset(m_scan_point_intensity, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); memset(m_two_echo_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); m_current_frame_number = 0; mp_scan_points = pcl::PointCloud::Ptr(new pcl::PointCloud); mp_two_echo_points = pcl::PointCloud::Ptr(new pcl::PointCloud); mp_thread_analysis = NULL; // 设置初始时间为昨天,以避免第一次点云更新前获取到空点云 m_scan_cloud_time = std::chrono::system_clock::now() - std::chrono::duration>(1); m_two_echo_cloud_time = std::chrono::system_clock::now() - std::chrono::duration>(1); memset(&m_polar_coordinates_box, 0, sizeof(Point2D_tool::Polar_coordinates_box)); memset(&m_point2D_box, 0, sizeof(Point2D_tool::Point2D_box)); memset(&m_point2D_transform, 0, sizeof(Point2D_tool::Point2D_transform)); mp_thread_analysis = NULL; } Wj_716_lidar_protocol::~Wj_716_lidar_protocol() { uninit(); } // 初始化 Error_manager Wj_716_lidar_protocol::init(Thread_safe_queue *p_communication_data_queue, Point2D_tool::Polar_coordinates_box polar_coordinates_box, Point2D_tool::Point2D_box point2D_box, Point2D_tool::Point2D_transform point2D_transform) { if (p_communication_data_queue == NULL) { return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR, " POINTER IS NULL "); } mp_communication_data_queue = p_communication_data_queue; m_polar_coordinates_box = polar_coordinates_box; m_point2D_box = point2D_box; m_point2D_transform = point2D_transform; //接受线程, 默认开启循环, 在内部的wait_and_pop进行等待 m_condition_analysis.reset(false, true, false); mp_thread_analysis = new std::thread(&Wj_716_lidar_protocol::thread_analysis, this); m_wanji_lidar_protocol_status = E_READY; return Error_code::SUCCESS; } //反初始化 Error_manager Wj_716_lidar_protocol::uninit() { LOG(INFO) << " ---Wj_716_lidar_protocol uninit --- "<< this; if ( mp_communication_data_queue ) { //终止队列,防止 wait_and_pop 阻塞线程。 mp_communication_data_queue->termination_queue(); } //关闭线程 if (mp_thread_analysis) { m_condition_analysis.kill_all(); } //回收线程的资源 if (mp_thread_analysis) { mp_thread_analysis->join(); delete mp_thread_analysis; mp_thread_analysis = NULL; } if ( mp_communication_data_queue ) { //清空队列 mp_communication_data_queue->clear_and_delete(); } //队列的内存由上级管理, 这里写空就好了. mp_communication_data_queue = NULL; if ( m_wanji_lidar_protocol_status != E_FAULT ) { m_wanji_lidar_protocol_status = E_UNKNOWN; } return Error_code::SUCCESS; } //检查状态 Error_manager Wj_716_lidar_protocol::check_status() { if ( m_wanji_lidar_protocol_status == E_READY ) { return Error_code::SUCCESS; } else { return Error_manager(Error_code::WJ_PROTOCOL_STATUS_ERROR, Error_level::MINOR_ERROR, " Wj_716_lidar_protocol::check_status() error "); } } //判断是否为待机,如果已经准备好,则可以执行任务。 bool Wj_716_lidar_protocol::is_ready() { if ( m_wanji_lidar_protocol_status == E_READY ) { return true; } else { return false; } } //获取状态 Wj_716_lidar_protocol::Wanji_lidar_protocol_status Wj_716_lidar_protocol::get_status() { return m_wanji_lidar_protocol_status; } //获取扫描周期 int Wj_716_lidar_protocol::get_scan_cycle() { return WANJI_FRAME_SCAN_CYCLE_MS; } //获取扫描点云 Error_manager Wj_716_lidar_protocol::get_scan_points(pcl::PointCloud::Ptr p_cloud_out) { if ( p_cloud_out.get() == NULL ) { return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR, " Wj_716_lidar_protocol::get_scan_points POINTER IS NULL "); } std::unique_lock lck(m_scan_mutex); //将扫描点云追加到p_cloud_out后面, 不要清除p_cloud_out原有的数据 (*p_cloud_out)+=(*mp_scan_points); return Error_code::SUCCESS; } //获取二次回波点云 Error_manager Wj_716_lidar_protocol::get_two_echo_points(pcl::PointCloud::Ptr p_cloud_out) { if ( p_cloud_out.get() == NULL ) { return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR, " Wj_716_lidar_protocol::get_two_echo_points POINTER IS NULL "); } std::unique_lock lck(m_two_echo_mutex); //将扫描点云追加到p_cloud_out后面, 不要清除p_cloud_out原有的数据 (*p_cloud_out)+=(*mp_two_echo_points); return Error_code::SUCCESS; } /** * 获取更新扫描点云时间 * */ std::chrono::system_clock::time_point Wj_716_lidar_protocol::get_scan_time() { std::unique_lock lck(m_scan_mutex); return m_scan_cloud_time; } /** * 获取更新二次回波时间 * */ std::chrono::system_clock::time_point Wj_716_lidar_protocol::get_two_echo_time() { std::unique_lock lck(m_two_echo_mutex); return m_two_echo_cloud_time; } //解析线程函数 void Wj_716_lidar_protocol::thread_analysis() { LOG(INFO) << " ---Wj_716_lidar_protocol::thread_analysis start ---" << this; Error_manager t_error; //接受雷达消息,包括连接,重连和接受数据 while (m_condition_analysis.is_alive()) { m_condition_analysis.wait(); if (m_condition_analysis.is_alive()) { std::this_thread::yield(); if (mp_communication_data_queue == NULL) { m_wanji_lidar_protocol_status = E_FAULT; } else { Binary_buf *tp_binary_buf = NULL; bool is_pop = mp_communication_data_queue->wait_and_pop(tp_binary_buf); if (is_pop == true && tp_binary_buf != NULL) { //检查数据头和长度, if (check_head_and_length(tp_binary_buf)) { // 消息完整性检查, 检查末尾的校验码, if (check_xor(tp_binary_buf)) { //至此, 我们确认消息已经被正常的接受, 后续错误就不可 // 万集通信协议, 解析数据, 转化为点云 t_error = data_protocol_analysis(tp_binary_buf); //暂时不管错误 } //else 错误不管, 当做无效消息处理 } //else 错误不管, 当做无效消息处理 delete(tp_binary_buf); } } } } LOG(INFO) << " -Wj_716_lidar_protocol::thread_analysis end :" << this; return; } //检查数据头和长度, 注:返回失败只是表示消息格式不对不是需要处理的消息, 忽略就好了 bool Wj_716_lidar_protocol::check_head_and_length(Binary_buf *p_binary_buf) { //检查总长度, 716固定为898byte if (p_binary_buf->get_length() != WANJI_FRAME_LENGTH_716) { return false; } char *tp_data = p_binary_buf->get_buf(); //检查数据头, 716的前4个字节固定为0x02020202 if (tp_data[0] == 0x02 && tp_data[1] == 0x02 && tp_data[2] == 0x02 && tp_data[3] == 0x02) { //4~7字节合并为32位的int, 是数据消息里面的长度值, 不包括数据头(4byte) 长度(4byte) 尾部校验码(1byte) unsigned int l_u32reallen = (tp_data[4] << 24) | (tp_data[5] << 16) | (tp_data[6] << 8) | (tp_data[7] << 0); if (l_u32reallen + 9 == WANJI_FRAME_LENGTH_716) { return true; } else { return false; } } else { return false; } } // 消息完整性检查, 检查末尾的校验码, 注:返回失败只是表示消息格式不对不是需要处理的消息, 忽略就好了 bool Wj_716_lidar_protocol::check_xor(Binary_buf *p_binary_buf) { int i = 0; char check = 0; //校验码的运算, 就是把中间所有的数据异或, 不包括数据头(4byte) 长度(4byte) 尾部校验码(1byte) char *tp_data = p_binary_buf->get_buf() + 8; int t_length = p_binary_buf->get_length() - 9; for (i = 0; i < t_length; i++) { check ^= *tp_data++; //后++, tp_data在最后 还会右移一个 } if (check == *tp_data) { return true; } else { return false; } } // 万集通信协议, 解析数据, 转化为点云 Error_manager Wj_716_lidar_protocol::data_protocol_analysis(Binary_buf *p_binary_buf) { Error_manager t_error; char *data = p_binary_buf->get_buf(); int len = p_binary_buf->get_length(); //消息指令类型判断, data[8] == 0x73 为数据类型, data[9] == 0x52||0x53 为传输方向(发送或接受) if ((data[8] == 0x73 && data[9] == 0x52) || (data[8] == 0x73 && data[9] == 0x53)) //command type:0x73(s) 0x52/0X53(R/S) { //716雷达扫描的数据量很大, 一次完整的扫描信息分成了6条消息分开发送, //数据的包号l_n32PackageNo, 实际为1~6, 无限循环, 循环完毕后,6条加起来就是一个完整的雷达扫描数据 //奇数包发送前面的405个点的数据, 偶数包发送后面406个点的数据 int l_n32PackageNo = (data[50] << 8) + data[51]; //数据的帧号l_u32FrameNo, 实际为0~2^32, 相同帧号的6条消息表示这6条是雷达一次扫描的完整消息, unsigned int l_u32FrameNo = (data[46] << 24) + (data[47] << 16) + (data[48] << 8) + data[49]; //1~2包为扫描点到雷达的距离, 405+406 = 811, if (l_n32PackageNo == 1) { //重置当前的帧号, 清空数据, 防止出错后复用上一次的数据. m_current_frame_number = l_u32FrameNo; memset(m_scan_point_intensity, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); memset(m_scan_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); memset(m_two_echo_point_distance, 0, WANJI_SCAN_POINT_NUMBER_TOTAL); for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i) { m_scan_point_distance[i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); m_scan_point_distance[i] /= 1000.0;//毫米->米 //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据) if (m_scan_point_distance[i] >= 25 || m_scan_point_distance[i] == 0) { m_scan_point_distance[i] = NAN; } } } else if (l_n32PackageNo == 2) { //检查帧号的一致性 if (m_current_frame_number == l_u32FrameNo) { for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i) { m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] /= 1000.0;//毫米->米 //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据) if (m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] >= 25 || m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] == 0) { m_scan_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = NAN; } } //至此就得到了扫描点到雷达的距离, 如有需要, 可以再此使用 //数据加锁的范围 { std::unique_lock lck(m_scan_mutex); mp_scan_points->clear(); // 把点到雷达的距离, 转化为标准坐标下的点云 t_error = polar_coordinates_transform_cloud(m_scan_point_distance, WANJI_SCAN_POINT_NUMBER_TOTAL, mp_scan_points); m_scan_cloud_time = std::chrono::system_clock::now(); } } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } } //1~2包为扫描点的光强, 405+406 = 811, else if (l_n32PackageNo == 3) { //检查帧号的一致性 if (m_current_frame_number == l_u32FrameNo) { for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i) { m_scan_point_intensity[i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); } } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } } else if (l_n32PackageNo == 4) { //检查帧号的一致性 if (m_current_frame_number == l_u32FrameNo) { for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i) { m_scan_point_intensity[WANJI_SCAN_POINT_NUMBER_FORMER + i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); } //至此就得到了扫描点的光强, 如有需要, 可以再此使用 } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } } else if (l_n32PackageNo == 5) { //检查帧号的一致性 if (m_current_frame_number == l_u32FrameNo) { for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_FORMER; ++i) { m_two_echo_point_distance[i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); m_two_echo_point_distance[i] /= 1000.0;//毫米->米 //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据) if (m_two_echo_point_distance[i] >= 25 || m_two_echo_point_distance[i] == 0) { m_two_echo_point_distance[i] = NAN; } } } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } } else if (l_n32PackageNo == 6) { //检查帧号的一致性 if (m_current_frame_number == l_u32FrameNo) { for (int i = 0; i < WANJI_SCAN_POINT_NUMBER_LATTER; ++i) { m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = (((unsigned char) data[85 + i * 2]) << 8) + ((unsigned char) data[86 + i * 2]); m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] /= 1000.0;//毫米->米 //有效距离范围0~25, 超出的点强制改为NAN(无效的浮点数据) if (m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] >= 25 || m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] == 0) { m_two_echo_point_distance[WANJI_SCAN_POINT_NUMBER_FORMER + i] = NAN; } } //至此就得到了二次反射的扫描点到雷达的距离, 如有需要, 可以再此使用 //数据加锁的范围 { std::unique_lock lck(m_two_echo_mutex); mp_two_echo_points->clear(); // 把点到雷达的距离, 转化为标准坐标下的点云 t_error = polar_coordinates_transform_cloud(m_two_echo_point_distance, WANJI_SCAN_POINT_NUMBER_TOTAL, mp_two_echo_points); m_two_echo_cloud_time = std::chrono::system_clock::now(); } } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } } return Error_manager(Error_code::SUCCESS); } else { return Error_manager(Error_code::WJ_PROTOCOL_PARSE_FAILED, Error_level::NEGLIGIBLE_ERROR, " Wj_716_lidar_protocol::data_protocol_analysis parse failed "); } return Error_code::SUCCESS; } // 把点到雷达的距离, 转化为标准坐标下的点云 Error_manager Wj_716_lidar_protocol::polar_coordinates_transform_cloud(float *p_point_distance, int number, pcl::PointCloud::Ptr p_cloud_out) { if (p_point_distance == NULL || p_cloud_out.get() == NULL) { return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR, " POINTER IS NULL "); } else { pcl::PointXYZ point; for (int i = 0; i < number; ++i) { float angle = WANJI_SCAN_POINT_ANGLE_MIN + i * WANJI_SCAN_POINT_ANGLE_INCREMENT; //判断极坐标点是否在限制范围 if (Point2D_tool::limit_with_polar_coordinates_box(p_point_distance[i], angle, &m_polar_coordinates_box)) { //极坐标 -> 平面坐标 float x = p_point_distance[i] * cos(angle); float y = p_point_distance[i] * sin(angle); //判断平面坐标点是否在限制范围 if (Point2D_tool::limit_with_point2D_box(x, y, &m_point2D_box)) { //平面坐标的转换, 可以进行旋转和平移, 不能缩放 point.x = x * m_point2D_transform.m00 + y * m_point2D_transform.m01 + m_point2D_transform.m02; point.y = x * m_point2D_transform.m10 + y * m_point2D_transform.m11 + m_point2D_transform.m12; //添加到最终点云 p_cloud_out->push_back(point); } //else直接忽略 } //else直接忽略 } } return Error_code::SUCCESS; }