Statistics
| Branch: | Tag: | Revision:

humotion / examples / yarp_icub / src / icub_jointinterface.cpp @ 87b50988

History | View | Annotate | Download (18.957 KB)

1
#include "icub_jointinterface.h"
2
#include "icub_faceinterface.h"
3

    
4
#include <yarp/os/Property.h>
5
using namespace yarp::dev;
6
using namespace yarp::sig;
7
using namespace yarp::os;
8
using namespace std;
9
/*running:
10
/media/local_data/sschulz/iros15/icub-nightly/share/iCub/contexts/simConfig:> iCub_SIM
11
/media/local_data/sschulz/iros15/icub-nightly/share/iCub/contexts/simFaceExpressions:> ../../../../bin/simFaceExpressions
12
yarp connect /face/eyelids /icubSim/face/eyelids
13
yarp connect /face/image/out /icubSim/texture/face
14

15
TEST: yarp write /writer /icubSim/face/raw/in
16

17
http://wiki.icub.org/wiki/Motor_control
18
*/
19

    
20
//WARNING: DO NOT CHANGE THIS; VELOCITYMODE IS NOT YET IMPLEMENTED
21
#define POSITION_CONTROL 0
22

    
23

    
24
//! constructor
25
iCubJointInterface::iCubJointInterface(string _scope) : humotion::server::JointInterface(){
26
    scope = _scope;
27
    face_interface = new iCubFaceInterface(scope);
28

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

    
36
    //MOUTH
37
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_UPPER,   ID_LIP_LEFT_UPPER));
38
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_LOWER,   ID_LIP_LEFT_LOWER));
39
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_UPPER, ID_LIP_CENTER_UPPER));
40
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_LOWER, ID_LIP_CENTER_LOWER));
41
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_UPPER,  ID_LIP_RIGHT_UPPER));
42
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_LOWER,  ID_LIP_RIGHT_LOWER));
43

    
44
    //NECK
45
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_PAN,    ID_NECK_PAN));
46
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_TILT,   ID_NECK_TILT));
47
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_ROLL,   ID_NECK_ROLL));
48

    
49
    //EYES
50
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_PAN,   ID_EYES_LEFT_LR));
51
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_VERGENCE,   ID_EYES_RIGHT_LR));
52
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_BOTH_UD,   ID_EYES_BOTH_UD));
53

    
54
    //EYELIDS
55
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_LOWER, ID_EYES_LEFT_LID_LOWER));
56
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_UPPER, ID_EYES_LEFT_LID_UPPER));
57
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_BROW, ID_EYES_LEFT_BROW));
58

    
59
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_LOWER, ID_EYES_RIGHT_LID_LOWER));
60
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_UPPER,ID_EYES_RIGHT_LID_UPPER));
61
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_BROW, ID_EYES_RIGHT_BROW));
62

    
63
    //init pd control variables
64
    enum_id_bimap_t::right_const_iterator it;
65
    for(it = enum_id_bimap.left.begin(); it == enum_id_bimap.left.end(); it++) {
66
        last_position_error[*it] = 0.0;
67
        PID_P[id] = 0.5;
68
        PID_D[id] = 0.1;
69
    }
70

    
71

    
72
    Property options;
73
    options.put("device", "remote_controlboard");
74
    options.put("local", "/local/head");
75
    options.put("remote", scope+"/head");
76
    dd.open(options);
77

    
78
    //fetch views:
79
    dd.view(iencs);
80
    dd.view(ipos);
81
    dd.view(ivel);
82
    dd.view(ilimits);
83
    dd.view(pid);
84
    dd.view(amp);
85

    
86

    
87
    if ( (!iencs) || (!ipos) || (!ilimits) || (!ivel) || (!amp) || (!pid)){
88
        printf("> ERROR: failed to open icub views\n");
89
        exit(EXIT_FAILURE);
90
    }
91

    
92
    int joints;
93

    
94
    //tell humotion about min/max joint values:
95
    init_joints();
96

    
97
    iencs->getAxes(&joints);
98
    positions.resize(joints);
99
    velocities.resize(joints);
100
    commands.resize(joints);
101

    
102
    //set position mode:
103
    if (POSITION_CONTROL){
104
        commands=200000.0;
105
        ipos->setRefAccelerations(commands.data());
106
        ipos->setPositionMode();
107
    }else{
108
        ivel->setVelocityMode();
109
        commands=100.0;
110
        ivel->setRefAccelerations(commands.data());
111
    }
112

    
113
}
114

    
115
//! destructor
116
iCubJointInterface::~iCubJointInterface(){
117
}
118

    
119

    
120

    
121
//! conversion table for humotion motor ids to our ids:
122
//! \param enum from JointInterface::JOINT_ID_ENUM
123
//! \return int value of motor id
124
int iCubJointInterface::convert_enum_to_motorid(int e){
125
    enum_id_bimap_t::right_const_iterator it = enum_id_bimap.right.find(e);
126
    if(it == enum_id_bimap.right.end()) {
127
        //key does not exists, we are not interested in that dataset, return -1
128
        return -1;
129
    }
130
    return it->second;
131
}
132

    
133

    
134
//! conversion table for our ids to humotion motor ids:
135
//! \param  int value of motor id
136
//! \return enum from JointInterface::JOINT_ID_ENUM
137
int iCubJointInterface::convert_motorid_to_enum(int id){
138
    enum_id_bimap_t::left_const_iterator it = enum_id_bimap.left.find(id);
139
    if(it == enum_id_bimap.left.end()) {
140
        //key does not exists, we are not interested in that dataset, return -1
141
        return -1;
142
    }
143
    return it->second;
144
}
145

    
146

    
147
void iCubJointInterface::run(){
148
    iCubDataReceiver *data_receiver = new iCubDataReceiver(0.5 * 1000.0 / MAIN_LOOP_FREQUENCY, iencs, this);
149
    data_receiver->start();
150
}
151

    
152
//! set the target position of a joint
153
//! \param enum id of joint
154
//! \param float value
155
void iCubJointInterface::publish_target_position(int e){
156
    //first: convert humotion enum to our enum:
157
    int id = convert_enum_to_motorid(e);
158

    
159
    if (id == -1){
160
        return; //we are not interested in that data, so we just return here
161
    }
162

    
163
    if (id == ICUB_ID_NECK_PAN){
164
        //PAN seems to be swapped
165
        store_joint(ICUB_ID_NECK_PAN, -joint_target[e]);
166
    }else if ((id == ICUB_ID_EYES_PAN) || ( id == ICUB_ID_EYES_VERGENCE)){
167
        //icub handles eyes differently, we have to set pan angle + vergence
168
        float pan      = (joint_target[ID_EYES_LEFT_LR] + joint_target[ID_EYES_RIGHT_LR]) / 2;
169
        float vergence = (joint_target[ID_EYES_LEFT_LR]  - joint_target[ID_EYES_RIGHT_LR]);
170
        //printf("EYEDBG %3.2f %3.2f --_> pan %3.2f verg=%3.2f\n",joint_target[ID_EYES_LEFT_LR], joint_target[ID_EYES_RIGHT_LR],pan,vergence);
171

    
172
        store_joint(ICUB_ID_EYES_PAN, pan);
173
        store_joint(ICUB_ID_EYES_VERGENCE, vergence);
174
    }else{
175
        store_joint(id, joint_target[e]);
176
    }
177
}
178

    
179

    
180
//! set the target position of a joint
181
//! \param id of joint
182
//! \param float value of position
183
void iCubJointInterface::store_joint(int id, float value){
184
    printf("> set joint %d = %f\n",id,value);
185
    target_angle[id] = value;
186
}
187

    
188
//! execute a move in position mode
189
//! \param id of joint
190
//! \param angle
191
void iCubJointInterface::set_target_in_positionmode(int id){
192
    double target = target_angle[id];
193

    
194
    if (id>ICUB_ID_EYES_VERGENCE){
195
        printf("> ERROR: set_target_positionmode(id=%d, %3.2f) not supported for this id\n",id,target);
196
        return;
197
    }
198

    
199
    // execute motion as position control cmd
200
    ipos->positionMove(id, target);
201

    
202
}
203

    
204
//! execute a move in velocity mode
205
//! \param id of joint
206
//! \param angle
207
void iCubJointInterface::set_target_in_velocitymode(int id){
208
    // set speed cacluated as in velocity + set position -> replicates smoothmotion from flobi?!
209
    //first: calculate necessary speed to reach the given target within the next clock tick:
210
    double distance = value - target_angle_previous[id];
211

    
212
    //make the motion smooth: we want to reach 85% of the target in the next iteration:
213
    distance = 0.85 * distance;
214

    
215
    //distance = -5.0 / 50.0;
216

    
217
    //calculate speed
218
    //double speed = distance * ((double)MAIN_LOOP_FREQUENCY);
219

    
220

    
221

    
222
    int e = convert_motorid_to_enum(id);
223
    double speed = joint_target_speed[e];
224

    
225
    double max = 150.0;
226
    if (speed > max) speed = max;
227
    if (speed < -max) speed = -max;
228

    
229
    //speed = -speed;
230

    
231

    
232
    // find out the latency between incoming data and now:
233
    float latency = get_ts_speed(e).get_last_timestamp().to_seconds() - humotion::Timestamp::now().to_seconds();
234
    printf("TS DIFF %fms\n",latency*1000.0);
235

    
236
    //execute:
237
    //ivel->velocityMove(id, speed);
238
    if ((id == ICUB_ID_NECK_PAN)  || (id == ICUB_ID_EYES_BOTH_UD) || (id == ICUB_ID_NECK_TILT) || (id == ICUB_ID_EYES_BOTH_UD) ||  (id == ICUB_ID_NECK_TILT) ){
239
        //do a pd control for velocity moves that incorporates position errors:
240
        humotion::Timestamp data_ts = get_ts_position(id).get_last_timestamp();
241
        //TODO: add interpolation into future!
242
        //humotion::Timestamp data_ts = humotion::Timestamp::now(); and extend get_interpol value with get_future_value
243
        double position_error = target_angle[id] - get_ts_position(id).get_interpolated_value(data_ts);
244
        double error_d = (position_error - last_position_error[id]) / (((double) rate)*1000.0);
245
        last_position_error[id] = position_error;
246
        //finally do a PD loop to get the target velocity
247
        double target_velocity = PID_P[id] * position_error + PID_D[id]*error_d + speed;
248

    
249
        //if (id == ICUB_ID_NECK_PAN) speed = -speed;
250
        ivel->velocityMove(id, target_velocity);
251
        printf("> VEL now=%3.2f target=%3.2f --> dist=%3.2f speed=%3.2f\n",target_angle_previous[id],value,distance,speed);
252
    }
253

    
254
    target_angle_previous[id] = get_ts_position(convert_motorid_to_enum(id)).get_newest_value();
255
}
256

    
257
//! actually execute the scheduled motion commands
258
void iCubJointInterface::execute_motion(){
259

    
260
    // set up neck and eye motion commands:
261
    if (POSITION_CONTROL){
262
        //position control
263
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
264
            set_target_in_positionmode(i, target_angle[i]);
265
        }
266
    }else{
267
        //velocity control
268
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
269
            set_target_in_velocitymode(i, target_angle[i]);
270
        }
271
    }
272
    //printf("> TARGET PAN = %3.2f\n",target_angle[ICUB_ID_NECK_PAN]);
273

    
274

    
275
    //eyelids: unfortuantely the icub has only 1dof for eyelids, so we use only one dof here:
276
    face_interface->set_eyelid_angle(target_angle[ICUB_ID_EYES_RIGHT_LID_UPPER]);
277

    
278
    //eyebrows are set using a special command as well:
279
    face_interface->set_eyebrow_angle(ICUB_ID_EYES_LEFT_BROW, target_angle);
280
    face_interface->set_eyebrow_angle(ICUB_ID_EYES_RIGHT_BROW, target_angle);
281

    
282
    //mouth
283
    face_interface->set_mouth(target_angle);
284

    
285

    
286
    //store joint values which we do not handle on icub here:
287
    double timestamp = get_timestamp_ms();
288
    JointInterface::store_incoming_position(ID_LIP_LEFT_UPPER,   target_angle[ICUB_ID_LIP_LEFT_UPPER], timestamp);
289
    JointInterface::store_incoming_position(ID_LIP_LEFT_LOWER,   target_angle[ICUB_ID_LIP_LEFT_LOWER], timestamp);
290
    JointInterface::store_incoming_position(ID_LIP_CENTER_UPPER, target_angle[ICUB_ID_LIP_CENTER_UPPER], timestamp);
291
    JointInterface::store_incoming_position(ID_LIP_CENTER_LOWER, target_angle[ICUB_ID_LIP_CENTER_LOWER], timestamp);
292
    JointInterface::store_incoming_position(ID_LIP_RIGHT_UPPER,  target_angle[ICUB_ID_LIP_RIGHT_UPPER], timestamp);
293
    JointInterface::store_incoming_position(ID_LIP_RIGHT_LOWER,  target_angle[ICUB_ID_LIP_RIGHT_LOWER], timestamp);
294
}
295

    
296
double iCubJointInterface::get_timestamp_ms(){
297
    struct timespec spec;
298
    clock_gettime(CLOCK_REALTIME, &spec);
299
    return spec.tv_sec*1000 + spec.tv_nsec / 1.0e6;
300
}
301

    
302
//! set the current position of a joint
303
//! \param id of joint
304
//! \param float value of position
305
//! \param double timestamp
306
void iCubJointInterface::fetch_position(int id, double value, double timestamp){
307
    //store joint based on id:
308
    switch(id){
309
        default:
310
            printf("> ERROR: unhandled joint id %d\n",id);
311
            return;
312

    
313
        case(100):
314
            //JointInterface::store_incoming_position(ID_EYES_RIGHT_LID_UPPER, lid_angle, timestamp);
315
            break;
316

    
317
        case(ICUB_ID_NECK_PAN):
318
            //PAN is inverted!
319
            JointInterface::store_incoming_position(ID_NECK_PAN, value, timestamp);
320
            break;
321

    
322
        case(ICUB_ID_NECK_TILT):
323
            JointInterface::store_incoming_position(ID_NECK_TILT, value, timestamp);
324
            break;
325

    
326
        case(ICUB_ID_NECK_ROLL):
327
            JointInterface::store_incoming_position(ID_NECK_ROLL, value, timestamp);
328
            break;
329

    
330
        case(ICUB_ID_EYES_BOTH_UD):
331
            JointInterface::store_incoming_position(ID_EYES_BOTH_UD, value, timestamp);
332
            break;
333

    
334
        //icub handles eyes differently, we have to set pan angle + vergence
335
        case(ICUB_ID_EYES_PAN): {//pan
336
            last_pos_eye_pan = value;
337
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
338
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
339

    
340
            //printf("> eye: pan=%3.2f vergence=%3.2f --> L=%3.2f R=%3.2f\n", last_pos_eye_pan, last_pos_eye_vergence, left, right);
341
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
342
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
343
            break;
344
        }
345

    
346
        case(ICUB_ID_EYES_VERGENCE): { //vergence
347
            last_pos_eye_vergence = value;
348
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
349
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
350

    
351
            //printf("> eye: pan=%3.2f vergence=%3.2f --> L=%3.2f R=%3.2f\n", last_pos_eye_pan, last_pos_eye_vergence, left, right);
352
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
353
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
354
            break;
355
        }
356
    }
357

    
358

    
359
}
360

    
361
//! set the current speed of a joint
362
//! \param enum id of joint
363
//! \param float value of speed
364
//! \param double timestamp
365
void iCubJointInterface::fetch_speed(int id, double value, double timestamp){
366

    
367
    switch(id){
368
        default:
369
            printf("> ERROR: unhandled joint id %d\n",id);
370
            return;
371

    
372
        case(ICUB_ID_NECK_PAN):
373
            //PAN IS INVERTED
374
            JointInterface::store_incoming_speed(ID_NECK_PAN, value, timestamp);
375
            break;
376

    
377
        case(ICUB_ID_NECK_TILT):
378
            JointInterface::store_incoming_speed(ID_NECK_TILT, value, timestamp);
379
            break;
380

    
381
        case(ICUB_ID_NECK_ROLL):
382
            JointInterface::store_incoming_speed(ID_NECK_ROLL, value, timestamp);
383
            break;
384

    
385
        case(ICUB_ID_EYES_BOTH_UD):
386
            JointInterface::store_incoming_speed(ID_EYES_BOTH_UD, value, timestamp);
387
            break;
388

    
389
        //icub handles eyes differently, we have to set pan angle + vergence
390
        case(ICUB_ID_EYES_PAN): {//pan
391
            last_vel_eye_pan = value;
392
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
393
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
394

    
395
            //printf("> eye: velocity pan=%3.2f vergence=%3.2f --> L=%3.2f R=%3.2f\n", last_vel_eye_pan, last_vel_eye_vergence, left, right);
396
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
397
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
398
            break;
399
        }
400

    
401
        case(ICUB_ID_EYES_VERGENCE): { //vergence
402
            last_vel_eye_pan = value;
403
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
404
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
405

    
406
            //printf("> eye: velocity pan=%3.2f vergence=%3.2f --> L=%3.2f R=%3.2f\n", last_vel_eye_pan, last_vel_eye_vergence, left, right);
407
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
408
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
409
            break;
410
        }
411
    }
412
}
413

    
414
void iCubJointInterface::set_joint_enable_state(int e, bool enable) {
415
    int icub_jointid = -1;
416

    
417
    switch(e){
418
        default:
419
            break;
420

    
421
    case(ID_NECK_PAN):
422
        icub_jointid = ICUB_ID_NECK_PAN;
423
        break;
424

    
425
    case(ID_NECK_TILT):
426
        icub_jointid = ICUB_ID_NECK_TILT;
427
        break;
428

    
429
    case(ID_NECK_ROLL):
430
        icub_jointid = ICUB_ID_NECK_ROLL;
431
        break;
432

    
433
    case(ID_EYES_BOTH_UD):
434
        icub_jointid = ICUB_ID_EYES_BOTH_UD;
435
        break;
436

    
437
    // icub handles eyes as pan angle + vergence...
438
    // -> hack: left eye enables pan and right eye enables vergence
439
    case(ID_EYES_LEFT_LR):
440
        icub_jointid = ICUB_ID_EYES_PAN;
441
        break;
442

    
443
    case(ID_EYES_RIGHT_LR):
444
        icub_jointid = ICUB_ID_EYES_VERGENCE;
445
        break;
446
    }
447

    
448
    if (icub_jointid != -1) {
449
        if (enable) {
450
            amp->enableAmp(icub_jointid);
451
            pid->enablePid(icub_jointid);
452
        } else {
453
            pid->disablePid(icub_jointid);
454
            amp->disableAmp(icub_jointid);
455
        }
456
    }
457
}
458

    
459
//! prepare and enable a joint
460
//! NOTE: this should also prefill the min/max positions for this joint
461
//! \param the enum id of a joint
462
void iCubJointInterface::enable_joint(int e){
463
    set_joint_enable_state(e, true);
464
}
465

    
466
//! shutdown and disable a joint
467
//! \param the enum id of a joint
468
void iCubJointInterface::disable_joint(int e){
469
    set_joint_enable_state(e, false);
470
}
471

    
472
void iCubJointInterface::store_min_max(IControlLimits *ilimits, int id, int e){
473
    double min, max;
474
    ilimits->getLimits(id, &min, &max);
475
    joint_min[e] = min;
476
    joint_max[e] = max;
477
}
478

    
479
//! initialise a joint (set up controller mode etc)
480
//! \param joint enum
481
void iCubJointInterface::init_joints(){
482
    store_min_max(ilimits, ICUB_ID_NECK_TILT, ID_NECK_TILT);
483
    store_min_max(ilimits, ICUB_ID_NECK_ROLL, ID_NECK_ROLL);
484
    store_min_max(ilimits, ICUB_ID_NECK_PAN, ID_NECK_PAN);
485
    store_min_max(ilimits, ICUB_ID_EYES_BOTH_UD, ID_EYES_BOTH_UD);
486

    
487
    //icub handles eyes differently, we have to set pan angle + vergence
488
    double pan_min, pan_max, vergence_min, vergence_max;
489
    ilimits->getLimits(ICUB_ID_EYES_PAN, &pan_min, &pan_max);
490
    ilimits->getLimits(ICUB_ID_EYES_VERGENCE, &vergence_min, &vergence_max);
491

    
492
    //this is not 100% correct, should be fixed:
493
    joint_min[ID_EYES_LEFT_LR] = pan_min; // - vergence_max/2;
494
    joint_max[ID_EYES_LEFT_LR] = pan_max; // - vergence_max/2;
495
    joint_min[ID_EYES_RIGHT_LR] = joint_min[ID_EYES_LEFT_LR];
496
    joint_max[ID_EYES_RIGHT_LR] = joint_max[ID_EYES_LEFT_LR];
497

    
498
    //eyelids:
499
    joint_min[ID_EYES_RIGHT_LID_UPPER] = -50; //24-30;
500
    joint_max[ID_EYES_RIGHT_LID_UPPER] = 50; //48-30;
501
    //lid_angle = joint_max[ID_EYES_RIGHT_LID_UPPER];
502

    
503
    //eyebrows:
504
    joint_min[ID_EYES_LEFT_BROW] = -50;
505
    joint_max[ID_EYES_LEFT_BROW] = 50;
506
    joint_min[ID_EYES_RIGHT_BROW] = joint_min[ID_EYES_LEFT_BROW];
507
    joint_max[ID_EYES_RIGHT_BROW] = joint_max[ID_EYES_LEFT_BROW];
508

    
509
    //mouth:
510
    joint_min[ID_LIP_CENTER_UPPER] = 5;
511
    joint_max[ID_LIP_CENTER_UPPER] = 50;
512
    joint_min[ID_LIP_CENTER_LOWER] = 5;
513
    joint_max[ID_LIP_CENTER_LOWER] = 50;
514
    joint_min[ID_LIP_LEFT_UPPER] = 5;
515
    joint_max[ID_LIP_LEFT_UPPER] = 50;
516
    joint_min[ID_LIP_LEFT_LOWER] = 5;
517
    joint_max[ID_LIP_LEFT_LOWER] = 50;
518
    joint_min[ID_LIP_RIGHT_UPPER] = 5;
519
    joint_max[ID_LIP_RIGHT_UPPER] = 50;
520
    joint_min[ID_LIP_RIGHT_LOWER] = 5;
521
    joint_max[ID_LIP_RIGHT_LOWER] = 50;
522

    
523

    
524
}