icub-client
pasar.cpp
Go to the documentation of this file.
1 // -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
2 
3 /*
4 * Copyright (C) 2014 WYSIWYD Consortium, European Commission FP7 Project IST-270490
5 * Authors: Stéphane Lallée, Grégoire Pointeau
6 * email: stephane.lallee@gmail.com, greg.pointeau@gmail.com
7 * Permission is granted to copy, distribute, and/or modify this program
8 * under the terms of the GNU General Public License, version 2 or any
9 * later version published by the Free Software Foundation.
10 *
11 * A copy of the license can be found at
12 * icub-client/license/gpl.txt
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details
18 */
19 
20 #include "pasar.h"
21 
22 using namespace icubclient;
23 using namespace yarp::os;
24 using namespace yarp::sig;
25 using namespace std;
26 
27 /************************************************************************/
28 bool PasarModule::configure(yarp::os::ResourceFinder &rf)
29 {
30  string moduleName = rf.check("name", Value("pasar")).asString().c_str();
31  setName(moduleName.c_str());
32 
33  //Parameters
34  pTopDownAppearanceBurst = rf.check("parameterTopDownAppearanceBurst",
35  Value(3.)).asDouble();
36  pTopDownDisappearanceBurst = rf.check("parameterTopDownDisappearanceBurst",
37  Value(2.)).asDouble();
38  pTopDownAccelerationCoef = rf.check("parameterTopDownAccelerationCoef",
39  Value(0.1)).asDouble();
40  pExponentialDecrease = rf.check("ExponentialDecrease",
41  Value(0.9)).asDouble();
42  pTopDownWaving = rf.check("pTopDownWaving",
43  Value(0.2)).asDouble();
44  dBurstOfPointing = rf.check("pBurstOfPointing",
45  Value(0.2)).asDouble();
46  dthresholdAppear = rf.check("thresholdAppear", Value(1.)).asDouble();
47  dthresholdDisappear = rf.check("thresholdDisappear", Value(2.)).asDouble();
48  thresholdPointing = rf.check("thresholdDistancePointing", Value(.5)).asDouble();
49 
50  //check for decrease
51  if (pExponentialDecrease >= 1 || pExponentialDecrease <= 0.0) pExponentialDecrease = 0.95;
52 
53  presentRightHand.first = false;
54  presentRightHand.second = false;
55  presentLeftHand.first = false;
56  presentLeftHand.first = false;
57 
58  rightHandt1 = Vector(3, 0.0);
59  rightHandt2 = Vector(3, 0.0);
60  leftHandt1 = Vector(3, 0.0);
61  leftHandt2 = Vector(3, 0.0);
62 
63  thresholdMovementAccelAgent = rf.check("thresholdMovementAccelAgent",
64  Value(0.02)).asDouble();
65  thresholdMovementAccelObject = rf.check("thresholdMovementAccelObject",
66  Value(0.2)).asDouble();
67  thresholdWaving = rf.check("thresholdWaving",
68  Value(0.02)).asDouble();
69  thresholdSaliency = rf.check("thresholdSaliency",
70  Value(0.005)).asDouble();
71 
72  bool isRFVerbose = true;
73  iCub = new ICubClient(moduleName, "pasar", "pasar.ini", isRFVerbose);
74  iCub->opc->isVerbose &= true;
75 
76  if (!iCub->connect())
77  {
78  yError() << "iCubClient : Some dependencies are not running...";
79  return false;
80  }
81 
82  checkPointing = rf.find("isPointing").asInt() == 1;
83  checkWaving = rf.find("isWaving").asInt() == 1;
84 
85  isPointing = false;
86  isWaving = false;
87 
88  yInfo() << " pointing: " << checkPointing;
89  yInfo() << " waving: " << checkWaving;
90 
91  if (!handlerPort.open(("/" + moduleName + "/rpc").c_str())) {
92  yError() << getName() << ": Unable to open port rpc";
93  return false;
94  }
95 
96  attach(handlerPort); // attach to port
97  presentObjectsLastStep.clear();
98  initTime = yarp::os::Time::now();
99  initializeMapTiming();
100 
101  for (auto &it : OPCEntities)
102  {
103  yInfo() << "start: checking entity: " << it.second.o.name() << " opcPresence: " << it.second.o.m_present << ", pasar presence: " << it.second.present;
104  }
105 
106  yInfo() << "\n \n" << "----------------------------------------------" << "\n \n" << moduleName << " ready ! \n \n ";
107 
108 
109  return true;
110 }
111 
112 /************************************************************************/
114 {
115  yDebug() << "Interrupt OPC";
116  iCub->opc->interrupt();
117  yDebug() << "Interrupt RPC port";
118  handlerPort.interrupt();
119  return true;
120 }
121 
122 /************************************************************************/
124 {
125  if(iCub) {
126  yDebug() << "Close iCub";
127  iCub->close();
128  delete iCub;
129  }
130  yDebug() << "Interrupt RPC";
131  handlerPort.interrupt();
132  yDebug() << "Close RPC";
133  handlerPort.close();
134  return true;
135 }
136 
137 /************************************************************************/
138 bool PasarModule::respond(const Bottle& command, Bottle& reply)
139 {
140  string helpMessage = string(getName().c_str()) +
141  " commands are: \n" +
142  "help \n" +
143  "pointing on/off: launch or stop pointing\n" +
144  "waving on/off: launch or stop waving\n" +
145  "quit \n";
146 
147  reply.clear();
148  reply.addString("ack");
149 
150  yInfo() << " rpc command received: " << command.toString();
151 
152  if (command.get(0).asString() == "quit") {
153  reply.addString("quitting");
154  return false;
155  }
156  else if (command.get(0).asString() == "help") {
157  reply.addString(helpMessage.c_str());
158  }
159  else if (command.get(0).asString() == "pointing") {
160  if (command.size() != 2)
161  {
162  reply.addString("error in PASAR: Bottle 'pointing' misses information (on/off)");
163  }
164  else
165  {
166  if (command.get(1).asString() == "off")
167  {
168  checkPointing = false;
169  yInfo() << " stop pointing";
170  reply.addString("ack");
171  reply.addString("stop pointing");
172  }
173  else if (command.get(1).asString() == "on")
174  {
175  checkPointing = true;
176  yInfo() << " start pointing";
177  reply.addString("ack");
178  reply.addString("start pointing");
179  }
180  }
181  }
182  else if (command.get(0).asString() == "waving") {
183  if (command.size() != 2)
184  {
185  reply.addString("error in PASAR: Bottle 'waving' misses information (on/off)");
186  }
187  else
188  {
189  if (command.get(1).asString() == "off")
190  {
191  checkWaving = false;
192  yInfo() << " stop waving";
193  reply.addString("stop waving");
194  }
195  else if (command.get(1).asString() == "on")
196  {
197  checkWaving = true;
198  yInfo() << " start waving";
199  reply.addString("start waving");
200  }
201  }
202  }
203  else if (command.get(0).asString() == "set") {
204  reply.addString("set");
205  reply.addString("ir");
206  }
207  return true;
208 }
209 
210 /***************************************************************************/
212 {
213  iCub->opc->checkout();
214  std::list<std::shared_ptr<icubclient::Entity>> entities = iCub->opc->EntitiesCacheCopy();
215 
216  presentLastSpeed = presentCurrentSpeed;
217  presentCurrentSpeed.clear();
218 
219  for (auto &entity : entities)
220  {
221  if (entity->name() != "icub")
222  {
223  if (entity->isType(ICUBCLIENT_OPC_ENTITY_AGENT) || entity->isType(ICUBCLIENT_OPC_ENTITY_OBJECT))
224  {
225  Object * ob = dynamic_cast<Object*>(entity.get());
226  if(ob)
227  OPCEntities[entity->opc_id()].o = *ob;
228  }
229  }
230  }
231 
232  if (presentObjectsLastStep.size() > 0)
233  {
234  //Compute top down saliency (concept based)
235  saliencyTopDown();
236  if (checkPointing) saliencyPointing();
237  if (checkWaving) saliencyWaving();
238 
239  //Leaky integrate
240  saliencyLeakyIntegration();
241 
242  //Update the OPC values
243  for (auto it = entities.begin(); it != entities.end(); it++)
244  {
245  if (OPCEntities.find((*it)->opc_id()) != OPCEntities.end())
246  {
247  Object* o = dynamic_cast<Object*>(iCub->opc->getEntity((*it)->name()));
248  if(o) {
249  o->m_saliency = OPCEntities[(*it)->opc_id()].o.m_saliency;
250  iCub->opc->commit(o);
251  }
252  }
253  }
254  }
255  else
256  {
257  yInfo("no objects present in the OPC");
258  }
259 
260  presentObjectsLastStep = OPCEntities;
261 
262  return true;
263 }
264 
265 /************************************************************************/
267 {
268  double now = yarp::os::Time::now() - initTime;
269  //Add up the top down saliency
270  for (auto &it : OPCEntities)
271  {
272  if (presentObjectsLastStep.find(it.first) != presentObjectsLastStep.end() && it.second.o.name() != "cursor_0" && it.second.o.name() != "icub")
273  {
274  //Objects appears/disappears
275  bool appeared, disappeared;
276 
277  // If the object is absent:
278  // if the lastTimeSeen was more than a threshold, the object dissapeared
279  disappeared = (now - it.second.lastTimeSeen > dthresholdDisappear) && (it.second.o.m_present == 0.0) && it.second.present;
280  if (disappeared){
281  yInfo() << "DISAPPEARED since: " << now - it.second.lastTimeSeen;
282  }
283 
284  // If the object is present:
285  // if the lastTimeSeen was more than a threshold, the object appeared
286  appeared = (now - it.second.lastTimeSeen > dthresholdAppear) && (it.second.o.m_present == 1.0) && !it.second.present;
287  if (appeared){
288  yInfo() << "APPEARED since: " << now - it.second.lastTimeSeen;
289  }
290 
291  if (it.second.o.m_present == 1.0) it.second.lastTimeSeen = now;
292 
293  //instantaneous speed/acceleration
294  Vector lastPos = presentObjectsLastStep[it.first].o.m_ego_position;
295  Vector currentPos = it.second.o.m_ego_position;
296  presentCurrentSpeed[it.first] = pair<double, double>(lastPos[0] - currentPos[0], lastPos[1] - currentPos[1]);
297 
298  double acceleration = sqrt(pow(presentCurrentSpeed[it.first].first - presentLastSpeed[it.first].first, 2.) + pow(presentCurrentSpeed[it.first].second - presentLastSpeed[it.first].second, 2.));
299 
300  OPCEntities[it.first].acceleration = acceleration;
301 
302  //Use the world model (CONCEPTS <=> RELATIONS) to modulate the saliency
303  if (appeared)
304  {
305  it.second.o.m_saliency += pTopDownAppearanceBurst;
306  yInfo() << "\t\t APPEARANCE OF: " << it.second.o.name();
307  it.second.present = true;
308  }
309 
310  if (disappeared)
311  {
312  it.second.o.m_saliency += pTopDownDisappearanceBurst;
313  yInfo() << "\t\t DISAPPEARANCE OF: " << it.second.o.name();
314  it.second.present = false;
315  }
316 
317  if (it.second.o.entity_type() == ICUBCLIENT_OPC_ENTITY_AGENT){
318  if (acceleration > thresholdMovementAccelAgent)
319  {
320  it.second.o.m_saliency += pTopDownAccelerationCoef;
321  yInfo() << " moving agent:" << it.second.o.name() << " salience : " << it.second.o.m_saliency << " acceleration: " << acceleration;
322  }
323 
324  }
325  else {
326  if (acceleration > thresholdMovementAccelObject)
327  {
328  it.second.o.m_saliency += pTopDownAccelerationCoef;
329  yInfo() << " moving object:" << it.second.o.name() << " salience : " << it.second.o.m_saliency << " acceleration: " << acceleration;
330  }
331  }
332  }
333  }
334 }
335 
336 /************************************************************************/
338 {
339  //Get the max
340  map< int, ObjectModel >::iterator mostSalientObject = OPCEntities.begin();
341 
342  for (map< int, ObjectModel >::iterator it = OPCEntities.begin(); it != OPCEntities.end(); it++)
343  {
344  if (it->second.o.m_saliency > mostSalientObject->second.o.m_saliency)
345  mostSalientObject = it;
346  }
347 
348  //Normalize
349  double maxS = mostSalientObject->second.o.m_saliency;
350  if (maxS == 0) maxS = 1.;
351  for (map< int, ObjectModel >::iterator it = OPCEntities.begin(); it != OPCEntities.end(); it++)
352  {
353  it->second.o.m_saliency /= maxS;
354  }
355 }
356 
357 /************************************************************************/
359 {
360  for (auto &it : OPCEntities)
361  {
362  if (it.second.o.name() != "" && it.second.o.m_present != 0.5)
363  {
364  it.second.o.m_saliency *= pExponentialDecrease;
365  }
366  if (it.second.o.m_saliency < thresholdSaliency)
367  it.second.o.m_saliency = 0.0;
368  }
369 }
370 
371 /************************************************************************/
373 {
374  return 0.1;
375 }
376 
377 
379 {
380  bool startPointing = false;
381  bool stopPointing = false;
382 
383  bool wasPresent = false;
384  Agent *ag = nullptr;
385  // founding the agent:
386  Vector vec;
387  for (auto &it : OPCEntities){
388  if (it.second.o.entity_type() == ICUBCLIENT_OPC_ENTITY_AGENT
389  && it.second.present
390  && (it.second.o.name() != "iCub")
391  && (it.second.o.name() != "icub")){
392  ag = dynamic_cast<Agent*>(iCub->opc->getEntity(it.second.o.name()));
393  vec = ag->m_body.m_parts["handRight"];
394  wasPresent = true;
395  }
396  }
397 
398 
399  if (!ag || !wasPresent){
400  yInfo() << " in PASAR:saliencyPointing no human agent present";
401  return false;
402  }
403 
404  double now = Time::now() - initTime;
405 
406  double x = vec[0];
407  double y = vec[1];
408  double z = vec[2];
409 
410  double closest = thresholdPointing;
411  string objectPointed = "none";
412  bool pointingNow = false;
413  for (auto &it : OPCEntities)
414  {
415  if (it.second.o.name() != ag->name() && it.second.present)
416  {
417  double distance;
418 
419  distance = sqrt(
420  (x - it.second.o.m_ego_position[0])*(x - it.second.o.m_ego_position[0]) +
421  (y - it.second.o.m_ego_position[1])*(y - it.second.o.m_ego_position[1]) +
422  (z - it.second.o.m_ego_position[2])*(z - it.second.o.m_ego_position[2])
423  );
424 
425  if (distance < closest)
426  {
427  closest = distance;
428  objectPointed = it.second.o.name();
429  pointingNow = true;
430  }
431  }
432  }
433 
434  stopPointing = (now - lastTimePointing > dthresholdDisappear) && isPointing && !pointingNow;
435  startPointing = (now - lastTimePointing > dthresholdAppear) && !isPointing && pointingNow;
436 
437  if (stopPointing){
438  yInfo() << "\t\t STOP POINTING ";
439  isPointing = false;
440  }
441 
442  if (startPointing){
443  yInfo() << "\t\t POINTING START " << objectPointed;
444  isPointing = true;
445  }
446  if (pointingNow){
447  lastTimePointing = now;
448  yInfo() << " pointed object is: \t" << objectPointed;
449  for (auto &it : OPCEntities)
450  {
451  if (it.second.o.name() == objectPointed)
452  {
453  it.second.o.m_saliency += dBurstOfPointing;
454  }
455  }
456  }
457  return pointingNow;
458 }
459 
460 
461 
463 {
464  bool wasPresent = false;
465  Agent *ag = nullptr;
466  // find the agent:
467  for (auto &it : OPCEntities){
468  if (it.second.o.entity_type() == ICUBCLIENT_OPC_ENTITY_AGENT
469  && it.second.present
470  && (it.second.o.name() != "iCub")
471  && (it.second.o.name() != "icub")){
472  ag = dynamic_cast<Agent*>(iCub->opc->getEntity(it.second.o.name()));
473  wasPresent = true;
474  }
475  }
476 
477  if (!wasPresent){
478  yInfo() << " in PASAR:saliencyWaving no human agent present";
479  return false;
480  }
481  double dAccelLeft;
482  double dAccelRight;
483  bool wavingNow = false;
484 
485  if (!ag || (ag->m_present != 1.0))
486  {
487  presentRightHand.first = presentRightHand.second;
488  presentLeftHand.first = presentLeftHand.second;
489 
490  presentRightHand.second = false;
491  presentLeftHand.second = false;
492 
493  return false;
494  }
495  else {
496  Vector vecRight = ag->m_body.m_parts["handRight"];
497  Vector vecLeft = ag->m_body.m_parts["handLeft"];
498 
499  Vector speedRightt1(3);
500  Vector speedRightt2(3);
501 
502  Vector speedLeftt1(3);
503  Vector speedLeftt2(3);
504 
505  Vector accelRight(3);
506  Vector accelLeft(3);
507 
508 
509  speedRightt2[0] = (rightHandt1[0] - rightHandt2[0]);
510  speedRightt2[1] = (rightHandt1[1] - rightHandt2[1]);
511  speedRightt2[2] = (rightHandt1[2] - rightHandt2[2]);
512 
513  speedRightt1[0] = (vecRight[0] - rightHandt1[0]);
514  speedRightt1[1] = (vecRight[1] - rightHandt1[1]);
515  speedRightt1[2] = (vecRight[2] - rightHandt1[2]);
516 
517  accelRight[0] = (speedRightt1[0] - speedRightt2[0]);
518  accelRight[1] = (speedRightt1[1] - speedRightt2[1]);
519  accelRight[2] = (speedRightt1[2] - speedRightt2[2]);
520 
521  speedLeftt1[0] = (vecLeft[0] - leftHandt1[0]);
522  speedLeftt1[1] = (vecLeft[1] - leftHandt1[1]);
523  speedLeftt1[2] = (vecLeft[2] - leftHandt1[2]);
524 
525  speedLeftt2[0] = (leftHandt1[0] - leftHandt2[0]);
526  speedLeftt2[1] = (leftHandt1[1] - leftHandt2[1]);
527  speedLeftt2[2] = (leftHandt1[2] - leftHandt2[2]);
528 
529  accelLeft[0] = (speedLeftt1[0] - speedLeftt2[0]);
530  accelLeft[1] = (speedLeftt1[1] - speedLeftt2[1]);
531  accelLeft[2] = (speedLeftt1[2] - speedLeftt2[2]);
532 
533  // get the norm of the accel vector
534  dAccelLeft = sqrt(accelLeft[0] * accelLeft[0] + accelLeft[1] * accelLeft[1] + accelLeft[2] * accelLeft[2]);
535  dAccelRight = sqrt(accelRight[0] * accelRight[0] + accelRight[1] * accelRight[1] + accelRight[2] * accelRight[2]);
536 
537  rightHandt2 = rightHandt1;
538  rightHandt1 = vecRight;
539 
540  leftHandt2 = leftHandt1;
541  leftHandt1 = vecLeft;
542 
543  double now = yarp::os::Time::now() - initTime;
544  wavingNow = false;
545 
546  // if the acceleration is made on 3 consecutive frames
547  if (dAccelRight > thresholdWaving && presentRightHand.first && presentRightHand.second){
548  yInfo() << "\tagent is waving right hand lastTime was: " << now - lastTimeWaving;
549  wavingNow = true;
550  }
551  if (dAccelLeft > thresholdWaving && presentLeftHand.first && presentLeftHand.second){
552  yInfo() << "\tagent is waving left hand lastTime was: " << now - lastTimeWaving;
553  wavingNow |= true;
554  }
555 
556  bool startWaving = (now - lastTimeWaving > dthresholdAppear) && !isWaving && wavingNow;
557  bool stopWaving = (now - lastTimeWaving > dthresholdDisappear) && isWaving && !wavingNow;
558 
559 
560  if (startWaving){
561  isWaving = true;
562  yInfo() << "\t\t START WAVING";
563  }
564  if (stopWaving){
565  isWaving = false;
566  yInfo() << "\t\t STOP WAVING";
567  }
568 
569  if (wavingNow){
570  ag->m_saliency += pTopDownWaving;
571  lastTimeWaving = now;
572  iCub->opc->commit(ag);
573  }
574 
575  presentRightHand.first = presentRightHand.second;
576  presentLeftHand.first = presentLeftHand.second;
577 
578  presentRightHand.second = true;
579  presentLeftHand.second = true;
580  }
581  return wavingNow;
582 }
583 
584 
585 
586 
588 {
589  isWaving = false;
590  isPointing = false;
591 
592  iCub->opc->checkout();
593  std::list<std::shared_ptr<icubclient::Entity>> entities = iCub->opc->EntitiesCacheCopy();
594  double now = yarp::os::Time::now() - initTime;
595  OPCEntities.clear();
596 
597  lastTimePointing = now - 10;
598  lastTimeWaving = now - 10;
599 
600  for (auto &entity : entities){
601 
602  if (entity->name() != "icub")
603  {
605 
606  if (entity->isType(ICUBCLIENT_OPC_ENTITY_AGENT) || entity->isType(ICUBCLIENT_OPC_ENTITY_OBJECT))
607  {
608  Object * ob = dynamic_cast<Object*>(entity.get());
609  if(ob) {
610  OPCEntities[entity->opc_id()].o = *ob;
611  OPCEntities[entity->opc_id()].lastTimeSeen = (ob->m_present == 1.0) ? now : now - 10;
612  OPCEntities[entity->opc_id()].present = (ob->m_present == 1.0);
613  }
614  }
615  }
616  }
617 }
618 
bool interruptModule()
Definition: pasar.cpp:113
bool respond(const yarp::os::Bottle &command, yarp::os::Bottle &reply)
Definition: pasar.cpp:138
Grants access to high level motor commands (grasp, touch, look, goto, etc) of the robot as well as it...
Definition: icubClient.h:66
void saliencyTopDown()
saliencyTopDown Update the salience according to the informations contained in the OPC (acceleration...
Definition: pasar.cpp:266
bool close()
Definition: pasar.cpp:123
double m_present
Is the object present in the scene A value of 1.0 means that the object currently is in the scene A v...
Definition: object.h:69
STL namespace.
Represent any physical entity (including objects and agents) that can be stored within the OPC...
Definition: object.h:35
bool updateModule()
Definition: pasar.cpp:211
bool saliencyWaving()
saliencyWaving Increase the saliency of the agent waving
Definition: pasar.cpp:462
Represent an agent.
Definition: agent.h:93
bool configure(yarp::os::ResourceFinder &rf)
Definition: pasar.cpp:28
bool saliencyPointing()
saliencyPointing Increase the salience of the closest object from the right hand
Definition: pasar.cpp:378
void saliencyLeakyIntegration()
saliencyLeakyIntegration Decrease of the salience through time.
Definition: pasar.cpp:358
std::string name() const
Return the name of an entity (which has to be unique within the OPC)
Definition: entity.h:93
void saliencyNormalize()
saliencyNormalize Normalize salience such that maximum salience = 1
Definition: pasar.cpp:337
double getPeriod()
Definition: pasar.cpp:372
#define ICUBCLIENT_OPC_ENTITY_OBJECT
Definition: tags.h:38
double m_saliency
A measurement of the object saliency [0,1].
Definition: object.h:74
#define ICUBCLIENT_OPC_ENTITY_AGENT
Definition: tags.h:40
void initializeMapTiming()
Definition: pasar.cpp:587
std::map< std::string, yarp::sig::VectorOf< double > > m_parts
Definition: agent.h:35