Statistics
| Branch: | Tag: | Revision:

humotion / src / server / gaze_motion_generator.cpp @ 6de0fc2e

History | View | Annotate | Download (6.024 KB)

1 8c6c1163 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 0c8d22a5 sschulz
#include "humotion/server/gaze_motion_generator.h"
29
#include "humotion/server/server.h"
30 8c6c1163 Simon Schulz
31 0c8d22a5 sschulz
using humotion::server::GazeMotionGenerator;
32 6d13138a sschulz
using humotion::server::Config;
33 8c6c1163 Simon Schulz
34
//! constructor
35 6d13138a sschulz
GazeMotionGenerator::GazeMotionGenerator(JointInterface *j, Config *cfg, int dof, float t)
36
    : ReflexxesMotionGenerator(j, cfg, dof, t) {
37 8c6c1163 Simon Schulz
}
38
39
//! destructor
40 0c8d22a5 sschulz
GazeMotionGenerator::~GazeMotionGenerator() {
41 8c6c1163 Simon Schulz
}
42
43
//! update gaze target:
44
//! \param GazeState with target values for the overall gaze
45 0c8d22a5 sschulz
void GazeMotionGenerator::set_gaze_target(GazeState new_gaze_target) {
46 ea068cf1 sschulz
    if (requested_gaze_state_.gaze_type == GazeState::GAZETYPE_RELATIVE) {
47 1c758459 Simon Schulz
        printf("> ERROR: gaze targets should be converted to absolute before calling this\n");
48
        exit(EXIT_FAILURE);
49 8c6c1163 Simon Schulz
    }
50
51 0c8d22a5 sschulz
    // check magnitude of gaze change to detect eye-neck saccades
52 ea068cf1 sschulz
    float dist = fabs(requested_gaze_state_.distance_pt_abs(new_gaze_target));
53 8c6c1163 Simon Schulz
54 0c8d22a5 sschulz
    // check requested speed
55 ea068cf1 sschulz
    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 8c6c1163 Simon Schulz
58 0c8d22a5 sschulz
    // check magnitude and speed of gaze change to detect eye-neck saccades
59 6d13138a sschulz
    if (dist > config->threshold_angle_neck_saccade) {
60 0c8d22a5 sschulz
        // the next saccade has to use neck motion as well
61 6d13138a sschulz
        if (speed > config->threshold_velocity_eye_saccade) {
62 8c6c1163 Simon Schulz
            neck_saccade_requested = true;
63
        }
64 0c8d22a5 sschulz
    } else {
65 8c6c1163 Simon Schulz
        neck_saccade_requested = false;
66
    }
67
68 0c8d22a5 sschulz
    // 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 ea068cf1 sschulz
    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 8c6c1163 Simon Schulz
75 0c8d22a5 sschulz
    // min/max bounds
76 6d13138a sschulz
    float left_min  = config->threshold_angle_omr_limit *
77 ea068cf1 sschulz
            joint_interface_->get_joint_min(JointInterface::ID_EYES_LEFT_LR);
78 6d13138a sschulz
    float left_max  = config->threshold_angle_omr_limit *
79 ea068cf1 sschulz
            joint_interface_->get_joint_max(JointInterface::ID_EYES_LEFT_LR);
80 6d13138a sschulz
    float right_min = config->threshold_angle_omr_limit *
81 ea068cf1 sschulz
            joint_interface_->get_joint_min(JointInterface::ID_EYES_RIGHT_LR);
82 6d13138a sschulz
    float right_max = config->threshold_angle_omr_limit *
83 ea068cf1 sschulz
            joint_interface_->get_joint_max(JointInterface::ID_EYES_RIGHT_LR);
84 6d13138a sschulz
    float ud_min    = config->threshold_angle_omr_limit *
85 ea068cf1 sschulz
            joint_interface_->get_joint_min(JointInterface::ID_EYES_BOTH_UD);
86 6d13138a sschulz
    float ud_max    = config->threshold_angle_omr_limit *
87 ea068cf1 sschulz
            joint_interface_->get_joint_max(JointInterface::ID_EYES_BOTH_UD);
88 8c6c1163 Simon Schulz
89
    if (
90 7ed40bef Simon Schulz
            (eye_target_l < left_min) || (eye_target_l > left_max) ||
91
            (eye_target_r < right_min) || (eye_target_r > right_max) ||
92 0c8d22a5 sschulz
            (eye_target_ud < ud_min) || (eye_target_ud > ud_max)) {
93
        // the eyeball gets close to OMR, activate a neck compensation motion
94 8c6c1163 Simon Schulz
        neck_saccade_omr = true;
95 0c8d22a5 sschulz
    } else {
96 8c6c1163 Simon Schulz
        neck_saccade_omr = false;
97
    }
98
99 0c8d22a5 sschulz
    // use base class set method
100 8c6c1163 Simon Schulz
    MotionGenerator::set_gaze_target(new_gaze_target);
101
}
102
103
//! check if an eye saccade is active:
104 0c8d22a5 sschulz
bool GazeMotionGenerator::get_eye_saccade_active() {
105 8c6c1163 Simon Schulz
    bool saccade_active;
106
107 ea068cf1 sschulz
    float speed_left  = joint_interface_->get_ts_speed(
108 0c8d22a5 sschulz
                JointInterface::ID_EYES_LEFT_LR).get_newest_value();
109 ea068cf1 sschulz
    float speed_right = joint_interface_->get_ts_speed(
110 0c8d22a5 sschulz
                JointInterface::ID_EYES_RIGHT_LR).get_newest_value();
111 ea068cf1 sschulz
    float speed_tilt  = joint_interface_->get_ts_speed(
112 0c8d22a5 sschulz
                JointInterface::ID_EYES_BOTH_UD).get_newest_value();
113 8c6c1163 Simon Schulz
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 0c8d22a5 sschulz
    // thresholding
118 6d13138a sschulz
    if ((speed_total_l > config->threshold_velocity_eye_saccade) ||
119
            (speed_total_r > config->threshold_velocity_eye_saccade)) {
120 0c8d22a5 sschulz
        // this is a saccade
121 8c6c1163 Simon Schulz
        saccade_active = true;
122 0c8d22a5 sschulz
    } else {
123 8c6c1163 Simon Schulz
        saccade_active = false;
124
    }
125
126
    return saccade_active;
127
}
128
129
//! get overall gaze
130 0c8d22a5 sschulz
humotion::GazeState GazeMotionGenerator::get_current_gaze() {
131
    // shortcut, makes the following easier to read
132 ea068cf1 sschulz
    JointInterface *j = joint_interface_;
133 8c6c1163 Simon Schulz
134 ea068cf1 sschulz
    GazeState gaze = requested_gaze_state_;
135 8c6c1163 Simon Schulz
136
    gaze.pan = j->get_ts_position(JointInterface::ID_NECK_PAN).get_newest_value() +
137 0c8d22a5 sschulz
            (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 8c6c1163 Simon Schulz
    gaze.roll = j->get_ts_position(JointInterface::ID_NECK_ROLL).get_newest_value();
142
143 0c8d22a5 sschulz
    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 8c6c1163 Simon Schulz
146
    return gaze;
147
}