该示例演示了如何通过 API 接口操作 A 系列相机采集点云数据。
包括如何发现相机并连接相机,如何设置 3d 参数,以及如何采集点云、保存点云。
关于参数的具体信息,以及设置后产生的影响,请使用 ALSON Viewer 进行操作验证。
如何在Visual Studio、QT、CLion中使用示例工程请参考示例工程使用说明。
注意:设置参数时请关注各个参数是否可写,以及参数的上下限!
// std
#include <iostream>
// alson
#include <alson/classic_client.h>
// 客户端事件监听器
class SimpleClientEventListener : public ALSON::BaseClientEventListener {
public:
void onDisconnectedByException() override {
// 当通信异常断开时,该函数会被调用。这里打印一条消息作为演示。
// 在实际的工程应用中应该及时向用户反馈,待异常解决后执行重连逻辑。
std::cout << "********************* client exception *******************" << std::endl;
}
};
// 设备事件监听器
class SimpleDeviceEventListener : public ALSON::ClassicDeviceEventListener {
public:
void onDeviceException(uint64_t code, const std::string& message) override {
// 当硬件出现异常时,该函数会被调用。这里打印一条消息作为演示。
// 硬件异常包括相机断开连接、串口断开连接等。
// 在实际的工程应用中应该及时向用户反馈,待异常解决后执行重连逻辑。
std::cout << "********************* device exception *******************" << std::endl;
}
};
int main(int argc, char** argv) {
try {
// 开启客户端日志,需要指定日志配置文件。
ALSON::Client::initLog("../../../LogConfig-Client.yaml");
// 检测所有服务端(即可用的设备),并获取其中第一个服务端的信息
std::vector<ALSON::ServerInfo> serverInfoList = ALSON::Client::discovery();
if (serverInfoList.empty()) {
std::cerr << "can not find any server or device" << std::endl;
return -1;
}
ALSON::ServerInfo serverInfo = serverInfoList.front();
// 构造客户端并建立通信连接
ALSON::Client client;
client.connect(serverInfo.getServerNetworkCardInfo().getIp(), serverInfo.getServerNetworkCardInfo().getBindPort());
std::cout << "is connected: " << client.isConnected() << std::endl;
// 心跳时间通常设置为 2000ms 至 3000ms。在开发调试过程中,可适当设置大些。
// 如果心跳时间很大,那么当通信意外断开时,客户端和服务端都需要经历很长的时间才能感知到。
// 在此期间,客户端将阻塞您的进程,服务端不能被新的客户端连接。
client.setHeartbeatTimeout(3000);
// 注册客户端事件监听器
ALSON::BaseClientEventListenerPtr clientEventListener = std::make_shared<SimpleClientEventListener>();
client.setClientEventListener(clientEventListener);
// 创建设备控制器对象
ALSON::ClassicDeviceController deviceController = client.createDeviceController<ALSON::ClassicDeviceController>();
// 注册设备事件监听器
ALSON::ClassicDeviceEventListenerPtr classicDeviceEventListener = std::make_shared<SimpleDeviceEventListener>();
deviceController.setDeviceEventListener(classicDeviceEventListener);
// 打开设备。注意无论设备是否关闭,在调用 DeviceController 中其他接口之前都必须调用 open 接口。
deviceController.open();
// 获取参数组管理器
ALSON::DeviceParameterManager parameterManager = client.createDeviceParameterManager();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 使用默认参数扫描点云
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 重置参数组,所有参数会恢复成默认值。
parameterManager.resetCurrentValue();
// 扫描点云并保存
ALSON::PointCloud pointCloud = deviceController.grabPointCloud();
pointCloud.save("./GrabPointCloud_A_PointCloud_Default.pcd");
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 快速进行大范围扫描
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 设置转动速度,转动速度会改变线激光器的电机转动速度,进而改变激光线的扫描速度。速度越快,点云越稀疏;速度越慢,点云越稠密。
parameterManager.updateCurrentIntegerValue("3dParameters.turnSpeed", 60);
// 设置触发频率,触发频率会改变硬件触发采图的频率。触发频率越高,点云越稠密;触发频率越低,点云越稀疏。
parameterManager.updateCurrentIntegerValue("3dParameters.triggerFrequency", 35);
// 设置左右角度会改变激光器的点击转动角度,进而改变激光器的扫描范围。
parameterManager.updateCurrentIntegerValue("3dParameters.leftAngle", 35);
parameterManager.updateCurrentIntegerValue("3dParameters.rightAngle", 35);
// 扫描点云并保存
pointCloud = deviceController.grabPointCloud();
pointCloud.save("./GrabPointCloud_A_PointCloud_FastSpeed.pcd");
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 开启点云平滑
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 重置参数组,所有参数会恢复成默认值。
parameterManager.resetCurrentValue();
// 点云平滑强度为 OFF 时不对点云做平滑处理;为 LOW、MEDIUM、HIGH 时平滑效果由弱到强。
// 设置点云平滑强度
parameterManager.updateCurrentEnumerationValue("3dParameters.laserLineSmoothIntensity", "HIGH");
// 扫描点云并保存
pointCloud = deviceController.grabPointCloud();
pointCloud.save("./GrabPointCloud_A_PointCloud_Smooth.pcd");
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 扫描感兴趣区域内的点云
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 重置参数组,所有参数会恢复成默认值。
parameterManager.resetCurrentValue();
// 左右相机可独立设置 3d ROI,每个相机最多可设置五组 ROI。同一相机的多个 ROI 取并集生效。
// 最终生成的点云取决于左右相机 ROI 的公共区域。因此通常只需要设置左相机 ROI 即可。
// 若环境中存在无法处理的干扰区域,则可能需要左右相机同时设置 ROI 避免干扰区域的影响。
// 为确保一定设置成功,可以先重置 ROI,再设置成目标值,先设置宽度和高度,再设置 x,y。
// 设置左相机 3d ROI
parameterManager.resetCurrentValue("3dParameters.leftRoiArray");
parameterManager.updateCurrentIntegerValue("3dParameters.leftRoiArray[0].roiW", 500);
parameterManager.updateCurrentIntegerValue("3dParameters.leftRoiArray[0].roiH", 300);
parameterManager.updateCurrentIntegerValue("3dParameters.leftRoiArray[0].roiX", 0);
parameterManager.updateCurrentIntegerValue("3dParameters.leftRoiArray[0].roiY", 0);
// 设置右相机 3d ROI
parameterManager.resetCurrentValue("3dParameters.rightRoiArray");
parameterManager.updateCurrentIntegerValue("3dParameters.rightRoiArray[0].roiW", 500);
parameterManager.updateCurrentIntegerValue("3dParameters.rightRoiArray[0].roiH", 300);
parameterManager.updateCurrentIntegerValue("3dParameters.rightRoiArray[0].roiX", 0);
parameterManager.updateCurrentIntegerValue("3dParameters.rightRoiArray[0].roiY", 0);
// 测量深度范围默认值为设备最佳工作距离范围,上限为设备的最远工作距离,下限为设备的最近工作距离。可根据实际的工作场景设置。
// 设置测量深度范围
parameterManager.updateCurrentIntegerValue("3dParameters.depthRange.lowerLimit", 50);
parameterManager.updateCurrentIntegerValue("3dParameters.depthRange.upperLimit", 5000);
// 扫描点云并保存
pointCloud = deviceController.grabPointCloud();
pointCloud.save("./GrabPointCloud_A_PointCloud_WithROI.pcd");
// 关闭设备。注意:close 接口一般情况下不需要调用,如果该接口被调用,下次调用 open 接口的时候就会比较耗时。
deviceController.close();
// 如果不再需要连接服务端,请及时调用 disconnect 断开连接。
client.disconnect();
}
catch (ALSON::CommonException& cause) {
// API 中的所有接口都有可能抛出异常,请按照这种方式进行捕获。否则异常发生时可能会导致程序崩溃。
std::cerr << cause.getStackTrace() << std::endl;
return -1;
}
return 0;
}