Revision 6d13138a

View differences:

CMakeLists.txt
106 106

  
107 107
## Declare a cpp library
108 108
add_library(${PROJECT_NAME}
109
    src/mouth_state.cpp
110
    src/gaze_state.cpp
111

  
112 109
    src/client/client.cpp
113 110
    src/client/middleware.cpp
114 111
    src/client/middleware_ros.cpp
115 112

  
116 113
    src/server/server.cpp
114
    src/server/config.cpp
117 115
    src/server/middleware.cpp
118 116
    src/server/middleware_ros.cpp
119

  
120 117
    src/server/controller.cpp
121 118
    src/server/joint_interface.cpp
122 119
    src/server/motion_generator.cpp
......
127 124
    src/server/eyelid_motion_generator.cpp
128 125
    src/server/eyebrow_motion_generator.cpp
129 126
    src/server/neck_motion_generator.cpp
127

  
128
    src/mouth_state.cpp
129
    src/gaze_state.cpp
130 130
    src/timestamp.cpp
131 131
    src/timestamped_list.cpp
132 132
)
cfg/humotion.cfg
4 4

  
5 5
gen = ParameterGenerator()
6 6

  
7
group = gen.add_group("My Group")
8
group.add("my_group_param", int_t, 0, "An int within My Group", 0)
7
general_group = gen.add_group("general")
8
general_group.add("eye_saccade_velocity_threshold", double_t, 0, "eye velocity threshold for saccade detection (in deg/s)", 15.0, 1.0, 30.0)
9
general_group.add("neck_saccade_threshold", double_t, 0, "magnitude of gaze change that triggers neck saccade (in deg)", 15.0, 1.0, 30.0)
10
general_group.add("neck_saccade_omr_trigger", double_t, 0, "a deflection exceeding <VAL> * OMR will trigger a correction neck saccade", 0.95, 0.1, 1.0)
11

  
12
neck_group = gen.add_group("neck")
13
neck_group.add("neck_max_acceleration", int_t, 0, "maximum neck acceleration limit (in deg/s^2)", 1000, 100, 4000)
14
neck_group.add("neck_max_velocity", int_t, 0, "maximum neck velocity limit (in deg/s)", 1000, 100, 800)
15
neck_group.add("neck_velocity_scale", double_t, 0, "scaling factor for neck accelerations (1.0 = full human velocities)", 0.7, 0.1, 1.0)
16

  
17
#float max_speed = (CONST_GUITTON87_A * distance_abs + CONST_GUITTON87_B);
18
neck_group.add("neck_velocity_lin_eq_const_a", double_t, 0, "constant A (scale) for linear velocity equation (guitton 4.39)", 4.39 / 2.0, 1.0, 10.0)
19
neck_group.add("neck_velocity_lin_eq_const_b", double_t, 0, "constant B (offset) for linear velocity equation (guitton 4.39)", 106.0 / 2.0, 1, 200)
20

  
21
#others
22
neck_group.add("neck_breath_period", int_t, 0, "breath period (inhale+pause+exhale) in ms)", 3*1500, 3000, 5000)
23
neck_group.add("neck_breath_amplitude", double_t, 0, "amplitude of head tilt deflection during breath (given in deg)", 1.0, 0.0, 5.0)
24

  
25
eye_group = gen.add_group("eye")
26
eye_group.add("eye_max_acceleration", int_t, 0, "maximum eye acceleration limit (in deg/s^2)", 80000, 1000, 80000)
27
eye_group.add("eye_max_velocity", int_t, 0, "maximum eye velocity limit (in deg/s)", 700, 100, 700)
28
eye_group.add("eye_velocity_scale", double_t, 0, "scaling factor for eye accelerations (1.0 = full human velocities)", 1.0, 0.1, 1.0)
29

  
30
eyeblink_group = gen.add_group("eyeblink")
31
eyeblink_group.add("eyeblink_duration", int_t, 0, "eyeblink duration (in ms)", 150, 50, 500)
32
eyeblink_group.add("eyeblink_every_min", int_t, 0, "eyeblink every n ms, lower bound (in ms)",  2000, 1000, 10000)
33
eyeblink_group.add("eyeblink_every_max", int_t, 0, "eyeblink every n ms, upper bound (in ms)", 10000, 1000, 20000)
34
eyeblink_group.add("eyeblink_blocking_time", int_t, 0, "eyeblink blocked timeout (in ms)", 1000, 100, 5000)
35

  
36

  
37

  
38

  
39
#eyelid:
40
# static const float SACCADE_SPEED_THRESHOLD;
41
#    static const float EYEBLINK_DURATION_MS;
42
#    static const float EYEBLINK_EYERY_MS_MIN;
43
#    static const float EYEBLINK_EYERY_MS_MAX;
44
#    static const float EYEBLINK_BLOCKING_TIME;
45
#
46

  
47
# static const float MOUTH_MIN_OPENING;
48
#
49
#neck
50
#    static const float CONST_GUITTON87_A;
51
#    static const float CONST_GUITTON87_B;
52
#
53
#    static const float CONST_BREATH_PERIOD;
54
#    static const float CONST_BREATH_AMPLITUDE;
55
#
56
#misc for neck and eyes:
57
#max accel
58
#v_scale
9 59

  
10 60
#timing_mode_enum = gen.enum([
11 61
#    gen.const("free_running", int_t, 0, "camera acquires images at a maximum possible framerate"),
include/humotion/server/config.h
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

  
29
#ifndef INCLUDE_HUMOTION_SERVER_CONFIG_H_
30
#define INCLUDE_HUMOTION_SERVER_CONFIG_H_
31

  
32
namespace humotion {
33
namespace server {
34

  
35
class Config {
36
 public:
37
    Config();
38
    ~Config();
39
    void init_defaults();
40

  
41
    // ********************************************************
42
    // NOTE: See config.cpp for explanations and default values
43
    // ********************************************************
44

  
45
    // saccade detection thresholds
46
    float threshold_velocity_eye_saccade;
47
    float threshold_angle_neck_saccade;
48
    float threshold_angle_omr_limit;
49

  
50

  
51
    // neck motion generation configuration
52
    float scale_velocity_neck;
53
    float scale_acceleration_neck;
54
    float limit_velocity_neck;
55
    float limit_acceleration_neck;
56

  
57
    // eye motion generation configuration
58
    float scale_velocity_eye;
59
    float scale_acceleration_eye;
60
    float limit_velocity_eye;
61
    float limit_acceleration_eye;
62

  
63
    // parameters fo the breathing pattern
64
    float breath_period;
65
    float breath_amplitude;
66

  
67
    // parameters for eye blinking
68
    float eyeblink_duration;
69
    float eyeblink_periodic_distribution_lower;
70
    float eyeblink_periodic_distribution_upper;
71
    float eyeblink_probability_after_saccade;
72
    float eyeblink_blocked_time;
73
};
74

  
75
}  // namespace server
76
}  // namespace humotion
77

  
78
#endif  // INCLUDE_HUMOTION_SERVER_CONFIG_H_
include/humotion/server/controller.h
32 32

  
33 33
#include "humotion/gaze_state.h"
34 34
#include "humotion/mouth_state.h"
35
#include "humotion/server/config.h"
35 36
#include "humotion/server/joint_interface.h"
36 37
#include "humotion/server/motion_generator.h"
37 38
#include "humotion/timestamp.h"
......
60 61
    motion_generator_vector_t motion_generator_vector_;
61 62

  
62 63
    JointInterface *joint_interface_;
64
    Config *config_;
63 65

  
64 66
    bool activated_;
65 67

  
include/humotion/server/eye_motion_generator.h
36 36

  
37 37
class EyeMotionGenerator : public GazeMotionGenerator {
38 38
 public:
39
    explicit EyeMotionGenerator(JointInterface *j);
39
    EyeMotionGenerator(JointInterface *j, Config *cfg);
40 40
    ~EyeMotionGenerator();
41 41

  
42 42
    void calculate_targets();
43 43
    void publish_targets();
44 44

  
45 45

  
46
    static const float SACCADE_SPEED_THRESHOLD;
46
    // static const float SACCADE_SPEED_THRESHOLD;
47 47
 private:
48 48
    void setup_eyemotion(int dof, float target, float current_position,
49 49
                         float current_velocity, Timestamp timestamp);
include/humotion/server/eyebrow_motion_generator.h
35 35

  
36 36
class EyebrowMotionGenerator : public MotionGenerator {
37 37
 public:
38
    explicit EyebrowMotionGenerator(JointInterface *j);
38
    explicit EyebrowMotionGenerator(JointInterface *j, Config *cfg);
39 39
    ~EyebrowMotionGenerator();
40 40
    void calculate_targets();
41 41
    void publish_targets();
include/humotion/server/eyelid_motion_generator.h
38 38

  
39 39
class EyelidMotionGenerator : public EyeMotionGenerator {
40 40
 public:
41
    explicit EyelidMotionGenerator(JointInterface *j);
41
    EyelidMotionGenerator(JointInterface *j, Config *cfg);
42 42
    ~EyelidMotionGenerator();
43 43

  
44 44
    void calculate_targets();
......
53 53
    void handle_eyeblink_timeout();
54 54
    void override_lids_for_eyeblink();
55 55
    void check_for_saccade();
56
    void start_eyeblink(int side, int duration = EYEBLINK_DURATION_MS);
56
    void start_eyeblink(int side, int duration);
57 57

  
58 58
    void close_eyelid(int joint_id);
59 59

  
......
69 69
    bool eyeblink_active_[SIDE_ID_SIZE];
70 70
    bool eyelid_closed_[SIDE_ID_SIZE];
71 71

  
72
    static const float SACCADE_SPEED_THRESHOLD;
73
    static const float EYEBLINK_DURATION_MS;
74
    static const float EYEBLINK_EYERY_MS_MIN;
75
    static const float EYEBLINK_EYERY_MS_MAX;
76
    static const float EYEBLINK_BLOCKING_TIME;
77

  
78 72
    boost::system_time periodic_blink_start_time_;
79 73
    boost::system_time eyeblink_timeout_[SIDE_ID_SIZE];
80 74
    boost::system_time eyeblink_blocked_timeout_;
include/humotion/server/gaze_motion_generator.h
36 36

  
37 37
class GazeMotionGenerator : public ReflexxesMotionGenerator {
38 38
 public:
39
    GazeMotionGenerator(JointInterface *j, int dof, float t);
39
    GazeMotionGenerator(JointInterface *j, Config *cfg, int dof, float t);
40 40
    ~GazeMotionGenerator();
41 41

  
42 42
    void set_gaze_target(GazeState s);
43 43

  
44
    static const float SACCADE_SPEED_THRESHOLD;
45
    static const float SACCADE_LATENCY;
46

  
47 44
 protected:
48 45
    GazeState get_current_gaze();
49 46

  
50 47
    bool get_eye_saccade_active();
51 48
    bool neck_saccade_requested;
52 49
    bool neck_saccade_omr;
53

  
54
 private:
55
    // constants
56
    static const float NECK_SACCADE_THRESHOLD;
57
    static const float EYE_SACCADE_SPEED_THRESHOLD;
58
    static const float OMR_LIMIT_TRIGGERS_NECK_SACCADE;
59 50
};
60 51

  
61 52
}  // namespace server
include/humotion/server/motion_generator.h
32 32

  
33 33
#include <string>
34 34

  
35
#include "humotion/server/config.h"
35 36
#include "humotion/server/joint_interface.h"
36 37

  
37 38
namespace humotion {
......
39 40

  
40 41
class MotionGenerator {
41 42
 public:
42
    explicit MotionGenerator(JointInterface *j);
43
    MotionGenerator(JointInterface *j, Config *cfg);
43 44
    ~MotionGenerator();
44 45

  
45 46
    virtual void calculate_targets() = 0;
......
49 50
    virtual void set_mouth_target(MouthState s);
50 51

  
51 52
 protected:
53
    Config *config;
54

  
52 55
    float get_current_position(int joint_id);
53 56
    float get_current_speed(int joint_id);
54 57
    humotion::Timestamp get_timestamped_state(int joint_id, float *position, float *velocity);
include/humotion/server/mouth_motion_generator.h
35 35

  
36 36
class MouthMotionGenerator : public MotionGenerator {
37 37
 public:
38
    explicit MouthMotionGenerator(JointInterface *j);
38
    MouthMotionGenerator(JointInterface *j, Config *cfg);
39 39
    ~MouthMotionGenerator();
40 40
    void calculate_targets();
41 41
    void publish_targets();
include/humotion/server/neck_motion_generator.h
34 34

  
35 35
class NeckMotionGenerator : public GazeMotionGenerator {
36 36
 public:
37
    explicit NeckMotionGenerator(JointInterface *j);
37
    NeckMotionGenerator(JointInterface *j, Config *cfg);
38 38
    ~NeckMotionGenerator();
39 39
    void calculate_targets();
40 40
    void publish_targets();
......
49 49
    bool neck_saccade_reached_goal_;
50 50
    bool neck_saccade_active_;
51 51
    float breath_time_;
52

  
53
    static const float CONST_GUITTON87_A;
54
    static const float CONST_GUITTON87_B;
55

  
56
    static const float CONST_BREATH_PERIOD;
57
    static const float CONST_BREATH_AMPLITUDE;
58 52
};
59 53

  
60 54
}  // namespace server
include/humotion/server/reflexxes_motion_generator.h
40 40

  
41 41
class ReflexxesMotionGenerator : public MotionGenerator{
42 42
 public:
43
    ReflexxesMotionGenerator(JointInterface *j, int dof, float t);
43
    ReflexxesMotionGenerator(JointInterface *j, Config *cfg, int dof, float t);
44 44
    ~ReflexxesMotionGenerator();
45 45

  
46 46
 protected:
src/server/config.cpp
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/config.h"
29

  
30
using humotion::server::Config;
31

  
32
Config::Config() {
33
    init_defaults();
34
}
35

  
36

  
37
Config::~Config() {
38
}
39

  
40
void Config::init_defaults() {
41
    // saccade detection thresholds:
42
    // 1) velocity threshold, values above this value trigger an eye saccade
43
    //    value is given in deg/s
44
    threshold_velocity_eye_saccade = 15.0;
45

  
46
    // 2) angular threshold, a target change higher than this value will trigger a neck saccade
47
    //    value is given in deg
48
    threshold_angle_neck_saccade = 15.0;
49

  
50
    // 3) eyes reaching ocolumotor limits will trigger correction saccade
51
    //    value given in percent (NOTE: 1.0 = 100%)
52
    threshold_angle_omr_limit = 0.95;
53

  
54

  
55
    // neck motion generation configuration
56
    // humotion calculates neck velocities based on the linear equation Hmax from
57
    // [Guitton87] "Gaze control in humans: eye-head coordination during orienting movements ..."
58
    // In order to allow better adaption to the robot capabilities humotion allows to
59
    // scale the calculated velocity, value is given in percent (NOTE: 1.0 = 100% human velocity)
60
    scale_velocity_neck = 0.5;
61

  
62
    // scale acceleration
63
    scale_acceleration_neck = 0.7;
64

  
65
    // additionally humotion allows to limit the maximum velocity, value is given in deg/s
66
    limit_velocity_neck = 700.0;
67

  
68
    // limit the maximum acceleration, value is given in deg/s^2
69
    limit_acceleration_neck = 1000.0;
70

  
71
    // eye motion generation configuration
72
    // scale the calculated velocity, value is given in percent (NOTE: 1.0 = 100% human velocity)
73
    scale_velocity_eye = 1.0;
74

  
75
    // scale acceleration
76
    scale_acceleration_eye = 1.0;
77

  
78
    // additionally humotion allows to limit the maximum velocity, value is given in deg/s
79
    limit_velocity_eye = 700.0;
80

  
81
    // limit the maximum acceleration, value is given in deg/s^2
82
    limit_acceleration_eye = 80000;
83

  
84

  
85
    // parameters fo the breathing pattern
86
    // healthy adult human: 12-15 breaths/min (see e.g. "Ganong's review of medical physiology")
87
    // total breathe: 60/12-15 = 3-5s
88
    // inhale 1.5-2s
89
    // exhale 1.5-2s
90
    // pause      2s
91
    // overall period given in seconds
92
    breath_period = 1.5 + 1.5 + 1.5;  // inhale, pause & exhale
93
    // amplitude given in degrees
94
    breath_amplitude = 1.0;
95

  
96

  
97
    // parameters for eye blinking
98
    // duration for one eyeblink, value is given in seconds
99
    eyeblink_duration = 0.15;
100

  
101
    // occurance of periodic eyeblinks, uniformly distributed over the given range
102
    // typical values for a human are one blink every 2...10s
103
    // values are given in seconds
104
    eyeblink_periodic_distribution_lower = 2.0;
105
    eyeblink_periodic_distribution_upper = 10.0;
106

  
107
    // probability that one eye saccade causes an eyeblink, value given in percent
108
    // for humans this is up to 95%, this gets quite annoying on the robot so the default is lower
109
    eyeblink_probability_after_saccade = 0.33;
110

  
111
    // blocking time where further eyeblinks are suppressed, value given in seconds
112
    eyeblink_blocked_time = 1000.0;
113
}
src/server/controller.cpp
38 38
// using namespace humotion::server;
39 39

  
40 40
using humotion::server::Controller;
41
using humotion::server::Config;
41 42

  
42 43
//! constructor
43 44
Controller::Controller(JointInterface *j) {
44 45
    activated_ = false;
45 46
    joint_interface_ = j;
47

  
48
    config_ = new Config();
46 49
}
47 50

  
48 51
//! destructor
......
55 58
    //       (i.e. the neck generator must be added after the eye generator!)
56 59

  
57 60
    // eye motion generation:
58
    add_motion_generator(new EyeMotionGenerator(joint_interface_));
61
    add_motion_generator(new EyeMotionGenerator(joint_interface_, config_));
59 62

  
60 63
    // eyelid motion generator
61
    add_motion_generator(new EyelidMotionGenerator(joint_interface_));
64
    add_motion_generator(new EyelidMotionGenerator(joint_interface_, config_));
62 65

  
63 66
    // neck motion generator
64
    add_motion_generator(new NeckMotionGenerator(joint_interface_));
67
    add_motion_generator(new NeckMotionGenerator(joint_interface_, config_));
65 68

  
66 69
    // mouth motion generator
67
    add_motion_generator(new MouthMotionGenerator(joint_interface_));
70
    add_motion_generator(new MouthMotionGenerator(joint_interface_, config_));
68 71

  
69 72
    // eyebrow motion generator
70
    add_motion_generator(new EyebrowMotionGenerator(joint_interface_));
73
    add_motion_generator(new EyebrowMotionGenerator(joint_interface_, config_));
71 74
}
72 75

  
73 76
//! add a single motion genrator
src/server/eye_motion_generator.cpp
34 34

  
35 35
using humotion::server::EyeMotionGenerator;
36 36

  
37
// saccade detection threshold in deg/s
38
const float EyeMotionGenerator::SACCADE_SPEED_THRESHOLD = 15.0;
39

  
40 37
//! constructor
41
EyeMotionGenerator::EyeMotionGenerator(JointInterface *j) :
42
    GazeMotionGenerator(j, 3, 1.0/Server::MOTION_UPDATERATE) {
38
EyeMotionGenerator::EyeMotionGenerator(JointInterface *j, Config *cfg) :
39
    GazeMotionGenerator(j, cfg, 3, 1.0/Server::MOTION_UPDATERATE) {
43 40
}
44 41

  
45 42

  
......
58 55
                                         humotion::Timestamp timestamp) {
59 56
    // get distance to target:
60 57
    float distance_abs = fabs(target - current_position);
58

  
61 59
    // get max speed: factor can be found in encyc britannica:
62 60
    // "linear.... being 300° per second for 10° and 500° per second for 30°" (max=700)
63
    float max_speed = fmin(700.0, 10.0*distance_abs + 200.0);
61
    float max_velocity = fmin(700.0, 10.0*distance_abs + 200.0);
62

  
63
    // scale and limit max speed
64
    max_velocity = max_velocity * config->scale_velocity_eye;
65
    max_velocity = fmin(max_velocity, config->limit_velocity_eye);
66

  
64 67
    // max accel: use data from:
65 68
    // "Speed and Accuracy of Saccadic Eye Movements:
66 69
    //      Characteristics of Impulse Variability in the Oculomotor System"
67 70
    // http://www-personal.umich.edu/~kornblum/files/journal_exp_psych_HPP_15-3.pdf [table 2]
68 71
    float max_accel = fmin(80000.0, 1526.53*distance_abs + 10245.4);
69 72

  
73
    // scale and limit max acceleration
74
    max_accel = max_accel * config->scale_acceleration_eye;
75
    max_accel = fmin(max_accel, config->limit_acceleration_eye);
76

  
70 77
    // feed reflexxes api with data
71 78
    reflexxes_set_input(dof, target, current_position, current_velocity,
72
                        timestamp, max_speed, max_accel);
79
                        timestamp, max_velocity, max_accel);
73 80
}
74 81

  
75 82
//! calculate joint targets
src/server/eyebrow_motion_generator.cpp
35 35
using humotion::server::EyebrowMotionGenerator;
36 36

  
37 37
//! constructor
38
EyebrowMotionGenerator::EyebrowMotionGenerator(JointInterface *j) : MotionGenerator(j) {
38
EyebrowMotionGenerator::EyebrowMotionGenerator(JointInterface *j, Config *cfg) :
39
    MotionGenerator(j, cfg) {
39 40
}
40 41

  
41 42

  
src/server/eyelid_motion_generator.cpp
34 34
// using namespace humotion::server;
35 35

  
36 36
using humotion::server::EyelidMotionGenerator;
37

  
38
// saccade detection threshold in deg/s
39
const float EyelidMotionGenerator::SACCADE_SPEED_THRESHOLD = 15.0;  // deg/s
40
// eyeblink duration:
41
const float EyelidMotionGenerator::EYEBLINK_DURATION_MS    = 150.0;  // ms
42
// periodic eyeblinks: every 2..10s:
43
const float EyelidMotionGenerator::EYEBLINK_EYERY_MS_MIN =  2000.0;  // ms
44
const float EyelidMotionGenerator::EYEBLINK_EYERY_MS_MAX = 10000.0;  // ms
45
// how many seconds do we block further blinks after each eyeblink?
46
const float EyelidMotionGenerator::EYEBLINK_BLOCKING_TIME = 1000.0;  // ms
37
using humotion::server::Config;
47 38

  
48 39
//! constructor
49
EyelidMotionGenerator::EyelidMotionGenerator(JointInterface *j) : EyeMotionGenerator(j) {
40
EyelidMotionGenerator::EyelidMotionGenerator(JointInterface *j, Config *cfg) :
41
    EyeMotionGenerator(j, cfg) {
50 42
    saccade_blink_active_ = false;
51 43
    saccade_blink_requested_ = false;
52 44
    eyelid_closed_[LEFT] = false;
......
153 145
void EyelidMotionGenerator::process_saccadic_eyeblinks() {
154 146
    if (saccade_blink_requested_) {
155 147
        // every n-th's saccade requests an eyeblink
156
        // here: use 0.3 even though humans use bigger prob value (but that looks stupid on robot)
157
        if ((std::rand()%3) == 0) {
158
            // printf("> saccadic eyeblink:\n");
159
            start_eyeblink(LEFT);
160
            start_eyeblink(RIGHT);
148
        float frnd = static_cast <float> (std::rand()) / static_cast <float> (RAND_MAX);
149
        if (frnd <= config->eyeblink_probability_after_saccade) {
150
            printf("> saccadic eyeblink:\n");
151
            start_eyeblink(LEFT, config->eyeblink_duration * 1000.0);
152
            start_eyeblink(RIGHT, config->eyeblink_duration * 1000.0);
161 153
        }
162 154
        saccade_blink_requested_ = false;
163 155
    }
......
167 159
//! -> we want to have an eyeblink every n...m seconds
168 160
void EyelidMotionGenerator::process_periodic_eyeblinks() {
169 161
    if (eyeblink_active_[LEFT] || eyeblink_active_[RIGHT]) {
162
        float range = config->eyeblink_periodic_distribution_upper
163
                - config->eyeblink_periodic_distribution_lower;
164

  
165
        // random number 0...1
166
        float frnd = static_cast <float> (std::rand()) / static_cast <float> (RAND_MAX);
167

  
170 168
        // calculate next timeout for a new periodic eyeblink
171
        int milliseconds_to_next_blink = EYEBLINK_EYERY_MS_MIN
172
                + (std::rand() % static_cast<int>(EYEBLINK_EYERY_MS_MAX-EYEBLINK_EYERY_MS_MIN));
169
        float seconds_to_next_blink =
170
                config->eyeblink_periodic_distribution_lower  + frnd * range;
171

  
173 172
        periodic_blink_start_time_ = boost::get_system_time()
174
                + boost::posix_time::milliseconds(milliseconds_to_next_blink);
173
                + boost::posix_time::seconds(seconds_to_next_blink);
175 174
    }
176 175

  
177 176
    if (boost::get_system_time() > periodic_blink_start_time_) {
178 177
        // printf("> periodic eyeblink:\n");
179
        start_eyeblink(LEFT);
180
        start_eyeblink(RIGHT);
178
        start_eyeblink(LEFT, config->eyeblink_duration * 1000.0);
179
        start_eyeblink(RIGHT, config->eyeblink_duration * 1000.0);
181 180
    }
182 181
}
183 182

  
......
198 197
    // take care of blocking time
199 198
    if (eyeblink_active_[LEFT] || eyeblink_active_[RIGHT]) {
200 199
        eyeblink_blocked_timeout_ = boost::get_system_time()
201
                + boost::posix_time::milliseconds(EYEBLINK_BLOCKING_TIME);
200
                + boost::posix_time::seconds(config->eyeblink_blocked_time);
202 201
    }
203 202
}
204 203

  
src/server/gaze_motion_generator.cpp
29 29
#include "humotion/server/server.h"
30 30

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

  
33
// saccade detection threshold in deg/s
34
// const float GazeMotionGenerator::SACCADE_SPEED_THRESHOLD = 15.0;
35
// some constants to decide if the requested move will trigger a neck or eye saccade
36
const float GazeMotionGenerator::NECK_SACCADE_THRESHOLD      = 15.0;  // deg
37
const float GazeMotionGenerator::EYE_SACCADE_SPEED_THRESHOLD = 15.0;  // deg/s
38

  
39
// close to ocolumotor-range?
40
// 0.95 = reaching 95% of OMR will trigger a correction
41
const float GazeMotionGenerator::OMR_LIMIT_TRIGGERS_NECK_SACCADE = 0.95;
42

  
32
using humotion::server::Config;
43 33

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

  
49 39
//! destructor
......
66 56
            / (new_gaze_target.timestamp.to_seconds()-requested_gaze_state_.timestamp.to_seconds());
67 57

  
68 58
    // check magnitude and speed of gaze change to detect eye-neck saccades
69
    if (dist > NECK_SACCADE_THRESHOLD) {
59
    if (dist > config->threshold_angle_neck_saccade) {
70 60
        // the next saccade has to use neck motion as well
71
        if (speed > EYE_SACCADE_SPEED_THRESHOLD) {
61
        if (speed > config->threshold_velocity_eye_saccade) {
72 62
            neck_saccade_requested = true;
73 63
        }
74 64
    } else {
......
83 73
    float eye_target_ud = joint_interface_->get_target_position(JointInterface::ID_EYES_BOTH_UD);
84 74

  
85 75
    // min/max bounds
86
    float left_min  = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
76
    float left_min  = config->threshold_angle_omr_limit *
87 77
            joint_interface_->get_joint_min(JointInterface::ID_EYES_LEFT_LR);
88
    float left_max  = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
78
    float left_max  = config->threshold_angle_omr_limit *
89 79
            joint_interface_->get_joint_max(JointInterface::ID_EYES_LEFT_LR);
90
    float right_min = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
80
    float right_min = config->threshold_angle_omr_limit *
91 81
            joint_interface_->get_joint_min(JointInterface::ID_EYES_RIGHT_LR);
92
    float right_max = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
82
    float right_max = config->threshold_angle_omr_limit *
93 83
            joint_interface_->get_joint_max(JointInterface::ID_EYES_RIGHT_LR);
94
    float ud_min    = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
84
    float ud_min    = config->threshold_angle_omr_limit *
95 85
            joint_interface_->get_joint_min(JointInterface::ID_EYES_BOTH_UD);
96
    float ud_max    = OMR_LIMIT_TRIGGERS_NECK_SACCADE *
86
    float ud_max    = config->threshold_angle_omr_limit *
97 87
            joint_interface_->get_joint_max(JointInterface::ID_EYES_BOTH_UD);
98 88

  
99 89
    if (
......
125 115
    float speed_total_r = sqrt(speed_right*speed_right + speed_tilt*speed_tilt);
126 116

  
127 117
    // thresholding
128
    if ((speed_total_l > EYE_SACCADE_SPEED_THRESHOLD) ||
129
            (speed_total_r > EYE_SACCADE_SPEED_THRESHOLD)) {
118
    if ((speed_total_l > config->threshold_velocity_eye_saccade) ||
119
            (speed_total_r > config->threshold_velocity_eye_saccade)) {
130 120
        // this is a saccade
131 121
        saccade_active = true;
132 122
    } else {
src/server/middleware_ros.cpp
109 109
//! attach to dynamic reconfigure server
110 110
void MiddlewareROS::attach_to_reconfiguration_server(ros::NodeHandle priv_nodehandle) {
111 111
    ROS_DEBUG("connecting to dynamic reconfiguration server");
112
    ros::NodeHandle reconf_node(priv_nodehandle, "configuration");
112
    ros::NodeHandle reconf_node(priv_nodehandle, "humotion/configuration");
113 113

  
114 114
    reconf_server_ = new dynamic_reconfigure::Server<humotion::humotionConfig>(reconf_node);
115 115
    reconf_server_->setCallback(boost::bind(
src/server/motion_generator.cpp
29 29
#include "humotion/server/motion_generator.h"
30 30

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

  
33 34
//! constructor
34
MotionGenerator::MotionGenerator(JointInterface *j) {
35
MotionGenerator::MotionGenerator(JointInterface *j, Config *cfg) {
36
    config = cfg;
35 37
    joint_interface_ = j;
36 38
    last_mouth_target_update_ = boost::posix_time::ptime(boost::posix_time::min_date_time);
37 39
    last_gaze_target_update_  = boost::posix_time::ptime(boost::posix_time::min_date_time);
src/server/mouth_motion_generator.cpp
28 28
#include "humotion/server/mouth_motion_generator.h"
29 29

  
30 30
using humotion::server::MouthMotionGenerator;
31
using humotion::server::Config;
31 32

  
32 33
// minimum mouth opening
33 34
const float MouthMotionGenerator::MOUTH_MIN_OPENING = 9.0;  // mm
34 35

  
35 36
//! constructor
36
MouthMotionGenerator::MouthMotionGenerator(JointInterface *j) : MotionGenerator(j) {
37
MouthMotionGenerator::MouthMotionGenerator(JointInterface *j, Config *cfg) :
38
    MotionGenerator(j, cfg) {
37 39
}
38 40

  
39 41
//! destructor
src/server/neck_motion_generator.cpp
32 32
#include "humotion/server/server.h"
33 33

  
34 34
using humotion::server::NeckMotionGenerator;
35

  
36
const float NeckMotionGenerator::CONST_GUITTON87_A = 4.39/2.0;
37
const float NeckMotionGenerator::CONST_GUITTON87_B = 106.0/2.0;
38

  
39
// healthy adult human: 12-15 breaths/min (see "Ganong's review of medical physiology")
40
// total: 60/12-15 = 3-5s
41
// inhale 1.5-2s
42
// exhale 1.5-2s
43
// pause      2s
44
const float NeckMotionGenerator::CONST_BREATH_PERIOD = 1500.0+1500.0+1500.0;  // given in ms
45
const float NeckMotionGenerator::CONST_BREATH_AMPLITUDE = 1.0;  // degrees
46

  
35
using humotion::server::Config;
47 36

  
48 37
//! constructor
49
NeckMotionGenerator::NeckMotionGenerator(JointInterface *j) :
50
    GazeMotionGenerator(j, 3, 1.0/Server::MOTION_UPDATERATE) {
38
NeckMotionGenerator::NeckMotionGenerator(JointInterface *j, Config *cfg) :
39
    GazeMotionGenerator(j, cfg, 3, 1.0/Server::MOTION_UPDATERATE) {
51 40
    breath_time_ = 0.0;
52 41
}
53 42

  
......
62 51
    // we want to have a constant acceleration
63 52
    // -> triangular wave as speeds -> (x<0.5)? 2*x*x:  1- 2*(1-x)**2 = 4x - 2x**2 - 1
64 53
    float breath_offset = 0.0;
54

  
65 55
    // 0...1 -> move up, 1..2 -> return, 2..3 -> still
66
    float breath_time_normalized = (breath_time_ * 3)/CONST_BREATH_PERIOD;
56
    float breath_time_normalized = (breath_time_ * 3)/config->breath_period;
67 57

  
68 58
    if (breath_time_normalized <= 0.5) {
69 59
        // accelerated motion
70
        breath_offset = CONST_BREATH_AMPLITUDE * (2.0 * pow(breath_time_normalized, 2));
60
        breath_offset = config->breath_amplitude * (2.0 * pow(breath_time_normalized, 2));
71 61
    } else if (breath_time_normalized <= 1.0) {
72 62
        // deaccelerate
73
        breath_offset = CONST_BREATH_AMPLITUDE * (1.0 - 2.0 * pow(1.0 - breath_time_normalized, 2));
63
        breath_offset = config->breath_amplitude * (1.0 - 2.0
64
                                                    * pow(1.0 - breath_time_normalized, 2));
74 65
    } else if (breath_time_normalized <= 1.5) {
75 66
        // accelerate again
76
        breath_offset = CONST_BREATH_AMPLITUDE * (1.0 - (2.0 * pow(breath_time_normalized-1, 2)));
67
        breath_offset = config->breath_amplitude * (1.0 - (2.0 * pow(breath_time_normalized-1, 2)));
77 68
    } else if (breath_time_normalized <= 2.0) {
78
        breath_offset = CONST_BREATH_AMPLITUDE * (2.0 * pow(2.0 - breath_time_normalized, 2));
69
        breath_offset = config->breath_amplitude * (2.0 * pow(2.0 - breath_time_normalized, 2));
79 70
    } else if (breath_time_normalized <= 3.0) {
80 71
        // pause for some time
81 72
        breath_offset = 0;
......
83 74

  
84 75
    // fetch next time
85 76
    breath_time_ += 1000.0/Server::MOTION_UPDATERATE;
86
    if (breath_time_ >= CONST_BREATH_PERIOD) {
87
        breath_time_ -= CONST_BREATH_PERIOD;
77

  
78
    if (breath_time_ >= config->breath_period) {
79
        breath_time_ -= config->breath_period;
88 80
    }
89 81

  
90 82
    return breath_offset;
......
205 197
    // get distance to target
206 198
    float distance_abs = fabs(target - current_position);
207 199

  
208
    // get max speed: according to [guitton87] there is a relation
200
    // get max speed: according to the equation Hmax from [guitton87] there is a linear relation
209 201
    // between distance_abs and v_max_head:
210 202
    // v_max = 4.39 * d_total + 106.0 (in degrees)
211
    float max_speed = (CONST_GUITTON87_A * distance_abs + CONST_GUITTON87_B);
203
    float max_velocity = 4.39 * distance_abs + 106.0;
204

  
205
    // scale and limit max speed:
206
    max_velocity = max_velocity * config->scale_velocity_neck;
207
    max_velocity = fmin(max_velocity, config->limit_velocity_neck);
212 208

  
213 209
    // max accel: assuming linear acceleration we have:
214 210
    /* v ^  _
......
225 221
    // and therefore
226 222
    // a = v_max^2 / d_total
227 223
    float max_accel = 0.0;
224

  
228 225
    if (distance_abs > 0.0) {
229
        max_accel = pow(max_speed, 2) / distance_abs;
226
        max_accel = pow(max_velocity, 2) / distance_abs;
230 227
    }
231 228

  
232
    // smoother motion
233
    max_accel = max_accel * 0.7;
229
    // scale and limit acceleration
230
    max_accel = max_accel * config->scale_acceleration_neck;
231
    max_accel = fmin(max_accel, config->limit_acceleration_neck);
234 232

  
235
    // limit maximum acceleration to reduce noise FIXME!
236
    if (max_accel > 1000) {
237
        max_accel = 1000;
238
    }
239 233
    // printf("MAX SPEED %4.2f / max accel %4.2f\n",max_speed, max_accel);
240 234

  
241 235
    // feed reflexxes api with data
242 236
    reflexxes_set_input(dof, target, current_position, current_velocity,
243
                        timestamp, max_speed, max_accel);
237
                        timestamp, max_velocity, max_accel);
244 238
}
src/server/reflexxes_motion_generator.cpp
28 28
#include "humotion/server/eye_motion_generator.h"
29 29

  
30 30
using humotion::server::ReflexxesMotionGenerator;
31
using humotion::server::Config;
31 32

  
32 33
//! constructor
33
ReflexxesMotionGenerator::ReflexxesMotionGenerator(JointInterface *j, int dof, float t) :
34
    MotionGenerator(j) {
34
ReflexxesMotionGenerator::ReflexxesMotionGenerator(JointInterface *j, Config *c, int dof, float t) :
35
    MotionGenerator(j, c) {
35 36
    dof_count = dof;
36 37

  
37 38
    // create Reflexxes API for <dof> DOF actuator

Also available in: Unified diff