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