Statistics
| Branch: | Tag: | Revision:

humotion / examples / yarp_icub / src / icub_faceinterface.cpp @ 06d6a491

History | View | Annotate | Download (8.393 KB)

1 6a2d467f Simon Schulz
/*
2
* This file is part of humotion
3
*
4
* Copyright(c) sschulz <AT> techfak.uni-bielefeld.de
5
* http://opensource.cit-ec.de/projects/humotion
6
*
7
* This file may be licensed under the terms of the
8
* GNU Lesser General Public License Version 3 (the ``LGPL''),
9
* or (at your option) any later version.
10
*
11
* Software distributed under the License is distributed
12
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13
* express or implied. See the LGPL for the specific language
14
* governing rights and limitations.
15
*
16
* You should have received a copy of the LGPL along with this
17
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
18
* or write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
*
21
* The development of this software was supported by the
22
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
23
* The Excellence Cluster EXC 277 is a grant of the Deutsche
24
* Forschungsgemeinschaft (DFG) in the context of the German
25
* Excellence Initiative.
26
*/
27
28
#include "humotion_yarp_icub/icub_faceinterface.h"
29
30 a5cc61d4 sschulz
#include <boost/format.hpp>
31 6a2d467f Simon Schulz
#include <algorithm>
32
#include <string>
33
34
using yarp::os::Network;
35
using yarp::os::Bottle;
36
using std::cout;
37
using std::cerr;
38
using std::string;
39
40
//! constructor
41
iCubFaceInterface::iCubFaceInterface(std::string _scope) {
42
    scope = _scope;
43
44
    // attach to facial expressions:
45
    std::string emotion_scope = scope + "/face/raw/in";
46
    cout << "opening connection to '"<< emotion_scope << "'\n";
47
48 07e68eb7 sschulz
    bool init_ok = true;
49 0c8d22a5 sschulz
    // open emotion port
50
    std::string emotion_port_out = "/emotionwriter";
51
    if (!emotion_port.open(emotion_port_out.c_str())) {
52
        cerr << "ERROR: failed to open emotion port '" << emotion_port_out << "'\n";
53
        init_ok = false;
54
    }
55
    if (!Network::connect(emotion_port_out.c_str(), emotion_scope.c_str())) {
56
        cerr << "ERROR: failed to connect to emotion port '" << emotion_port_out << "'\n";
57
        init_ok = false;
58 6a2d467f Simon Schulz
    }
59 07e68eb7 sschulz
60
    if (!init_ok) {
61
        cerr << "ERROR: failed to set up emotion component\n";
62
        cerr << "       please make sure that the faceExpressions yarpdev is started\n";
63
        cerr << "       (e.g.  yarpdev --name /icub/face/raw --device serial ... is running)\n";
64
        exit(EXIT_FAILURE);
65
    }
66 6a2d467f Simon Schulz
}
67
68
//! destructor
69
iCubFaceInterface::~iCubFaceInterface() {
70
}
71
72
//! special command to set eyelid angle
73
//! \param angle in degrees
74
void iCubFaceInterface::set_eyelid_angle(float angle) {
75 0c8d22a5 sschulz
    if (emotion_port.getOutputCount() > 0) {
76 6a2d467f Simon Schulz
        // try to set the value based on the upper one
77
        // some guesses from the sim: S30 = 0° / S40 = 10°
78
        int opening = (25.0 + 0.8*angle);
79
        opening = std::min(48, std::max(24, opening));
80
81
        if (opening == lid_opening_previous) {
82
            // no update necessary
83
            return;
84
        }
85
86
        lid_angle = angle;
87
        lid_opening_previous = opening;
88
89
        char buf[20];
90
        snprintf(buf, sizeof(buf), "S%2d", opening);
91
92
        // cout << "SETTING EYELID '" << buf << "' (" << angle << " -> " << opening << "\n";
93 0c8d22a5 sschulz
        Bottle &cmd = emotion_port.prepare();
94 6a2d467f Simon Schulz
        cmd.clear();
95
        cmd.addString(buf);
96 0c8d22a5 sschulz
        // NOTE: writeStrict is important in order not to loose packets
97
        emotion_port.writeStrict();
98 6a2d467f Simon Schulz
    } else {
99
        cerr << "ERROR: no icub emotion output\n";
100
        exit(EXIT_FAILURE);
101
    }
102
}
103
104
//! special command to set the eyebrow angle
105
//! \param id {0=left, 1=right)
106
//! \param angle in degrees
107
void iCubFaceInterface::set_eyebrow_angle(int id, float *target_angle) {
108
109 0c8d22a5 sschulz
    if (emotion_port.getOutputCount() > 0) {
110 6a2d467f Simon Schulz
        double angle = target_angle[id];
111
        int icub_val = 0;
112
113
        // swap rotation direction for eyebrow
114
        if (id == iCubJointInterface::ICUB_ID_EYES_LEFT_BROW) {
115
            angle = -angle;
116
        }
117
118
        // convert to icub representation
119
        if (angle < -20) {
120
            icub_val = 1;
121
        } else if (angle < 10) {
122
            icub_val = 2;
123
        } else if (angle < 20) {
124
            icub_val = 4;
125
        } else {
126
            icub_val = 8;
127
        }
128
129
        // make sure to update only on new values
130
        if (icub_val == target_angle_previous[id]) {
131
                // no updata necessary
132
                return;
133
        }
134
135
        // store actual value
136
        target_angle_previous[id] = icub_val;
137
138
139
        std::string cmd_s;
140
        if (id == iCubJointInterface::ICUB_ID_EYES_LEFT_BROW) {
141 07e68eb7 sschulz
            cmd_s = "L0" + boost::lexical_cast<std::string>(icub_val);
142 6a2d467f Simon Schulz
        } else {
143 07e68eb7 sschulz
            cmd_s = "R0" + boost::lexical_cast<std::string>(icub_val);
144 6a2d467f Simon Schulz
        }
145
146 0c8d22a5 sschulz
        // cout << "SETTING EYEBROW " << id << " (" << angle << " -> " << cmd_s << ")\n";
147 6a2d467f Simon Schulz
148 0c8d22a5 sschulz
        Bottle &cmd = emotion_port.prepare();
149 6a2d467f Simon Schulz
        cmd.clear();
150
        cmd.addString(cmd_s);
151 0c8d22a5 sschulz
        // NOTE: writeStrict is important in order not to loose packets
152
        emotion_port.writeStrict();
153 6a2d467f Simon Schulz
    } else {
154
        cerr << "ERROR: no icub emotion output\n";
155
        exit(EXIT_FAILURE);
156
    }
157
}
158
159
void iCubFaceInterface::set_mouth(float *target_angle) {
160
    // convert from 6DOF mouth displacement to icub leds:
161
    int led_value = 0;
162
163
    // fetch center opening
164
    double center_opening = target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_LOWER] -
165
            target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_UPPER];
166
    bool mouth_open = (center_opening > 15.0) ? true : false;
167
168
    // side of mouth high or low?
169
    double center_avg = (target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_LOWER] +
170
            target_angle[iCubJointInterface::ICUB_ID_LIP_CENTER_UPPER])/2.0;
171
    double left_avg   = (target_angle[iCubJointInterface::ICUB_ID_LIP_LEFT_LOWER] +
172
            target_angle[iCubJointInterface::ICUB_ID_LIP_LEFT_UPPER])/2.0;
173
    double right_avg  = (target_angle[iCubJointInterface::ICUB_ID_LIP_RIGHT_LOWER] +
174
            target_angle[iCubJointInterface::ICUB_ID_LIP_RIGHT_UPPER])/2.0;
175
176
    // happy, neutral or sad?
177
    double diff_l = center_avg - left_avg;
178
    double diff_r = center_avg - right_avg;
179
    double diff   = (diff_l+diff_r)/2.0;
180
181
    if (diff > 2.0) {
182
        if (mouth_open) {
183
            led_value = 0x14;
184
        } else {
185
            if (diff > 2.6) {
186
                led_value = 0x0A;
187
            } else {
188
                led_value = 0x0B;
189
            }
190
        }
191
    } else if (diff < -3.0) {
192
        if (mouth_open) {
193
            led_value = 0x06;
194
        } else {
195
            led_value = 0x18;
196
        }
197
    } else if (diff < -2.0) {
198
        if (mouth_open) {
199
            led_value = 0x04;  // 0x25;
200
        } else {
201
            led_value = 0x08;
202
        }
203
    } else {
204
        if (mouth_open) {
205
            led_value = 0x16;
206
        } else {
207
            led_value = 0x08;
208
        }
209
    }
210
211
212
    if (led_value == previous_mouth_state) {
213
        // no update necessary
214
        return;
215
    }
216
217
    previous_mouth_state = led_value;
218
219
    // convert to string
220
    char buf[10];
221
    snprintf(buf, sizeof(buf), "M%02X", led_value);
222
223
    /*
224
    cout << "sending mouth " << buf << "\n";
225
    cout << boost::format("  mouth angles: %3.2f %3.2f %3.2f\n")
226
            % target_angle[ICUB_ID_LIP_LEFT_UPPER]
227
            % target_angle[ICUB_ID_LIP_CENTER_UPPER]
228
            % target_angle[ICUB_ID_LIP_RIGHT_UPPER];
229
    cout << boost::format("  mouth         %3.2f %3.2f %3.2f\n")
230
            % target_angle[ICUB_ID_LIP_LEFT_LOWER]
231
            % target_angle[ICUB_ID_LIP_CENTER_LOWER]
232
            % target_angle[ICUB_ID_LIP_RIGHT_LOWER];
233
    cout << boost::format("  mouth  open=%3.2f diff=%3.2f\n")
234
            % center_opening
235
            % diff;
236
    */
237
238
    // add mouth
239 0c8d22a5 sschulz
    Bottle &cmd = emotion_port.prepare();
240 6a2d467f Simon Schulz
    cmd.clear();
241
    cmd.addString(buf);
242 0c8d22a5 sschulz
    // NOTE: writeStrict is important in order not to loose packets
243
    emotion_port.writeStrict();
244 6a2d467f Simon Schulz
245
/*
246
    //store joint values which we do not handle on icub here:
247
    double timestamp = get_timestamp_ms();
248
    JointInterface::store_incoming_position(ID_LIP_LEFT_UPPER,   target_angle[ICUB_ID_LIP_LEFT_UPPER], timestamp);
249
    JointInterface::store_incoming_position(ID_LIP_LEFT_LOWER,   target_angle[ICUB_ID_LIP_LEFT_LOWER], timestamp);
250
    JointInterface::store_incoming_position(ID_LIP_CENTER_UPPER, target_angle[ICUB_ID_LIP_CENTER_UPPER], timestamp);
251
    JointInterface::store_incoming_position(ID_LIP_CENTER_LOWER, target_angle[ICUB_ID_LIP_CENTER_LOWER], timestamp);
252
    JointInterface::store_incoming_position(ID_LIP_RIGHT_UPPER,  target_angle[ICUB_ID_LIP_RIGHT_UPPER], timestamp);
253
    JointInterface::store_incoming_position(ID_LIP_RIGHT_LOWER,  target_angle[ICUB_ID_LIP_RIGHT_LOWER], timestamp);
254
*/
255
}