icub-client
touchDetectorThread.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 iCub Facility - Istituto Italiano di Tecnologia
3  * Author: Bertand HIGY
4  * email: bertrand.higy@iit.it
5  * Permission is granted to copy, distribute, and/or modify this program
6  * under the terms of the GNU General Public License, version 2 or any
7  * later version published by the Free Software Foundation.
8  *
9  * A copy of the license can be found at
10  * http://www.robotcub.org/icub/license/gpl.txt
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details
16 */
17 
18 #include <cstring>
19 #include <fstream>
20 #include <string>
21 #include <sstream>
22 
23 #include <yarp/os/LogStream.h>
24 #include <yarp/os/Value.h>
25 #include <yarp/os/Property.h>
26 
27 #include "touchDetectorThread.h"
28 
29 using namespace std;
30 using namespace yarp::os;
31 
32 const int TouchDetectorThread::noCluster = -1;
34 const char* TouchDetectorThread::bodyParts[7] = {"torso", "left_arm", "right_arm", "left_forearm", "right_forearm", "left_hand", "right_hand"};
35 const int TouchDetectorThread::nbTaxels[7] = {4 * 192, 4 * 192, 4 * 192, 2 * 192, 2 * 192, 192, 192};
36 
37 TouchDetectorThread::TouchDetectorThread(BufferedPort<Bottle> *torsoPort, BufferedPort<Bottle> *leftArmPort, BufferedPort<Bottle> *rightArmPort, BufferedPort<Bottle> *leftForearmPort, BufferedPort<Bottle> *rightForearmPort, BufferedPort<Bottle> *leftHandPort, BufferedPort<Bottle> *rightHandPort, BufferedPort<Bottle> *touchPort, BufferedPort<Bottle> *touchPortCleaned, int period, string clustersConfFilepath, double threshold, int taxelThreshold)
38  : RateThread(period), nbClusters(0), threshold(threshold), taxelThreshold(taxelThreshold), clustersConfFilepath(clustersConfFilepath), torsoPort(torsoPort), leftArmPort(leftArmPort), rightArmPort(rightArmPort), leftForearmPort(leftForearmPort), rightForearmPort(rightForearmPort), leftHandPort(leftHandPort), rightHandPort(rightHandPort), touchPort(touchPort), touchPortCleaned(touchPortCleaned)
39 {
40  for (int i = 0; i < nbBodyParts; ++i)
41  {
42  taxels2Clusters[i].resize(nbTaxels[i]);
43  for (int j = 0; j < nbTaxels[i]; ++j)
44  {
45  taxels2Clusters[i][j] = noCluster;
46  }
47  }
48 }
49 
51 {
52  try
53  {
55  }
56  catch (ParsingException ex)
57  {
58  yError() << ex.what();
59  return false;
60  }
61 
62  return true;
63 }
64 
66 {
67  Property p;
68  p.fromConfigFile(filename);
69  int clusterId = 0;
70  for (int iPart = 0; iPart < nbBodyParts; ++iPart)
71  {
72  Bottle clusters = p.findGroup(bodyParts[iPart]).tail();
73  for (unsigned int iCluster = 0; iCluster < clusters.size(); ++iCluster)
74  {
75  ++clusterId;
76  Bottle *c = clusters.get(iCluster).asList();
77  for (unsigned int iRange = 0; iRange < c->size(); ++iRange)
78  {
79  Bottle *range = c->get(iRange).asList();
80  if (range->size() == 1)
81  {
82  int taxel = range->get(0).asInt();
83  updateMapping(iPart, taxel, taxel, clusterId);
84  }
85  if (range->size() >= 2)
86  {
87  int first = range->get(0).asInt();
88  int last = range->get(1).asInt();
89  updateMapping(iPart, first, last, clusterId);
90  }
91  }
92  }
93  }
94 
95  nbClusters = clusterId;
96 
97  return true;
98 }
99 
100 int TouchDetectorThread::getBodyPartId(string bodyPartName)
101 {
102  int id = -1;
103  for (int i = 0; i < nbBodyParts; ++i)
104  {
105  if (bodyParts[i] == bodyPartName)
106  {
107  id = i;
108  break;
109  }
110  }
111  if (id == -1)
112  {
113  throw ParsingException();
114  }
115 
116  return id;
117 }
118 
119 void TouchDetectorThread::updateMapping(int bodyPart, int firstTaxel, int lastTaxel, int cluster)
120 {
121  for (int i = firstTaxel - 1; i < lastTaxel; ++i)
122  {
123  taxels2Clusters[bodyPart][i] = cluster;
124  }
125 }
126 
128 {
129  vector<int> activations;
130  for(int i = 0; i < nbClusters; i++) {
131  activations.push_back(0);
132  }
133 
134  int port = 0;
135  try
136  {
137  processPort(port, torsoPort, activations);
138  processPort(++port, leftArmPort, activations);
139  processPort(++port, rightArmPort, activations);
140  processPort(++port, leftForearmPort, activations);
141  processPort(++port, rightForearmPort, activations);
142  processPort(++port, leftHandPort, activations);
143  processPort(++port, rightHandPort, activations);
144  }
145  catch(BadFormatException &ex)
146  {
147  ex.portName = bodyParts[port];
148  throw ex;
149  }
150 
151  int activatedTaxelNumber = -1; // which taxel patch was activated
152  int i = 0;
153  Bottle& output = touchPort->prepare();
154  output.clear();
155  for (auto& activation : activations)
156  {
157  if(activation >= taxelThreshold) {
158  activatedTaxelNumber = i;
159  }
160  output.addInt(activation);
161  i++;
162  }
163  touchPort->write();
164 
165  if(activatedTaxelNumber >= 0) {
166  Bottle& outputClean = touchPortCleaned->prepare();
167  outputClean.clear();
168  outputClean.addInt(activatedTaxelNumber);
169  touchPortCleaned->write();
170  }
171 }
172 
173 void TouchDetectorThread::processPort(int portNum, yarp::os::BufferedPort<yarp::os::Bottle> *port, vector<int> &activations)
174 {
175  Bottle *tactileData = port->read(false);
176  if (tactileData != nullptr)
177  {
178  countActivations(portNum, tactileData, activations);
179  }
180  else
181  {
182  yWarning() << "Unable to read data for " << bodyParts[portNum];
183  }
184 }
185 
186 void TouchDetectorThread::countActivations(int bodyPart, Bottle* data, vector<int> &activations)
187 {
188  int i = 0;
189  for (vector<int>::iterator it = taxels2Clusters[bodyPart].begin() ; it != taxels2Clusters[bodyPart].end(); ++it)
190  {
191  Value v = data->get(i);
192  if (v.isNull() || !v.isDouble())
193  {
195  ex.expectedType = "double";
196  throw ex;
197  }
198  if (v.asDouble() > threshold && *it != noCluster)
199  {
200  ++activations[*it];
201  }
202  ++i;
203  }
204 }
205 
207 {
208  line = -1;
209 }
210 
211 const char* ParsingException::what() const throw()
212 {
213  if (line != -1)
214  {
215  std::string return_msg = "Error parsing line " + std::to_string(line);
216  char* return_msg_char = new char[return_msg.size() + 1];
217  strcpy(return_msg_char, return_msg.c_str());
218  return return_msg_char;
219  }
220  else
221  {
222  return "Parsing error";
223  }
224 }
225 
227 
228 const char* BadFormatException::what() const throw()
229 {
230  std::string msg;
231  msg = "Bad format encountered ";
232 
233  if (expectedType != "")
234  {
235  msg += "(expecting ";
236  msg += expectedType;
237  msg += ") ";
238  }
239  msg += "while reading ";
240  if (portName != "")
241  {
242  msg += "port ";
243  msg += portName;
244  }
245  else
246  {
247  msg += "a port";
248  }
249 
250  yError() << msg;
251 
252  return "Bad format encountered";
253 }
254 
bool readTaxelsMapping(std::string filename)
readTaxelsMapping Read taxels map from configure file, which relates to nbBodyParts and bodyParts ...
int getBodyPartId(std::string bodyPartName)
getBodyPartId Obtain the ID of body parts, which are "torso", "left_arm", "right_arm", "left_forearm", "right_forearm", "left_hand", "right_hand"
yarp::os::BufferedPort< yarp::os::Bottle > * rightHandPort
Yarp BufferedPort of bottle for input right hand activations.
int taxelThreshold
integer value of touched threshold
STL namespace.
void countActivations(int bodyPart, yarp::os::Bottle *data, std::vector< int > &activations)
countActivations Counts number of activations to a body part through a buffered port of that part ...
yarp::os::BufferedPort< yarp::os::Bottle > * leftArmPort
Yarp BufferedPort of bottle for input left arm activations.
yarp::os::BufferedPort< yarp::os::Bottle > * rightForearmPort
Yarp BufferedPort of bottle for input right forearm activations.
yarp::os::BufferedPort< yarp::os::Bottle > * touchPort
Yarp BufferedPort of bottle for output touched activations.
virtual const char * what() const
yarp::os::BufferedPort< yarp::os::Bottle > * leftHandPort
Yarp BufferedPort of bottle for input left hand activations.
yarp::os::BufferedPort< yarp::os::Bottle > * torsoPort
Yarp BufferedPort of bottle for input torso activations.
yarp::os::BufferedPort< yarp::os::Bottle > * rightArmPort
Yarp BufferedPort of bottle for input right arm activations.
static const int noCluster
yarp::os::BufferedPort< yarp::os::Bottle > * touchPortCleaned
Yarp BufferedPort of bottle for output touched taxel.
std::string clustersConfFilepath
string value of the path to configure file of clusters
yarp::os::BufferedPort< yarp::os::Bottle > * leftForearmPort
Yarp BufferedPort of bottle for input left forearm activations.
static const int nbBodyParts
void processPort(int portNum, yarp::os::BufferedPort< yarp::os::Bottle > *port, std::vector< int > &activations)
processPort Process port of body part to receive activations to that body part
static const int nbTaxels[7]
virtual const char * what() const
void updateMapping(int bodyPart, int firstTaxel, int lastTaxel, int cluster)
updateMapping Change all taxels of a body part to clusterID
std::vector< int > taxels2Clusters[7]
standard vector of integer containing the taxel IDs in form of cluster ID
static const char * bodyParts[7]
TouchDetectorThread(yarp::os::BufferedPort< yarp::os::Bottle > *torsoPort, yarp::os::BufferedPort< yarp::os::Bottle > *leftArmPort, yarp::os::BufferedPort< yarp::os::Bottle > *rightArmPort, yarp::os::BufferedPort< yarp::os::Bottle > *leftForearmPort, yarp::os::BufferedPort< yarp::os::Bottle > *rightForearmPort, yarp::os::BufferedPort< yarp::os::Bottle > *leftHandPort, yarp::os::BufferedPort< yarp::os::Bottle > *rightHandPort, yarp::os::BufferedPort< yarp::os::Bottle > *touchPort, yarp::os::BufferedPort< yarp::os::Bottle > *touchPortCleaned, int period, std::string clustersConfFilepath, double threshold, int taxelThreshold)