OptoForceUnit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::OptoForceUnit
17 * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "OptoForceUnit.h"
24
27
28
29using namespace armarx;
30
31OptoForceUnit::OptoForceUnit() : isRecording(false), stopRecordingFlag(false)
32{
33}
34
35void
37{
38 std::string calibrationFilePath = getProperty<std::string>("CalibrationFilePath").getValue();
39 if (!ArmarXDataPath::getAbsolutePath(calibrationFilePath, calibrationFilePath))
40 {
41 throw LocalException("Could not find calibration file '") << calibrationFilePath << "'";
42 }
43 ARMARX_INFO << "reading config " << calibrationFilePath;
44 RapidXmlReaderPtr reader = RapidXmlReader::FromFile(calibrationFilePath);
45 RapidXmlReaderNode rootNode = reader->getRoot("Calibration");
46
47 auto findDaqNode = [&](std::string serialNumber)
48 {
49 for (RapidXmlReaderNode daqNode : rootNode.nodes("Daq"))
50 {
51 if (daqNode.attribute_value("serialNumber") == serialNumber)
52 {
53 return daqNode;
54 }
55 }
57 };
58
59 offeringTopic(getProperty<std::string>("OptoForceTopicName").getValue());
60
61 OPort* portlist = ports.listPorts(true);
62 ARMARX_INFO << "Found " << ports.getLastSize() << " Optoforce device(s).";
63
64
65 portlist = ports.listPorts(true);
66 ARMARX_INFO << "Found " << ports.getLastSize() << " Optoforce device(s):";
67
68 for (int i = 0; i < ports.getLastSize(); i++)
69 {
70 std::string deviceName(portlist[i].name);
71 std::string serialNumber(portlist[i].serialNumber);
72 ARMARX_INFO << "Found DAQ: deviceName='" << deviceName << "', serialNumber='"
73 << serialNumber << "'";
74 RapidXmlReaderNode daqNode = findDaqNode(serialNumber);
75 if (!daqNode.is_valid())
76 {
77 throw LocalException("Could not find config node for device deviceName='")
78 << deviceName << "', serialNumber='" << serialNumber << "'";
79 }
80 DaqWrapperPtr daqPtr(new DaqWrapper(deviceName, serialNumber, daqNode));
81 daqList.push_back(daqPtr);
82 }
83
84 ARMARX_INFO << "number of ports: " << ports.getLastSize();
85
86 for (int i = 0; i < ports.getLastSize(); ++i)
87 {
88 const DaqWrapperPtr& daq = daqList.at(i);
89 ARMARX_IMPORTANT << "Opening port #" << i << " " << portlist[i].name;
90 daq->daq.open(portlist[i]);
91 daq->printInfo();
92 daq->checkSensorCount();
93 }
94
95 readTask = new RunningTask<OptoForceUnit>(this, &OptoForceUnit::run, "OptoForceUnit");
96}
97
98void
100{
102 getProperty<std::string>("OptoForceTopicName").getValue());
103 readTask->start();
104}
105
106void
107OptoForceUnit::run()
108{
109 ARMARX_IMPORTANT << "run";
110
111
112 OptoForceUnitListenerPrx batchPrx = topicPrx->ice_batchOneway();
113 ARMARX_IMPORTANT << "got batch Proxy";
114
115 while (readTask->isRunning())
116 {
117 bool flushNeeded = false;
118
119 for (const DaqWrapperPtr& daqPtr : daqList)
120 {
121 OptoPackage* pa = 0;
122 int size = daqPtr->daq.readAll(pa, false);
123 if (size == 0)
124 {
125 // size == 0: no new data for daq
126 continue;
127 }
128 if (size < 0)
129 {
130 // size == -1: buffer full
131 ARMARX_WARNING << "buffer full of daq " << daqPtr->deviceName;
132 }
133 if (daqPtr->daq.getSize() > 0)
134 {
135 IceUtil::Time now = IceUtil::Time::now();
136 TimestampVariantPtr nowTimestamp = new TimestampVariant(now);
137
138 int sensorCount = daqPtr->daq.getSensorSize();
139
140 std::vector<std::array<float, 3>> data;
141 data.resize(sensorCount);
142
143 for (int i = 0; i < sensorCount; i++)
144 {
145 if (!daqPtr->enableFlags.at(i))
146 {
147 continue;
148 }
149 for (int n = 0; n < size; n++)
150 {
151 float countsPerN = daqPtr->countsPerN.at(i);
152 float x = pa[i * size + n].x / countsPerN - daqPtr->offsets.at(i).at(0);
153 float y = pa[i * size + n].y / countsPerN - daqPtr->offsets.at(i).at(1);
154 float z = pa[i * size + n].z / countsPerN - daqPtr->offsets.at(i).at(2);
155
156 batchPrx->reportSensorValues(daqPtr->deviceName + ":" + to_string(i),
157 daqPtr->sensorNames.at(i),
158 x,
159 y,
160 z,
161 nowTimestamp);
162 flushNeeded = true;
163 data.at(i) = {x, y, z};
164 }
165 }
166 delete[] pa;
167
168 if (isRecording)
169 {
170 recordingFile << "{\"timestamp\":\"" << now.toDateTime() << "\",";
171 recordingFile << "\"daq\":\"" << daqPtr->serialNumber << "\",\"data\":[";
172 bool first = true;
173 for (int i = 0; i < sensorCount; i++)
174 {
175 if (!daqPtr->enableFlags.at(i))
176 {
177 continue;
178 }
179 if (!first)
180 {
181 recordingFile << ",";
182 }
183 first = false;
184 recordingFile << "[" << data.at(i).at(0) << "," << data.at(i).at(1) << ","
185 << data.at(i).at(2) << "]";
186 }
187 recordingFile << "]}\n";
188 recordingFile.flush();
189 }
190 }
191 }
192 if (isRecording && stopRecordingFlag)
193 {
194 recordingFile.close();
195 isRecording = false;
196 }
197 stopRecordingFlag = false;
198 if (flushNeeded)
199 {
200 batchPrx->ice_flushBatchRequests();
201 }
202 else
203 {
204 usleep(1000); // 1ms
205 }
206 }
207}
208
209void
213
214void
216{
217 readTask->stop();
218}
219
226
227OptoForceUnit::DaqWrapper::DaqWrapper(const std::string& deviceName,
228 const std::string& serialNumber,
229 const RapidXmlReaderNode& daqNode) :
230 deviceName(deviceName), serialNumber(serialNumber)
231{
232 int i = 0;
233 for (RapidXmlReaderNode sensorNode : daqNode.nodes("Sensor"))
234 {
235 float counts_at_nc = sensorNode.attribute_as_float("counts_at_nc");
236 float nominalCapacity = sensorNode.attribute_as_float("nominalCapacity");
237 std::string sensorName =
238 sensorNode.attribute_value_or_default("name", serialNumber + "-" + to_string(i));
239 countsPerN.push_back(counts_at_nc / nominalCapacity);
240 sensorNames.push_back(sensorName);
241 enableFlags.push_back(
242 sensorNode.attribute_as_optional_bool("enabled", "true", "false", true));
243 offsets.push_back({sensorNode.attribute_as_float("offsetX"),
244 sensorNode.attribute_as_float("offsetY"),
245 sensorNode.attribute_as_float("offsetZ")});
246 i++;
247 }
248}
249
250void
251OptoForceUnit::DaqWrapper::printInfo()
252{
253 SensorConfig config = daq.getConfig();
254 int state = config.getState();
255 int speed = config.getSpeed();
256 int filter = config.getFilter();
257 int mode = config.getMode();
258
259 ARMARX_IMPORTANT_S << "device: " << deviceName << " serialNumber:" << serialNumber;
260 ARMARX_IMPORTANT_S << "state: " << state;
261 ARMARX_IMPORTANT_S << "speed: " << speed;
262 ARMARX_IMPORTANT_S << "filter: " << filter;
263 ARMARX_IMPORTANT_S << "mode: " << mode;
264 ARMARX_IMPORTANT_S << "getBytesPerRead: " << daq.getBytesPerRead();
265 ARMARX_IMPORTANT_S << "getSensorSize: " << daq.getSensorSize();
266 ARMARX_IMPORTANT_S << "getSize: " << daq.getSize();
267 ARMARX_IMPORTANT_S << "getVersion: " << daq.getVersion();
268}
269
270void
271OptoForceUnit::DaqWrapper::checkSensorCount()
272{
273 if ((int)countsPerN.size() != daq.getSensorSize())
274 {
275 throw LocalException("Sensor count mismatch. Configured: ")
276 << ((int)countsPerN.size()) << " found: " << daq.getSensorSize();
277 }
278 ARMARX_INFO_S << "Configured: " << ((int)countsPerN.size()) << " found: " << daq.getSensorSize()
279 << " sensors";
280}
281
282void
283armarx::OptoForceUnit::startRecording(const std::string& filepath, const Ice::Current&)
284{
285 ARMARX_IMPORTANT << "start recording: " << filepath;
286 recordingFile.open(filepath);
287 isRecording = true;
288}
289
290void
292{
293 stopRecordingFlag = true;
294}
uint8_t data[1]
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
void onInitComponent() override
void onDisconnectComponent() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
void startRecording(const std::string &filepath, const Ice::Current &) override
void stopRecording(const Ice::Current &) override
void onExitComponent() override
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
static RapidXmlReaderNode NullNode()
static RapidXmlReaderPtr FromFile(const std::string &path)
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_IMPORTANT_S
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:210
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
const std::string & to_string(const std::string &s)
IceInternal::Handle< TimestampVariant > TimestampVariantPtr
constexpr auto n() noexcept