Mech-Eye API 2.5.2
API reference documentation for Mech-Eye 3D Laser Profiler
Loading...
Searching...
No Matches
api_util.h
1/*******************************************************************************
2 *BSD 3-Clause License
3 *
4 *Copyright (c) 2016-2025, Mech-Mind Robotics Technologies Co., Ltd.
5 *All rights reserved.
6 *
7 *Redistribution and use in source and binary forms, with or without
8 *modification, are permitted provided that the following conditions are met:
9 *
10 *1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 *2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 *3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 *DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 *SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 *CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 *OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 *OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ******************************************************************************/
32
33#pragma once
34#include <iomanip>
35#include <iostream>
36#include <regex>
37#include <set>
38#include <utility>
39#ifdef WIN32
40#include <windows.h>
41#endif
42#include "ErrorStatus.h"
43#include "CommonTypes.h"
44#include "profiler/parameters/ScanParameters.h"
45#include "Profiler.h"
46#include "ProfilerInfo.h"
47
51inline void printProfilerInfo(const mmind::eye::ProfilerInfo& profilerInfo)
52{
53 std::cout << "........................................." << std::endl;
54 std::cout << "Model: " << profilerInfo.model << std::endl;
55#ifdef WIN32
56 const auto consoleCP = GetConsoleOutputCP();
57 SetConsoleOutputCP(CP_UTF8);
58#endif
59 std::cout << "Device name: " << profilerInfo.deviceName << std::endl;
60#ifdef WIN32
61 SetConsoleOutputCP(consoleCP);
62#endif
63 std::cout << "Controller serial number: " << profilerInfo.controllerSN << std::endl;
64 std::cout << "Sensor head serial number: " << profilerInfo.sensorSN << std::endl;
65 std::cout << "IP address: " << profilerInfo.ipAddress << std::endl;
66 std::cout << "Subnet mask: " << profilerInfo.subnetMask << std::endl;
67 std::cout << "IP address assignment method: "
68 << mmind::eye::ipAssignmentMethodToString(profilerInfo.ipAssignmentMethod)
69 << std::endl;
70 std::cout << "Hardware version: "
71 << "V" << profilerInfo.hardwareVersion.toString() << std::endl;
72 std::cout << "Firmware version: "
73 << "V" << profilerInfo.firmwareVersion.toString() << std::endl;
74 std::cout << "Support status: "
75 << (profilerInfo.supported ? "Supported" : "Unsupported") << std::endl;
76 if (!profilerInfo.lastSupportedVersion.isEmpty()) {
77 std::cout << "Last supported version: "
78 << "V" << profilerInfo.lastSupportedVersion.toString() << std::endl;
79 }
80 std::cout << "........................................." << std::endl;
81 std::cout << std::endl;
82}
83
84inline void printProfilerStatus(const mmind::eye::ProfilerStatus& profilerStatus)
85{
86 std::cout << ".....Profiler temperatures....." << std::endl;
87 std::cout << std::fixed << std::setprecision(1);
88 std::cout << "Controller CPU: " << profilerStatus.temperature.controllerCpuTemperature << "°C"
89 << std::endl;
90 std::cout << "Sensor CPU: " << profilerStatus.temperature.sensorCpuTemperature << "°C"
91 << std::endl;
92 std::cout << "..............................." << std::endl;
93 std::cout << std::defaultfloat << std::setprecision(6);
94 std::cout << std::endl;
95}
96
101inline bool findAndConnect(mmind::eye::Profiler& profiler)
102{
103 std::cout << "Looking for available profilers..." << std::endl;
104 std::vector<mmind::eye::ProfilerInfo> profilerInfoList =
106
107 if (profilerInfoList.empty()) {
108 std::cout << "No profilers are available." << std::endl;
109 return false;
110 }
111
112 for (size_t i = 0; i < profilerInfoList.size(); i++) {
113 std::cout << "Mech-Eye device index: " << i << std::endl;
114 printProfilerInfo(profilerInfoList[i]);
115 }
116
117 std::cout << "Enter the index of the device to which you want to connect: ";
118 unsigned inputIndex = 0;
119
120 while (true) {
121 std::string str;
122 std::cin >> str;
123 if (std::regex_match(str.begin(), str.end(), std::regex{"[0-9]+"}) &&
124 atoi(str.c_str()) < static_cast<int>(profilerInfoList.size())) {
125 inputIndex = atoi(str.c_str());
126 break;
127 }
128 std::cout << "The entered index is invalid. Please enter the device index again: ";
129 }
130
132 status = profiler.connect(profilerInfoList[inputIndex]);
133
134 if (!status.isOK()) {
135 showError(status);
136 return false;
137 }
138
139 std::cout << "Successfully connected to the profiler." << std::endl;
140 return true;
141}
142
143inline std::vector<mmind::eye::Profiler> findAndConnectMultiProfiler()
144{
145 std::cout << "Looking for available profilers..." << std::endl;
146 std::vector<mmind::eye::ProfilerInfo> profilerInfoList =
148
149 if (profilerInfoList.empty()) {
150 std::cout << "No profilers are available." << std::endl;
151 return {};
152 }
153
154 for (size_t i = 0; i < profilerInfoList.size(); i++) {
155 std::cout << "Mech-Eye device index: " << i << std::endl;
156 printProfilerInfo(profilerInfoList[i]);
157 }
158
159 std::string str;
160 std::set<unsigned> indices;
161
162 while (true) {
163 std::cout << "Enter the indices of the devices to which you want to connect: " << std::endl;
164 std::cout << "Enter the character \"c\" at the end of all the indices" << std::endl;
165
166 std::cin >> str;
167 if (str == "c")
168 break;
169 if (std::regex_match(str.begin(), str.end(), std::regex{"[0-9]+"}) &&
170 atoi(str.c_str()) < static_cast<int>(profilerInfoList.size()))
171 indices.insert(atoi(str.c_str()));
172 else
173 std::cout << "The entered indices are invalid. Please enter the device indices again: ";
174 }
175
176 std::vector<mmind::eye::Profiler> profilerList{};
177
178 for (const auto index : indices) {
179 mmind::eye::Profiler profiler;
180 const auto status = profiler.connect(profilerInfoList[index]);
181 if (status.isOK())
182 profilerList.push_back(profiler);
183 else
184 showError(status);
185 }
186
187 return profilerList;
188}
189
190inline bool confirmCapture()
191{
192 std::cout
193 << "Do you want the profiler to capture image? Enter \"y\" to confirm or \"n\" to cancel: "
194 << std::endl;
195 while (true) {
196 std::string confirmStr;
197 std::cin >> confirmStr;
198 if (confirmStr == "y") {
199 return true;
200 } else if (confirmStr == "n") {
201 std::cout << "The capture command was canceled." << std::endl;
202 return false;
203 } else {
204 std::cout << "The entered character was invalid. Please enter \"y\" ot confirm or "
205 "\"n\" to cancel:"
206 << std::endl;
207 }
208 }
209}
210
211inline void savePointCloud(const mmind::eye::ProfileBatch& batch,
212 const mmind::eye::UserSet& userSet, bool savePLY = true,
213 bool saveCSV = true, bool isOrganized = false)
214{
215 if (batch.isEmpty())
216 return;
217
218 // Get the X-axis resolution
219 double xResolution{};
220 auto status = userSet.getFloatValue(mmind::eye::point_cloud_resolutions::XAxisResolution::name,
221 xResolution);
222 if (!status.isOK()) {
223 showError(status);
224 return;
225 }
226
227 // Get the Y resolution
228 double yResolution{};
229 status =
230 userSet.getFloatValue(mmind::eye::point_cloud_resolutions::YResolution::name, yResolution);
231 if (!status.isOK()) {
232 showError(status);
233 return;
234 }
235 // // Uncomment the following lines for custom Y Unit
236 // // Prompt to enter the desired encoder resolution, which is the travel distance corresponding
237 // // to
238 // // one quadrature signal.
239 // std::cout << "Please enter the desired encoder resolution (integer, unit: μm, min: "
240 // "1, max: 65535): ";
241 // while (true) {
242 // std::string str;
243 // std::cin >> str;
244 // if (std::regex_match(str.begin(), str.end(), std::regex{"[0-9]+"})) {
245 // yResolution = atoi(str.c_str());
246 // break;
247 // }
248 // std::cout << "Input invalid! Please enter the desired encoder resolution (integer, unit:
249 // "
250 // "μm, min: 1, max: 65535): ";
251 // }
252
253 int lineScanTriggerSource{};
254 status = userSet.getEnumValue(mmind::eye::trigger_settings::LineScanTriggerSource::name,
255 lineScanTriggerSource);
256 if (!status.isOK()) {
257 showError(status);
258 return;
259 }
260
261 bool useEncoderValues =
262 lineScanTriggerSource ==
263 static_cast<int>(mmind::eye::trigger_settings::LineScanTriggerSource::Value::Encoder);
264
265 int triggerInterval{};
266 status = userSet.getIntValue(mmind::eye::trigger_settings::EncoderTriggerInterval::name,
267 triggerInterval);
268 if (!status.isOK()) {
269 showError(status);
270 return;
271 }
272
273 std::cout << "Save the point cloud." << std::endl;
274 if (saveCSV)
275 showError(batch.saveUntexturedPointCloud(
276 xResolution, yResolution, useEncoderValues, triggerInterval,
277 mmind::eye::FileFormat::CSV, "PointCloud.csv", mmind::eye::CoordinateUnit::Millimeter,
278 isOrganized));
279 if (savePLY)
280 showError(batch.saveUntexturedPointCloud(
281 xResolution, yResolution, useEncoderValues, triggerInterval,
282 mmind::eye::FileFormat::PLY, "PointCloud.ply", mmind::eye::CoordinateUnit::Millimeter,
283 isOrganized));
284}
285
286inline mmind::eye::ProfileBatch::PointCloud getUntexturedPointCloud(
287 const mmind::eye::ProfileBatch& batch, const mmind::eye::UserSet& userSet)
288{
289 if (batch.isEmpty())
290 return {0};
291
292 // Get the X-axis resolution
293 double xResolution{};
294 auto status = userSet.getFloatValue(mmind::eye::point_cloud_resolutions::XAxisResolution::name,
295 xResolution);
296 if (!status.isOK()) {
297 showError(status);
298 return {0};
299 }
300
301 // Get the Y resolution
302 double yResolution{};
303 status =
304 userSet.getFloatValue(mmind::eye::point_cloud_resolutions::YResolution::name, yResolution);
305 if (!status.isOK()) {
306 showError(status);
307 return {0};
308 }
309 // // Uncomment the following lines for custom Y Unit
310 // // Prompt to enter the desired encoder resolution, which is the travel distance corresponding
311 // // to
312 // // one quadrature signal.
313 // std::cout << "Please enter the desired encoder resolution (integer, unit: μm, min: "
314 // "1, max: 65535): ";
315 // while (true) {
316 // std::string str;
317 // std::cin >> str;
318 // if (std::regex_match(str.begin(), str.end(), std::regex{"[0-9]+"})) {
319 // yResolution = atoi(str.c_str());
320 // break;
321 // }
322 // std::cout << "Input invalid! Please enter the desired encoder resolution (integer, unit:
323 // "
324 // "μm, min: 1, max: 65535): ";
325 // }
326
327 int lineScanTriggerSource{};
328 status = userSet.getEnumValue(mmind::eye::trigger_settings::LineScanTriggerSource::name,
329 lineScanTriggerSource);
330 if (!status.isOK()) {
331 showError(status);
332 return {0};
333 }
334
335 bool useEncoderValues =
336 lineScanTriggerSource ==
337 static_cast<int>(mmind::eye::trigger_settings::LineScanTriggerSource::Value::Encoder);
338
339 int triggerInterval{};
340 status = userSet.getIntValue(mmind::eye::trigger_settings::EncoderTriggerInterval::name,
341 triggerInterval);
342 if (!status.isOK()) {
343 showError(status);
344 return {0};
345 }
346
347 return batch.getUntexturedPointCloud(xResolution, yResolution, useEncoderValues,
348 triggerInterval, mmind::eye::CoordinateUnit::Millimeter);
349}
350
351inline mmind::eye::ProfileBatch::TexturedPointCloud getTexturedPointCloud(
352 const mmind::eye::ProfileBatch& batch, const mmind::eye::UserSet& userSet)
353{
354 if (batch.isEmpty())
355 return {0};
356
357 // Get the X-axis resolution
358 double xResolution{};
359 auto status = userSet.getFloatValue(mmind::eye::point_cloud_resolutions::XAxisResolution::name,
360 xResolution);
361 if (!status.isOK()) {
362 showError(status);
363 return {0};
364 }
365
366 // Get the Y resolution
367 double yResolution{};
368 status =
369 userSet.getFloatValue(mmind::eye::point_cloud_resolutions::YResolution::name, yResolution);
370 if (!status.isOK()) {
371 showError(status);
372 return {0};
373 }
374 // // Uncomment the following lines for custom Y Unit
375 // // Prompt to enter the desired encoder resolution, which is the travel distance corresponding
376 // // to
377 // // one quadrature signal.
378 // std::cout << "Please enter the desired encoder resolution (integer, unit: μm, min: "
379 // "1, max: 65535): ";
380 // while (true) {
381 // std::string str;
382 // std::cin >> str;
383 // if (std::regex_match(str.begin(), str.end(), std::regex{"[0-9]+"})) {
384 // yResolution = atoi(str.c_str());
385 // break;
386 // }
387 // std::cout << "Input invalid! Please enter the desired encoder resolution (integer, unit:
388 // "
389 // "μm, min: 1, max: 65535): ";
390 // }
391
392 int lineScanTriggerSource{};
393 status = userSet.getEnumValue(mmind::eye::trigger_settings::LineScanTriggerSource::name,
394 lineScanTriggerSource);
395 if (!status.isOK()) {
396 showError(status);
397 return {0};
398 }
399
400 bool useEncoderValues =
401 lineScanTriggerSource ==
402 static_cast<int>(mmind::eye::trigger_settings::LineScanTriggerSource::Value::Encoder);
403
404 int triggerInterval{};
405 status = userSet.getIntValue(mmind::eye::trigger_settings::EncoderTriggerInterval::name,
406 triggerInterval);
407 if (!status.isOK()) {
408 showError(status);
409 return {0};
410 }
411
412 return batch.getTexturedPointCloud(xResolution, yResolution, useEncoderValues, triggerInterval,
413 mmind::eye::CoordinateUnit::Millimeter);
414}
Represents the data struct of the profile data.
Definition BatchArray.h:16
Represents a batch of profiles, which can be obtained by calling Profiler::retrieveBatchData()....
Definition ProfileData.h:74
bool isEmpty() const
Checks if the ProfileBatch object has no elements.
TexturedPointCloud getTexturedPointCloud(double xResolution, double yResolution, bool useEncoderValues, int triggerInterval, CoordinateUnit coordinateUnit=CoordinateUnit::Millimeter) const
Gets the textured point cloud data in the batch. Each point in TexturedPointCloud contains the X,...
UntexturedPointCloud getUntexturedPointCloud(double xResolution, double yResolution, bool useEncoderValues, int triggerInterval, CoordinateUnit coordinateUnit=CoordinateUnit::Millimeter) const
Gets the untextured point cloud data in the batch. Each point in UntexturedPointCloud contains the X,...
ErrorStatus saveUntexturedPointCloud(double xResolution, double yResolution, bool useEncoderValues, int triggerInterval, FileFormat fileFormat, const std::string &fileName, CoordinateUnit coordinateUnit=CoordinateUnit::Millimeter, bool isOrganized=false) const
Saves the untextured point cloud data in the batch. Each point in UntexturedPointCloud contains the X...
Operates the laser profiler. Use Profiler::connect to connect an available laser profiler,...
Definition Profiler.h:100
ErrorStatus connect(const ProfilerInfo &info, unsigned int timeoutMs=5000)
Connects to a laser profiler via ProfilerInfo.
static std::vector< ProfilerInfo > discoverProfilers(unsigned int timeoutMs=5000)
Discovers all available laser profilers and returns the list of information of all available laser pr...
ErrorStatus getIntValue(const std::string &parameterName, int &value) const
Gets the current value of an _Int-type device parameter. See Parameter for details.
ErrorStatus getFloatValue(const std::string &parameterName, double &value) const
Gets the current value of a _Float-type device parameter. See Parameter for details.
ErrorStatus getEnumValue(const std::string &parameterName, int &value) const
Gets the current value of an _Enum-type device parameter in the form of the integer value....
std::string toString() const
Converts a Version object to a string.
Definition Version.h:71
bool isEmpty() const
Checks if a Version object is empty.
Definition Version.h:95
Describes the types of errors.
Definition ErrorStatus.h:12
bool isOK() const
Returns true if the operation succeeded.
Definition ErrorStatus.h:85
Describes the laser profiler information.
Version hardwareVersion
The version of the hardware. The hardware cannot be upgraded.
Version firmwareVersion
The version of the firmware. The firmware can be upgraded.
std::string subnetMask
The IP subnet mask of the laser profiler.
Version lastSupportedVersion
The last supported version of the device.
IpAssignmentMethod ipAssignmentMethod
The IP address assignment method of the laser profiler.
std::string model
The laser profiler model.
bool supported
The support status of the device.
std::string controllerSN
The controller serial number.
std::string deviceName
The device name (UTF-8 encoded).
std::string sensorSN
The sensor serial number.
std::string ipAddress
The IP address of the laser profiler.
Describes the laser profiler's statuses.
Definition Profiler.h:90
float controllerCpuTemperature
The temperature (in °C) of the controller CPU.
Definition Profiler.h:82
float sensorCpuTemperature
The temperature (in °C) of the FPGA.
Definition Profiler.h:83