Statistics
| Branch: | Tag: | Revision:

humotion / examples / meka / src / mekajointinterface.cpp @ 99ebae32

History | View | Annotate | Download (30.423 KB)

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

    
4
//WARNING: DO NOT CHANGE THIS; VELOCITYMODE IS NOT YET IMPLEMENTED
5
#define POSITION_CONTROL 1
6

    
7
void MekaJointInterface::incoming_jointstates(const sensor_msgs::JointState & msg){
8
    //joint_pos_global = msg.position[3];
9
    cout << msg;
10
}
11

    
12
//! constructor
13
MekaJointInterface::MekaJointInterface(string _scope) : humotion::server::JointInterface(){
14
    scope = _scope;
15

    
16
    //subscribe to meka joint states
17
    int argc = 0;
18
    ros::init(argc, (char**)NULL, "meka_humotion");
19
    ros::NodeHandle n;
20
    joint_state_subscriber = n.subscribe(scope + "joint_states", 150, &MekaJointInterface::incoming_jointstates , this);
21

    
22

    
23
    //add mapping from ids to enums:
24
    //this might look strange at the first sight but we need to have a generic
25
    //way to acces joints from libhumotion. therefore the lib uses its enum with ID_* enum ids
26
    //to access the joints. now we need to define a mapping to map those to our motor ids.
27
    //this is what we use the enum bimap for (convertion fro/to motorid is handled
28
    //by \sa convert_enum_to_motorid() and \sa convert_motorid_to_enum() lateron
29
/*
30
    //MOUTH
31
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_UPPER,   ID_LIP_LEFT_UPPER));
32
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_LEFT_LOWER,   ID_LIP_LEFT_LOWER));
33
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_UPPER, ID_LIP_CENTER_UPPER));
34
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_CENTER_LOWER, ID_LIP_CENTER_LOWER));
35
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_UPPER,  ID_LIP_RIGHT_UPPER));
36
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_LIP_RIGHT_LOWER,  ID_LIP_RIGHT_LOWER));
37

38
    //NECK
39
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_PAN,    ID_NECK_PAN));
40
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_TILT,   ID_NECK_TILT));
41
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_NECK_ROLL,   ID_NECK_ROLL));
42

43
    //EYES
44
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LR,   ID_EYES_LEFT_LR));
45
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LR,   ID_EYES_RIGHT_LR));
46
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_BOTH_UD,   ID_EYES_BOTH_UD));
47

48
    //EYELIDS
49
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_LOWER, ID_EYES_LEFT_LID_LOWER));
50
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_LID_UPPER, ID_EYES_LEFT_LID_UPPER));
51
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_LEFT_BROW, ID_EYES_LEFT_BROW));
52

53
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_LOWER, ID_EYES_RIGHT_LID_LOWER));
54
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_LID_UPPER,ID_EYES_RIGHT_LID_UPPER));
55
    enum_id_bimap.insert(enum_id_bimap_entry_t(ICUB_ID_EYES_RIGHT_BROW, ID_EYES_RIGHT_BROW));
56

57
    Property options;
58
    options.put("device", "remote_controlboard");
59
    options.put("local", "/local/head");
60
    options.put("remote", scope+"/head");
61
    dd.open(options);
62

63
    //fetch views:
64
    dd.view(iencs);
65
    dd.view(ipos);
66
    dd.view(ivel);
67
    dd.view(ilimits);
68

69
    if ( (!iencs) || (!ipos) || (!ilimits) || (!ivel)){
70
        printf("> ERROR: failed to open icub views\n");
71
        exit(EXIT_FAILURE);
72
    }
73

74
    int joints;
75

76
    //tell humotion about min/max joint values:
77
    init_joints();
78

79
    iencs->getAxes(&joints);
80
    positions.resize(joints);
81
    velocities.resize(joints);
82
    commands.resize(joints);
83

84
    //set position mode:
85
    if (POSITION_CONTROL){
86
        commands=200000.0;
87
        ipos->setRefAccelerations(commands.data());
88
        ipos->setPositionMode();
89
    }else{
90
        ivel->setVelocityMode();
91
        commands=1000000;
92
        ivel->setRefAccelerations(commands.data());
93
    }
94

95
    //attach to facial expressions:
96
    string emotion_scope = scope + "/face/raw/in";
97
    printf("> opening connection to %s\n", emotion_scope.c_str());
98

99
    for(int i=0; i<4; i++){
100
        //strange, if we use one output port only the first command is executed?! flushing issues?
101
        string emotion_port_out = "/emotionwriter" + to_string(i);
102
        if (!emotion_port[i].open(emotion_port_out.c_str())){
103
            printf("> ERROR: failed to open to %s\n",emotion_port_out.c_str());
104
            exit(EXIT_FAILURE);
105
        }
106
        if (!Network::connect(emotion_port_out.c_str(), emotion_scope.c_str())){
107
            printf("> ERROR: failed to connect emotion ports\n");
108
            exit(EXIT_FAILURE);
109
        }
110
    }
111
    */
112
}
113

    
114
//! destructor
115
MekaJointInterface::~MekaJointInterface(){
116
}
117

    
118

    
119

    
120
void MekaJointInterface::run(){
121
   //iCubDataReceiver *data_receiver = new iCubDataReceiver(10/*1000.0 / MAIN_LOOP_FREQUENCY*/, iencs, this);
122
   //data_receiver->start();
123
}
124

    
125

    
126
//! set the target position of a joint
127
//! \param enum id of joint
128
//! \param float value
129
void MekaJointInterface::publish_target_position(int e){
130
    #if 0
131
    //first: convert humotion enum to our enum:
132
    int id = convert_enum_to_motorid(e);
133
    if (id == -1){
134
        return; //we are not interested in that data, so we just return here
135
    }
136

137
    if (id == ICUB_ID_NECK_PAN){
138
        //PAN seems to be swapped
139
        store_joint(ICUB_ID_NECK_PAN, -joint_target[e]);
140
    }else if ((id == ICUB_ID_EYES_LEFT_LR) || ( id == ICUB_ID_EYES_RIGHT_LR)){
141
        //icub handles eyes differently, we have to set pan angle + vergence
142
        float pan      = (joint_target[ID_EYES_LEFT_LR] + joint_target[ID_EYES_RIGHT_LR]) / 2;
143
        float vergence = (joint_target[ID_EYES_LEFT_LR]  - joint_target[ID_EYES_RIGHT_LR]);
144
        //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);
145

146
        store_joint(ICUB_ID_EYES_PAN, pan);
147
        store_joint(ICUB_ID_EYES_VERGENCE, vergence);
148
    }else{
149
        store_joint(id, joint_target[e]);
150
    }
151
    #endif
152
}
153

154

155
//! actually execute the scheduled motion commands
156
void MekaJointInterface::execute_motion(){
157
    #if 0
158
    // set up neck and eye motion commands:
159
    if (POSITION_CONTROL){
160
        //position control
161
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
162
            set_target_in_positionmode(i, target_angle[i]);
163
        }
164
    }else{
165
        //velocity control
166
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
167
            set_target_in_velocitymode(i, target_angle[i]);
168
        }
169
    }
170
    //printf("> TARGET PAN = %3.2f\n",target_angle[ICUB_ID_NECK_PAN]);
171

172

173
    //eyelids: unfortuantely the icub has only 1dof for eyelids, so we use only one dof here:
174
    set_eyelid_angle(target_angle[ICUB_ID_EYES_RIGHT_LID_UPPER]);
175

176
    //eyebrows are set using a special command as well:
177
    set_eyebrow_angle(ICUB_ID_EYES_LEFT_BROW);
178
    set_eyebrow_angle(ICUB_ID_EYES_RIGHT_BROW);
179

180
    //mouth
181
    set_mouth();
182

183
    #endif
184
}
185

186

187
//! prepare and enable a joint
188
//! NOTE: this should also prefill the min/max positions for this joint
189
//! \param the enum id of a joint
190
void MekaJointInterface::enable_joint(int e){
191
#if 0
192
    //FIXME ADD THIS:
193
    // enable the amplifier and the pid controller on each joint
194
    /*for (i = 0; i < nj; i++) {
195
       amp->enableAmp(i);
196
       pid->enablePid(i);
197
    }*/
198

199

200
    //set up smooth motion controller
201
    //step1: set up framerate
202
    //dev->set_register_blocking(XSC3_REGISTER_PID_RAMP, framerate, true);
203

204
    //step2: set controllertype:
205
    //printf("> activating smooth motion control for joint id 0x%02X (%s)\n", motor_id, joint_name.c_str());
206
    //dev->set_register_blocking(XSC3_REGISTER_PID_CONTROLLER, XSC3_PROTOCOL_PID_CONTROLLERTYPE_SMOOTH_PLAYBACK, true);
207

208
    //step3: set pid controller:
209
    /*if ((e == ID_LIP_LEFT_UPPER) || (e == ID_LIP_LEFT_LOWER) || (e == ID_LIP_CENTER_UPPER) || (e == ID_LIP_CENTER_LOWER) || (e == ID_LIP_RIGHT_UPPER) || (e == ID_LIP_RIGHT_LOWER)){
210
        printf("> fixing PID i controller value for smooth motion (FIXME: restore old value!!)\n");
211
        dev->set_register_blocking(XSC3_REGISTER_CONST_I, 10, true);
212
    }*/
213

214
    //uint16_t result = dev->get_register_blocking_raw(XSC3_REGISTER_PID_CONTROLLER);
215

216
    //check if setting pid controllertype was successfull:
217
    /*if (result != XSC3_PROTOCOL_PID_CONTROLLERTYPE_SMOOTH_PLAYBACK){
218
        printf("> failed to set smooth motion controller for joint %s (res=0x%04X)\n",joint_name.c_str(),result);
219
        exit(1);
220
    }*/
221

222
    //fetch min/max:
223
   // init_joint(e);
224

225
    //ok fine, now enable motor:
226
    //printf("> enabling motor %s\n", joint_name.c_str());
227
    //dev->set_register_blocking(XSC3_REGISTER_STATUS, XSC3_PROTOCOL_STATUS_BITMASK_MOTOR_ENABLE, true);
228
#endif
229
}
230

    
231
//! shutdown and disable a joint
232
//! \param the enum id of a joint
233
void MekaJointInterface::disable_joint(int e){
234
    /*
235
        //first: convert humotion enum to our enum:
236
        int motor_id = convert_enum_to_motorid(e);
237
        if (motor_id == -1){
238
            return; //we are not interested in that data, so we just return here
239
        }
240

241
        //fetch device:
242
        Device *dev = get_device(motor_id);
243
        printf("> FIXME: ADD DISABLE CODE\n");
244
        printf("> FIXME: ADD DISABLE CODE\n");
245
        printf("> FIXME: ADD DISABLE CODE\n");
246
        printf("> FIXME: ADD DISABLE CODE\n");
247
        printf("> FIXME: ADD DISABLE CODE\n");
248
        printf("> FIXME: ADD DISABLE CODE\n");
249
        printf("> FIXME: ADD DISABLE CODE\n");
250
        printf("> FIXME: ADD DISABLE CODE\n");
251
        printf("> FIXME: ADD DISABLE CODE\n");
252
        */
253
}
254

    
255
#if 0
256

257
//! conversion table for humotion motor ids to our ids:
258
//! \param enum from JointInterface::JOINT_ID_ENUM
259
//! \return int value of motor id
260
int iCubJointInterface::convert_enum_to_motorid(int e){
261
    enum_id_bimap_t::right_const_iterator it = enum_id_bimap.right.find(e);
262
    if(it == enum_id_bimap.right.end()) {
263
        //key does not exists, we are not interested in that dataset, return -1
264
        return -1;
265
    }
266
    return it->second;
267
}
268

269

270
//! conversion table for our ids to humotion motor ids:
271
//! \param  int value of motor id
272
//! \return enum from JointInterface::JOINT_ID_ENUM
273
int iCubJointInterface::convert_motorid_to_enum(int id){
274
    enum_id_bimap_t::left_const_iterator it = enum_id_bimap.left.find(id);
275
    if(it == enum_id_bimap.left.end()) {
276
        //key does not exists, we are not interested in that dataset, return -1
277
        return -1;
278
    }
279
    return it->second;
280
}
281

282
//! special command to set eyelid angle
283
//! \param angle in degrees
284
void iCubJointInterface::set_eyelid_angle(double angle){
285
    if (emotion_port[0].getOutputCount()>0){
286
        //try to set the value based on the upper one
287
        //some guesses from the sim: S30 = 0° / S40 = 10°
288
        int opening = (25.0 + 0.8*angle);
289
        opening = min(48, max(24, opening));
290

291
        if (opening == lid_opening_previous){
292
            //no update necessary
293
            return;
294
        }
295

296
        lid_angle = angle;
297
        lid_opening_previous = opening;
298

299
        char buf[20];
300
        sprintf(buf, "S%2d", opening);
301

302
        //printf("> SETTING EYELID '%s' (%f -> %d)\n",buf,angle,opening);
303
        Bottle &cmd = emotion_port[0].prepare();
304
        cmd.clear();
305
        cmd.addString(buf);
306
        emotion_port[0].write();
307
    }else{
308
        printf("> ERROR: no icub emotion output\n");
309
        exit(EXIT_FAILURE);
310
    }
311
}
312

313
//! special command to set the eyebrow angle
314
//! \param id {0=left, 1=right)
315
//! \param angle in degrees
316
void iCubJointInterface::set_eyebrow_angle(int id){
317
    int port_id;
318
    if (id == ICUB_ID_EYES_LEFT_BROW){
319
        port_id = 1;
320
    }else{
321
        port_id = 2;
322
    }
323

324
    if (emotion_port[port_id].getOutputCount()>0){
325
        double angle = target_angle[id];
326
        int icub_val = 0;
327

328
        //swap rotation direction:
329
        if (id==ICUB_ID_EYES_LEFT_BROW) angle = -angle;
330

331
        //convert to icub representation
332
        if (angle < -20){
333
            icub_val = 1;
334
        }else if (angle<10){
335
            icub_val = 2;
336
        }else if (angle<20){
337
            icub_val = 4;
338
        }else{
339
            icub_val = 8;
340
        }
341

342
        //make sure to update only on new values:
343
        if (icub_val == target_angle_previous[id]){
344
                //no updata necessary
345
                return;
346
        }
347

348
        //store actual value:
349
        target_angle_previous[id] = icub_val;
350

351

352
        string cmd_s;
353
        if (id==ICUB_ID_EYES_LEFT_BROW){
354
            cmd_s = "L0" + to_string(icub_val);
355
        }else{
356
            cmd_s = "R0" + to_string(icub_val);
357
        }
358

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

361
        Bottle &cmd = emotion_port[port_id].prepare();
362
        cmd.clear();
363
        cmd.addString(cmd_s);
364
        emotion_port[port_id].write();
365
    }else{
366
        printf("> ERROR: no icub emotion output\n");
367
        exit(EXIT_FAILURE);
368
    }
369
}
370

371
void iCubJointInterface::run(){
372
    iCubDataReceiver *data_receiver = new iCubDataReceiver(10/*1000.0 / MAIN_LOOP_FREQUENCY*/, iencs, this);
373
    data_receiver->start();
374
}
375

376
//! set the target position of a joint
377
//! \param enum id of joint
378
//! \param float value
379
void iCubJointInterface::publish_target_position(int e){
380
    //first: convert humotion enum to our enum:
381
    int id = convert_enum_to_motorid(e);
382
    if (id == -1){
383
        return; //we are not interested in that data, so we just return here
384
    }
385

386
    if (id == ICUB_ID_NECK_PAN){
387
        //PAN seems to be swapped
388
        store_joint(ICUB_ID_NECK_PAN, -joint_target[e]);
389
    }else if ((id == ICUB_ID_EYES_LEFT_LR) || ( id == ICUB_ID_EYES_RIGHT_LR)){
390
        //icub handles eyes differently, we have to set pan angle + vergence
391
        float pan      = (joint_target[ID_EYES_LEFT_LR] + joint_target[ID_EYES_RIGHT_LR]) / 2;
392
        float vergence = (joint_target[ID_EYES_LEFT_LR]  - joint_target[ID_EYES_RIGHT_LR]);
393
        //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);
394

395
        store_joint(ICUB_ID_EYES_PAN, pan);
396
        store_joint(ICUB_ID_EYES_VERGENCE, vergence);
397
    }else{
398
        store_joint(id, joint_target[e]);
399
    }
400
}
401

402

403
//! set the target position of a joint
404
//! \param id of joint
405
//! \param float value of position
406
void iCubJointInterface::store_joint(int id, float value){
407
    //printf("> set joint %d = %f\n",id,value);
408
    target_angle[id] = value;
409
    //ipos->positionMove(id, value);
410
}
411

412
//! execute a move in position mode
413
//! \param id of joint
414
//! \param angle
415
void iCubJointInterface::set_target_in_positionmode(int id, double value){
416
    if (id>ICUB_ID_EYES_VERGENCE){
417
        printf("> ERROR: set_target_positionmode(id=%d, %3.2f) not supported for this id\n",id,value);
418
        return;
419
    }
420
#if 0
421
    //set speed cacluated as in velocity + set position -> replicates smoothmotion from flobi?!
422

423
    //first: calculate necessary speed to reach the given target within the next clock tick:
424
    double distance = value - target_angle_previous[id];
425
    //make the motion smooth: we want to reach 85% of the target in the next iteration:
426
    //calculate speed for that:
427
    double speed = 0.85 * distance * ((double)MAIN_LOOP_FREQUENCY);
428

429
    //set up speed for controller:
430
    ipos->setRefSpeed(id, speed);
431
#endif
432
    //execute motion
433
    ipos->positionMove(id, value);
434
}
435

    
436
//! execute a move in velocity mode
437
//! \param id of joint
438
//! \param angle
439
void iCubJointInterface::set_target_in_velocitymode(int id, double value){
440
    //first: calculate necessary speed to reach the given target within the next clock tick:
441
    double distance = value - target_angle_previous[id];
442
    //make the motion smooth: we want to reach 85% of the target in the next iteration:
443
    distance = 0.85 * distance;
444
    //calculate speed
445
    double speed = distance * ((double)MAIN_LOOP_FREQUENCY);
446
    //execute:
447
    ivel->velocityMove(id, speed);
448
    //if (id == ICUB_ID_NECK_PAN) printf("> VEL now=%3.2f target=%3.2f --> dist=%3.2f speed=%3.2f\n",target_angle_previous[id],value,distance,speed);
449

    
450
    target_angle_previous[id] = get_ts_position(convert_motorid_to_enum(id)).get_newest_value();
451
}
452

    
453
//! actually execute the scheduled motion commands
454
void iCubJointInterface::execute_motion(){
455

    
456
    // set up neck and eye motion commands:
457
    if (POSITION_CONTROL){
458
        //position control
459
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
460
            set_target_in_positionmode(i, target_angle[i]);
461
        }
462
    }else{
463
        //velocity control
464
        for(int i=ICUB_ID_NECK_TILT; i<=ICUB_ID_EYES_VERGENCE; i++){
465
            set_target_in_velocitymode(i, target_angle[i]);
466
        }
467
    }
468
    //printf("> TARGET PAN = %3.2f\n",target_angle[ICUB_ID_NECK_PAN]);
469

    
470

    
471
    //eyelids: unfortuantely the icub has only 1dof for eyelids, so we use only one dof here:
472
    set_eyelid_angle(target_angle[ICUB_ID_EYES_RIGHT_LID_UPPER]);
473

    
474
    //eyebrows are set using a special command as well:
475
    set_eyebrow_angle(ICUB_ID_EYES_LEFT_BROW);
476
    set_eyebrow_angle(ICUB_ID_EYES_RIGHT_BROW);
477

    
478
    //mouth
479
    set_mouth();
480

    
481

    
482
}
483

    
484
void iCubJointInterface::set_mouth(){
485
    //convert from 6DOF mouth displacement to icub leds:
486
    int led_value = 0;
487

    
488
    //fetch center opening:
489
    double center_opening = target_angle[ICUB_ID_LIP_CENTER_LOWER] - target_angle[ICUB_ID_LIP_CENTER_UPPER];
490
    bool mouth_open = (center_opening>15.0)?true:false;
491

    
492
    //side of mouth high or low?
493
    double center_avg = (target_angle[ICUB_ID_LIP_CENTER_LOWER] + target_angle[ICUB_ID_LIP_CENTER_UPPER])/2.0;
494
    double left_avg   = (target_angle[ICUB_ID_LIP_LEFT_LOWER] + target_angle[ICUB_ID_LIP_LEFT_UPPER])/2.0;
495
    double right_avg  = (target_angle[ICUB_ID_LIP_RIGHT_LOWER] + target_angle[ICUB_ID_LIP_RIGHT_UPPER])/2.0;
496

    
497
    //happy, neutral or sad?
498
    double diff_l = center_avg - left_avg;
499
    double diff_r = center_avg - right_avg;
500
    double diff   = (diff_l+diff_r)/2.0;
501

    
502
    if (diff > 2.0){
503
        if (mouth_open){
504
            led_value = 0x14;
505
        }else{
506
            if (diff > 2.6){
507
                led_value = 0x0A;
508
            }else{
509
                led_value = 0x0B;
510
            }
511
        }
512
    }else if (diff < -3.0){
513
        if (mouth_open){
514
            led_value = 0x06;
515
        }else{
516
            led_value = 0x18;
517
        }
518
    }else if (diff < -2.0){
519
        if (mouth_open){
520
            led_value = 0x04; //0x25;
521
        }else{
522
            led_value = 0x08;
523
        }
524
    }else{
525
        if (mouth_open){
526
            led_value = 0x16;
527
        }else{
528
            led_value = 0x08;
529
        }
530
    }
531

    
532

    
533
    if (led_value == previous_mouth_state){
534
        //no update necessary
535
        return;
536
    }
537

    
538
    previous_mouth_state = led_value;
539

    
540
    //convert to string:
541
    char buf[10];
542
    sprintf(buf, "M%02X",led_value);
543

    
544
    /*printf("> sending mouth '%s'\n",buf);
545
    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]);
546
    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]);
547
    printf("  mouth  open=%3.2f diff=%3.2f\n", center_opening, diff);*/
548

    
549
    //add mouth:
550
    Bottle &cmd = emotion_port[3].prepare();
551
    cmd.clear();
552
    cmd.addString(buf);
553
    emotion_port[3].write();
554

    
555

    
556
    //store joint values which we do not handle on icub here:
557
    double timestamp = get_timestamp_ms();
558
    JointInterface::store_incoming_position(ID_LIP_LEFT_UPPER,   target_angle[ICUB_ID_LIP_LEFT_UPPER], timestamp);
559
    JointInterface::store_incoming_position(ID_LIP_LEFT_LOWER,   target_angle[ICUB_ID_LIP_LEFT_LOWER], timestamp);
560
    JointInterface::store_incoming_position(ID_LIP_CENTER_UPPER, target_angle[ICUB_ID_LIP_CENTER_UPPER], timestamp);
561
    JointInterface::store_incoming_position(ID_LIP_CENTER_LOWER, target_angle[ICUB_ID_LIP_CENTER_LOWER], timestamp);
562
    JointInterface::store_incoming_position(ID_LIP_RIGHT_UPPER,  target_angle[ICUB_ID_LIP_RIGHT_UPPER], timestamp);
563
    JointInterface::store_incoming_position(ID_LIP_RIGHT_LOWER,  target_angle[ICUB_ID_LIP_RIGHT_LOWER], timestamp);
564

    
565
}
566

    
567
double iCubJointInterface::get_timestamp_ms(){
568
    struct timespec spec;
569
    clock_gettime(CLOCK_REALTIME, &spec);
570
    return spec.tv_sec*1000 + spec.tv_nsec / 1.0e6;
571
}
572

    
573
//! set the current position of a joint
574
//! \param id of joint
575
//! \param float value of position
576
//! \param double timestamp
577
void iCubJointInterface::fetch_position(int id, double value, double timestamp){
578
    //store joint based on id:
579
    switch(id){
580
        default:
581
            printf("> ERROR: unhandled joint id %d\n",id);
582
            return;
583

    
584
        case(100):
585
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LID_UPPER, lid_angle, timestamp);
586
            break;
587

    
588
        case(2):
589
            //PAN is inverted!
590
            JointInterface::store_incoming_position(ID_NECK_PAN, -value, timestamp);
591
            break;
592

    
593
        case(0):
594
            JointInterface::store_incoming_position(ID_NECK_TILT, value, timestamp);
595
            break;
596

    
597
        case(1):
598
            JointInterface::store_incoming_position(ID_NECK_ROLL, value, timestamp);
599
            break;
600

    
601
        case(3):
602
            JointInterface::store_incoming_position(ID_EYES_BOTH_UD, value, timestamp);
603
            break;
604

    
605
        //icub handles eyes differently, we have to set pan angle + vergence
606
        case(4): {//pan
607
            last_pos_eye_pan = value;
608
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
609
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
610

    
611
            //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);
612
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
613
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
614
            break;
615
        }
616

    
617
        case(5): { //vergence
618
            last_pos_eye_vergence = value;
619
            float left  = last_pos_eye_pan + last_pos_eye_vergence/2.0;
620
            float right = last_pos_eye_pan - last_pos_eye_vergence/2.0;
621

    
622
            //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);
623
            JointInterface::store_incoming_position(ID_EYES_LEFT_LR, left, timestamp);
624
            JointInterface::store_incoming_position(ID_EYES_RIGHT_LR, right, timestamp);
625
            break;
626
        }
627
    }
628

    
629

    
630
}
631

    
632
//! set the current speed of a joint
633
//! \param enum id of joint
634
//! \param float value of speed
635
//! \param double timestamp
636
void iCubJointInterface::fetch_speed(int id, double value, double timestamp){
637

    
638
    switch(id){
639
        default:
640
            printf("> ERROR: unhandled joint id %d\n",id);
641
            return;
642

    
643
        case(2):
644
            JointInterface::store_incoming_speed(ID_NECK_PAN, value, timestamp);
645
            break;
646

    
647
        case(0):
648
            JointInterface::store_incoming_speed(ID_NECK_TILT, value, timestamp);
649
            break;
650

    
651
        case(1):
652
            JointInterface::store_incoming_speed(ID_NECK_ROLL, value, timestamp);
653
            break;
654

    
655
        case(3):
656
            JointInterface::store_incoming_speed(ID_EYES_BOTH_UD, value, timestamp);
657
            break;
658

    
659
        //icub handles eyes differently, we have to set pan angle + vergence
660
        case(4): {//pan
661
            last_vel_eye_pan = value;
662
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
663
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
664

    
665
            //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);
666
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
667
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
668
            break;
669
        }
670

    
671
        case(5): { //vergence
672
            last_vel_eye_pan = value;
673
            float left  = last_vel_eye_pan + last_vel_eye_vergence/2.0;
674
            float right = last_vel_eye_pan - last_vel_eye_vergence/2.0;
675

    
676
            //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);
677
            JointInterface::store_incoming_speed(ID_EYES_LEFT_LR, left, timestamp);
678
            JointInterface::store_incoming_speed(ID_EYES_RIGHT_LR, right, timestamp);
679
            break;
680
        }
681
    }
682
/*
683
    JointInterface::store_incoming_speed(ID_LIP_LEFT_UPPER, 0.0, timestamp);
684
    JointInterface::store_incoming_speed(ID_LIP_LEFT_LOWER, 0.0, timestamp);
685
    JointInterface::store_incoming_speed(ID_LIP_CENTER_UPPER, 0.0, timestamp);
686
    JointInterface::store_incoming_speed(ID_LIP_CENTER_LOWER, 0.0, timestamp);
687
    JointInterface::store_incoming_speed(ID_LIP_RIGHT_UPPER, 0.0, timestamp);
688
    JointInterface::store_incoming_speed(ID_LIP_RIGHT_LOWER, 0.0, timestamp);
689

690
    JointInterface::store_incoming_speed(ID_EYES_LEFT_LID_LOWER, 0.0, timestamp);
691
    JointInterface::store_incoming_speed(ID_EYES_LEFT_LID_UPPER, 0.0, timestamp);
692
    JointInterface::store_incoming_speed(ID_EYES_LEFT_BROW, 0.0, timestamp);
693

694
    JointInterface::store_incoming_speed(ID_EYES_RIGHT_LID_LOWER, 0.0, timestamp);
695
    JointInterface::store_incoming_speed(ID_EYES_RIGHT_LID_UPPER,0.0, timestamp);
696
    JointInterface::store_incoming_speed(ID_EYES_RIGHT_BROW, 0.0, timestamp);*/
697
    /*
698
    //fetch enum id:
699
    int e = convert_motorid_to_enum(device->get_device_id());
700
    if (e == -1){
701
        return; //we are not interested in that data, so we just return here
702
    }
703

704
    JointInterface::store_incoming_speed(e, device->get_register(XSC3_REGISTER_MOTORSPEED), timestamp);*/
705

    
706
}
707
/*
708
//! conversion table for humotion motor ids to our ids:
709
//! \param enum from JointInterface::JOINT_ID_ENUM
710
//! \return int value of motor id
711
int HumotionJointInterface::convert_enum_to_motorid(int e){
712
    enum_id_bimap_t::right_const_iterator it = enum_id_bimap.right.find(e);
713
    if(it == enum_id_bimap.right.end()) {
714
        //key does not exists, we are not interested in that dataset, return -1
715
        return -1;
716
    }
717

718
    return it->second;
719
}
720

721

722
//! conversion table for our ids to humotion motor ids:
723
//! \param  int value of motor id
724
//! \return enum from JointInterface::JOINT_ID_ENUM
725
int HumotionJointInterface::convert_motorid_to_enum(int id){
726
    enum_id_bimap_t::left_const_iterator it = enum_id_bimap.left.find(id);
727
    if(it == enum_id_bimap.left.end()) {
728
        //key does not exists, we are not interested in that dataset, return -1
729
        return -1;
730
    }
731

732
    return it->second;
733
}
734
*/
735

    
736
//! prepare and enable a joint
737
//! NOTE: this should also prefill the min/max positions for this joint
738
//! \param the enum id of a joint
739
void iCubJointInterface::enable_joint(int e){
740
    //FIXME ADD THIS:
741
    // enable the amplifier and the pid controller on each joint
742
    /*for (i = 0; i < nj; i++) {
743
       amp->enableAmp(i);
744
       pid->enablePid(i);
745
    }*/
746

    
747

    
748
    //set up smooth motion controller
749
    //step1: set up framerate
750
    //dev->set_register_blocking(XSC3_REGISTER_PID_RAMP, framerate, true);
751

    
752
    //step2: set controllertype:
753
    //printf("> activating smooth motion control for joint id 0x%02X (%s)\n", motor_id, joint_name.c_str());
754
    //dev->set_register_blocking(XSC3_REGISTER_PID_CONTROLLER, XSC3_PROTOCOL_PID_CONTROLLERTYPE_SMOOTH_PLAYBACK, true);
755

    
756
    //step3: set pid controller:
757
    /*if ((e == ID_LIP_LEFT_UPPER) || (e == ID_LIP_LEFT_LOWER) || (e == ID_LIP_CENTER_UPPER) || (e == ID_LIP_CENTER_LOWER) || (e == ID_LIP_RIGHT_UPPER) || (e == ID_LIP_RIGHT_LOWER)){
758
        printf("> fixing PID i controller value for smooth motion (FIXME: restore old value!!)\n");
759
        dev->set_register_blocking(XSC3_REGISTER_CONST_I, 10, true);
760
    }*/
761

    
762
    //uint16_t result = dev->get_register_blocking_raw(XSC3_REGISTER_PID_CONTROLLER);
763

    
764
    //check if setting pid controllertype was successfull:
765
    /*if (result != XSC3_PROTOCOL_PID_CONTROLLERTYPE_SMOOTH_PLAYBACK){
766
        printf("> failed to set smooth motion controller for joint %s (res=0x%04X)\n",joint_name.c_str(),result);
767
        exit(1);
768
    }*/
769

    
770
    //fetch min/max:
771
   // init_joint(e);
772

    
773
    //ok fine, now enable motor:
774
    //printf("> enabling motor %s\n", joint_name.c_str());
775
    //dev->set_register_blocking(XSC3_REGISTER_STATUS, XSC3_PROTOCOL_STATUS_BITMASK_MOTOR_ENABLE, true);
776

    
777
}
778

    
779
void iCubJointInterface::store_min_max(IControlLimits *ilimits, int id, int e){
780
    double min, max;
781
    ilimits->getLimits(id, &min, &max);
782
    joint_min[e] = min;
783
    joint_max[e] = max;
784
}
785

    
786
//! initialise a joint (set up controller mode etc)
787
//! \param joint enum
788
void iCubJointInterface::init_joints(){
789
    store_min_max(ilimits, 0, ID_NECK_TILT);
790
    store_min_max(ilimits, 1, ID_NECK_ROLL);
791
    store_min_max(ilimits, 2, ID_NECK_PAN);
792
    store_min_max(ilimits, 3, ID_EYES_BOTH_UD);
793

    
794
    //icub handles eyes differently, we have to set pan angle + vergence
795
    double pan_min, pan_max, vergence_min, vergence_max;
796
    ilimits->getLimits(4, &pan_min, &pan_max);
797
    ilimits->getLimits(5, &vergence_min, &vergence_max);
798

    
799
    //this is not 100% correct, should be fixed:
800
    joint_min[ID_EYES_LEFT_LR] = pan_min; // - vergence_max/2;
801
    joint_max[ID_EYES_LEFT_LR] = pan_max; // - vergence_max/2;
802
    joint_min[ID_EYES_RIGHT_LR] = joint_min[ID_EYES_LEFT_LR];
803
    joint_max[ID_EYES_RIGHT_LR] = joint_max[ID_EYES_LEFT_LR];
804

    
805
    //eyelids:
806
    joint_min[ID_EYES_RIGHT_LID_UPPER] = -50; //24-30;
807
    joint_max[ID_EYES_RIGHT_LID_UPPER] = 50; //48-30;
808
    lid_angle = joint_max[ID_EYES_RIGHT_LID_UPPER];
809

    
810
    //eyebrows:
811
    joint_min[ID_EYES_LEFT_BROW] = -50;
812
    joint_max[ID_EYES_LEFT_BROW] = 50;
813
    joint_min[ID_EYES_RIGHT_BROW] = joint_min[ID_EYES_LEFT_BROW];
814
    joint_max[ID_EYES_RIGHT_BROW] = joint_max[ID_EYES_LEFT_BROW];
815

    
816
    //mouth:
817
    joint_min[ID_LIP_CENTER_UPPER] = 5;
818
    joint_max[ID_LIP_CENTER_UPPER] = 50;
819
    joint_min[ID_LIP_CENTER_LOWER] = 5;
820
    joint_max[ID_LIP_CENTER_LOWER] = 50;
821
    joint_min[ID_LIP_LEFT_UPPER] = 5;
822
    joint_max[ID_LIP_LEFT_UPPER] = 50;
823
    joint_min[ID_LIP_LEFT_LOWER] = 5;
824
    joint_max[ID_LIP_LEFT_LOWER] = 50;
825
    joint_min[ID_LIP_RIGHT_UPPER] = 5;
826
    joint_max[ID_LIP_RIGHT_UPPER] = 50;
827
    joint_min[ID_LIP_RIGHT_LOWER] = 5;
828
    joint_max[ID_LIP_RIGHT_LOWER] = 50;
829

    
830

    
831
}
832

    
833
//! shutdown and disable a joint
834
//! \param the enum id of a joint
835
void iCubJointInterface::disable_joint(int e){
836
    /*
837
        //first: convert humotion enum to our enum:
838
        int motor_id = convert_enum_to_motorid(e);
839
        if (motor_id == -1){
840
            return; //we are not interested in that data, so we just return here
841
        }
842

843
        //fetch device:
844
        Device *dev = get_device(motor_id);
845
        printf("> FIXME: ADD DISABLE CODE\n");
846
        printf("> FIXME: ADD DISABLE CODE\n");
847
        printf("> FIXME: ADD DISABLE CODE\n");
848
        printf("> FIXME: ADD DISABLE CODE\n");
849
        printf("> FIXME: ADD DISABLE CODE\n");
850
        printf("> FIXME: ADD DISABLE CODE\n");
851
        printf("> FIXME: ADD DISABLE CODE\n");
852
        printf("> FIXME: ADD DISABLE CODE\n");
853
        printf("> FIXME: ADD DISABLE CODE\n");
854
        */
855
}
856
#endif