Revision 2aa96942
cfg/humotion.cfg | ||
---|---|---|
38 | 38 |
|
39 | 39 |
gen = ParameterGenerator() |
40 | 40 |
|
41 |
debug_group = gen.add_group("debug") |
|
42 |
add_entry_bool(debug_group, "publish_internals", "publish debugging data on different topics") |
|
43 |
|
|
41 | 44 |
general_group = gen.add_group("thresholds") |
42 | 45 |
add_entry(general_group, "threshold_velocity_eye_saccade", "velocity threshold for eye saccade detection (in deg/s)", 1.0, 30.0) |
43 | 46 |
add_entry(general_group, "threshold_angle_neck_saccade", "magnitude of gaze change that triggers neck saccade (in deg)", 1.0, 30.0) |
include/humotion/server/config.h | ||
---|---|---|
29 | 29 |
#ifndef INCLUDE_HUMOTION_SERVER_CONFIG_H_ |
30 | 30 |
#define INCLUDE_HUMOTION_SERVER_CONFIG_H_ |
31 | 31 |
|
32 |
#include <map> |
|
33 |
#include <string> |
|
34 |
|
|
32 | 35 |
namespace humotion { |
33 | 36 |
namespace server { |
34 | 37 |
|
38 |
typedef std::map<std::string, float> debug_data_t; |
|
39 |
|
|
35 | 40 |
class Config { |
36 | 41 |
public: |
37 | 42 |
Config(); |
... | ... | |
42 | 47 |
// NOTE: See config.cpp for explanations and default values |
43 | 48 |
// ******************************************************** |
44 | 49 |
|
50 |
// publish debug information |
|
51 |
bool publish_internals; |
|
52 |
|
|
45 | 53 |
// saccade detection thresholds |
46 | 54 |
float threshold_velocity_eye_saccade; |
47 | 55 |
float threshold_angle_neck_saccade; |
include/humotion/server/controller.h | ||
---|---|---|
48 | 48 |
void init_motion_generators(); |
49 | 49 |
void calculate_targets(); |
50 | 50 |
void publish_targets(); |
51 |
debug_data_t get_debug_data(); |
|
51 | 52 |
|
52 | 53 |
void set_gaze_target(GazeState s); |
53 | 54 |
void set_mouth_target(MouthState s); |
include/humotion/server/middleware.h | ||
---|---|---|
30 | 30 |
|
31 | 31 |
#include <cstdint> |
32 | 32 |
#include <cstdio> |
33 |
#include <map> |
|
33 | 34 |
#include <string> |
35 |
#include <utility> |
|
34 | 36 |
|
35 | 37 |
#include "humotion/gaze_state.h" |
36 | 38 |
#include "humotion/mouth_state.h" |
... | ... | |
47 | 49 |
virtual bool ok() = 0; |
48 | 50 |
virtual void tick() = 0; |
49 | 51 |
|
52 |
virtual void publish_debug_dataset(debug_data_t) = 0; |
|
53 |
|
|
50 | 54 |
protected: |
51 | 55 |
Controller *controller_; |
52 | 56 |
std::string base_scope_; |
include/humotion/server/middleware_ros.h | ||
---|---|---|
32 | 32 |
#include <dynamic_reconfigure/server.h> |
33 | 33 |
#include <ros/ros.h> |
34 | 34 |
|
35 |
#include <map> |
|
35 | 36 |
#include <string> |
37 |
#include <utility> |
|
36 | 38 |
|
37 | 39 |
#include "humotion/gaze.h" |
38 | 40 |
#include "humotion/humotionConfig.h" |
... | ... | |
50 | 52 |
void tick(); |
51 | 53 |
|
52 | 54 |
void dynamic_reconfigure_callback(const humotion::humotionConfig &config, uint32_t level); |
55 |
void publish_debug_dataset(debug_data_t); |
|
53 | 56 |
|
54 | 57 |
private: |
58 |
void publish_debug_data(std::string name, float value); |
|
59 |
|
|
55 | 60 |
void incoming_mouth_target(const humotion::mouth::ConstPtr& msg); |
56 | 61 |
void incoming_gaze_target(const humotion::gaze::ConstPtr& msg); |
57 | 62 |
void attach_to_reconfiguration_server(ros::NodeHandle priv_nodehandle); |
58 |
|
|
63 |
void debug_initialize(); |
|
59 | 64 |
|
60 | 65 |
bool tick_necessary_; |
66 |
bool debug_initialized_; |
|
61 | 67 |
|
62 | 68 |
ros::Subscriber mouth_target_subscriber_; |
63 | 69 |
ros::Subscriber gaze_target_subscriber_; |
70 |
|
|
71 |
ros::NodeHandle nh_; |
|
72 |
|
|
73 |
typedef std::map<std::string, ros::Publisher> debug_topic_map_t; |
|
74 |
debug_topic_map_t debug_topic_map; |
|
75 |
|
|
64 | 76 |
dynamic_reconfigure::Server<humotion::humotionConfig> *reconf_server_; |
65 | 77 |
}; |
66 | 78 |
|
include/humotion/server/motion_generator.h | ||
---|---|---|
30 | 30 |
|
31 | 31 |
#include <boost/date_time/posix_time/posix_time.hpp> |
32 | 32 |
|
33 |
#include <map> |
|
33 | 34 |
#include <string> |
34 | 35 |
|
35 | 36 |
#include "humotion/server/config.h" |
... | ... | |
49 | 50 |
virtual void set_gaze_target(GazeState s); |
50 | 51 |
virtual void set_mouth_target(MouthState s); |
51 | 52 |
|
53 |
debug_data_t get_debug_data(); |
|
54 |
|
|
55 |
|
|
52 | 56 |
protected: |
53 | 57 |
Config *config; |
58 |
debug_data_t debug_data; |
|
59 |
void store_debug_data(std::string name, float value); |
|
54 | 60 |
|
55 | 61 |
float get_current_position(int joint_id); |
56 | 62 |
float get_current_speed(int joint_id); |
57 | 63 |
humotion::Timestamp get_timestamped_state(int joint_id, float *position, float *velocity); |
64 |
|
|
58 | 65 |
float limit_target(int joint_id, float val); |
59 | 66 |
bool mouth_target_input_active(); |
60 | 67 |
bool gaze_target_input_active(); |
src/server/config.cpp | ||
---|---|---|
38 | 38 |
} |
39 | 39 |
|
40 | 40 |
void Config::init_defaults() { |
41 |
// publish internal debug data as topics? |
|
42 |
publish_internals = false; |
|
43 |
|
|
41 | 44 |
// saccade detection thresholds: |
42 | 45 |
// 1) velocity threshold, values above this value trigger an eye saccade |
43 | 46 |
// value is given in deg/s |
src/server/controller.cpp | ||
---|---|---|
39 | 39 |
|
40 | 40 |
using humotion::server::Controller; |
41 | 41 |
using humotion::server::Config; |
42 |
using humotion::server::debug_data_t; |
|
42 | 43 |
|
43 | 44 |
//! constructor |
44 | 45 |
Controller::Controller(JointInterface *j) { |
... | ... | |
82 | 83 |
void Controller::calculate_targets() { |
83 | 84 |
Controller::motion_generator_vector_t::iterator it; |
84 | 85 |
for (it = motion_generator_vector_.begin(); it < motion_generator_vector_.end(); it++) { |
85 |
(*it)->calculate_targets(); |
|
86 |
MotionGenerator *mg = *it; |
|
87 |
// calculate targets |
|
88 |
mg->calculate_targets(); |
|
86 | 89 |
} |
87 | 90 |
} |
88 | 91 |
|
92 |
debug_data_t Controller::get_debug_data() { |
|
93 |
debug_data_t debug_data; |
|
94 |
|
|
95 |
Controller::motion_generator_vector_t::iterator it; |
|
96 |
for (it = motion_generator_vector_.begin(); it < motion_generator_vector_.end(); it++) { |
|
97 |
MotionGenerator *mg = *it; |
|
98 |
// fetch and append debug data |
|
99 |
debug_data_t dataset = mg->get_debug_data(); |
|
100 |
debug_data.insert(dataset.begin(), dataset.end()); |
|
101 |
} |
|
102 |
|
|
103 |
return debug_data; |
|
104 |
} |
|
105 |
|
|
89 | 106 |
//! publish all target angles to the devices: |
90 | 107 |
//! NOTE: this is done in an extra loop to have a low delay between consequent sets: |
91 | 108 |
void Controller::publish_targets() { |
src/server/eye_motion_generator.cpp | ||
---|---|---|
155 | 155 |
joint_interface_->set_target(JointInterface::ID_EYES_BOTH_UD, |
156 | 156 |
reflexxes_position_output->NewPositionVector->VecData[2], |
157 | 157 |
reflexxes_position_output->NewVelocityVector->VecData[2]); |
158 |
|
|
159 |
// store debug data: |
|
160 |
store_debug_data("eye/neck_pan_now", neck_pan_now); |
|
161 |
store_debug_data("eye/neck_tilt_now", neck_tilt_now); |
|
162 |
store_debug_data("eye/eye_pan_r_target", eye_pan_r_target); |
|
163 |
store_debug_data("eye/eye_pan_l_target", eye_pan_l_target); |
|
164 |
store_debug_data("eye/eye_tilt_target", eye_tilt_target); |
|
165 |
|
|
166 |
store_debug_data("eye/gaze_target_pan", requested_gaze_state_.pan); |
|
167 |
store_debug_data("eye/gaze_target_tilt", requested_gaze_state_.tilt); |
|
168 |
|
|
169 |
store_debug_data("eye/eye_pan_r_now", eye_pan_r_now); |
|
170 |
store_debug_data("eye/eye_pan_l_now", eye_pan_l_now); |
|
171 |
store_debug_data("eye/eye_tilt_now", eye_tilt_now); |
|
172 |
|
|
173 |
store_debug_data("eye/output_l_lr", reflexxes_position_output->NewPositionVector->VecData[0]); |
|
174 |
store_debug_data("eye/output_r_lr", reflexxes_position_output->NewPositionVector->VecData[1]); |
|
175 |
store_debug_data("eye/output_ud", reflexxes_position_output->NewPositionVector->VecData[2]); |
|
158 | 176 |
} |
159 | 177 |
|
160 | 178 |
|
src/server/middleware_ros.cpp | ||
---|---|---|
27 | 27 |
|
28 | 28 |
#include <boost/algorithm/string/classification.hpp> |
29 | 29 |
|
30 |
#include <std_msgs/Float32.h> |
|
30 | 31 |
#include <string> |
31 | 32 |
|
32 | 33 |
#include "humotion/server/middleware_ros.h" |
... | ... | |
35 | 36 |
|
36 | 37 |
//! constructor |
37 | 38 |
MiddlewareROS::MiddlewareROS(std::string scope, Controller *c) |
38 |
: Middleware(scope, c) { |
|
39 |
: Middleware(scope, c), nh_(scope + "/humotion") {
|
|
39 | 40 |
ROS_DEBUG_STREAM_NAMED("MiddlewareROS", "will use ros middleware"); |
41 |
debug_initialized_ = false; |
|
40 | 42 |
|
41 | 43 |
// start ros core? |
42 | 44 |
if (ros::isInitialized()) { |
... | ... | |
58 | 60 |
} |
59 | 61 |
|
60 | 62 |
// create node handle |
61 |
ros::NodeHandle n; |
|
62 | 63 |
ros::NodeHandle pnh("~"); |
63 | 64 |
|
64 | 65 |
// set up subscribers |
65 |
mouth_target_subscriber_ = n.subscribe(scope + "/humotion/mouth/target", 150,
|
|
66 |
mouth_target_subscriber_ = nh_.subscribe("mouth/target", 150,
|
|
66 | 67 |
&MiddlewareROS::incoming_mouth_target , |
67 | 68 |
this, ros::TransportHints().unreliable()); |
68 |
gaze_target_subscriber_ = n.subscribe(scope + "/humotion/gaze/target", 150,
|
|
69 |
gaze_target_subscriber_ = nh_.subscribe("gaze/target", 150,
|
|
69 | 70 |
&MiddlewareROS::incoming_gaze_target, |
70 | 71 |
this, ros::TransportHints().unreliable()); |
71 | 72 |
|
... | ... | |
79 | 80 |
// fetch config |
80 | 81 |
humotion::server::Config *config = controller_->get_config(); |
81 | 82 |
|
83 |
// debug |
|
84 |
config->publish_internals = dyn_config.publish_internals; |
|
85 |
|
|
82 | 86 |
// saccade detection thresholds |
83 | 87 |
config->threshold_velocity_eye_saccade = dyn_config.threshold_velocity_eye_saccade; |
84 | 88 |
config->threshold_angle_neck_saccade = dyn_config.threshold_angle_neck_saccade; |
85 | 89 |
config->threshold_angle_omr_limit = dyn_config.threshold_angle_omr_limit; |
86 | 90 |
|
87 |
config->use_neck_target_instead_of_position_eye = dyn_config.use_neck_target_instead_of_position_eye; |
|
91 |
config->use_neck_target_instead_of_position_eye = |
|
92 |
dyn_config.use_neck_target_instead_of_position_eye; |
|
88 | 93 |
|
89 | 94 |
// neck motion generation configuration |
90 | 95 |
config->scale_velocity_neck = dyn_config.scale_velocity_neck; |
... | ... | |
141 | 146 |
} |
142 | 147 |
} |
143 | 148 |
|
149 |
//! init debug dataset publishers |
|
150 |
void MiddlewareROS::debug_initialize() { |
|
151 |
if (debug_initialized_) { |
|
152 |
return; |
|
153 |
} |
|
154 |
|
|
155 |
debug_initialized_ = true; |
|
156 |
} |
|
157 |
|
|
158 |
//! publish a debug dataset |
|
159 |
void MiddlewareROS::publish_debug_dataset(debug_data_t debug_data) { |
|
160 |
if (!controller_->get_config()->publish_internals) { |
|
161 |
// no debugging data enabled, return |
|
162 |
return; |
|
163 |
} |
|
164 |
|
|
165 |
debug_initialize(); |
|
166 |
|
|
167 |
// iterate over all debug variables and publish them |
|
168 |
debug_data_t::iterator it; |
|
169 |
for (it = debug_data.begin(); it != debug_data.end(); it++) { |
|
170 |
publish_debug_data(it->first, it->second); |
|
171 |
} |
|
172 |
} |
|
173 |
|
|
174 |
void MiddlewareROS::publish_debug_data(std::string name, float value) { |
|
175 |
debug_topic_map_t::iterator it = debug_topic_map.find(name); |
|
176 |
if (it == debug_topic_map.end()) { |
|
177 |
// we have no publisher for this dataset, create one: |
|
178 |
ROS_DEBUG_STREAM("creating debug output stream " << name); |
|
179 |
ros::Publisher pub = nh_.advertise<std_msgs::Float32>("debug_data/" + name, 1000); |
|
180 |
|
|
181 |
std::pair<debug_topic_map_t::iterator, bool> ret; |
|
182 |
ret = debug_topic_map.insert(std::pair<std::string, ros::Publisher>(name, pub)); |
|
183 |
it = ret.first; |
|
184 |
} |
|
185 |
|
|
186 |
// in any case, it is now the publisher we want so publish data now |
|
187 |
std_msgs::Float32 msg; |
|
188 |
msg.data = value; |
|
189 |
|
|
190 |
// std::cout << "DEBUG HUMOTION " << name << " " << value << std::endl; |
|
191 |
|
|
192 |
// send it |
|
193 |
it->second.publish(msg); |
|
194 |
} |
|
195 |
|
|
144 | 196 |
//! callback to handle incoming mouth target |
145 | 197 |
void MiddlewareROS::incoming_mouth_target(const humotion::mouth::ConstPtr& msg) { |
146 | 198 |
// printf("> incoming mouth_target\n"); |
src/server/motion_generator.cpp | ||
---|---|---|
26 | 26 |
*/ |
27 | 27 |
|
28 | 28 |
#include <boost/date_time/posix_time/posix_time.hpp> |
29 |
|
|
30 |
#include <utility> |
|
31 |
|
|
29 | 32 |
#include "humotion/server/motion_generator.h" |
30 | 33 |
|
31 | 34 |
using humotion::server::MotionGenerator; |
32 | 35 |
using humotion::server::Config; |
36 |
using humotion::server::debug_data_t; |
|
33 | 37 |
|
34 | 38 |
//! constructor |
35 | 39 |
MotionGenerator::MotionGenerator(JointInterface *j, Config *cfg) { |
... | ... | |
44 | 48 |
MotionGenerator::~MotionGenerator() { |
45 | 49 |
} |
46 | 50 |
|
51 |
//! return all accumulated debug data |
|
52 |
debug_data_t MotionGenerator::get_debug_data() { |
|
53 |
return debug_data; |
|
54 |
} |
|
55 |
|
|
56 |
//! store debug data |
|
57 |
void MotionGenerator::store_debug_data(std::string name, float value) { |
|
58 |
debug_data[name] = value; |
|
59 |
} |
|
60 |
|
|
47 | 61 |
//! fetch the latest position and velocity and return the timestamp of that dataset |
48 | 62 |
//! \param joint id |
49 | 63 |
//! \param pointer to position variable |
50 |
//! \param pointer to veolocity variable
|
|
64 |
//! \param pointer to velocity variable |
|
51 | 65 |
//! \return Timestamp of this dataset |
52 | 66 |
humotion::Timestamp MotionGenerator::get_timestamped_state(int joint_id, |
53 | 67 |
float *position, float *velocity) { |
54 |
humotion::Timestamp stamp = joint_interface_->get_ts_position(joint_id).get_last_timestamp(); |
|
68 |
humotion::Timestamp stamp_p = joint_interface_->get_ts_position(joint_id).get_last_timestamp(); |
|
69 |
humotion::Timestamp stamp_v = joint_interface_->get_ts_speed(joint_id).get_last_timestamp(); |
|
70 |
humotion::Timestamp stamp; |
|
71 |
|
|
72 |
if (stamp_v < stamp_p) { |
|
73 |
// right now there is no velocity with that timestamp yet, therefore use the velocity ts |
|
74 |
// for both: |
|
75 |
stamp = stamp_v; |
|
76 |
} else { |
|
77 |
// both are available at the position ts, use that one |
|
78 |
stamp = stamp_p; |
|
79 |
} |
|
80 |
|
|
81 |
// fetch data |
|
55 | 82 |
*position = joint_interface_->get_ts_position(joint_id).get_interpolated_value(stamp); |
56 | 83 |
*velocity = joint_interface_->get_ts_speed(joint_id).get_interpolated_value(stamp); |
57 | 84 |
return stamp; |
src/server/neck_motion_generator.cpp | ||
---|---|---|
181 | 181 |
get_current_gaze().pan, |
182 | 182 |
(get_current_position(JointInterface::ID_EYES_LEFT_LR) + get_current_position(JointInterface::ID_EYES_RIGHT_LR))/2.0, |
183 | 183 |
get_current_position(JointInterface::ID_NECK_PAN));*/ |
184 |
|
|
185 |
// store debug data: |
|
186 |
store_debug_data("neck/neck_pan_now", neck_pan_now); |
|
187 |
store_debug_data("neck/neck_tilt_now", neck_tilt_now); |
|
188 |
store_debug_data("neck/neck_pan_target", neck_pan_target); |
|
189 |
store_debug_data("neck/neck_tilt_target", neck_tilt_target); |
|
190 |
|
|
191 |
store_debug_data("neck/gaze_target_pan", requested_gaze_state_.pan); |
|
192 |
store_debug_data("neck/gaze_target_tilt", requested_gaze_state_.tilt); |
|
193 |
|
|
194 |
store_debug_data("neck/output_pan", reflexxes_position_output->NewPositionVector->VecData[0]); |
|
195 |
store_debug_data("neck/output_tilt", reflexxes_position_output->NewPositionVector->VecData[1]); |
|
184 | 196 |
} |
185 | 197 |
|
186 | 198 |
//! publish targets to motor boards: |
src/server/server.cpp | ||
---|---|---|
128 | 128 |
// mw tick |
129 | 129 |
middleware_->tick(); |
130 | 130 |
|
131 |
// do some logging |
|
132 |
// controller->dump_angles(); |
|
133 | 131 |
|
134 | 132 |
// calculate all targets |
135 | 133 |
controller_->calculate_targets(); |
136 | 134 |
|
135 |
// do some logging |
|
136 |
middleware_->publish_debug_dataset(controller_->get_debug_data()); |
|
137 |
|
|
137 | 138 |
// publish data to joints |
138 | 139 |
controller_->publish_targets(); |
139 | 140 |
|
Also available in: Unified diff