From ddb45457cf14160f3cb2cf5d171e694fcdadfcb6 Mon Sep 17 00:00:00 2001 From: Simon Ottenhaus <simon.ottenhaus@kit.edu> Date: Wed, 8 Mar 2017 16:48:47 +0100 Subject: [PATCH] added OptoForce daq calibration --- .../RobotAPI/sensors/OptoForceCalibration.xml | 11 + .../units/OptoForceUnitObserver.cpp | 19 +- .../drivers/OptoForceUnit/OptoForceUnit.cpp | 215 ++++++++++-------- .../drivers/OptoForceUnit/OptoForceUnit.h | 23 +- 4 files changed, 166 insertions(+), 102 deletions(-) create mode 100644 data/RobotAPI/sensors/OptoForceCalibration.xml diff --git a/data/RobotAPI/sensors/OptoForceCalibration.xml b/data/RobotAPI/sensors/OptoForceCalibration.xml new file mode 100644 index 000000000..b863b0de8 --- /dev/null +++ b/data/RobotAPI/sensors/OptoForceCalibration.xml @@ -0,0 +1,11 @@ +<Calibration> + <Daq serialNumber="KIT0A003"> + <Sensor nominalCapacity="10" counts_at_nc="3870" name="DSE0A102"/> + <Sensor nominalCapacity="10" counts_at_nc="4001" name="DSE0A103"/> + <Sensor nominalCapacity="10" counts_at_nc="4021" name="DSE0A104"/> + <Sensor nominalCapacity="10" counts_at_nc="4048" name="DSE0A108"/> + </Daq> + <Daq serialNumber="DSE0A114"> + <Sensor nominalCapacity="10" counts_at_nc="4048" name="DSE0A114" /> + </Daq> +</Calibration> diff --git a/source/RobotAPI/components/units/OptoForceUnitObserver.cpp b/source/RobotAPI/components/units/OptoForceUnitObserver.cpp index f70392b30..0b43e68d9 100644 --- a/source/RobotAPI/components/units/OptoForceUnitObserver.cpp +++ b/source/RobotAPI/components/units/OptoForceUnitObserver.cpp @@ -69,19 +69,20 @@ void OptoForceUnitObserver::reportSensorValues(const std::string& device, const ScopedLock lock(dataMutex); TimestampVariantPtr timestampPtr = TimestampVariantPtr::dynamicCast(timestamp); - if (!existsChannel(device)) + if (!existsChannel(name)) { - offerChannel(device, "Force data"); + offerChannel(name, "Force data"); } - offerOrUpdateDataField(device, "name", Variant(name), "Name of the sensor"); - offerOrUpdateDataField(device, "fx", Variant(fx), "Force x"); - offerOrUpdateDataField(device, "fy", Variant(fy), "Force y"); - offerOrUpdateDataField(device, "fz", Variant(fz), "Force z"); - offerOrUpdateDataField(device, "timestamp", timestampPtr, "Timestamp"); - offerOrUpdateDataField(device, "force", Vector3(fx, fy, fz), "Force"); + offerOrUpdateDataField(name, "name", Variant(name), "Name of the sensor"); + offerOrUpdateDataField(name, "device", Variant(device), "Device name"); + offerOrUpdateDataField(name, "fx", Variant(fx), "Force x"); + offerOrUpdateDataField(name, "fy", Variant(fy), "Force y"); + offerOrUpdateDataField(name, "fz", Variant(fz), "Force z"); + offerOrUpdateDataField(name, "timestamp", timestampPtr, "Timestamp"); + offerOrUpdateDataField(name, "force", Vector3(fx, fy, fz), "Force"); - updateChannel(device); + updateChannel(name); } /*void OptoForceUnitObserver::reportSensorValues(const std::string& device, const std::string& name, const IMUData& values, const TimestampBasePtr& timestamp, const Ice::Current& c) diff --git a/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.cpp b/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.cpp index a9f44abd1..9fdfeaf16 100644 --- a/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.cpp +++ b/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.cpp @@ -25,144 +25,133 @@ #include <ArmarXCore/observers/variant/TimestampVariant.h> + using namespace armarx; void OptoForceUnit::onInitComponent() { + std::string calibrationFilePath = getProperty<std::string>("CalibrationFilePath").getValue(); + if(!ArmarXDataPath::getAbsolutePath(calibrationFilePath, calibrationFilePath)) + { + throw LocalException("Could not find calibration file '") << calibrationFilePath << "'"; + } + ARMARX_INFO << "reading config " << calibrationFilePath; + RapidXmlReaderPtr reader = RapidXmlReader::FromFile(calibrationFilePath); + RapidXmlReaderNode rootNode = reader->getRoot("Calibration"); + + auto findDaqNode = [&](std::string serialNumber) + { + for(RapidXmlReaderNode daqNode : rootNode.nodes("Daq")) + { + if(daqNode.attribute_value("serialNumber") == serialNumber) + { + return daqNode; + } + } + return RapidXmlReaderNode::NullNode(); + }; + offeringTopic(getProperty<std::string>("OptoForceTopicName").getValue()); OPort* portlist = ports.listPorts(true); ARMARX_INFO << "Found " << ports.getLastSize() << " Optoforce device(s)."; - int numPorts = ports.getLastSize(); - ARMARX_INFO << "number of ports: " << numPorts; - - OPort* portListNew = ports.listPorts(true); - ARMARX_INFO << "Found " << ports.getLastSize() << " Optoforce device(s)."; + portlist = ports.listPorts(true); + ARMARX_INFO << "Found " << ports.getLastSize() << " Optoforce device(s):"; for (int i = 0; i < ports.getLastSize(); i++) { - ARMARX_INFO << "device name: " << portListNew[i].name; - daqList.push_back(OptoDAQ()); + std::string deviceName(portlist[i].name); + std::string serialNumber(portlist[i].serialNumber); + ARMARX_INFO << "Found DAQ: deviceName='" << deviceName << "', serialNumber='" << serialNumber << "'"; + RapidXmlReaderNode daqNode = findDaqNode(serialNumber); + if(!daqNode.is_valid()) + { + throw LocalException("Could not find config node for device deviceName='") << deviceName << "', serialNumber='" << serialNumber << "'"; + } + DaqWrapperPtr daqPtr(new DaqWrapper(deviceName, serialNumber, daqNode)); + daqList.push_back(daqPtr); } ARMARX_INFO << "number of ports: " << ports.getLastSize(); - if (ports.getLastSize() > 0) + for (int i = 0; i < ports.getLastSize(); ++i) { - for (int i = 0; i < ports.getLastSize(); ++i) - { - ARMARX_INFO << "Opening port #" << i << " " << portListNew[i].name; - //daqList.at(i).open(portListNew[i]); - if (i == 0) - { - daq.open(portListNew[i]); - ARMARX_INFO << "opened port 1"; - } - if (daq.getVersion() == _95 || daq.getVersion() == _64) - { - ARMARX_IMPORTANT << "Wrong sensor type! (not 3D)"; - daq.close(); - return; - } - } + const DaqWrapperPtr& daq = daqList.at(i); + ARMARX_IMPORTANT << "Opening port #" << i << " " << portlist[i].name; + daq->daq.open(portlist[i]); + daq->printInfo(); + daq->checkSensorCount(); } readTask = new RunningTask<OptoForceUnit>(this, &OptoForceUnit::run, "OptoForceUnit"); - readTask->start(); + } void OptoForceUnit::onConnectComponent() { topicPrx = getTopic<OptoForceUnitListenerPrx>(getProperty<std::string>("OptoForceTopicName").getValue()); + readTask->start(); } void OptoForceUnit::run() { ARMARX_IMPORTANT << "run"; - SensorConfig config = daq.getConfig(); - - int state = config.getState(); - int speed = config.getSpeed(); - int filter = config.getFilter(); - int mode = config.getMode(); - - ARMARX_IMPORTANT << "state: " << state; - ARMARX_IMPORTANT << "speed: " << speed; - ARMARX_IMPORTANT << "filter: " << filter; - ARMARX_IMPORTANT << "mode: " << mode; OptoForceUnitListenerPrx batchPrx = topicPrx->ice_batchOneway(); + ARMARX_IMPORTANT << "got batch Proxy"; while(readTask->isRunning()) { - OptoPackage* pa = 0; - //OptoPackage* pa2 = 0; + bool flushNeeded = false; - int size = daq.readAll(pa, false); - if (size <= 0) + for(const DaqWrapperPtr& daqPtr : daqList) { - usleep(1000); // 1ms - continue; - } - //ARMARX_IMPORTANT << "size: " << size; - //ARMARX_IMPORTANT << "daq.getSize(): " << daq.getSize(); - // necessary so that there are no lines without values - if (daq.getSize() > 0) - { - //optoForceOutputFile << "getsize: " << daq.getSize() << "\n"; - //optoForceOutputFile << "getBytesperRead: " << daq.getBytesPerRead() << "\n"; - - //optoForceOutputFile << "getsize2: " << daq2.getSize() << "\n"; - //optoForceOutputFile << "getBytesperRead2: " << daq2.getBytesPerRead() << "\n"; - - //optoForceOutputFile << IceUtil::Time::now().toDateTime() << " OptoForce: "; - // get values of first DAQ - 4 OptoForce sensors connected - IceUtil::Time now = IceUtil::Time::now(); - TimestampVariantPtr nowTimestamp = new TimestampVariant(now); - - - for (int k = 0; k < daq.getSensorSize(); k++) + OptoPackage* pa = 0; + int size = daqPtr->daq.readAll(pa, false); + if (size == 0) { - //ARMARX_INFO << "Sensor " << k; - - for (int i = 0; i < size; i++) - { - float x = pa[k * size + i].x; - float y = pa[k * size + i].y; - float z = pa[k * size + i].z; - - //ARMARX_INFO << "x: " << pa[k * size + i].x << " y: " << pa[k * size + i].y << " z: " << pa[k * size + i].z << " s1: " << pa[k * size + i].s1 << " s2: " << pa[k * size + i].s2 << " s3: " << pa[k * size + i].s3 << " s4: " << pa[k * size + i].s4 << " TEMP: " << pa[k * size + i].temp << flush; - //optoForceOutputFile << "x: " << pa[k * size + i].x << " y: " << pa[k * size + i].y << " z: " << pa[k * size + i].z << " "; - batchPrx->reportSensorValues("sensor" + std::to_string(k), "sensor" + std::to_string(k), x, y, z, nowTimestamp); - } + // size == 0: no new data for daq + continue; } - - batchPrx->ice_flushBatchRequests(); - - /*// get values of second DAQ - 3 OptoForce sensors connected - //needs to be (daq2.getSensorSize()-1) to read out only 3 ports - for (int k = 0; k < (daq2.getSensorSize() - 1) ; k++) + if(size < 0) { - ARMARX_INFO << "Sensor " << k; - + // size == -1: buffer full + ARMARX_WARNING << "buffer full of daq " << daqPtr->deviceName; + } + if (daqPtr->daq.getSize() > 0) + { + IceUtil::Time now = IceUtil::Time::now(); + TimestampVariantPtr nowTimestamp = new TimestampVariant(now); - for (int i = 0; i < size2; i++) + for (int i = 0; i < daqPtr->daq.getSensorSize(); i++) { - ARMARX_INFO << "x: " << pa2[k * size2 + i].x << " y: " << pa2[k * size2 + i].y << " z: " << pa2[k * size2 + i].z << " s1: " << pa2[k * size2 + i].s1 << " s2: " << pa2[k * size2 + i].s2 << " s3: " << pa2[k * size2 + i].s3 << " s4: " << pa2[k * size2 + i].s4 << " TEMP: " << pa2[k * size2 + i].temp << flush; - optoForceOutputFile << "x: " << pa2[k * size2 + i].x << " y: " << pa2[k * size2 + i].y << " z: " << pa2[k * size2 + i].z << " "; - + for (int n = 0; n < size; n++) + { + float countsPerN = daqPtr->countsPerN.at(i); + float x = pa[i * size + n].x / countsPerN; + float y = pa[i * size + n].y / countsPerN; + float z = pa[i * size + n].z / countsPerN; + + batchPrx->reportSensorValues(daqPtr->deviceName + ":" + std::to_string(i), daqPtr->sensorNames.at(i), x, y, z, nowTimestamp); + flushNeeded = true; + } } - }*/ - // buffer needs to be deleted - delete[] pa; - //delete[] pa2; - //optoForceOutputFile << "\n"; - //optoForceOutputFile.flush(); + + delete[] pa; + } + } + if(flushNeeded) + { + batchPrx->ice_flushBatchRequests(); + } + else + { + usleep(1000); // 1ms } } } @@ -185,3 +174,47 @@ armarx::PropertyDefinitionsPtr OptoForceUnit::createPropertyDefinitions() getConfigIdentifier())); } + + +OptoForceUnit::DaqWrapper::DaqWrapper(const std::string& deviceName, const std::string& serialNumber, const RapidXmlReaderNode& daqNode) + : deviceName(deviceName), serialNumber(serialNumber) +{ + int i = 0; + for(RapidXmlReaderNode sensorNode : daqNode.nodes("Sensor")) + { + float counts_at_nc = sensorNode.attribute_as_float("counts_at_nc"); + float nominalCapacity = sensorNode.attribute_as_float("nominalCapacity"); + std::string sensorName = sensorNode.attribute_value_or_default("name", serialNumber + "-" + std::to_string(i)); + countsPerN.push_back(counts_at_nc / nominalCapacity); + sensorNames.push_back(sensorName); + i++; + } +} + +void OptoForceUnit::DaqWrapper::printInfo() +{ + SensorConfig config = daq.getConfig(); + int state = config.getState(); + int speed = config.getSpeed(); + int filter = config.getFilter(); + int mode = config.getMode(); + + ARMARX_IMPORTANT_S << "device: " << deviceName << " serialNumber:" << serialNumber; + ARMARX_IMPORTANT_S << "state: " << state; + ARMARX_IMPORTANT_S << "speed: " << speed; + ARMARX_IMPORTANT_S << "filter: " << filter; + ARMARX_IMPORTANT_S << "mode: " << mode; + ARMARX_IMPORTANT_S << "getBytesPerRead: " << daq.getBytesPerRead(); + ARMARX_IMPORTANT_S << "getSensorSize: " << daq.getSensorSize(); + ARMARX_IMPORTANT_S << "getSize: " << daq.getSize(); + ARMARX_IMPORTANT_S << "getVersion: " << daq.getVersion(); +} + +void OptoForceUnit::DaqWrapper::checkSensorCount() +{ + if((int)countsPerN.size() != daq.getSensorSize()) + { + throw LocalException("Sensor count mismatch. Configured: ") << ((int)countsPerN.size()) << " found: " << daq.getSensorSize(); + } + ARMARX_INFO_S << "Configured: " << ((int)countsPerN.size()) << " found: " << daq.getSensorSize() << " sensors"; +} diff --git a/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.h b/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.h index 695d9c048..50c7fccdd 100644 --- a/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.h +++ b/source/RobotAPI/drivers/OptoForceUnit/OptoForceUnit.h @@ -28,6 +28,7 @@ #include <ArmarXCore/core/services/tasks/RunningTask.h> #include <RobotAPI/interface/units/OptoForceUnit.h> #include <OptoForce/omd/opto.h> +#include <ArmarXCore/core/rapidxml/wrapper/RapidXmlReader.h> namespace armarx { @@ -44,6 +45,7 @@ namespace armarx { //defineRequiredProperty<std::string>("PropertyName", "Description"); defineOptionalProperty<std::string>("OptoForceTopicName", "OptoForceValues", "Name of the OptoForce Topic"); + defineOptionalProperty<std::string>("CalibrationFilePath", "RobotAPI/sensors/OptoForceCalibration.xml", "Path of the Calibration File"); } }; @@ -61,6 +63,23 @@ namespace armarx class OptoForceUnit : virtual public armarx::Component { + private: + class DaqWrapper + { + public: + DaqWrapper(const std::string& deviceName, const std::string& serialNumber, const RapidXmlReaderNode& daqNode); + + OptoDAQ daq; + std::string deviceName; + std::string serialNumber; + std::vector<float> countsPerN; + std::vector<std::string> sensorNames; + + void printInfo(); + void checkSensorCount(); + }; + typedef boost::shared_ptr<DaqWrapper> DaqWrapperPtr; + public: /** * @see armarx::ManagedIceObject::getDefaultName() @@ -102,8 +121,8 @@ namespace armarx OptoForceUnitListenerPrx topicPrx; OptoPorts ports; - OptoDAQ daq; - std::vector<OptoDAQ> daqList; + //OptoDAQ daq; + std::vector<DaqWrapperPtr> daqList; RunningTask<OptoForceUnit>::pointer_type readTask; }; -- GitLab