Statistics
| Branch: | Tag: | Revision:

humotion / examples / yarp_icub / src / icub_faceinterface.cpp @ 708960ff

History | View | Annotate | Download (9.821 KB)

1
#include "icub_faceinterface.h"
2
using namespace std;
3

    
4
using yarp::os::Network;
5
using yarp::os::Bottle;
6

    
7
//! constructor
8
iCubFaceInterface::iCubFaceInterface(string _scope) {
9
    scope = _scope;
10

    
11
/*
12
    //add mapping from ids to enums:
13
    //this might look strange at the first sight but we need to have a generic
14
    //way to acces joints from libhumotion. therefore the lib uses its enum with ID_* enum ids
15
    //to access the joints. now we need to define a mapping to map those to our motor ids.
16
    //this is what we use the enum bimap for (convertion fro/to motorid is handled
17
    //by \sa convert_enum_to_motorid() and \sa convert_motorid_to_enum() lateron
18

19
    //MOUTH
20
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_UPPER,   ID_LIP_LEFT_UPPER));
21
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_LOWER,   ID_LIP_LEFT_LOWER));
22
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_UPPER, ID_LIP_CENTER_UPPER));
23
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_LOWER, ID_LIP_CENTER_LOWER));
24
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_UPPER,  ID_LIP_RIGHT_UPPER));
25
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_LOWER,  ID_LIP_RIGHT_LOWER));
26

27
    //NECK
28
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_PAN,    ID_NECK_PAN));
29
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_TILT,   ID_NECK_TILT));
30
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_ROLL,   ID_NECK_ROLL));
31

32
    //EYES
33
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_PAN,   ID_EYES_LEFT_LR));
34
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_VERGENCE,   ID_EYES_RIGHT_LR));
35
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_BOTH_UD,   ID_EYES_BOTH_UD));
36

37
    //EYELIDS
38
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_LOWER, ID_EYES_LEFT_LID_LOWER));
39
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_UPPER, ID_EYES_LEFT_LID_UPPER));
40
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_BROW, ID_EYES_LEFT_BROW));
41

42
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_LOWER, ID_EYES_RIGHT_LID_LOWER));
43
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_UPPER,ID_EYES_RIGHT_LID_UPPER));
44
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_BROW, ID_EYES_RIGHT_BROW));
45

46
    Property options;
47
    options.put("device", "remote_controlboard");
48
    options.put("local", "/local/head");
49
    options.put("remote", scope+"/head");
50
    dd.open(options);
51

52
    //fetch views:
53
    dd.view(iencs);
54
    dd.view(ipos);
55
    dd.view(ivel);
56
    dd.view(ilimits);
57
    dd.view(pid);
58
    dd.view(amp);
59

60

61
    if ( (!iencs) || (!ipos) || (!ilimits) || (!ivel) || (!amp) || (!pid)){
62
        printf("> ERROR: failed to open icub views\n");
63
        exit(EXIT_FAILURE);
64
    }
65

66
    int joints;
67

68
    //tell humotion about min/max joint values:
69
    init_joints();
70

71
    iencs->getAxes(&joints);
72
    positions.resize(joints);
73
    velocities.resize(joints);
74
    commands.resize(joints);
75

76
    //set position mode:
77
    if (POSITION_CONTROL){
78
        commands=200000.0;
79
        ipos->setRefAccelerations(commands.data());
80
        ipos->setPositionMode();
81
    }else{
82
        ivel->setVelocityMode();
83
        commands=100.0;
84
        ivel->setRefAccelerations(commands.data());
85
    }*/
86

    
87
    //attach to facial expressions:
88
    string emotion_scope = scope + "/face/raw/in";
89
    printf("> opening connection to %s\n", emotion_scope.c_str());
90

    
91
    for(int i=0; i<4; i++){
92
        //strange, if we use one output port only the first command is executed?! flushing issues?
93
        string emotion_port_out = "/emotionwriter" + to_string((unsigned long long)i);
94
        if (!emotion_port[i].open(emotion_port_out.c_str())){
95
            printf("> ERROR: failed to open to %s\n",emotion_port_out.c_str());
96
            exit(EXIT_FAILURE);
97
        }
98
        if (!Network::connect(emotion_port_out.c_str(), emotion_scope.c_str())){
99
            printf("> ERROR: failed to connect emotion ports\n");
100
            exit(EXIT_FAILURE);
101
        }
102
    }
103
}
104

    
105
//! destructor
106
iCubFaceInterface::~iCubFaceInterface(){
107
}
108

    
109
//! special command to set eyelid angle
110
//! \param angle in degrees
111
void iCubFaceInterface::set_eyelid_angle(float angle){
112
    if (emotion_port[0].getOutputCount()>0){
113
        //try to set the value based on the upper one
114
        //some guesses from the sim: S30 = 0° / S40 = 10°
115
        int opening = (25.0 + 0.8*angle);
116
        opening = min(48, max(24, opening));
117

    
118
        if (opening == lid_opening_previous){
119
            //no update necessary
120
            return;
121
        }
122

    
123
        lid_angle = angle;
124
        lid_opening_previous = opening;
125

    
126
        char buf[20];
127
        sprintf(buf, "S%2d", opening);
128

    
129
        //printf("> SETTING EYELID '%s' (%f -> %d)\n",buf,angle,opening);
130
        Bottle &cmd = emotion_port[0].prepare();
131
        cmd.clear();
132
        cmd.addString(buf);
133
        emotion_port[0].writeStrict();
134
    }else{
135
        printf("> ERROR: no icub emotion output\n");
136
        exit(EXIT_FAILURE);
137
    }
138
}
139

    
140
//! special command to set the eyebrow angle
141
//! \param id {0=left, 1=right)
142
//! \param angle in degrees
143
void iCubFaceInterface::set_eyebrow_angle(int id, float *target_angle){
144
    int port_id;
145
    if (id == iCubJointInterface::ICUB_ID_EYES_LEFT_BROW){
146
        port_id = 1;
147
    }else{
148
        port_id = 2;
149
    }
150

    
151
    if (emotion_port[port_id].getOutputCount()>0){
152
        double angle = target_angle[id];
153
        int icub_val = 0;
154

    
155
        //swap rotation direction:
156
        if (id==iCubJointInterface::ICUB_ID_EYES_LEFT_BROW) angle = -angle;
157

    
158
        //convert to icub representation
159
        if (angle < -20){
160
            icub_val = 1;
161
        }else if (angle<10){
162
            icub_val = 2;
163
        }else if (angle<20){
164
            icub_val = 4;
165
        }else{
166
            icub_val = 8;
167
        }
168

    
169
        //make sure to update only on new values:
170
        if (icub_val == target_angle_previous[id]){
171
                //no updata necessary
172
                return;
173
        }
174

    
175
        //store actual value:
176
        target_angle_previous[id] = icub_val;
177

    
178

    
179
        string cmd_s;
180
        if (id==iCubJointInterface::ICUB_ID_EYES_LEFT_BROW){
181
            cmd_s = "L0" + to_string((unsigned long long)icub_val);
182
        }else{
183
            cmd_s = "R0" + to_string((unsigned long long)icub_val);
184
        }
185

    
186
        printf("> SETTING EYEBROW %d (%f -> %s)\n",id,angle,cmd_s.c_str());
187

    
188
        Bottle &cmd = emotion_port[port_id].prepare();
189
        cmd.clear();
190
        cmd.addString(cmd_s);
191
        emotion_port[port_id].writeStrict();
192
    }else{
193
        printf("> ERROR: no icub emotion output\n");
194
        exit(EXIT_FAILURE);
195
    }
196
}
197

    
198
void iCubFaceInterface::set_mouth(float *target_angle){
199
    //convert from 6DOF mouth displacement to icub leds:
200
    int led_value = 0;
201

    
202
    //fetch center opening:
203
    double center_opening = target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_LOWER] -
204
            target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_UPPER];
205
    bool mouth_open = (center_opening>15.0)?true:false;
206

    
207
    //side of mouth high or low?
208
    double center_avg = (target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_LOWER] +
209
            target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_UPPER])/2.0;
210
    double left_avg   = (target_angle[iCubJointInterface::ICUB_ID_LIP_LEFT_LOWER] +
211
            target_angle[iCubJointInterface::ICUB_ID_LIP_LEFT_UPPER])/2.0;
212
    double right_avg  = (target_angle[iCubJointInterface::ICUB_ID_LIP_RIGHT_LOWER] +
213
            target_angle[iCubJointInterface::ICUB_ID_LIP_RIGHT_UPPER])/2.0;
214

    
215
    //happy, neutral or sad?
216
    double diff_l = center_avg - left_avg;
217
    double diff_r = center_avg - right_avg;
218
    double diff   = (diff_l+diff_r)/2.0;
219

    
220
    if (diff > 2.0){
221
        if (mouth_open){
222
            led_value = 0x14;
223
        }else{
224
            if (diff > 2.6){
225
                led_value = 0x0A;
226
            }else{
227
                led_value = 0x0B;
228
            }
229
        }
230
    }else if (diff < -3.0){
231
        if (mouth_open){
232
            led_value = 0x06;
233
        }else{
234
            led_value = 0x18;
235
        }
236
    }else if (diff < -2.0){
237
        if (mouth_open){
238
            led_value = 0x04; //0x25;
239
        }else{
240
            led_value = 0x08;
241
        }
242
    }else{
243
        if (mouth_open){
244
            led_value = 0x16;
245
        }else{
246
            led_value = 0x08;
247
        }
248
    }
249

    
250

    
251
    if (led_value == previous_mouth_state){
252
        //no update necessary
253
        return;
254
    }
255

    
256
    previous_mouth_state = led_value;
257

    
258
    //convert to string:
259
    char buf[10];
260
    sprintf(buf, "M%02X",led_value);
261

    
262
    /*printf("> sending mouth '%s'\n",buf);
263
    printf("> mouth angles: %3.2f %3.2f %3.2f\n",target_angle[ICUB_ID_LIP_LEFT_UPPER],target_angle[ICUB_ID_LIP_CENTER_UPPER],target_angle[ICUB_ID_LIP_RIGHT_UPPER]);
264
    printf("  mouth         %3.2f %3.2f %3.2f\n",target_angle[ICUB_ID_LIP_LEFT_LOWER],target_angle[ICUB_ID_LIP_CENTER_LOWER],target_angle[ICUB_ID_LIP_RIGHT_LOWER]);
265
    printf("  mouth  open=%3.2f diff=%3.2f\n", center_opening, diff);*/
266

    
267
    //add mouth:
268
    Bottle &cmd = emotion_port[3].prepare();
269
    cmd.clear();
270
    cmd.addString(buf);
271
    emotion_port[3].writeStrict();
272

    
273
/*
274
    //store joint values which we do not handle on icub here:
275
    double timestamp = get_timestamp_ms();
276
    JointInterface::store_incoming_position(ID_LIP_LEFT_UPPER,   target_angle[ICUB_ID_LIP_LEFT_UPPER], timestamp);
277
    JointInterface::store_incoming_position(ID_LIP_LEFT_LOWER,   target_angle[ICUB_ID_LIP_LEFT_LOWER], timestamp);
278
    JointInterface::store_incoming_position(ID_LIP_CENTER_UPPER, target_angle[ICUB_ID_LIP_CENTER_UPPER], timestamp);
279
    JointInterface::store_incoming_position(ID_LIP_CENTER_LOWER, target_angle[ICUB_ID_LIP_CENTER_LOWER], timestamp);
280
    JointInterface::store_incoming_position(ID_LIP_RIGHT_UPPER,  target_angle[ICUB_ID_LIP_RIGHT_UPPER], timestamp);
281
    JointInterface::store_incoming_position(ID_LIP_RIGHT_LOWER,  target_angle[ICUB_ID_LIP_RIGHT_LOWER], timestamp);
282
*/
283
}