Statistics
| Branch: | Tag: | Revision:

humotion / examples / yarp_icub / src / icub_jointinterface.cpp @ 55a4b313

History | View | Annotate | Download (19.549 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::const_iterator it;
65
    last_position_error.resize(ICUB_JOINT_ID_ENUM_SIZE);
66
    PID_P.resize(ICUB_JOINT_ID_ENUM_SIZE);
67
    PID_D.resize(ICUB_JOINT_ID_ENUM_SIZE);
68

    
69
    for(it = enum_id_bimap.begin(); it != enum_id_bimap.end(); ++it) {
70
        int id = it->left;
71
        last_position_error[id] = 0.0;
72
        PID_P[id] = 4.5;
73
        PID_D[id] = 0.3;
74
    }
75

    
76

    
77
    Property options;
78
    options.put("device", "remote_controlboard");
79
    options.put("local", "/local/head");
80
    options.put("remote", scope+"/head");
81
    dd.open(options);
82

    
83
    //fetch views:
84
    dd.view(iencs);
85
    dd.view(ipos);
86
    dd.view(ivel);
87
    dd.view(ilimits);
88
    dd.view(pid);
89
    dd.view(amp);
90

    
91

    
92
    if ( (!iencs) || (!ipos) || (!ilimits) || (!ivel) || (!amp) || (!pid)){
93
        printf("> ERROR: failed to open icub views\n");
94
        exit(EXIT_FAILURE);
95
    }
96

    
97
    int joints;
98

    
99
    //tell humotion about min/max joint values:
100
    init_joints();
101

    
102
    iencs->getAxes(&joints);
103
    positions.resize(joints);
104
    velocities.resize(joints);
105
    commands.resize(joints);
106

    
107
    //set position mode:
108
    if (POSITION_CONTROL){
109
        commands=200000.0;
110
        ipos->setRefAccelerations(commands.data());
111
        ipos->setPositionMode();
112
    }else{
113
        ivel->setVelocityMode();
114
        commands=300.0;
115
        ivel->setRefAccelerations(commands.data());
116
    }
117

    
118
}
119

    
120
//! destructor
121
iCubJointInterface::~iCubJointInterface(){
122
}
123

    
124

    
125

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

    
138

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

    
151

    
152
void iCubJointInterface::run(){
153
    iCubDataReceiver *data_receiver = new iCubDataReceiver(0.5 * 1000.0 / MAIN_LOOP_FREQUENCY, iencs, this);
154
    data_receiver->start();
155
}
156

    
157
//! set the target position of a joint
158
//! \param enum id of joint
159
//! \param float value
160
void iCubJointInterface::publish_target_position(int e){
161
    //first: convert humotion enum to our enum:
162
    int id = convert_enum_to_motorid(e);
163

    
164
    if (id == -1){
165
        return; //we are not interested in that data, so we just return here
166
    }
167

    
168
    if (id == ICUB_ID_NECK_PAN){
169
        //PAN seems to be swapped
170
        store_joint(ICUB_ID_NECK_PAN, -joint_target[e]);
171
    }else if ((id == ICUB_ID_EYES_PAN) || ( id == ICUB_ID_EYES_VERGENCE)){
172
        //icub handles eyes differently, we have to set pan angle + vergence
173
        float pan      = (joint_target[ID_EYES_LEFT_LR] + joint_target[ID_EYES_RIGHT_LR]) / 2;
174
        float vergence = (joint_target[ID_EYES_LEFT_LR]  - joint_target[ID_EYES_RIGHT_LR]);
175
        //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);
176

    
177
        store_joint(ICUB_ID_EYES_PAN, pan);
178
        store_joint(ICUB_ID_EYES_VERGENCE, vergence);
179
    }else{
180
        store_joint(id, joint_target[e]);
181
    }
182
}
183

    
184

    
185
//! set the target position of a joint
186
//! \param id of joint
187
//! \param float value of position
188
void iCubJointInterface::store_joint(int id, float value){
189
    printf("> set joint %d = %f\n",id,value);
190
    target_angle[id] = value;
191
}
192

    
193
//! execute a move in position mode
194
//! \param id of joint
195
//! \param angle
196
void iCubJointInterface::set_target_in_positionmode(int id){
197
    double target = target_angle[id];
198

    
199
    if (id>ICUB_ID_EYES_VERGENCE){
200
        printf("> ERROR: set_target_positionmode(id=%d, %3.2f) not supported for this id\n",id,target);
201
        return;
202
    }
203

    
204
    // execute motion as position control cmd
205
    ipos->positionMove(id, target);
206

    
207
}
208

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

    
217
    //make the motion smooth: we want to reach 85% of the target in the next iteration:
218
    distance = 0.85 * distance;
219

    
220
    //distance = -5.0 / 50.0;
221

    
222
    //calculate speed
223
    //double speed = distance * ((double)MAIN_LOOP_FREQUENCY);
224

    
225

    
226

    
227
    int e = convert_motorid_to_enum(id);
228
    double speed = joint_target_speed[e];
229

    
230
    double max = 150.0;
231
    if (speed > max) speed = max;
232
    if (speed < -max) speed = -max;
233

    
234
    //speed = -speed;
235

    
236

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

    
241
    //execute:
242
    //ivel->velocityMove(id, speed);
243
    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) ){
244
        //do a pd control for velocity moves that incorporates position errors:
245
        humotion::Timestamp data_ts = get_ts_position(e).get_last_timestamp();
246
        //TODO: add interpolation into future!
247
        //humotion::Timestamp data_ts = humotion::Timestamp::now(); and extend get_interpol value with get_future_value
248
        double position_error = target_angle[id] - get_ts_position(e).get_interpolated_value(data_ts);
249
        double error_d = (position_error - last_position_error[id]) / (framerate*1000.0);
250
        last_position_error[id] = position_error;
251
        //finally do a PD loop to get the target velocity
252
        double target_velocity = 0.1*(PID_P[id] * position_error + PID_D[id]*error_d) - speed;
253

    
254
        printf("%f %f %f %f %f %f PID%d\n",
255
               get_ts_position(e).get_interpolated_value(data_ts),
256
               target_angle[id],
257
               get_ts_speed(e).get_interpolated_value(data_ts), speed now is zERO?!?!?
258
                                                                                        speed pan is inverted??
259
               target_velocity,
260
               speed,
261
               position_error,
262
               id
263
               );
264

    
265

    
266
        //if (id == ICUB_ID_NECK_PAN) speed = -speed;
267
        ivel->velocityMove(id, target_velocity);
268
        printf("> VEL now=%3.2f target=%3.2f --> dist=%3.2f speed=%3.2f\n",target_angle_previous[id],target_angle[id],distance,speed);
269
    }
270

    
271
    target_angle_previous[id] = get_ts_position(convert_motorid_to_enum(id)).get_newest_value();
272
}
273

    
274
//! actually execute the scheduled motion commands
275
void iCubJointInterface::execute_motion(){
276

    
277
    // set up neck and eye motion commands:
278
    if (POSITION_CONTROL){
279
        //position control
280
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
281
            set_target_in_positionmode(i);
282
        }
283
    }else{
284
        //velocity control
285
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
286
            set_target_in_velocitymode(i);
287
        }
288
    }
289
    //printf("> TARGET PAN = %3.2f\n",target_angle[ICUB_ID_NECK_PAN]);
290

    
291

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

    
295
    //eyebrows are set using a special command as well:
296
    face_interface->set_eyebrow_angle(ICUB_ID_EYES_LEFT_BROW, target_angle);
297
    face_interface->set_eyebrow_angle(ICUB_ID_EYES_RIGHT_BROW, target_angle);
298

    
299
    //mouth
300
    face_interface->set_mouth(target_angle);
301

    
302

    
303
    //store joint values which we do not handle on icub here:
304
    double timestamp = get_timestamp_ms();
305
    JointInterface::store_incoming_position(ID_LIP_LEFT_UPPER,   target_angle[ICUB_ID_LIP_LEFT_UPPER], timestamp);
306
    JointInterface::store_incoming_position(ID_LIP_LEFT_LOWER,   target_angle[ICUB_ID_LIP_LEFT_LOWER], timestamp);
307
    JointInterface::store_incoming_position(ID_LIP_CENTER_UPPER, target_angle[ICUB_ID_LIP_CENTER_UPPER], timestamp);
308
    JointInterface::store_incoming_position(ID_LIP_CENTER_LOWER, target_angle[ICUB_ID_LIP_CENTER_LOWER], timestamp);
309
    JointInterface::store_incoming_position(ID_LIP_RIGHT_UPPER,  target_angle[ICUB_ID_LIP_RIGHT_UPPER], timestamp);
310
    JointInterface::store_incoming_position(ID_LIP_RIGHT_LOWER,  target_angle[ICUB_ID_LIP_RIGHT_LOWER], timestamp);
311
}
312

    
313
double iCubJointInterface::get_timestamp_ms(){
314
    struct timespec spec;
315
    clock_gettime(CLOCK_REALTIME, &spec);
316
    return spec.tv_sec*1000 + spec.tv_nsec / 1.0e6;
317
}
318

    
319
//! set the current position of a joint
320
//! \param id of joint
321
//! \param float value of position
322
//! \param double timestamp
323
void iCubJointInterface::fetch_position(int id, double value, double timestamp){
324
    //store joint based on id:
325
    switch(id){
326
        default:
327
            printf("> ERROR: unhandled joint id %d\n",id);
328
            return;
329

    
330
        case(100):
331
            //JointInterface::store_incoming_position(ID_EYES_RIGHT_LID_UPPER, lid_angle, timestamp);
332
            break;
333

    
334
        case(ICUB_ID_NECK_PAN):
335
            //PAN is inverted!
336
            JointInterface::store_incoming_position(ID_NECK_PAN, value, timestamp);
337
            break;
338

    
339
        case(ICUB_ID_NECK_TILT):
340
            JointInterface::store_incoming_position(ID_NECK_TILT, value, timestamp);
341
            break;
342

    
343
        case(ICUB_ID_NECK_ROLL):
344
            JointInterface::store_incoming_position(ID_NECK_ROLL, value, timestamp);
345
            break;
346

    
347
        case(ICUB_ID_EYES_BOTH_UD):
348
            JointInterface::store_incoming_position(ID_EYES_BOTH_UD, value, timestamp);
349
            break;
350

    
351
        //icub handles eyes differently, we have to set pan angle + vergence
352
        case(ICUB_ID_EYES_PAN): {//pan
353
            last_pos_eye_pan = value;
354
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
355
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
356

    
357
            //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);
358
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
359
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
360
            break;
361
        }
362

    
363
        case(ICUB_ID_EYES_VERGENCE): { //vergence
364
            last_pos_eye_vergence = value;
365
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
366
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
367

    
368
            //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);
369
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
370
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
371
            break;
372
        }
373
    }
374

    
375

    
376
}
377

    
378
//! set the current speed of a joint
379
//! \param enum id of joint
380
//! \param float value of speed
381
//! \param double timestamp
382
void iCubJointInterface::fetch_speed(int id, double value, double timestamp){
383

    
384
    switch(id){
385
        default:
386
            printf("> ERROR: unhandled joint id %d\n",id);
387
            return;
388

    
389
        case(ICUB_ID_NECK_PAN):
390
            //PAN IS INVERTED
391
            JointInterface::store_incoming_speed(ID_NECK_PAN, value, timestamp);
392
            break;
393

    
394
        case(ICUB_ID_NECK_TILT):
395
            JointInterface::store_incoming_speed(ID_NECK_TILT, value, timestamp);
396
            break;
397

    
398
        case(ICUB_ID_NECK_ROLL):
399
            JointInterface::store_incoming_speed(ID_NECK_ROLL, value, timestamp);
400
            break;
401

    
402
        case(ICUB_ID_EYES_BOTH_UD):
403
            JointInterface::store_incoming_speed(ID_EYES_BOTH_UD, value, timestamp);
404
            break;
405

    
406
        //icub handles eyes differently, we have to set pan angle + vergence
407
        case(ICUB_ID_EYES_PAN): {//pan
408
            last_vel_eye_pan = value;
409
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
410
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
411

    
412
            //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);
413
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
414
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
415
            break;
416
        }
417

    
418
        case(ICUB_ID_EYES_VERGENCE): { //vergence
419
            last_vel_eye_pan = value;
420
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
421
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
422

    
423
            //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);
424
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
425
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
426
            break;
427
        }
428
    }
429
}
430

    
431
void iCubJointInterface::set_joint_enable_state(int e, bool enable) {
432
    int icub_jointid = -1;
433

    
434
    switch(e){
435
        default:
436
            break;
437

    
438
    case(ID_NECK_PAN):
439
        icub_jointid = ICUB_ID_NECK_PAN;
440
        break;
441

    
442
    case(ID_NECK_TILT):
443
        icub_jointid = ICUB_ID_NECK_TILT;
444
        break;
445

    
446
    case(ID_NECK_ROLL):
447
        icub_jointid = ICUB_ID_NECK_ROLL;
448
        break;
449

    
450
    case(ID_EYES_BOTH_UD):
451
        icub_jointid = ICUB_ID_EYES_BOTH_UD;
452
        break;
453

    
454
    // icub handles eyes as pan angle + vergence...
455
    // -> hack: left eye enables pan and right eye enables vergence
456
    case(ID_EYES_LEFT_LR):
457
        icub_jointid = ICUB_ID_EYES_PAN;
458
        break;
459

    
460
    case(ID_EYES_RIGHT_LR):
461
        icub_jointid = ICUB_ID_EYES_VERGENCE;
462
        break;
463
    }
464

    
465
    if (icub_jointid != -1) {
466
        if (enable) {
467
            amp->enableAmp(icub_jointid);
468
            pid->enablePid(icub_jointid);
469
        } else {
470
            pid->disablePid(icub_jointid);
471
            amp->disableAmp(icub_jointid);
472
        }
473
    }
474
}
475

    
476
//! prepare and enable a joint
477
//! NOTE: this should also prefill the min/max positions for this joint
478
//! \param the enum id of a joint
479
void iCubJointInterface::enable_joint(int e){
480
    set_joint_enable_state(e, true);
481
}
482

    
483
//! shutdown and disable a joint
484
//! \param the enum id of a joint
485
void iCubJointInterface::disable_joint(int e){
486
    set_joint_enable_state(e, false);
487
}
488

    
489
void iCubJointInterface::store_min_max(IControlLimits *ilimits, int id, int e){
490
    double min, max;
491
    ilimits->getLimits(id, &min, &max);
492
    joint_min[e] = min;
493
    joint_max[e] = max;
494
}
495

    
496
//! initialise a joint (set up controller mode etc)
497
//! \param joint enum
498
void iCubJointInterface::init_joints(){
499
    store_min_max(ilimits, ICUB_ID_NECK_TILT, ID_NECK_TILT);
500
    store_min_max(ilimits, ICUB_ID_NECK_ROLL, ID_NECK_ROLL);
501
    store_min_max(ilimits, ICUB_ID_NECK_PAN, ID_NECK_PAN);
502
    store_min_max(ilimits, ICUB_ID_EYES_BOTH_UD, ID_EYES_BOTH_UD);
503

    
504
    //icub handles eyes differently, we have to set pan angle + vergence
505
    double pan_min, pan_max, vergence_min, vergence_max;
506
    ilimits->getLimits(ICUB_ID_EYES_PAN, &pan_min, &pan_max);
507
    ilimits->getLimits(ICUB_ID_EYES_VERGENCE, &vergence_min, &vergence_max);
508

    
509
    //this is not 100% correct, should be fixed:
510
    joint_min[ID_EYES_LEFT_LR] = pan_min; // - vergence_max/2;
511
    joint_max[ID_EYES_LEFT_LR] = pan_max; // - vergence_max/2;
512
    joint_min[ID_EYES_RIGHT_LR] = joint_min[ID_EYES_LEFT_LR];
513
    joint_max[ID_EYES_RIGHT_LR] = joint_max[ID_EYES_LEFT_LR];
514

    
515
    //eyelids:
516
    joint_min[ID_EYES_RIGHT_LID_UPPER] = -50; //24-30;
517
    joint_max[ID_EYES_RIGHT_LID_UPPER] = 50; //48-30;
518
    //lid_angle = joint_max[ID_EYES_RIGHT_LID_UPPER];
519

    
520
    //eyebrows:
521
    joint_min[ID_EYES_LEFT_BROW] = -50;
522
    joint_max[ID_EYES_LEFT_BROW] = 50;
523
    joint_min[ID_EYES_RIGHT_BROW] = joint_min[ID_EYES_LEFT_BROW];
524
    joint_max[ID_EYES_RIGHT_BROW] = joint_max[ID_EYES_LEFT_BROW];
525

    
526
    //mouth:
527
    joint_min[ID_LIP_CENTER_UPPER] = 5;
528
    joint_max[ID_LIP_CENTER_UPPER] = 50;
529
    joint_min[ID_LIP_CENTER_LOWER] = 5;
530
    joint_max[ID_LIP_CENTER_LOWER] = 50;
531
    joint_min[ID_LIP_LEFT_UPPER] = 5;
532
    joint_max[ID_LIP_LEFT_UPPER] = 50;
533
    joint_min[ID_LIP_LEFT_LOWER] = 5;
534
    joint_max[ID_LIP_LEFT_LOWER] = 50;
535
    joint_min[ID_LIP_RIGHT_UPPER] = 5;
536
    joint_max[ID_LIP_RIGHT_UPPER] = 50;
537
    joint_min[ID_LIP_RIGHT_LOWER] = 5;
538
    joint_max[ID_LIP_RIGHT_LOWER] = 50;
539

    
540

    
541
}