OrientedTactileSensorUnit.cpp
Go to the documentation of this file.
2
3#include <math.h>
4
5#include <fcntl.h>
6#include <sys/ioctl.h>
7#include <termios.h>
8
13
15
16using namespace armarx;
17
19{
20
21 sampleIndexRotation = 0;
22 sampleIndexPressure = 0;
23 sampleIndexAcceleration = 0;
24 sampleIndexPressureRate = 0;
25}
26
27void
29{
30 //logger part
31 if (getProperty<bool>("logData").getValue())
32 {
33 IceUtil::Time now = IceUtil::Time::now();
34 time_t timer = now.toSeconds();
35 struct tm* ts;
36 char buffer[80];
37 ts = localtime(&timer);
38 strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", ts);
39 std::string packageName = "RobotAPI";
40 armarx::CMakePackageFinder finder(packageName);
41 std::string dataDir = finder.getDataDir() + "/" + packageName + "/logs/";
42 std::string filename = dataDir + buffer + std::string("_data") + ".json";
43 //ARMARX_IMPORTANT << filename;
44
45 logger.reset(new SimpleJsonLogger(filename, true));
46 prefix = std::string(buffer);
47 }
48 maxSamplesRotation = stoi(getProperty<std::string>("SamplesRotation").getValue());
49 maxSamplesPressure = stoi(getProperty<std::string>("SamplesPressure").getValue());
50 maxSamplesAcceleration = stoi(getProperty<std::string>("SamplesAcceleration").getValue());
51
52 std::string topicName = getProperty<std::string>("TopicName").getValue();
53 offeringTopic(topicName);
54
55 //open serial port
56 std::string portname = getProperty<std::string>("SerialInterfaceDevice").getValue();
57 arduinoIn.open(getProperty<std::string>("SerialInterfaceDevice").getValue(), std::ios::in);
58 arduinoOut.open(getProperty<std::string>("SerialInterfaceDevice").getValue(), std::ios::out);
59
60 fd = open(portname.c_str(), O_RDWR | O_NOCTTY);
61 struct termios toptions;
62
63 /* Get currently set options for the tty */
64 tcgetattr(fd, &toptions);
65
66 /* Set custom options */
67 cfsetispeed(&toptions, B115200);
68 cfsetospeed(&toptions, B115200);
69
70 /* 8 bits, no parity, no stop bits */
71 toptions.c_lflag = 0;
72 toptions.c_iflag = 0;
73 toptions.c_oflag = 0;
74
75 /* commit the options */
76 tcsetattr(fd, TCSANOW, &toptions);
77
78 /* Wait for the Arduino to reset */
79 usleep(1000 * 1000);
80
81 /* Flush anything already in the serial buffer */
82 tcflush(fd, TCIFLUSH);
83
84 ARMARX_INFO << "opening device "
85 << getProperty<std::string>("SerialInterfaceDevice").getValue();
86
87 if (!arduinoIn.is_open())
88 {
89
90 throw LocalException("Cannot open Arduino on ")
91 << getProperty<std::string>("SerialInterfaceDevice").getValue();
92 }
93
94 ARMARX_INFO << "Arduino restarts, please wait ...";
95
96 //wait for the Arduino to reboot
97 usleep(4000000);
98 std::string arduinoLine;
99
100 //wait for the IMU to be calibrated or load calibration
101 ARMARX_INFO << "waiting for IMU calibration - this can take some time";
102 if (getProperty<bool>("calibrateSensor").getValue())
103 {
104 //calibrate
105
106 while (arduinoLine.find("mode") == std::string::npos)
107 {
108 getline(arduinoIn, arduinoLine, '\n');
109 }
110
111 arduinoOut << "calibrate";
112 arduinoOut.flush();
113
114 while (arduinoLine.find("Calibration Sucessfull") == std::string::npos)
115 {
116 getline(arduinoIn, arduinoLine, '\n');
117 ARMARX_INFO << arduinoLine;
118 }
119 getline(arduinoIn, arduinoLine, '\n');
120 if (getCalibrationValues(arduinoLine))
121 {
122 ARMARX_IMPORTANT << "calibrated sensor";
123 }
124 }
125 else
126 {
127 //load calibration
128 ARMARX_INFO << "load calibration data "
129 << getProperty<std::string>("CalibrationData").getValue();
130 if (loadCalibration())
131 {
132 ARMARX_IMPORTANT << "loaded calibration";
133 first = true;
134 /*std::string line;
135 getline(arduinoIn, line, '\n');
136 ARMARX_IMPORTANT<<line;
137 SensorData dataInit = getValues(line.c_str());
138 ARMARX_IMPORTANT<<dataInit.qw<<" "dataInit.qx<<" "<<dataInit.qy<<" "<<dataInit.qz;
139 Eigen::Quaternionf initialOrientation = Eigen::Quaternionf(dataInit.qw, dataInit.qx, dataInit.qy, dataInit.qz);
140 inverseOrientation = initialOrientation.inverse();*/
141 }
142 }
143 readTask = new RunningTask<OrientedTactileSensorUnit>(this, &OrientedTactileSensorUnit::run);
144 readTask->start();
145}
146
147void
149{
150 debugDrawerTopic = getTopic<DebugDrawerInterfacePrx>(
151 getProperty<std::string>("DebugDrawerTopicName").getValue());
152 std::string topicName = getProperty<std::string>("TopicName").getValue();
154}
155
162
163void
164OrientedTactileSensorUnit::run()
165{
166 while (readTask->isRunning())
167 {
168 std::string line;
169 getline(arduinoIn, line, '\n');
170 SensorData data = getValues(line.c_str());
171 IceUtil::Time now = IceUtil::Time::now();
172 TimestampVariantPtr nowTimestamp = new TimestampVariant(now);
173
174 //compute rotationRate
175 float rotationRate = 0;
176
177 //condition for inverse quaternion
178 if ((pow(data.qw, 2) + pow(data.qx, 2) + pow(data.qy, 2) + pow(data.qz, 2)) != 0)
179 {
180 RotationRate sampleRotation;
181 sampleRotation.timestamp = now;
182 sampleRotation.orientation = Eigen::Quaternionf(data.qw, data.qx, data.qy, data.qz);
183 //sampleRotation.orientation = sampleRotation.orientation * inverseOrientation;
184 if (0 < maxSamplesRotation &&
185 samplesRotation.size() < static_cast<std::size_t>(maxSamplesRotation))
186 {
187 samplesRotation.push_back(sampleRotation);
188 }
189 else
190 {
191 samplesRotation[sampleIndexRotation].timestamp = sampleRotation.timestamp;
192 samplesRotation[sampleIndexRotation].orientation = sampleRotation.orientation;
193 sampleIndexRotation = (sampleIndexRotation + 1) % maxSamplesRotation;
194 RotationRate oldsampleRotation;
195 oldsampleRotation.timestamp = samplesRotation.at(sampleIndexRotation).timestamp;
196 oldsampleRotation.orientation = samplesRotation.at(sampleIndexRotation).orientation;
197 Eigen::AngleAxisf aa(sampleRotation.orientation *
198 oldsampleRotation.orientation.inverse());
199 //ARMARX_IMPORTANT << "aa: " << aa.axis() << " " << aa.angle();
200 rotationRate =
201 aa.angle() /
202 (sampleRotation.timestamp - oldsampleRotation.timestamp).toSecondsDouble();
203 }
204 }
205 //compute pressureRate
206 float pressureRate = 0;
207 PressureRate samplePressure;
208 samplePressure.timestamp = now;
209 samplePressure.pressure = data.pressure;
210 if (0 < maxSamplesPressure &&
211 samplesPressure.size() < static_cast<std::size_t>(maxSamplesPressure))
212 {
213 samplesPressure.push_back(samplePressure);
214 }
215 else
216 {
217 samplesPressure[sampleIndexPressure] = samplePressure;
218 sampleIndexPressure = (sampleIndexPressure + 1) % maxSamplesPressure;
219 PressureRate oldsamplePressure;
220 oldsamplePressure.timestamp = samplesPressure.at(sampleIndexPressure).timestamp;
221 oldsamplePressure.pressure = samplesPressure.at(sampleIndexPressure).pressure;
222 pressureRate =
223 (samplePressure.pressure - oldsamplePressure.pressure) /
224 (samplePressure.timestamp - oldsamplePressure.timestamp).toSecondsDouble();
225 }
226
227 //compute angular accceleration Rate
228 float accelerationRate = 0;
229 AccelerationRate sampleAcceleration;
230 sampleAcceleration.timestamp = now;
231 sampleAcceleration.rotationRate = rotationRate;
232 if (0 < maxSamplesAcceleration &&
233 samplesAcceleration.size() < static_cast<std::size_t>(maxSamplesAcceleration))
234 {
235 samplesAcceleration.push_back(sampleAcceleration);
236 }
237 else
238 {
239 samplesAcceleration[sampleIndexAcceleration] = sampleAcceleration;
240 sampleIndexAcceleration = (sampleIndexAcceleration + 1) % maxSamplesAcceleration;
241 AccelerationRate oldsampleAcceleration;
242 oldsampleAcceleration.timestamp =
243 samplesAcceleration.at(sampleIndexAcceleration).timestamp;
244 oldsampleAcceleration.rotationRate =
245 samplesAcceleration.at(sampleIndexAcceleration).rotationRate;
246 accelerationRate =
247 (sampleAcceleration.rotationRate - oldsampleAcceleration.rotationRate) /
248 (sampleAcceleration.timestamp - oldsampleAcceleration.timestamp).toSecondsDouble();
249 }
250 if (0 < maxSamplesPressure &&
251 pressureRates.size() < static_cast<std::size_t>(maxSamplesPressure))
252 {
253 pressureRates.push_back(pressureRate);
254 }
255 else
256 {
257 pressureRates[sampleIndexPressureRate] = pressureRate;
258 sampleIndexPressureRate = (sampleIndexPressureRate + 1) % maxSamplesPressure;
259 }
260 if (pressureRate > 50)
261 {
262 ARMARX_IMPORTANT << "contact";
263 }
264
265 Eigen::Quaternionf orientationQuaternion =
266 Eigen::Quaternionf(data.qw, data.qx, data.qy, data.qz);
267 if (getProperty<bool>("logData").getValue())
268 {
269
270 if (i < 50)
271 {
272 inverseOrientation = orientationQuaternion.inverse();
273 i++;
274 }
275 Eigen::Matrix3f quatMatrix = orientationQuaternion.toRotationMatrix();
276 Eigen::Matrix4f quat4Matrix = Eigen::Matrix4f::Identity();
277
278 quat4Matrix.block(0, 0, 3, 3) = quatMatrix;
279
280 Eigen::Vector3f linearAcceleration(data.accelx, data.accely, data.accelz);
281 SimpleJsonLoggerEntry e;
282 e.AddTimestamp();
283 e.Add("Pressure", data.pressure);
284 e.Add("PressureRate", pressureRate);
285 e.Add("RotationRate", rotationRate);
286 e.AddAsArr("Orientation", quat4Matrix);
287 e.AddAsArr("Linear Acceleration", linearAcceleration);
288 logger->log(e);
289 }
290 /*Eigen::Matrix3f rotZ;
291 rotZ(0, 0) = 0;
292 rotZ(0, 1) = 1;
293 rotZ(0, 2) = 0;
294 rotZ(1, 0) = -1;
295 rotZ(1, 1) = 0;
296 rotZ(1, 2) = 0;
297 rotZ(2, 0) = 0;
298 rotZ(2, 1) = 0;
299 rotZ(2, 2) = 1;
300 Eigen::Matrix3f rotX;
301 rotX(0, 0) = 1;
302 rotX(0, 1) = 0;
303 rotX(0, 2) = 0;
304 rotX(1, 0) = 0;
305 rotX(1, 1) = -1;
306 rotX(1, 2) = 0;
307 rotX(2, 0) = 0;
308 rotX(2, 1) = 0;
309 rotX(2, 2) = -1;*/
310 Eigen::Matrix3f rotY;
311 rotY(0, 0) = 0;
312 rotY(0, 1) = 0;
313 rotY(0, 2) = 1;
314 rotY(1, 0) = 0;
315 rotY(1, 1) = 1;
316 rotY(1, 2) = 0;
317 rotY(2, 0) = -1;
318 rotY(2, 1) = 0;
319 rotY(2, 2) = 0;
320 Eigen::Matrix3f rawOrientation = orientationQuaternion.toRotationMatrix();
321
322 PosePtr pose = new Pose(rawOrientation, Eigen::Vector3f(100.0, 200.0, 0.0));
323 if (debugDrawerTopic)
324 {
325 debugDrawerTopic->setPoseVisu("debugdrawerlayer", "pose", pose);
326 }
327 Eigen::Quaternionf quaternion(rawOrientation);
328 data.qw = quaternion.w();
329 data.qx = quaternion.x();
330 data.qy = quaternion.y();
331 data.qz = quaternion.z();
332 ARMARX_IMPORTANT << "or " << orientationQuaternion.w() << " " << orientationQuaternion.x()
333 << " " << orientationQuaternion.y() << " " << orientationQuaternion.z();
334 if (topicPrx)
335 {
336 topicPrx->reportSensorValues(data.id,
337 data.pressure,
338 data.qw,
339 data.qx,
340 data.qy,
341 data.qz,
342 pressureRate,
343 rotationRate,
344 accelerationRate,
345 data.accelx,
346 data.accely,
347 data.accelz,
348 nowTimestamp);
349 }
350 }
351}
352
353// get imu values from incoming string
355OrientedTactileSensorUnit::getValues(std::string line)
356{
358 std::vector<std::string> splitValues = Split(line, " ");
359 data.id = stoi(splitValues.at(0));
360 data.pressure = std::stof(splitValues.at(1));
361 data.qw = std::stof(splitValues.at(2));
362 data.qx = std::stof(splitValues.at(3));
363 data.qy = std::stof(splitValues.at(4));
364 data.qz = std::stof(splitValues.at(5));
365 data.accelx = std::stof(splitValues.at(6));
366 data.accely = std::stof(splitValues.at(7));
367 data.accelz = std::stof(splitValues.at(8));
368 return data;
369}
370
371std::string space = " ";
372
373bool
374OrientedTactileSensorUnit::loadCalibration()
375{
376 std::string calibrationStream = getProperty<std::string>("CalibrationData").getValue();
377 std::string arduinoLine;
378 while (arduinoLine.find("mode") == std::string::npos)
379 {
380 getline(arduinoIn, arduinoLine, '\n');
381 }
382 arduinoOut << "load";
383 arduinoOut.flush();
384 while (arduinoLine.find("calibration data") == std::string::npos)
385 {
386 getline(arduinoIn, arduinoLine, '\n');
387 }
388
389 arduinoOut << calibrationStream;
390 arduinoOut.flush();
391
392 while (arduinoLine.find("Calibration Sucessfull") == std::string::npos)
393 {
394 getline(arduinoIn, arduinoLine, '\n');
395 }
396 return true;
397}
398
399bool
400OrientedTactileSensorUnit::getCalibrationValues(std::string line)
401{
402 std::vector<std::string> splitValues = Split(line, " ");
403 calibration.accel_offset_x = stoi(splitValues.at(0));
404 calibration.accel_offset_y = stoi(splitValues.at(1));
405 calibration.accel_offset_z = stoi(splitValues.at(2));
406 calibration.gyro_offset_x = stoi(splitValues.at(3));
407 calibration.gyro_offset_y = stoi(splitValues.at(4));
408 calibration.gyro_offset_z = stoi(splitValues.at(5));
409 calibration.mag_offset_x = stoi(splitValues.at(6));
410 calibration.mag_offset_y = stoi(splitValues.at(7));
411 calibration.mag_offset_z = stoi(splitValues.at(8));
412 calibration.accel_radius = stoi(splitValues.at(9));
413 calibration.mag_radius = stoi(splitValues.at(10));
414 std::string space = " ";
415 std::string calibrationStream = "";
416 calibrationStream =
417 calibrationStream + to_string(calibration.accel_offset_x) + space +
418 to_string(calibration.accel_offset_y) + space + to_string(calibration.accel_offset_z) +
419 space + to_string(calibration.gyro_offset_x) + space +
420 to_string(calibration.gyro_offset_y) + space + to_string(calibration.gyro_offset_z) +
421 space + to_string(calibration.mag_offset_x) + space + to_string(calibration.mag_offset_y) +
422 space + to_string(calibration.mag_offset_z) + space + to_string(calibration.accel_radius) +
423 space + to_string(calibration.mag_radius) + space;
424 ARMARX_IMPORTANT << "calibration data: " << calibrationStream;
425 return true;
426}
uint8_t data[1]
std::string space
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
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
Pure virtual hook for the subclass.
void onConnectComponent() override
Pure virtual hook for the subclass.
PropertyDefinitionsPtr createPropertyDefinitions() override
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
void Add(const std::string &key, const std::string &value)
void AddAsArr(const std::string &key, const Eigen::Vector3f &vec)
Implements a Variant type for timestamps.
#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
Quaternion< float, 0 > Quaternionf
StringVariantContainerBaseMap getValues(const StateParameterMap &paramMap)
T getValue(nlohmann::json &userConfig, nlohmann::json &defaultConfig, const std::string &entryName)
Definition utils.h:80
Eigen::Isometry3f Pose
Definition basic_types.h:31
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceInternal::Handle< Pose > PosePtr
Definition Pose.h:306
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
const std::string & to_string(const std::string &s)
IceInternal::Handle< TimestampVariant > TimestampVariantPtr