14 #include <yarp/os/ResourceFinder.h>
15 #include <yarp/dev/IControlMode.h>
16 #include <yarp/dev/IControlLimits.h>
20 void EmotionInitReport::report(
const PortInfo &
info) {
21 if ((emo!=
nullptr) && info.created && !info.incoming)
27 std::bitset<32> bitSet{};
28 for(
size_t i=0; i<bt.size(); i++){
29 bitSet.set(bt.get(i).asInt32());
41 auto botBits = bot.get(1).asList();
42 if (!botBits || botBits->size() == 0 || botBits->size()>32)
44 yError()<<
"The bitmask has to be defined as a list of <32 integers";
49 ss << setfill(
'0') << setw(8) << hex << uppercase << bitSet.to_ulong();
55 std::string helpMessage{};
56 helpMessage = helpMessage +
58 "help to display this message\n" +
60 "set <part> <emotion> set a specific emotion for a defined part \n" +
61 "\tthe available part are: mou, eli, leb, reb, all\n"+
62 "\tthe available emotions are: neu, hap, sad, sur, ang, evi, shy, cun\n"+
64 "set col <color> set the color of the led\n" +
65 "\t!! available only for rfe board !!\n"+
66 "\tthe available colors are: black, white, red, lime, blue, yellow,"
67 " cyan, magenta, silver, gray, maroon, olive, green, purple, teal, navy\n"+
69 "set brig <brig> set the brightness of the leds\n"+
70 "\t!! available only for rfe board !!\n"+
71 "\tthe brightness is defined by an integer from 0 to 5, where 0 means led off\n"+
73 "set mask (<col_leb> <m_name_leb> <brig_leb>) (<col_reb> <m_name_reb> <brig_reb>) (<col_mou> <m_name_mou> <brig_mou>) set color, bitmask and brightness for each part(leb, reb, mou)\n"+
74 "\t!! available only for rfe board !!\n"+
75 "\tm_name stands for mask name and the availble bitmasks can be consulted/added in faceExpressions/emotions_rfe.ini\n";
78 reply.addVocab32(
"many");
79 reply.addString(helpMessage.c_str());
87 std::string modName = config.find(
"name").asString();
88 setName(modName.c_str());
90 _lasttime = Time::now();
91 if (config.check(
"help",
"if present, display usage message")) {
92 yError(
"Call with --name /module_prefix --file configFile.ini \n");
96 _highlevelemotions = config.check(
"emotions", Value(0),
"Number of predefined facial expressions").asInt32();
97 _numberOfColors = config.check(
"colors", Value(0),
"Number of predefined colors").asInt32();
98 _eyebrowmaskemotions = config.check(
"bitmask_eyebrow_emotions", Value(0),
"Number of predefined bitmask eyebrow expressions").asInt32();
99 _mouthmaskemotions = config.check(
"bitmask_mouth_emotions", Value(0),
"Number of predefined bitmask eyebrow expressions").asInt32();
100 _auto = config.check(
"auto");
101 _period = config.check(
"period", Value(10.0),
"Period for expression switching in auto mode").asFloat64();
102 if(_highlevelemotions == 0)
104 _emotion_table =
nullptr;
108 _emotion_table =
new EM_CODE[_highlevelemotions];
111 yError(
"Memory allocation problem\n");
114 for(
int i = 0; i < _highlevelemotions; i++)
116 std::ostringstream ss;
118 std::string name = ss.str();
119 if(!config.check(name))
121 yError(
"Missing identifier %s.", name.c_str());
126 Bottle& bot = config.findGroup(name);
129 printf(
"Invalid parameter list for identifier %s.", name.c_str());
133 std::string n1 = bot.get(1).toString();
137 yError(
"First field of identifier %s has invalid size (must be 3).", name.c_str());
142 const char *buffer = n1.c_str();
143 strncpy(_emotion_table[i].name, buffer, 3);
147 std::string n2 = bot.get(2).toString();
148 const char * sfd = n2.c_str();
151 yError(
"Second field of identifier %s has invalid size (must be 3).", name.c_str());
156 const char *buffer = n2.c_str();
157 strncpy(_emotion_table[i].leb, buffer, 2);
160 std::string n3 = bot.get(3).toString();
163 yError(
"Third field of identifier %s has invalid size (must be 3).", name.c_str());
168 const char *buffer = n3.c_str();
169 strncpy(_emotion_table[i].reb, buffer, 2);
173 std::string n4 = bot.get(4).toString();
176 yError(
"Fourth field of identifier %s has invalid size (must be 3).", name.c_str());
181 const char *buffer = n4.c_str();
182 strncpy(_emotion_table[i].mou, buffer, 2);
186 std::string n5 = bot.get(5).toString();
189 yError(
"Fifth field of identifier %s has invalid size (must be 3).", name.c_str());
194 const char *buffer = n5.c_str();
195 strncpy(_emotion_table[i].eli, buffer, 2);
200 if(_numberOfColors) {
201 std::string color_id;
202 for(
size_t index=0; index<_numberOfColors; index++){
203 color_id =
"C"+std::to_string(index);
204 Bottle& bot = config.findGroup(color_id);
207 yError(
"Invalid parameter list for the identifier %s.", color_id.c_str());
211 std::string code = bot.get(2).toString();
212 if (code.length()!=3)
214 yError(
"The identifier must have size 3");
217 _color_table[bot.get(1).asString()] = code.substr(0,code.length()-1);
220 if(_eyebrowmaskemotions) {
222 for(
size_t index=0; index<_eyebrowmaskemotions; index++){
223 id =
"BM_EB"+std::to_string(index);
224 Bottle& bot = config.findGroup(
id);
227 yError()<<
"Parsing of the bitmap failed";
230 _bitmask_emotion_table[id] = hexCode;
234 if(_mouthmaskemotions) {
237 for(
size_t index=0; index<_mouthmaskemotions; index++){
238 id =
"BM_M"+std::to_string(index);
239 Bottle& bot = config.findGroup(
id);
242 yError()<<
"Parsing of the bitmap failed";
245 _bitmask_emotion_table[id] = hexCode;
250 yarp::os::Property rcb_face_conf{ {
"device",Value(
"remote_controlboard")},
251 {
"local", Value(getName(
"/face/remoteControlBoard"))},
252 {
"remote",Value(
"/icub/face")},
253 {
"part",Value(
"face")} };
255 if (_poly.open(rcb_face_conf))
257 yarp::dev::IControlMode* iCM{
nullptr };
258 yarp::dev::IControlLimits* iCtrlLim{
nullptr };
259 auto ok = _poly.view(iCM);
260 ok &= _poly.view(_iPos);
261 ok &= _poly.view(iCtrlLim);
263 ok &= iCM->setControlMode(_joint_eylids, VOCAB_CM_POSITION);
265 ok &= iCtrlLim->getLimits(_joint_eylids, &_min, &_max);
269 ok &= _iPos->setRefSpeed(_joint_eylids, 50.0);
274 yError() <<
"Fail to configure correctly the remote_controlboard";
280 yWarning() <<
"Failed to open the remote_controlboard device for commanding the eyelids, you can ignore this warning if your robot doesn't have the rfe board";
284 _inputPort.open(getName(
"/in"));
285 _outputPort.open(getName(
"/out"));
286 _outputPort.setReporter(emotionInitReport);
287 _initEmotionTrigger=0;
295 if(_inputPort.isOpen())
297 if(!_outputPort.isClosed())
300 if (_emotion_table !=
nullptr)
302 delete [] _emotion_table;
303 _emotion_table =
nullptr;
317 _inputPort.interrupt();
318 _outputPort.interrupt();
323 _initEmotionTrigger++;
331 curtime = Time::now();
332 if(curtime - _lasttime > _period)
335 expr = rand() % _highlevelemotions;
336 std::string
cmd(_emotion_table[expr].name);
340 else if (_initEmotionTrigger>0)
343 _initEmotionTrigger=0;
357 switch (command.get(0).asVocab32()) {
364 switch(command.get(1).asVocab32()) {
382 ok =
setAll(command.get(2).toString());
386 ok =
setRaw(command.get(2).toString());
402 cout <<
"received an unknown request after a VOCAB_SET" << endl;
456 int EmotionInterfaceModule::getIndex(
const std::string
cmd)
458 if(_highlevelemotions == 0)
462 for(i = 0; i < _highlevelemotions; i++)
464 if(strncmp(_emotion_table[i].name,
cmd.c_str(), 3) == 0)
468 if( i == _highlevelemotions )
475 bool EmotionInterfaceModule::writePort(
const char*
cmd)
477 Bottle &btmp = _outputPort.prepare();
480 _outputPort.write(
true);
489 char cmdbuffer[] = {0,0,0,0};
495 if( _emotion_table[i].leb[0] ==
'*' || _emotion_table[i].leb[1] ==
'*')
499 cmdbuffer[1]=_emotion_table[i].
leb[0];
500 cmdbuffer[2]=_emotion_table[i].
leb[1];
501 writePort(cmdbuffer);
507 char cmdbuffer[] = {0,0,0,0};
513 if( _emotion_table[i].reb[0] ==
'*' || _emotion_table[i].reb[1] ==
'*')
517 cmdbuffer[1]=_emotion_table[i].
reb[0];
518 cmdbuffer[2]=_emotion_table[i].
reb[1];
519 writePort(cmdbuffer);
525 char cmdbuffer[] = {0,0,0,0};
531 if( _emotion_table[i].mou[0] ==
'*' || _emotion_table[i].mou[1] ==
'*')
535 cmdbuffer[1]=_emotion_table[i].
mou[0];
536 cmdbuffer[2]=_emotion_table[i].
mou[1];
537 writePort(cmdbuffer);
543 char cmdbuffer[] = {0,0,0,0};
544 const auto i = getIndex(
cmd);
550 if( _emotion_table[i].eli[0] ==
'*' || _emotion_table[i].eli[1] ==
'*')
554 auto target_pos = getEyelidsTarget(_emotion_table[i].eli[0], _emotion_table[i].eli[1]);
555 res = _iPos->positionMove(_joint_eylids, target_pos);
560 cmdbuffer[1] = _emotion_table[i].
eli[0];
561 cmdbuffer[2] = _emotion_table[i].
eli[1];
562 res = writePort(cmdbuffer);
580 if (
cmd.size() == 3 &&
cmd.at(0) ==
'p' && _iPos)
582 const auto target_pos = getEyelidsTarget(
cmd[1],
cmd[2]);
583 res = _iPos->positionMove(_joint_eylids, target_pos);
586 res &= writePort(
cmd.c_str());
593 char cmdbuffer[] = {0,0,0,0};
595 if(_color_table.find(
cmd) == _color_table.end()){
596 yError()<<
"Color"<<
cmd<<
"not available";
601 cmdbuffer[1]=_color_table[
cmd][0];
602 cmdbuffer[2]=_color_table[
cmd][1];
603 return writePort(cmdbuffer);
608 char cmdbuffer[] = {0,0,0,0};
612 cmdbuffer[2]=
cmd[0];
613 return writePort(cmdbuffer);
621 yError()<<
"Bad request, it should be set mask (color mask) (color mask) (color mask)";
624 auto botLeb =
cmd.get(2).asList();
625 auto botReb =
cmd.get(3).asList();
626 auto botMou =
cmd.get(4).asList();
628 if(!botLeb || !botReb || !botMou) {
629 yError()<<
"Bad request, missing one of the three list";
633 if(botLeb->size()!=3 || botReb->size()!=3 || botMou->size()!=3) {
634 yError()<<
"Bad request, each list has to be (color mask brightness)";
637 auto colLeb = botLeb->get(0).asString();
638 auto colReb = botReb->get(0).asString();
639 auto colMou = botMou->get(0).asString();
641 auto maskLeb = botLeb->get(1).asString();
642 auto maskReb = botReb->get(1).asString();
643 auto maskMou = botMou->get(1).asString();
645 auto brightLeb =
'0'+ botLeb->get(2).toString();
646 auto brightReb =
'0'+ botReb->get(2).toString();
647 auto brightMou =
'0'+ botMou->get(2).toString();
649 if(_bitmask_emotion_table.find(maskLeb) == _bitmask_emotion_table.end() ||
650 _bitmask_emotion_table.find(maskReb) == _bitmask_emotion_table.end() ||
651 _bitmask_emotion_table.find(maskMou) == _bitmask_emotion_table.end()) {
652 yError()<<
"One or more bitmask has not been defined in the ini file";
658 cmdbuffer += _color_table[colLeb];
659 cmdbuffer += brightLeb;
660 cmdbuffer += _bitmask_emotion_table[maskLeb];
662 cmdbuffer += _color_table[colReb];
663 cmdbuffer += brightReb;
664 cmdbuffer += _bitmask_emotion_table[maskReb];
666 cmdbuffer += _color_table[colMou];
667 cmdbuffer += brightMou;
668 cmdbuffer += _bitmask_emotion_table[maskMou];
670 return writePort(cmdbuffer.c_str());
673 double EmotionInterfaceModule::getEyelidsTarget(
const char eli0,
const char eli1)
675 std::string percentage_str{ eli0 };
676 percentage_str +=
'.';
677 percentage_str += eli1;
678 auto percentage = std::stod(percentage_str);
679 if (percentage > 1.0)
681 return (1.0 - percentage) * (_max - _min);
bool setMouth(const std::string cmd) override
bool setRaw(const std::string cmd) override
double getPeriod() override
bool setAll(const std::string cmd) override
bool setBrightness(const string &cmd)
bool setEyelids(const std::string cmd) override
bool setLeftEyebrow(const std::string cmd) override
bool setRightEyebrow(const std::string cmd) override
bool interruptModule() override
bool configure(ResourceFinder &config) override
bool setColor(const string &cmd)
bool setMask(const Bottle &cmd)
bool updateModule() override
bool respond(const Bottle &command, Bottle &reply) override
std::bitset< 32 > populateBitset(const yarp::os::Bottle &bt)
void printHelp(yarp::os::Bottle &reply)
std::string getHexCode(const Bottle &bot)
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_BRIG
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_FAILED
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_SET
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_ALL
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_EYELIDS
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_RIGHTEYEBROW
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_GET
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_LEFTEYEBROW
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_MASK
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_COLOR
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_OK
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_MOUTH
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_HELP
constexpr yarp::conf::vocab32_t EMOTION_VOCAB_RAW