Statistics
| Branch: | Tag: | Revision:

humotion / src / server / gaze_motion_generator.cpp @ 51a1f01d

History | View | Annotate | Download (6.024 KB)

1
/*
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/server/gaze_motion_generator.h"
29
#include "humotion/server/server.h"
30

    
31
using humotion::server::GazeMotionGenerator;
32
using humotion::server::Config;
33

    
34
//! constructor
35
GazeMotionGenerator::GazeMotionGenerator(JointInterface *j, Config *cfg, int dof, float t)
36
    : ReflexxesMotionGenerator(j, cfg, dof, t) {
37
}
38

    
39
//! destructor
40
GazeMotionGenerator::~GazeMotionGenerator() {
41
}
42

    
43
//! update gaze target:
44
//! \param GazeState with target values for the overall gaze
45
void GazeMotionGenerator::set_gaze_target(GazeState new_gaze_target) {
46
    if (requested_gaze_state_.gaze_type == GazeState::GAZETYPE_RELATIVE) {
47
        printf("> ERROR: gaze targets should be converted to absolute before calling this\n");
48
        exit(EXIT_FAILURE);
49
    }
50

    
51
    // check magnitude of gaze change to detect eye-neck saccades
52
    float dist = fabs(requested_gaze_state_.distance_pt_abs(new_gaze_target));
53

    
54
    // check requested speed
55
    float speed = fabs(requested_gaze_state_.distance_pt_abs(new_gaze_target))
56
            / (new_gaze_target.timestamp.to_seconds()-requested_gaze_state_.timestamp.to_seconds());
57

    
58
    // check magnitude and speed of gaze change to detect eye-neck saccades
59
    if (dist > config->threshold_angle_neck_saccade) {
60
        // the next saccade has to use neck motion as well
61
        if (speed > config->threshold_velocity_eye_saccade) {
62
            neck_saccade_requested = true;
63
        }
64
    } else {
65
        neck_saccade_requested = false;
66
    }
67

    
68
    // check for eye getting close to ocolomotor range
69
    // actually it makes more sense to trigger the neck saccade based on
70
    // the target getting out of the OMR
71
    float eye_target_l  = joint_interface_->get_target_position(JointInterface::ID_EYES_LEFT_LR);
72
    float eye_target_r  = joint_interface_->get_target_position(JointInterface::ID_EYES_RIGHT_LR);
73
    float eye_target_ud = joint_interface_->get_target_position(JointInterface::ID_EYES_BOTH_UD);
74

    
75
    // min/max bounds
76
    float left_min  = config->threshold_angle_omr_limit *
77
            joint_interface_->get_joint_min(JointInterface::ID_EYES_LEFT_LR);
78
    float left_max  = config->threshold_angle_omr_limit *
79
            joint_interface_->get_joint_max(JointInterface::ID_EYES_LEFT_LR);
80
    float right_min = config->threshold_angle_omr_limit *
81
            joint_interface_->get_joint_min(JointInterface::ID_EYES_RIGHT_LR);
82
    float right_max = config->threshold_angle_omr_limit *
83
            joint_interface_->get_joint_max(JointInterface::ID_EYES_RIGHT_LR);
84
    float ud_min    = config->threshold_angle_omr_limit *
85
            joint_interface_->get_joint_min(JointInterface::ID_EYES_BOTH_UD);
86
    float ud_max    = config->threshold_angle_omr_limit *
87
            joint_interface_->get_joint_max(JointInterface::ID_EYES_BOTH_UD);
88

    
89
    if (
90
            (eye_target_l < left_min) || (eye_target_l > left_max) ||
91
            (eye_target_r < right_min) || (eye_target_r > right_max) ||
92
            (eye_target_ud < ud_min) || (eye_target_ud > ud_max)) {
93
        // the eyeball gets close to OMR, activate a neck compensation motion
94
        neck_saccade_omr = true;
95
    } else {
96
        neck_saccade_omr = false;
97
    }
98

    
99
    // use base class set method
100
    MotionGenerator::set_gaze_target(new_gaze_target);
101
}
102

    
103
//! check if an eye saccade is active:
104
bool GazeMotionGenerator::get_eye_saccade_active() {
105
    bool saccade_active;
106

    
107
    float speed_left  = joint_interface_->get_ts_speed(
108
                JointInterface::ID_EYES_LEFT_LR).get_newest_value();
109
    float speed_right = joint_interface_->get_ts_speed(
110
                JointInterface::ID_EYES_RIGHT_LR).get_newest_value();
111
    float speed_tilt  = joint_interface_->get_ts_speed(
112
                JointInterface::ID_EYES_BOTH_UD).get_newest_value();
113

    
114
    float speed_total_l = sqrt(speed_left*speed_left + speed_tilt*speed_tilt);
115
    float speed_total_r = sqrt(speed_right*speed_right + speed_tilt*speed_tilt);
116

    
117
    // thresholding
118
    if ((speed_total_l > config->threshold_velocity_eye_saccade) ||
119
            (speed_total_r > config->threshold_velocity_eye_saccade)) {
120
        // this is a saccade
121
        saccade_active = true;
122
    } else {
123
        saccade_active = false;
124
    }
125

    
126
    return saccade_active;
127
}
128

    
129
//! get overall gaze
130
humotion::GazeState GazeMotionGenerator::get_current_gaze() {
131
    // shortcut, makes the following easier to read
132
    JointInterface *j = joint_interface_;
133

    
134
    GazeState gaze = requested_gaze_state_;
135

    
136
    gaze.pan = j->get_ts_position(JointInterface::ID_NECK_PAN).get_newest_value() +
137
            (j->get_ts_position(JointInterface::ID_EYES_LEFT_LR).get_newest_value()
138
             + j->get_ts_position(JointInterface::ID_EYES_RIGHT_LR).get_newest_value())/2.0;
139
    gaze.tilt = j->get_ts_position(JointInterface::ID_NECK_TILT).get_newest_value()
140
            + j->get_ts_position(JointInterface::ID_EYES_BOTH_UD).get_newest_value();
141
    gaze.roll = j->get_ts_position(JointInterface::ID_NECK_ROLL).get_newest_value();
142

    
143
    gaze.vergence = j->get_ts_position(JointInterface::ID_EYES_LEFT_LR).get_newest_value()
144
            - j->get_ts_position(JointInterface::ID_EYES_RIGHT_LR).get_newest_value();
145

    
146
    return gaze;
147
}