GrabBag/Device/RsLidarDevice/Src/RsLidarDevice.cpp

338 lines
8.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "RsLidarDevice.h"
#include <cmath>
// WSAStartup 引用计数
static std::atomic<int> g_sockRefCount{0};
// ============================================================
// 工厂方法
// ============================================================
int IRsLidarDevice::CreateObject(IRsLidarDevice** ppDevice)
{
if (!ppDevice) return -1;
CRsLidarDevice* p = new CRsLidarDevice();
*ppDevice = p;
return 0;
}
// ============================================================
// 构造 / 析构
// ============================================================
CRsLidarDevice::CRsLidarDevice()
: m_pDriver(std::make_unique<LidarDriver<SdkCloudMsg>>())
{
}
CRsLidarDevice::~CRsLidarDevice()
{
Stop();
CloseDevice();
}
// ============================================================
// InitDevice
// ============================================================
int CRsLidarDevice::InitDevice()
{
#ifdef _WIN32
if (g_sockRefCount == 0)
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return -1;
}
}
g_sockRefCount++;
#endif
return 0;
}
// ============================================================
// 类型转换: RsLidarConfig → RSDriverParam
// ============================================================
RSDriverParam CRsLidarDevice::toDriverParam(const RsLidarConfig& config)
{
RSDriverParam param;
param.lidar_type = strToLidarType(config.lidarType);
param.input_type = InputType::ONLINE_LIDAR;
param.frame_id = config.frameId;
param.input_param.host_address = config.hostAddress;
param.input_param.msop_port = config.msopPort;
param.input_param.difop_port = config.difopPort;
param.input_param.imu_port = config.imuPort;
param.decoder_param.min_distance = config.minDistance;
param.decoder_param.max_distance = config.maxDistance;
param.decoder_param.dense_points = config.densePoints;
param.decoder_param.use_lidar_clock = config.useLidarClock;
param.decoder_param.ts_first_point = config.tsFirstPoint;
param.decoder_param.wait_for_difop = config.waitForDifop;
param.decoder_param.start_angle = config.startAngle;
param.decoder_param.end_angle = config.endAngle;
param.decoder_param.split_angle = config.splitAngle;
return param;
}
// ============================================================
// OpenDevice
// ============================================================
int CRsLidarDevice::OpenDevice(const RsLidarConfig& config)
{
if (!m_pDriver)
{
return -1;
}
CloseDevice();
m_param = toDriverParam(config);
m_pDriver->regPointCloudCallback(
[this]() -> SdkCloudPtr { return this->getFreeCloud(); },
[this](SdkCloudPtr msg) { this->putStuffedCloud(msg); }
);
m_pDriver->regPacketCallback(
[this](const Packet& pkt) { this->onPacket(pkt); }
);
m_pDriver->regExceptionCallback(
[this](const Error& code) { this->onException(code); }
);
if (!m_pDriver->init(m_param))
{
return -2;
}
m_bOpened = true;
return 0;
}
// ============================================================
// CloseDevice
// ============================================================
int CRsLidarDevice::CloseDevice()
{
if (m_bRunning)
{
Stop();
}
m_bOpened = false;
m_freeQueue.clear();
m_stuffedQueue.clear();
#ifdef _WIN32
if (--g_sockRefCount == 0)
{
WSACleanup();
}
#endif
return 0;
}
bool CRsLidarDevice::IsOpened() const
{
return m_bOpened;
}
// ============================================================
// Start / Stop
// ============================================================
int CRsLidarDevice::Start()
{
if (!m_bOpened || !m_pDriver)
{
return -1;
}
if (m_bRunning)
{
return 0;
}
for (int i = 0; i < 8; ++i)
{
m_freeQueue.push(std::make_shared<SdkCloudMsg>());
}
m_bStopProcess = false;
m_pDriver->start();
m_bRunning = true;
m_processThread = std::thread(&CRsLidarDevice::processCloudThread, this);
return 0;
}
int CRsLidarDevice::Stop()
{
if (!m_bRunning)
{
return 0;
}
m_bStopProcess = true;
if (m_pDriver)
{
m_pDriver->stop();
}
if (m_processThread.joinable())
{
m_processThread.join();
}
m_bRunning = false;
return 0;
}
bool CRsLidarDevice::IsRunning() const
{
return m_bRunning;
}
// ============================================================
// 回调注册
// ============================================================
int CRsLidarDevice::SetPointCloudCallback(PointCloudCallback callback)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
m_pointCloudCallback = std::move(callback);
return 0;
}
int CRsLidarDevice::SetPacketCallback(PacketCallback callback)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
m_packetCallback = std::move(callback);
return 0;
}
int CRsLidarDevice::SetExceptionCallback(ExceptionCallback callback)
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
m_exceptionCallback = std::move(callback);
return 0;
}
std::string CRsLidarDevice::GetVersion()
{
return getDriverVersion();
}
// ============================================================
// 内部:点云处理线程
// ============================================================
void CRsLidarDevice::processCloudThread()
{
while (!m_bStopProcess)
{
SdkCloudPtr sdkCloud = m_stuffedQueue.popWait(500000);
if (!sdkCloud || sdkCloud->points.empty())
{
continue;
}
PointCloudCallback cb;
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
cb = m_pointCloudCallback;
}
if (cb)
{
// 转换并清洗数据: NaN→0, m→mm
const auto& src = sdkCloud->points;
std::vector<RsPointXYZI> transformed;
transformed.reserve(src.size());
for (const auto& s : src)
{
RsPointXYZI p;
p.x = (std::isnan(s.x) ? 0.0f : s.x) * 1000.0f;
p.y = (std::isnan(s.y) ? 0.0f : s.y) * 1000.0f;
p.z = (std::isnan(s.z) ? 0.0f : s.z) * 1000.0f;
p.intensity = s.intensity;
transformed.push_back(p);
}
RsPointCloudData data;
data.seq = sdkCloud->seq;
data.timestamp = sdkCloud->timestamp;
data.height = sdkCloud->height;
data.width = sdkCloud->width;
data.isDense = sdkCloud->is_dense;
data.frameId = sdkCloud->frame_id;
data.pointCount = static_cast<uint32_t>(transformed.size());
data.points = transformed.data();
cb(data);
}
m_freeQueue.push(sdkCloud);
}
}
// ============================================================
// 内部:空闲/就绪队列回调rs_driver 内部线程)
// ============================================================
CRsLidarDevice::SdkCloudPtr CRsLidarDevice::getFreeCloud()
{
auto msg = m_freeQueue.pop();
if (msg) return msg;
return std::make_shared<SdkCloudMsg>();
}
void CRsLidarDevice::putStuffedCloud(SdkCloudPtr msg)
{
m_stuffedQueue.push(msg);
}
// ============================================================
// 内部Packet → RsPacketInfo
// ============================================================
void CRsLidarDevice::onPacket(const Packet& pkt)
{
PacketCallback cb;
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
cb = m_packetCallback;
}
if (cb)
{
RsPacketInfo info;
info.timestamp = pkt.timestamp;
info.seq = pkt.seq;
info.is_difop = pkt.is_difop;
info.is_frame_begin = pkt.is_frame_begin;
info.frameId = pkt.frame_id;
info.dataSize = static_cast<uint32_t>(pkt.buf_.size());
cb(info);
}
}
// ============================================================
// 内部Error → RsExceptionInfo
// ============================================================
void CRsLidarDevice::onException(const Error& code)
{
ExceptionCallback cb;
{
std::lock_guard<std::mutex> lock(m_callbackMutex);
cb = m_exceptionCallback;
}
if (cb)
{
RsExceptionInfo info;
info.code = static_cast<int>(code.error_code);
info.message = code.toString();
cb(info);
}
}