update: 扩大ip搜索范围,修改点云可视化逻辑,添加上位机与下位机曝光值同步
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#include "DeviceScanner.h"
|
||||
#include <QNetworkDatagram>
|
||||
#include <QNetworkInterface>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
|
||||
DeviceScanner::DeviceScanner(QObject *parent)
|
||||
@@ -8,8 +10,9 @@ DeviceScanner::DeviceScanner(QObject *parent)
|
||||
, m_socket(new QUdpSocket(this))
|
||||
, m_timeoutTimer(new QTimer(this))
|
||||
, m_scanTimer(new QTimer(this))
|
||||
, m_currentHost(HOST_START)
|
||||
, m_totalHosts(HOST_END - HOST_START + 1)
|
||||
, m_prefixLength(24)
|
||||
, m_currentHost(0)
|
||||
, m_totalHosts(0)
|
||||
, m_isScanning(false)
|
||||
{
|
||||
connect(m_socket, &QUdpSocket::readyRead, this, &DeviceScanner::onReadyRead);
|
||||
@@ -33,8 +36,9 @@ void DeviceScanner::startScan(const QString &subnet)
|
||||
return;
|
||||
}
|
||||
|
||||
m_subnet = subnet.isEmpty() ? getLocalSubnet() : subnet;
|
||||
m_currentHost = HOST_START;
|
||||
// Get network info (base IP and prefix length)
|
||||
getLocalNetworkInfo(m_baseIp, m_prefixLength);
|
||||
|
||||
m_foundDevices.clear();
|
||||
m_isScanning = true;
|
||||
|
||||
@@ -44,17 +48,62 @@ void DeviceScanner::startScan(const QString &subnet)
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Starting fast device scan on subnet:" << m_subnet;
|
||||
|
||||
// Send DISCOVER to all hosts at once (batch mode)
|
||||
for (int host = HOST_START; host <= HOST_END; host++) {
|
||||
QString ip = m_subnet + "." + QString::number(host);
|
||||
sendDiscoveryPacket(ip);
|
||||
// Calculate IP range based on prefix length
|
||||
QStringList parts = m_baseIp.split('.');
|
||||
if (parts.size() != 4) {
|
||||
emit scanError("Invalid base IP");
|
||||
m_isScanning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait 3 seconds for all responses
|
||||
m_timeoutTimer->start(3000);
|
||||
qDebug() << "Sent discovery packets to all hosts, waiting for responses...";
|
||||
quint32 baseAddr = (parts[0].toUInt() << 24) | (parts[1].toUInt() << 16) |
|
||||
(parts[2].toUInt() << 8) | parts[3].toUInt();
|
||||
quint32 mask = (0xFFFFFFFF << (32 - m_prefixLength)) & 0xFFFFFFFF;
|
||||
quint32 networkAddr = baseAddr & mask;
|
||||
quint32 broadcastAddr = networkAddr | (~mask & 0xFFFFFFFF);
|
||||
|
||||
qDebug() << "Starting device scan - Base IP:" << m_baseIp << "Prefix:" << m_prefixLength;
|
||||
|
||||
int packetsSent = 0;
|
||||
|
||||
// For large subnets (/16 or larger), use broadcast + batched unicast
|
||||
if (m_prefixLength <= 16) {
|
||||
// First: send to subnet broadcast address
|
||||
QHostAddress broadcast(broadcastAddr);
|
||||
qDebug() << "Large subnet detected, using broadcast discovery:" << broadcast.toString();
|
||||
sendDiscoveryPacket(broadcast.toString());
|
||||
packetsSent++;
|
||||
|
||||
// Second: scan all /24 subnets with throttling to avoid buffer overflow
|
||||
qDebug() << "Scanning all /24 subnets within /16 range (throttled)...";
|
||||
for (int oct3 = 0; oct3 <= 255; oct3++) {
|
||||
quint32 subNetBase = (networkAddr & 0xFFFF0000) | (oct3 << 8);
|
||||
for (int oct4 = 1; oct4 <= 254; oct4++) {
|
||||
quint32 addr = subNetBase | oct4;
|
||||
sendDiscoveryPacket(QHostAddress(addr).toString());
|
||||
packetsSent++;
|
||||
}
|
||||
// Process events and add small delay every /24 subnet to avoid buffer overflow
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(5);
|
||||
}
|
||||
} else {
|
||||
// For smaller subnets, scan all hosts
|
||||
qDebug() << "Network range:" << QHostAddress(networkAddr + 1).toString()
|
||||
<< "to" << QHostAddress(broadcastAddr - 1).toString();
|
||||
|
||||
for (quint32 addr = networkAddr + 1; addr < broadcastAddr; addr++) {
|
||||
sendDiscoveryPacket(QHostAddress(addr).toString());
|
||||
packetsSent++;
|
||||
}
|
||||
}
|
||||
|
||||
m_totalHosts = packetsSent;
|
||||
qDebug() << "Sent" << packetsSent << "discovery packets, waiting for responses...";
|
||||
|
||||
// Adjust timeout based on network size
|
||||
int timeout = (m_prefixLength >= 24) ? 3000 : 10000;
|
||||
m_timeoutTimer->start(timeout);
|
||||
}
|
||||
|
||||
void DeviceScanner::stopScan()
|
||||
@@ -91,7 +140,14 @@ void DeviceScanner::onReadyRead()
|
||||
|
||||
qDebug() << "Received response from" << senderIp << ":" << response;
|
||||
|
||||
if (response.contains("D330M_CAMERA")) {
|
||||
if (response.startsWith("EXPOSURE:")) {
|
||||
bool ok;
|
||||
int exposure = response.mid(9).trimmed().toInt(&ok);
|
||||
if (ok && exposure > 0) {
|
||||
qDebug() << "Received exposure from camera:" << exposure << "us";
|
||||
emit exposureReceived(exposure);
|
||||
}
|
||||
} else if (response.contains("D330M_CAMERA")) {
|
||||
DeviceInfo device;
|
||||
device.ipAddress = senderIp;
|
||||
device.deviceName = "Camera";
|
||||
@@ -122,7 +178,7 @@ void DeviceScanner::sendDiscoveryPacket(const QString &ip)
|
||||
m_socket->writeDatagram(data, QHostAddress(ip), SCAN_PORT);
|
||||
}
|
||||
|
||||
QString DeviceScanner::getLocalSubnet()
|
||||
void DeviceScanner::getLocalNetworkInfo(QString &baseIp, int &prefixLength)
|
||||
{
|
||||
// Get all network interfaces
|
||||
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
|
||||
@@ -144,12 +200,14 @@ QString DeviceScanner::getLocalSubnet()
|
||||
for (const QNetworkAddressEntry &entry : entries) {
|
||||
QHostAddress addr = entry.ip();
|
||||
if (addr.protocol() == QAbstractSocket::IPv4Protocol && !addr.isLoopback()) {
|
||||
QString ip = addr.toString();
|
||||
QStringList parts = ip.split('.');
|
||||
if (parts.size() == 4) {
|
||||
qDebug() << "Found Ethernet adapter:" << iface.humanReadableName() << "IP:" << ip;
|
||||
return parts[0] + "." + parts[1] + "." + parts[2];
|
||||
baseIp = addr.toString();
|
||||
prefixLength = entry.prefixLength();
|
||||
if (prefixLength <= 0 || prefixLength > 32) {
|
||||
prefixLength = 24; // Default to /24 if invalid
|
||||
}
|
||||
qDebug() << "Found Ethernet adapter:" << iface.humanReadableName()
|
||||
<< "IP:" << baseIp << "Prefix:" << prefixLength;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,15 +227,19 @@ QString DeviceScanner::getLocalSubnet()
|
||||
for (const QNetworkAddressEntry &entry : entries) {
|
||||
QHostAddress addr = entry.ip();
|
||||
if (addr.protocol() == QAbstractSocket::IPv4Protocol && !addr.isLoopback()) {
|
||||
QString ip = addr.toString();
|
||||
QStringList parts = ip.split('.');
|
||||
if (parts.size() == 4) {
|
||||
qDebug() << "Found adapter:" << iface.humanReadableName() << "IP:" << ip;
|
||||
return parts[0] + "." + parts[1] + "." + parts[2];
|
||||
baseIp = addr.toString();
|
||||
prefixLength = entry.prefixLength();
|
||||
if (prefixLength <= 0 || prefixLength > 32) {
|
||||
prefixLength = 24;
|
||||
}
|
||||
qDebug() << "Found adapter:" << iface.humanReadableName()
|
||||
<< "IP:" << baseIp << "Prefix:" << prefixLength;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "192.168.0";
|
||||
// Default fallback
|
||||
baseIp = "192.168.0.1";
|
||||
prefixLength = 24;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
|
||||
signals:
|
||||
void deviceFound(const DeviceInfo &device);
|
||||
void exposureReceived(int exposureUs);
|
||||
void scanProgress(int current, int total);
|
||||
void scanFinished(int devicesFound);
|
||||
void scanError(const QString &error);
|
||||
@@ -40,13 +41,14 @@ private slots:
|
||||
|
||||
private:
|
||||
void sendDiscoveryPacket(const QString &ip);
|
||||
QString getLocalSubnet();
|
||||
void getLocalNetworkInfo(QString &baseIp, int &prefixLength);
|
||||
|
||||
QUdpSocket *m_socket;
|
||||
QTimer *m_timeoutTimer;
|
||||
QTimer *m_scanTimer;
|
||||
|
||||
QString m_subnet;
|
||||
QString m_baseIp;
|
||||
int m_prefixLength;
|
||||
int m_currentHost;
|
||||
int m_totalHosts;
|
||||
bool m_isScanning;
|
||||
@@ -55,8 +57,6 @@ private:
|
||||
|
||||
static constexpr int SCAN_PORT = 6790; // Control port for device discovery
|
||||
static constexpr int SCAN_TIMEOUT = 10;
|
||||
static constexpr int HOST_START = 1;
|
||||
static constexpr int HOST_END = 254;
|
||||
};
|
||||
|
||||
#endif // DEVICESCANNER_H
|
||||
|
||||
@@ -16,6 +16,9 @@ NetworkManager::NetworkManager(QObject *parent)
|
||||
connect(m_dataSocket, &QUdpSocket::readyRead, this, &NetworkManager::onReadyRead);
|
||||
connect(m_dataSocket, &QUdpSocket::errorOccurred, this, &NetworkManager::onError);
|
||||
|
||||
// 连接控制socket接收信号(用于接收相机回复,如曝光值)
|
||||
connect(m_controlSocket, &QUdpSocket::readyRead, this, &NetworkManager::onControlReadyRead);
|
||||
|
||||
// 连接GVSP解析器信号
|
||||
connect(m_gvspParser, &GVSPParser::imageReceived, this, &NetworkManager::imageReceived);
|
||||
connect(m_gvspParser, &GVSPParser::leftImageReceived, this, &NetworkManager::leftImageReceived);
|
||||
@@ -67,6 +70,10 @@ bool NetworkManager::connectToCamera(const QString &ip, int controlPort, int dat
|
||||
m_isConnected = true;
|
||||
qDebug() << "Connected to camera:" << m_cameraIp << "Control port:" << m_controlPort << "Data port:" << m_dataPort;
|
||||
|
||||
// Send DISCOVER to get camera's current exposure value
|
||||
sendCommand("DISCOVER");
|
||||
qDebug() << "Sent DISCOVER to fetch camera exposure";
|
||||
|
||||
// Send STOP command to register client IP on camera
|
||||
sendStopCommand();
|
||||
qDebug() << "Sent STOP command to register client IP";
|
||||
@@ -213,6 +220,27 @@ void NetworkManager::onReadyRead()
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkManager::onControlReadyRead()
|
||||
{
|
||||
while (m_controlSocket->hasPendingDatagrams()) {
|
||||
QByteArray datagram;
|
||||
datagram.resize(m_controlSocket->pendingDatagramSize());
|
||||
m_controlSocket->readDatagram(datagram.data(), datagram.size());
|
||||
|
||||
QString response = QString::fromUtf8(datagram);
|
||||
qDebug() << "[NetworkManager] Control response:" << response;
|
||||
|
||||
if (response.startsWith("EXPOSURE:")) {
|
||||
bool ok;
|
||||
int exposure = response.mid(9).trimmed().toInt(&ok);
|
||||
if (ok && exposure > 0) {
|
||||
qDebug() << "[NetworkManager] Camera exposure:" << exposure << "us";
|
||||
emit exposureReceived(exposure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkManager::onError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
QString error = QString("Socket error: %1").arg(m_dataSocket->errorString());
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void exposureReceived(int exposureUs);
|
||||
void errorOccurred(const QString &error);
|
||||
void dataReceived(const QByteArray &data);
|
||||
void imageReceived(const QImage &image, uint32_t blockId);
|
||||
@@ -54,6 +55,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void onReadyRead();
|
||||
void onControlReadyRead();
|
||||
void onError(QAbstractSocket::SocketError socketError);
|
||||
|
||||
private:
|
||||
|
||||
@@ -106,9 +106,8 @@ bool PointCloudProcessor::initializeOpenCL()
|
||||
"int y = idx / width; "
|
||||
"int x = idx % width; "
|
||||
"float z = depth[idx] * z_scale; "
|
||||
// 完全平面的圆柱投影:X和Y直接使用像素坐标,缩放到合适的范围
|
||||
"xyz[idx*3] = (x - cx) * 2.0f; " // X坐标,缩放系数2.0
|
||||
"xyz[idx*3+1] = -(y - cy) * 2.0f; " // Y坐标取反,修正上下颠倒
|
||||
"xyz[idx*3] = (x - cx) * z * inv_fx; "
|
||||
"xyz[idx*3+1] = (y - cy) * z * inv_fy; "
|
||||
"xyz[idx*3+2] = z; "
|
||||
"}";
|
||||
|
||||
@@ -283,31 +282,30 @@ void PointCloudProcessor::processPointCloudData(const QByteArray &cloudData, uin
|
||||
// 从int16_t数组读取点云数据
|
||||
const int16_t* cloudShort = reinterpret_cast<const int16_t*>(cloudData.constData());
|
||||
|
||||
float inv_fx = 1.0f / m_fx;
|
||||
float inv_fy = 1.0f / m_fy;
|
||||
|
||||
if (isZOnly) {
|
||||
// Z-only格式:转换为正交投影(柱形)
|
||||
// Z-only格式:标准针孔模型反投影
|
||||
for (size_t i = 0; i < m_totalPoints; i++) {
|
||||
int row = i / m_imageWidth;
|
||||
int col = i % m_imageWidth;
|
||||
|
||||
// 读取深度值(单位:毫米)
|
||||
float z = static_cast<float>(cloudShort[i]) * m_zScale;
|
||||
|
||||
// 正交投影:X、Y使用像素坐标(Y轴翻转以修正镜像)
|
||||
cloud->points[i].x = static_cast<float>(col);
|
||||
cloud->points[i].y = static_cast<float>(m_imageHeight - 1 - row);
|
||||
cloud->points[i].x = (col - m_cx) * z * inv_fx;
|
||||
cloud->points[i].y = (row - m_cy) * z * inv_fy;
|
||||
cloud->points[i].z = z;
|
||||
}
|
||||
} else {
|
||||
// XYZ格式:完整的三维坐标
|
||||
// 转换为正交投影(柱形),使用像素坐标作为X、Y
|
||||
// XYZ格式:使用Z值进行针孔模型反投影
|
||||
for (size_t i = 0; i < m_totalPoints; i++) {
|
||||
int row = i / m_imageWidth;
|
||||
int col = i % m_imageWidth;
|
||||
|
||||
// 正交投影:X、Y使用像素坐标(Y轴翻转以修正镜像),Z使用深度值
|
||||
cloud->points[i].x = static_cast<float>(col);
|
||||
cloud->points[i].y = static_cast<float>(m_imageHeight - 1 - row);
|
||||
cloud->points[i].z = static_cast<float>(cloudShort[i * 3 + 2]) * m_zScale;
|
||||
float z = static_cast<float>(cloudShort[i * 3 + 2]) * m_zScale;
|
||||
cloud->points[i].x = (col - m_cx) * z * inv_fx;
|
||||
cloud->points[i].y = (row - m_cy) * z * inv_fy;
|
||||
cloud->points[i].z = z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user