22#include <unordered_map>
31#include <yarp/os/LogStream.h>
32#include <yarp/os/Property.h>
33#include <yarp/os/Log.h>
34#include <yarp/os/Searchable.h>
42 YARP_LOG_COMPONENT(FineCalibrationCheckerCOMPONENT,
"yarp.device.FineCalibrationChecker")
46 :
yarp::os::Thread(), _deviceName(
"fineCalibrationChecker"), _portPrefix(
"/fineCalibrationChecker"),
47 _robotName(
"icub"), _remoteRawValuesPort(
"/icub/rawvalues"), _axesNamesList(
yarp::os::Bottle()),
48 _goldPositionsList(
yarp::os::Bottle()), _encoderResolutionsList(
yarp::os::Bottle()), _calibrationDeltasList(
yarp::os::Bottle()), _deviceStatus(
deviceStatus::NONE)
51 _remappedControlBoardDevice = std::make_unique<yarp::dev::PolyDriver>();
52 _remappedRawValuesPublisherDevice = std::make_unique<yarp::dev::PolyDriver>();
58 yarp::os::Property property;
59 property.fromString(config.toString().c_str());
60 if (property.isNull())
62 yCError(FineCalibrationCheckerCOMPONENT) <<
"Failed to read configuration file. Stopping device...";
68 if (property.check(
"devicename")) { _deviceName =
property.find(
"devicename").asString(); }
69 if (property.check(
"robotname")) { _robotName =
property.find(
"robotname").asString(); }
70 if (property.check(
"remoteRawValuesPort")) { _remoteRawValuesPort =
property.find(
"remoteRawValuesPort").asString(); }
71 if (property.check(
"axesNamesList"))
73 yarp::os::Bottle* _jointsList =
property.find(
"axesNamesList").asList();
74 yarp::os::Bottle &axesNames = _axesNamesList.addList();
76 for (
size_t i = 0; i < _jointsList->size(); i++)
78 axesNames.addString(_jointsList->get(i).asString());
81 if(property.check(
"goldPositions"))
83 yarp::os::Bottle* _goldPositions =
property.find(
"goldPositions").asList();
84 yarp::os::Bottle &goldPositions = _goldPositionsList.addList();
86 for (
size_t i = 0; i < _goldPositions->size(); i++)
88 goldPositions.addInt32(_goldPositions->get(i).asInt32());
91 if(property.check(
"calibrationDeltas"))
93 yarp::os::Bottle* _calibrationDeltas =
property.find(
"calibrationDeltas").asList();
94 yarp::os::Bottle &calibrationDeltas = _calibrationDeltasList.addList();
96 for (
size_t i = 0; i < _calibrationDeltas->size(); i++)
98 calibrationDeltas.addFloat64(_calibrationDeltas->get(i).asFloat64());
101 if(property.check(
"encoderResolutions"))
103 yarp::os::Bottle* _encoderResolutions =
property.find(
"encoderResolutions").asList();
104 yarp::os::Bottle &encoderResolutions = _encoderResolutionsList.addList();
106 for (
size_t i = 0; i < _encoderResolutions->size(); i++)
108 encoderResolutions.addInt32(_encoderResolutions->get(i).asInt32());
111 if (property.check(
"axesSigns"))
113 yarp::os::Bottle* _axesSigns =
property.find(
"axesSigns").asList();
114 yarp::os::Bottle &axesSigns = _axesSignsList.addList();
116 for (
size_t i = 0; i < _axesSigns->size(); i++)
118 axesSigns.addInt32(_axesSigns->get(i).asInt32());
124 yarp::os::Bottle* axes = _axesNamesList.get(0).asList();
125 yarp::os::Bottle* goldpos = _goldPositionsList.get(0).asList();
126 yarp::os::Bottle* encres = _encoderResolutionsList.get(0).asList();
127 yarp::os::Bottle* caldeltas = _calibrationDeltasList.get(0).asList();
128 yarp::os::Bottle* signs = _axesSignsList.get(0).asList();
131 if (axes->size() != goldpos->size() ||
132 axes->size() != encres->size() ||
133 axes->size() != caldeltas->size() ||
134 axes->size() != signs->size())
136 yCError(FineCalibrationCheckerCOMPONENT) <<
"Axes names, gold positions and encoder resolutions lists must have the same size. Stopping device...";
141 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Axes names list:" << _axesNamesList.toString();
142 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Gold positions list:" << goldpos->toString();
143 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Encoder resolutions list:" << encres->toString();
144 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Calibration deltas list:" << caldeltas->toString();
145 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Axes signs list:" << signs->toString();
149 for (
size_t i = 0; i < axes->size(); i++)
151 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Adding to MAP key:" << axes->get(i).asString()
152 <<
"GP:" << goldpos->get(i).asInt32() <<
"ER:" << encres->get(i).asInt32() <<
"CD:" << caldeltas->get(i).asFloat64();
153 axesRawGoldenPositionsResMap[axes->get(i).asString()] = {goldpos->get(i).asInt32(), encres->get(i).asInt32()};
154 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Array added to MAP:" << axesRawGoldenPositionsResMap.at(axes->get(i).asString())[0]
155 <<
"and" << axesRawGoldenPositionsResMap.at(axes->get(i).asString())[1];
159 _withGui =
property.check(
"withGui", yarp::os::Value(
false)).asBool();
161 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Initialized device driver";
166 yarp::os::Property deviceProperties;
168 deviceProperties.put(
"device",
"controlboardremapper");
169 deviceProperties.put(
"axesNames", _axesNamesList.get(0));
171 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Configuring device driver with properties:" << deviceProperties.toString();
173 _remappedControlBoardDevice->open(deviceProperties);
175 if (!_remappedControlBoardDevice->isValid())
177 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open device driver. Aborting...";
182 if (_remoteRawValuesPort.empty())
184 yCError(FineCalibrationCheckerCOMPONENT) <<
"Remote raw values port is empty. Cannot open device driver. Stopping device...";
189 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Remote raw values port:" << _remoteRawValuesPort;
193 yarp::os::Property rawValuesDeviceProperties;
194 rawValuesDeviceProperties.put(
"device",
"rawValuesPublisherRemapper");
195 rawValuesDeviceProperties.put(
"axesNames", _axesNamesList.get(0));
196 rawValuesDeviceProperties.put(
"remote", _remoteRawValuesPort);
197 rawValuesDeviceProperties.put(
"local",
"/" + _deviceName +
"/rawValuesPublisherRemapper");
199 _remappedRawValuesPublisherDevice->open(rawValuesDeviceProperties);
201 if (!_remappedRawValuesPublisherDevice->isValid()) {
202 yCError(FineCalibrationCheckerCOMPONENT)
204 <<
"Unable to open raw values device driver. Aborting...";
208 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Opened all devices successfully";
217 if(_remappedControlBoardDevice->close())
219 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Closed device" << _deviceName;
223 yCError(FineCalibrationCheckerCOMPONENT) <<
"Unable to close device" << _deviceName;
226 if (_remappedRawValuesPublisherDevice->close())
228 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Closed raw values publisher device";
232 yCError(FineCalibrationCheckerCOMPONENT) <<
"Unable to close raw values publisher device";
234 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Closed all devices successfully";
242 if (!_remappedControlBoardDevice->view(remappedControlBoardInterfaces._imot) || remappedControlBoardInterfaces._imot ==
nullptr)
244 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open motor interface. Aborting...";
248 if (!_remappedControlBoardDevice->view(remappedControlBoardInterfaces._ienc) || remappedControlBoardInterfaces._ienc ==
nullptr)
250 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open encoders interface. Aborting...";
254 if (!_remappedControlBoardDevice->view(remappedControlBoardInterfaces._icontrolcalib) || remappedControlBoardInterfaces._icontrolcalib ==
nullptr)
256 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open control calibration interface. Aborting...";
260 if (!_remappedRawValuesPublisherDevice->view(remappedRawValuesPublisherInterfaces._iravap) || remappedRawValuesPublisherInterfaces._iravap ==
nullptr)
262 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open raw values publisher interface. Aborting...";
268 rawDataMetadata = {};
269 remappedRawValuesPublisherInterfaces._iravap->getMetadataMap(rawDataMetadata);
270 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Configured raw values with metadata";
273 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"\n"
274 <<
"\t Key: " << k <<
"\n"
275 <<
"\t axesName: " << m.axesNames <<
"\n"
276 <<
"\t rawValueNames: " << m.rawValueNames
280 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Opened remote calibrator and control calibration interfaces successfully";
290 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Thread started to run";
293 static auto lastTimerLog = std::chrono::steady_clock::now();
294 static auto shoutdownTimer = std::chrono::steady_clock::now();
296 while(!this->isStopping())
300 auto now = std::chrono::steady_clock::now();
301 if (std::chrono::duration_cast<std::chrono::milliseconds>(now - lastTimerLog).count() > 1000)
303 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Device configured, waiting for attachAll() to be called.";
306 yarp::os::Time::delay(0.1);
313 if(!_axesNamesList.isNull() && _axesNamesList.size() > 0 && _axesNamesList.get(0).isList())
315 numAxes = _axesNamesList.get(0).asList()->size();
318 bool calibDone =
true;
319 for (
size_t i = 0; i < numAxes; i++)
321 calibDone &= remappedControlBoardInterfaces._icontrolcalib->calibrationDone(i);
326 yCWarning(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Calib not complete for all axis. Waiting for calibration to finish...";
327 yarp::os::Time::delay(0.1);
332 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Calibration done successfully";
343 if(!remappedRawValuesPublisherInterfaces._iravap->getRawDataMap(rawDataValuesMap))
345 yCWarning(FineCalibrationCheckerCOMPONENT) <<
"embObjMotionControl::IRawValuesPublisher warning : raw_data_values map was not read correctly";
349 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Get raw values from encoders:";
350 for (
auto [key,value] : rawDataValuesMap)
352 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"\t key:" << key <<
"value:" << value;
358 evaluateHardStopPositionDelta(_rawValuesTag,
"zeroPositionsDataDelta.csv");
364 auto now = std::chrono::steady_clock::now();
365 if (std::chrono::duration_cast<std::chrono::milliseconds>(now - shoutdownTimer).count() > 5000)
367 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Operation completed successfully. Waiting yarprobotinterface to stop the thread...";
373 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Device is in unknown state. Stopping thread...";
379 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Thread stopping";
393 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Attaching all devices";
397 if (!_remappedControlBoardDevice->view(remappedControlBoardInterfaces._imultwrap) || remappedControlBoardInterfaces._imultwrap ==
nullptr)
399 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open multiple wrapper interface. Aborting...";
403 if (!_remappedControlBoardDevice->isValid())
405 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Device is not valid. Cannot attach.";
409 if(!_remappedRawValuesPublisherDevice->view(remappedRawValuesPublisherInterfaces._imultwrap) || remappedRawValuesPublisherInterfaces._imultwrap ==
nullptr)
411 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Unable to open multiple wrapper interface for raw values publisher. Aborting...";
415 if(!_remappedRawValuesPublisherDevice->isValid())
417 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Raw values publisher device is not valid. Cannot attach.";
422 if (!this->attachToAllControlBoards(device2attach))
424 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Failed to attach all devices.";
428 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Successfully attached all devices. Starting the thread...";
432 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Failed to start the thread.";
435 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Thread started successfully";
444 if (this->isRunning())
446 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Stopping the thread before detaching all devices";
449 if(!remappedControlBoardInterfaces._imultwrap->detachAll() || !remappedRawValuesPublisherInterfaces._imultwrap->detachAll())
451 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Failed to detach all devices";
456 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Detached all devices successfully";
469bool FineCalibrationChecker::attachToAllControlBoards(
const yarp::dev::PolyDriverList& polyList)
472 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Attaching all control boards";
473 if (!_remappedControlBoardDevice->isValid())
475 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Device is not valid. Cannot attach.";
480 yarp::dev::PolyDriverList controlBoardsList;
481 for (
size_t i = 0; i < polyList.size(); i++)
483 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Attaching control board" << polyList[i]->key;
484 controlBoardsList.push(
const_cast<yarp::dev::PolyDriverDescriptor&
>(*polyList[i]));
487 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Control boards list size:" << controlBoardsList.size();
490 if(!remappedControlBoardInterfaces._imultwrap->attachAll(controlBoardsList))
492 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Failed to attach all control boards";
496 if(!remappedRawValuesPublisherInterfaces._imultwrap->attachAll(controlBoardsList))
498 yCError(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Failed to attach all control boards to raw values publisher";
502 yCDebug(FineCalibrationCheckerCOMPONENT) << _deviceName <<
"Successfully attached all control boards";
507void FineCalibrationChecker::evaluateHardStopPositionDelta(
const std::string& key,
const std::string& outputFileName)
511 const int32_t RAW_VALUES_STRIDE = 3;
512 const int64_t ICUB_DEGREES_RANGE = (65535);
514 std::filesystem::path outputPath(outputFileName);
515 int64_t goldPosition = 0;
516 int64_t rawPosition = 0;
517 int64_t resolution = 0;
518 int64_t rescaledPos = 0;
520 std::vector<ItemData> sampleItems = {};
522 yarp::os::Bottle* caldeltas = _calibrationDeltasList.get(0).asList();
523 yarp::os::Bottle* axesSigns = _axesSignsList.get(0).asList();
525 std::ofstream
outFile(outputPath);
528 yCError(FineCalibrationCheckerCOMPONENT) <<
"Unable to open output file:" << outputPath.string();
532 outFile <<
"AxisName,GoldPosition,RescaledPosition,RawPosition,Delta\n";
533 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Evaluating deltas.....";
534 if(
auto it = rawDataValuesMap.find(key); it != rawDataValuesMap.end())
536 std::vector<std::string> axesNames = {};
537 std::vector<std::int32_t> rawData = {};
540 axesNames = rawDataMetadata.
metadataMap.at(it->first).axesNames;
541 rawData = it->second;
543 std::vector<double> homePositions(axesNames.size(), 0);
544 std::vector<double> calibrationDelta(axesNames.size(), 0.0);
547 for (
size_t i = 0; i < axesNames.size(); ++i)
553 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Evaluating axis:" << axesNames[i];
554 if (
auto it = axesRawGoldenPositionsResMap.find(axesNames[i]); it != axesRawGoldenPositionsResMap.end())
556 calibrationDelta[i] = caldeltas->get(i).asFloat64();
558 remappedControlBoardInterfaces._ienc->getEncoder(i, &pos);
559 homePositions[i] = (axesSigns->get(i).asInt32() > 0) ? pos : -pos;
560 goldPosition = it->second[0];
561 resolution = it->second[1];
562 rawPosition = rawData[RAW_VALUES_STRIDE*i];
566 rescaledPos = rawPosition * ICUB_DEGREES_RANGE / resolution;
578 delta =
static_cast<double>((goldPosition - rescaledPos) / (ICUB_DEGREES_RANGE/360.0)) + homePositions[i];
579 calibrationDelta[i] = (axesSigns->get(i).asInt32() > 0) ? calibrationDelta[i] : -calibrationDelta[i];
580 delta += calibrationDelta[i];
581 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"GP:" << goldPosition <<
"HP:" << homePositions[i] <<
"RSP:" << rescaledPos <<
"RWP:" << rawPosition <<
"DD:" << delta;
585 yCWarning(FineCalibrationCheckerCOMPONENT) <<
"This device axes has not ben requested to be checked. Continue...";
590 outFile << axesNames[i] <<
"," << goldPosition <<
"," << rescaledPos <<
"," << rawPosition <<
"," << delta <<
"\n";
591 sampleItems.push_back({axesNames[i], goldPosition, rescaledPos, rawPosition, delta});
596 yCError(FineCalibrationCheckerCOMPONENT) <<
"Key" << key <<
"not found in rawDataValuesMap";
597 outFile <<
"Key not found in rawDataValuesMap\n";
601 yCDebug(FineCalibrationCheckerCOMPONENT) <<
"Output CSV written to:" << outputPath.string();
604 generateOutputImage(1800, 400, sampleItems);
608void FineCalibrationChecker::generateOutputImage(
int frameWidth,
int frameHeight,
const std::vector<ItemData>& items)
610 cv::Mat image = cv::Mat::zeros(frameHeight, frameWidth, CV_8UC3);
611 image.setTo(cv::Scalar(255, 255, 255));
616 int colWidthAvg = (frameWidth - 2 * padding) / 5;
619 std::vector<std::string> headers = {
"AxisName",
"GoldPosition[iCubDegrees]",
"RescaledPosition[iCubDegrees]",
"RawPosition[Ticks]",
"Delta[Degrees]"};
620 std::vector<int> colWidths(5, colWidthAvg);
621 std::vector<int> colX(headers.size());
622 colX[0] = padding + 5;
623 for (
size_t i = 1; i < headers.size(); ++i) {
624 colX[i] = colX[i-1] + colWidths[i-1];
628 int headerY = padding;
629 cv::Scalar headerBgColor(220, 220, 220);
632 cv::Point(padding, headerY),
633 cv::Point(frameWidth - padding, headerY + lineHeight - 5),
634 headerBgColor, cv::FILLED);
637 cv::Point(padding, headerY),
638 cv::Point(frameWidth - padding, headerY + lineHeight - 5),
639 cv::Scalar(100, 100, 100), 1);
640 for (
size_t c = 0; c < headers.size(); ++c) {
641 cv::putText(image, headers[c], cv::Point(colX[c], headerY + textOffset),
642 cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 0, 0), 2);
646 for (
size_t i = 0; i < items.size(); ++i)
648 int y = padding + (i + 1) * lineHeight;
650 cv::Scalar bgColor = getColorForDelta(items[i].val4, 1.0, 3.0);
652 cv::Point(padding,
y),
653 cv::Point(frameWidth - padding,
y + lineHeight - 5),
654 bgColor, cv::FILLED);
658 cv::Point(padding,
y),
659 cv::Point(frameWidth - padding,
y + lineHeight - 5),
660 cv::Scalar(200, 200, 200), 1);
663 std::vector<std::string> rowVals = {
665 std::to_string(items[i].val1),
666 std::to_string(items[i].val2),
667 std::to_string(items[i].val3),
668 std::to_string(items[i].val4)
670 for (
size_t c = 0; c < rowVals.size(); ++c) {
671 cv::putText(image, rowVals[c], cv::Point(colX[c],
y + textOffset),
672 cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 0, 0), 2);
676 cv::imwrite(
"output_frame.png", image);
678 cv::imshow(
"Output Frame", image);
680 cv::destroyAllWindows();
683cv::Scalar FineCalibrationChecker::getColorForDelta(
double delta,
double threshold_1,
double threshold_2)
685 if (std::abs(delta) > threshold_2)
return cv::Scalar(0, 0, 255);
686 else if (std::abs(delta) > threshold_1)
return cv::Scalar(0, 165, 255);
687 else return cv::Scalar(0, 255, 0);
bool threadInit() override
bool open(yarp::os::Searchable &config) override
bool detachAll() override
bool isCalibrationSuccessful() const
bool attachAll(const yarp::dev::PolyDriverList &device2attach) override
Copyright (C) 2008 RobotCub Consortium.