00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include <jsk_topic_tools/rosparam_utils.h>
00037 #include "jsk_footstep_controller/footcoords.h"
00038 #include <std_msgs/String.h>
00039 #include <tf_conversions/tf_eigen.h>
00040 #include <jsk_pcl_ros/pcl_conversion_util.h>
00041 #include <kdl/chainfksolverpos_recursive.hpp>
00042 #include <kdl/chainfksolvervel_recursive.hpp>
00043 #include <tf_conversions/tf_kdl.h>
00044 #include <geometry_msgs/TwistStamped.h>
00045 #include <kdl_conversions/kdl_msg.h>
00046 #include <boost/assign/list_of.hpp>
00047 
00048 namespace jsk_footstep_controller
00049 {
00050 
00051   Footcoords::Footcoords():
00052     diagnostic_updater_(new diagnostic_updater::Updater)
00053   {
00054     ros::NodeHandle nh, pnh("~");
00055     tf_listener_.reset(new tf::TransformListener());
00056     odom_status_ = UNINITIALIZED;
00057     odom_pose_ = Eigen::Affine3d::Identity();
00058     ground_transform_.setRotation(tf::Quaternion(0, 0, 0, 1));
00059     root_link_pose_.setIdentity();
00060     midcoords_.setRotation(tf::Quaternion(0, 0, 0, 1));
00061     estimated_odom_pose_.setRotation(tf::Quaternion(0, 0, 0, 1));
00062     diagnostic_updater_->setHardwareID("none");
00063     diagnostic_updater_->add("Support Leg Status", this,
00064                              &Footcoords::updateLegDiagnostics);
00065 
00066     
00067     pnh.param("alpha", alpha_, 0.1);
00068     pnh.param("sampling_time_", sampling_time_, 0.2);
00069     pnh.param("output_frame_id", output_frame_id_,
00070               std::string("odom_on_ground"));
00071     pnh.param("zmp_frame_id", zmp_frame_id_,
00072               std::string("zmp"));
00073 
00074     pnh.param("parent_frame_id", parent_frame_id_, std::string("odom"));
00075     pnh.param("midcoords_frame_id", midcoords_frame_id_, std::string("ground"));
00076     pnh.param("root_frame_id", root_frame_id_, std::string("BODY"));
00077     pnh.param("body_on_odom_frame", body_on_odom_frame_, std::string("body_on_odom"));
00078     pnh.param("odom_init_frame_id", odom_init_frame_id_, std::string("odom_init"));
00079     pnh.param("invert_odom_init", invert_odom_init_, true);
00080     pnh.param("lfoot_frame_id", lfoot_frame_id_,
00081               std::string("lleg_end_coords"));
00082     pnh.param("rfoot_frame_id", rfoot_frame_id_,
00083               std::string("rleg_end_coords"));
00084     pnh.param("publish_odom_tf", publish_odom_tf_, true);
00085     urdf::Model robot_model;
00086     KDL::Tree tree;
00087     robot_model.initParam("robot_description");
00088     if (!kdl_parser::treeFromUrdfModel(robot_model, tree)) {
00089       ROS_FATAL("Failed to load robot_description");
00090       return;
00091     }
00092 
00093     tree.getChain(root_frame_id_, lfoot_frame_id_, lfoot_chain_);
00094     tree.getChain(root_frame_id_, rfoot_frame_id_, rfoot_chain_);
00095     for (size_t i=0; i < lfoot_chain_.getNrOfSegments(); i++){
00096       ROS_INFO_STREAM("kdl_chain(" << i << ") "
00097                       << lfoot_chain_.getSegment(i).getJoint().getName().c_str());
00098     }
00099     for (size_t i=0; i < rfoot_chain_.getNrOfSegments(); i++){
00100       ROS_INFO_STREAM("kdl_chain(" << i << ") "
00101                       << rfoot_chain_.getSegment(i).getJoint().getName().c_str());
00102     }
00103     pnh.param("lfoot_sensor_frame", lfoot_sensor_frame_, std::string("lleg_end_coords"));
00104     pnh.param("rfoot_sensor_frame", rfoot_sensor_frame_, std::string("rleg_end_coords"));
00105     
00106     
00107     pnh.param("force_threshold", force_thr_, 200.0);
00108     support_status_ = AIR;
00109     pub_low_level_ = pnh.advertise<jsk_footstep_controller::FootCoordsLowLevelInfo>("low_level_info", 1);
00110     pub_state_ = pnh.advertise<std_msgs::String>("state", 1);
00111     pub_contact_state_ = pnh.advertise<jsk_footstep_controller::GroundContactState>("contact_state", 1);
00112     pub_synchronized_forces_ = pnh.advertise<jsk_footstep_controller::SynchronizedForces>("synchronized_forces", 1);
00113     pub_debug_lfoot_pos_ = pnh.advertise<geometry_msgs::Pose>("debug/lfoot_pose", 1);
00114     pub_debug_rfoot_pos_ = pnh.advertise<geometry_msgs::Pose>("debug/rfoot_pose", 1);
00115     pub_leg_odometory_ = pnh.advertise<geometry_msgs::PoseStamped>("leg_odometry", 1);
00116     pub_twist_ = pnh.advertise<geometry_msgs::TwistStamped>("base_vel", 1);
00117     pub_odom_init_transform_ = pnh.advertise<geometry_msgs::TransformStamped>("odom_init_transform", 1, true);
00118     pub_odom_init_pose_stamped_ = pnh.advertise<geometry_msgs::PoseStamped>("odom_init_pose_stamped", 1, true);
00119     before_on_the_air_ = true;
00120     pnh.param("use_imu", use_imu_, false);
00121     pnh.param("use_imu_yaw", use_imu_yaw_, true);
00122     if (publish_odom_tf_) {
00123       odom_sub_.subscribe(pnh, "/odom", 50);
00124       imu_sub_.subscribe(pnh, "/imu", 50);
00125       odom_imu_sync_ = boost::make_shared<message_filters::Synchronizer<OdomImuSyncPolicy> >(100);
00126       odom_imu_sync_->connectInput(odom_sub_, imu_sub_);
00127       odom_imu_sync_->registerCallback(boost::bind(&Footcoords::odomImuCallback, this, _1, _2));
00128     }
00129     odom_init_pose_ = Eigen::Affine3d::Identity();
00130     odom_init_trigger_sub_ = pnh.subscribe("/odom_init_trigger", 1,
00131                                            &Footcoords::odomInitTriggerCallback, this);
00132     periodic_update_timer_ = pnh.createTimer(ros::Duration(1.0 / 25),
00133                                              boost::bind(&Footcoords::periodicTimerCallback, this, _1));
00134     sub_lfoot_force_.subscribe(nh, "lfsensor", 50);
00135     sub_rfoot_force_.subscribe(nh, "rfsensor", 50);
00136     sub_joint_states_.subscribe(nh, "joint_states",50);
00137     sub_zmp_.subscribe(nh, "zmp", 50);
00138     floor_coeffs_sub_ = pnh.subscribe("/floor_coeffs", 1,
00139                                       &Footcoords::floorCoeffsCallback, this);
00140     floor_coeffs_ = boost::assign::list_of(0)(0)(1)(0);
00141     sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00142     sync_->connectInput(sub_lfoot_force_, sub_rfoot_force_, sub_joint_states_, sub_zmp_);
00143     sync_->registerCallback(boost::bind(&Footcoords::synchronizeForces, this, _1, _2, _3, _4));
00144     synchronized_forces_sub_ = pnh.subscribe("synchronized_forces", 20,
00145                                              &Footcoords::filter, this);
00146   }
00147 
00148   Footcoords::~Footcoords()
00149   {
00150 
00151   }
00152 
00153   void Footcoords::updateLegDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00154   {
00155     
00156     
00157     if (support_status_ == AIR) {
00158       stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "On Air");
00159     }
00160     else {
00161       if (support_status_ == LLEG_GROUND) {
00162         stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Left leg on the ground");
00163       }
00164       else if (support_status_ == RLEG_GROUND) {
00165         stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Right leg on the ground");
00166       }
00167       else if (support_status_ == BOTH_GROUND) {
00168         stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Both legs on the ground");
00169       }
00170     }
00171   }
00172 
00173   double Footcoords::applyLowPassFilter(double current_val, double prev_val) const
00174   {
00175     return prev_val + alpha_ * (current_val - prev_val);
00176   }
00177 
00178   bool Footcoords::allValueLargerThan(TimeStampedVector<ValueStamped::Ptr>& values,
00179                                       double threshold)
00180   {
00181     for (size_t i = 0; i < values.size(); i++) {
00182       if (values[i]->value < threshold) {
00183         return false;
00184       }
00185     }
00186     return true;
00187   }
00188 
00189   bool Footcoords::allValueSmallerThan(TimeStampedVector<ValueStamped::Ptr>& values,
00190                                         double threshold)
00191   {
00192     for (size_t i = 0; i < values.size(); i++) {
00193       if (values[i]->value > threshold) {
00194         return false;
00195       }
00196     }
00197     return true;
00198   }
00199 
00200   bool Footcoords::resolveForceTf(const geometry_msgs::WrenchStamped& lfoot,
00201                                   const geometry_msgs::WrenchStamped& rfoot,
00202                                   tf::Vector3& lfoot_force,
00203                                   tf::Vector3& rfoot_force)
00204   {
00205     try {
00206       if (!waitForSensorFrameTransformation(lfoot.header.stamp, rfoot.header.stamp, lfoot.header.frame_id, rfoot.header.frame_id)) {
00207         ROS_ERROR("[Footcoords::resolveForceTf] failed to lookup transformation for sensor value");
00208         return false;
00209       }
00210       tf::StampedTransform lfoot_transform, rfoot_transform;
00211       tf_listener_->lookupTransform(
00212         lfoot.header.frame_id, lfoot_sensor_frame_, lfoot.header.stamp, lfoot_transform);
00213       tf_listener_->lookupTransform(
00214         rfoot.header.frame_id, rfoot_sensor_frame_, rfoot.header.stamp, rfoot_transform);
00215       
00216       lfoot_transform.setOrigin(tf::Vector3(0, 0, 0));
00217       rfoot_transform.setOrigin(tf::Vector3(0, 0, 0));
00218 
00219       tf::Vector3 lfoot_local, rfoot_local;
00220       tf::vector3MsgToTF(lfoot.wrench.force, lfoot_local);
00221       tf::vector3MsgToTF(rfoot.wrench.force, rfoot_local);
00222       lfoot_force = lfoot_transform * lfoot_local;
00223       rfoot_force = rfoot_transform * rfoot_local;
00224       
00225       
00226       return true;
00227     }
00228     catch (tf2::ConnectivityException &e) {
00229       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00230       return false;
00231     }
00232     catch (tf2::InvalidArgumentException &e) {
00233       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00234       return false;
00235     }
00236     catch (tf2::ExtrapolationException &e) {
00237       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00238       return false;
00239     }
00240     catch (tf2::LookupException &e) {
00241       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00242       return false;
00243     }
00244   }
00245 
00246   void Footcoords::periodicTimerCallback(const ros::TimerEvent& event)
00247   {
00248     boost::mutex::scoped_lock lock(mutex_);
00249     bool success_to_update = computeMidCoords(event.current_real);
00250     if (support_status_ == AIR || support_status_ == BOTH_GROUND) {
00251       publishState("ground");
00252     }
00253     else {
00254       if (support_status_ == LLEG_GROUND) {
00255         publishState("lfoot");
00256       }
00257       else if (support_status_ == RLEG_GROUND) {
00258         publishState("rfoot");
00259       }
00260     }
00261     
00262     tf::StampedTransform root_transform;
00263     try {
00264       
00265       
00266       
00267     }
00268     catch (tf2::ConnectivityException &e) {
00269       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00270     }
00271     catch (tf2::InvalidArgumentException &e) {
00272       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00273     }
00274     catch (tf2::ExtrapolationException &e) {
00275       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00276     }
00277     catch (tf2::LookupException &e) {
00278       ROS_ERROR("[Footcoords::resolveForceTf] transform error: %s", e.what());
00279     }
00280       
00281 
00282       
00283       
00284       
00285       
00286       
00287       
00288     
00289     ground_transform_ = midcoords_;
00290       publishTF(event.current_real);
00291       diagnostic_updater_->update();
00292       publishContactState(event.current_real);
00293   }
00294 
00295   void Footcoords::synchronizeForces(const geometry_msgs::WrenchStamped::ConstPtr& lfoot,
00296                                      const geometry_msgs::WrenchStamped::ConstPtr& rfoot,
00297                                      const sensor_msgs::JointState::ConstPtr& joint_states,
00298                                      const geometry_msgs::PointStamped::ConstPtr& zmp)
00299   {
00300     jsk_footstep_controller::SynchronizedForces forces;
00301     forces.header = lfoot->header;
00302     forces.lleg_force = *lfoot;
00303     forces.rleg_force = *rfoot;
00304     forces.joint_angles = *joint_states;
00305     forces.zmp = *zmp;
00306     pub_synchronized_forces_.publish(forces);
00307     Eigen::Vector3d zmp_point;
00308     tf::pointMsgToEigen(zmp->point, zmp_point);
00309     
00310     if (zmp->point.z < 0) {
00311       geometry_msgs::TransformStamped ros_zmp_coords;
00312       ros_zmp_coords.header = zmp->header;
00313       ros_zmp_coords.child_frame_id = zmp_frame_id_;
00314       Eigen::Affine3d zmp_pose = Eigen::Affine3d::Identity() * Eigen::Translation3d(zmp_point);        
00315       tf::transformEigenToMsg(zmp_pose, ros_zmp_coords.transform);
00316       std::vector<geometry_msgs::TransformStamped> tf_transforms;
00317       tf_transforms.push_back(ros_zmp_coords);
00318       {
00319         boost::mutex::scoped_lock lock(mutex_);
00320         tf_broadcaster_.sendTransform(tf_transforms);
00321       }
00322     }
00323   }
00324   
00325   void Footcoords::updateChain(std::map<std::string, double>& joint_angles,
00326                                KDL::Chain& chain,
00327                                tf::Pose& output_pose)
00328   {
00329     KDL::JntArray jnt_pos(chain.getNrOfJoints());
00330     for (int i = 0, j = 0; i < chain.getNrOfSegments(); i++) {
00331       
00332 
00333 
00334 
00335       std::string joint_name = chain.getSegment(i).getJoint().getName();
00336       if (joint_angles.find(joint_name) != joint_angles.end()) {
00337         jnt_pos(j++) = joint_angles[joint_name];
00338       }
00339     }
00340     KDL::ChainFkSolverPos_recursive fk_solver(chain);
00341     KDL::Frame pose;
00342     if (fk_solver.JntToCart(jnt_pos, pose) < 0) {
00343       ROS_FATAL("Failed to compute FK");
00344     }
00345     tf::poseKDLToTF(pose, output_pose);
00346   }
00347 
00348   void Footcoords::updateRobotModel(std::map<std::string, double>& joint_angles)
00349   {
00350 
00351     updateChain(joint_angles, lfoot_chain_, lfoot_pose_);
00352     updateChain(joint_angles, rfoot_chain_, rfoot_pose_);
00353     geometry_msgs::Pose ros_lfoot_pose, ros_rfoot_pose;
00354     tf::poseTFToMsg(lfoot_pose_, ros_lfoot_pose);
00355     tf::poseTFToMsg(rfoot_pose_, ros_rfoot_pose);
00356     pub_debug_lfoot_pos_.publish(ros_lfoot_pose);
00357     pub_debug_rfoot_pos_.publish(ros_rfoot_pose);
00358   }
00359 
00360   void Footcoords::computeVelicity(double dt,
00361                                    std::map<std::string, double>& joint_angles,
00362                                    KDL::Chain& chain,
00363                                    geometry_msgs::Twist& output)
00364   {
00365     KDL::ChainFkSolverVel_recursive fk_solver(chain);
00366     KDL::JntArrayVel jnt_pos(chain.getNrOfJoints());
00367     KDL::JntArray q(chain.getNrOfJoints()), qdot(chain.getNrOfJoints());
00368     for (int i = 0, j = 0; i < chain.getNrOfSegments(); i++) {
00369       std::string joint_name = chain.getSegment(i).getJoint().getName();
00370       if (joint_angles.find(joint_name) != joint_angles.end()) {
00371         qdot(j) = (joint_angles[joint_name] - prev_joints_[joint_name]) / dt;
00372         q(j++) = joint_angles[joint_name];
00373       }
00374     }
00375     jnt_pos.q = q;
00376     jnt_pos.qdot = qdot;
00377     KDL::FrameVel vel;
00378     if (fk_solver.JntToCart(jnt_pos, vel) < 0) {
00379       ROS_FATAL("Failed to compute velocity");
00380     }
00381     KDL::Twist twist = vel.GetTwist();
00382     tf::twistKDLToMsg(twist, output);
00383   }
00384 
00385   void Footcoords::estimateVelocity(const ros::Time& stamp, std::map<std::string, double>& joint_angles)
00386   {
00387     geometry_msgs::TwistStamped twist_stamped;
00388     if (!prev_joints_.empty()) {
00389       double dt = (stamp - last_time_).toSec();
00390       if (odom_status_ == LLEG_SUPPORT || odom_status_ == INITIALIZING) {
00391         computeVelicity(dt, joint_angles, lfoot_chain_, twist_stamped.twist);
00392       }
00393       else if (odom_status_ == RLEG_SUPPORT) {
00394         computeVelicity(dt, joint_angles, rfoot_chain_, twist_stamped.twist);
00395       }
00396       twist_stamped.header.stamp = stamp;
00397       twist_stamped.header.frame_id = root_frame_id_;
00398       pub_twist_.publish(twist_stamped);
00399     }
00400   }
00401 
00402   void Footcoords::filter(const jsk_footstep_controller::SynchronizedForces::ConstPtr& msg)
00403   {
00404     boost::mutex::scoped_lock lock(mutex_);
00405     geometry_msgs::WrenchStamped lfoot = msg->lleg_force;
00406     geometry_msgs::WrenchStamped rfoot = msg->rleg_force;
00407     zmp_ = Eigen::Vector3f(msg->zmp.point.x, msg->zmp.point.y, msg->zmp.point.z);
00408     sensor_msgs::JointState joint_angles = msg->joint_angles;
00409     std::map<std::string, double> angles;
00410     for (size_t i = 0; i < joint_angles.name.size(); i++) {
00411       angles[joint_angles.name[i]] = joint_angles.position[i];
00412     }
00413 
00414     updateRobotModel(angles);
00415 
00416     
00417     tf::Vector3 lfoot_force_vector, rfoot_force_vector;
00418     if (!resolveForceTf(lfoot, rfoot, lfoot_force_vector, rfoot_force_vector)) {
00419       ROS_ERROR("[Footcoords::filter] failed to resolve tf of force sensor");
00420       return;
00421     }
00422     
00423     double lfoot_force = applyLowPassFilter(lfoot_force_vector[2], prev_lforce_);
00424     double rfoot_force = applyLowPassFilter(rfoot_force_vector[2], prev_rforce_);
00425 
00426     
00427     FootCoordsLowLevelInfo info;
00428     info.header = lfoot.header;
00429     info.raw_lleg_force = lfoot_force_vector[2];
00430     info.raw_rleg_force = rfoot_force_vector[2];
00431     info.filtered_lleg_force = lfoot_force;
00432     info.filtered_rleg_force = rfoot_force;
00433     info.threshold = force_thr_;
00434     pub_low_level_.publish(info);
00435     prev_lforce_ = lfoot_force;
00436     prev_rforce_ = rfoot_force;
00437 
00438     if (lfoot_force >= force_thr_ && rfoot_force >= force_thr_) {
00439       support_status_ = BOTH_GROUND;
00440     }
00441     else if (lfoot_force < force_thr_ && rfoot_force < force_thr_) {
00442       support_status_ = AIR;
00443     }
00444     else if (lfoot_force >= force_thr_) {
00445       
00446       support_status_ = LLEG_GROUND;
00447     }
00448     else if (rfoot_force >= force_thr_) {
00449       
00450       support_status_ = RLEG_GROUND;
00451     }
00452     estimateOdometry();
00453     estimateVelocity(msg->header.stamp, angles);
00454     geometry_msgs::PoseStamped leg_odometory;
00455     leg_odometory.header.stamp = msg->header.stamp;
00456     leg_odometory.header.frame_id = root_frame_id_;
00457     tf::poseTFToMsg(estimated_odom_pose_, leg_odometory.pose);
00458     pub_leg_odometory_.publish(leg_odometory);
00459     
00460     std::vector<geometry_msgs::TransformStamped> tf_transforms;
00461     geometry_msgs::TransformStamped odom_transform;
00462     tf::transformTFToMsg(estimated_odom_pose_, odom_transform.transform);
00463     odom_transform.header = leg_odometory.header;
00464     odom_transform.child_frame_id = "leg_odom";
00465     tf_transforms.push_back(odom_transform);
00466     tf_broadcaster_.sendTransform(tf_transforms);
00467     prev_joints_ = angles;
00468     last_time_ = msg->header.stamp;
00469   }
00470 
00471   void Footcoords::estimateOdometry()
00472   {
00473     
00474     estimateOdometryZMPSupportLeg();
00475   }
00476 
00477   void Footcoords::estimateOdometryNaive()
00478   {
00479     if (odom_status_ == UNINITIALIZED && support_status_ == BOTH_GROUND) {
00480       ROS_INFO("changed to INITIALIZING");
00481       odom_status_ = INITIALIZING;
00482     }
00483     if (odom_status_ == INITIALIZING && support_status_ == BOTH_GROUND) {
00484       ROS_INFO_THROTTLE(1.0, "INITIALIZING");
00485       
00486       tf::Quaternion midcoords_rot = lfoot_pose_.getRotation().slerp(rfoot_pose_.getRotation(), 0.5);
00487       tf::Vector3 midcoords_pos = lfoot_pose_.getOrigin().lerp(rfoot_pose_.getOrigin(), 0.5);
00488       tf::Pose midcoords;
00489       midcoords.setOrigin(midcoords_pos);
00490       midcoords.setRotation(midcoords_rot);
00491       lfoot_to_origin_pose_ = lfoot_pose_.inverse() * midcoords;
00492       rfoot_to_origin_pose_ = rfoot_pose_.inverse() * midcoords;
00493       estimated_odom_pose_ = midcoords;
00494     }
00495     if (odom_status_ == INITIALIZING && support_status_ ==RLEG_GROUND) {
00496       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00497       odom_status_ = RLEG_SUPPORT;
00498       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00499     }
00500     else if (odom_status_ == INITIALIZING && support_status_ == LLEG_GROUND) {
00501       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00502       odom_status_ = LLEG_SUPPORT;
00503       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00504     }
00505     else if (odom_status_ == RLEG_SUPPORT && support_status_ == RLEG_GROUND) {
00506       ROS_INFO_THROTTLE(1.0, "keep RLEG support phase");
00507       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00508     }
00509     else if (odom_status_ == RLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00510       ROS_INFO_THROTTLE(1.0, "dual leg support phase but use RLEG");
00511       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00512       lfoot_to_origin_pose_ = lfoot_pose_.inverse() * rfoot_pose_ * rfoot_to_origin_pose_;
00513     }
00514     else if (odom_status_ == RLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00515       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00516       odom_status_ = LLEG_SUPPORT;
00517       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00518     }
00519     else if (odom_status_ == LLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00520       ROS_INFO_THROTTLE(1.0, "keep LLEG support phase");
00521       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00522     }
00523     else if (odom_status_ == LLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00524       ROS_INFO_THROTTLE(1.0, "dual leg support phase but use LLEG");
00525       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00526       rfoot_to_origin_pose_ = rfoot_pose_.inverse() * lfoot_pose_ * lfoot_to_origin_pose_;
00527     }
00528     else if (odom_status_ == LLEG_SUPPORT && support_status_ == RLEG_GROUND) {
00529       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00530       odom_status_ = RLEG_SUPPORT;
00531       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00532     }
00533     if (support_status_ == AIR) {
00534       ROS_INFO_THROTTLE(1.0, "resetting");
00535       odom_status_ = UNINITIALIZED;
00536     }
00537   }
00538 
00539   void Footcoords::estimateOdometryMainSupportLeg()
00540   {
00541     if (odom_status_ == UNINITIALIZED && support_status_ == BOTH_GROUND) {
00542       ROS_INFO("changed to INITIALIZING");
00543       odom_status_ = INITIALIZING;
00544     }
00545     if (odom_status_ == INITIALIZING && support_status_ == BOTH_GROUND) {
00546       ROS_INFO_THROTTLE(1.0, "INITIALIZING");
00547       
00548       tf::Quaternion midcoords_rot = lfoot_pose_.getRotation().slerp(rfoot_pose_.getRotation(), 0.5);
00549       tf::Vector3 midcoords_pos = lfoot_pose_.getOrigin().lerp(rfoot_pose_.getOrigin(), 0.5);
00550       tf::Pose midcoords;
00551       midcoords.setOrigin(midcoords_pos);
00552       midcoords.setRotation(midcoords_rot);
00553       lfoot_to_origin_pose_ = lfoot_pose_.inverse() * midcoords;
00554       rfoot_to_origin_pose_ = rfoot_pose_.inverse() * midcoords;
00555       estimated_odom_pose_ = midcoords;
00556     }
00557     if (odom_status_ == INITIALIZING && support_status_ == RLEG_GROUND) {
00558       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00559       odom_status_ = RLEG_SUPPORT;
00560       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00561     }
00562     else if (odom_status_ == INITIALIZING && support_status_ == LLEG_GROUND) {
00563       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00564       odom_status_ = LLEG_SUPPORT;
00565       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00566     }
00567     else if (odom_status_ == RLEG_SUPPORT && support_status_ ==RLEG_GROUND) {
00568       ROS_INFO_THROTTLE(1.0, "keep RLEG support phase");
00569       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00570     }
00571     else if (odom_status_ == RLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00572       if (prev_lforce_ > prev_rforce_) {
00573         
00574         odom_status_ = LLEG_SUPPORT;
00575         ROS_INFO_THROTTLE(1.0, "dual leg support phase, switch to lleg");
00576         estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00577         rfoot_to_origin_pose_ = rfoot_pose_.inverse() * lfoot_pose_ * lfoot_to_origin_pose_;
00578       }
00579       else {
00580         ROS_INFO_THROTTLE(1.0, "dual leg support phase but use RLEG");
00581         estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00582         lfoot_to_origin_pose_ = lfoot_pose_.inverse() * rfoot_pose_ * rfoot_to_origin_pose_;
00583       }
00584     }
00585     else if (odom_status_ == RLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00586       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00587       odom_status_ = LLEG_SUPPORT;
00588       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00589     }
00590     else if (odom_status_ == LLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00591       ROS_INFO_THROTTLE(1.0, "keep LLEG support phase");
00592       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00593     }
00594     else if (odom_status_ == LLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00595       if (prev_rforce_ > prev_lforce_) {
00596         odom_status_ = RLEG_SUPPORT;
00597         ROS_INFO_THROTTLE(1.0, "dual leg support phase, switch to rleg");
00598         estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00599         lfoot_to_origin_pose_ = lfoot_pose_.inverse() * rfoot_pose_ * rfoot_to_origin_pose_;
00600       }
00601       else {
00602         ROS_INFO_THROTTLE(1.0, "dual leg support phase but use LLEG");
00603         estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00604         rfoot_to_origin_pose_ = rfoot_pose_.inverse() * lfoot_pose_ * lfoot_to_origin_pose_;
00605       }
00606     }
00607     else if (odom_status_ == LLEG_SUPPORT && support_status_ == RLEG_GROUND) {
00608       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00609       odom_status_ = RLEG_SUPPORT;
00610       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00611     }
00612     if (support_status_ == AIR) {
00613       ROS_INFO_THROTTLE(1.0, "resetting");
00614       odom_status_ = UNINITIALIZED;
00615     }
00616   }
00617 
00618     void Footcoords::estimateOdometryZMPSupportLeg()
00619   {
00620     if (odom_status_ == UNINITIALIZED && support_status_ == BOTH_GROUND) {
00621       ROS_INFO("changed to INITIALIZING");
00622       odom_status_ = INITIALIZING;
00623     }
00624     if (odom_status_ == INITIALIZING && support_status_ == BOTH_GROUND) {
00625       ROS_INFO_THROTTLE(1.0, "INITIALIZING");
00626       
00627       tf::Quaternion midcoords_rot = lfoot_pose_.getRotation().slerp(rfoot_pose_.getRotation(), 0.5);
00628       tf::Vector3 midcoords_pos = lfoot_pose_.getOrigin().lerp(rfoot_pose_.getOrigin(), 0.5);
00629       tf::Pose midcoords;
00630       midcoords.setOrigin(midcoords_pos);
00631       midcoords.setRotation(midcoords_rot);
00632       lfoot_to_origin_pose_ = lfoot_pose_.inverse() * midcoords;
00633       rfoot_to_origin_pose_ = rfoot_pose_.inverse() * midcoords;
00634       estimated_odom_pose_ = midcoords;
00635     }
00636     if (odom_status_ == INITIALIZING && support_status_ == RLEG_GROUND) {
00637       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00638       odom_status_ = RLEG_SUPPORT;
00639       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00640     }
00641     else if (odom_status_ == INITIALIZING && support_status_ == LLEG_GROUND) {
00642       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00643       odom_status_ = LLEG_SUPPORT;
00644       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00645     }
00646     else if (odom_status_ == RLEG_SUPPORT && support_status_ ==RLEG_GROUND) {
00647       ROS_INFO_THROTTLE(1.0, "keep RLEG support phase");
00648       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00649     }
00650     else if (odom_status_ == RLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00651       if (zmp_[1] > 0) {
00652         
00653         odom_status_ = LLEG_SUPPORT;
00654         ROS_INFO_THROTTLE(1.0, "dual leg support phase, switch to lleg");
00655         estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00656         rfoot_to_origin_pose_ = rfoot_pose_.inverse() * lfoot_pose_ * lfoot_to_origin_pose_;
00657       }
00658       else {
00659         ROS_INFO_THROTTLE(1.0, "dual leg support phase but use RLEG");
00660         estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00661         lfoot_to_origin_pose_ = lfoot_pose_.inverse() * rfoot_pose_ * rfoot_to_origin_pose_;
00662       }
00663     }
00664     else if (odom_status_ == RLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00665       ROS_INFO_THROTTLE(1.0, "detect LLEG support phase");
00666       odom_status_ = LLEG_SUPPORT;
00667       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;
00668     }
00669     else if (odom_status_ == LLEG_SUPPORT && support_status_ == LLEG_GROUND) {
00670       ROS_INFO_THROTTLE(1.0, "keep LLEG support phase");
00671       estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00672     }
00673     else if (odom_status_ == LLEG_SUPPORT && support_status_ == BOTH_GROUND) {
00674       if (zmp_[1] < 0) {
00675         odom_status_ = RLEG_SUPPORT;
00676         ROS_INFO_THROTTLE(1.0, "dual leg support phase, switch to rleg");
00677         estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00678         lfoot_to_origin_pose_ = lfoot_pose_.inverse() * rfoot_pose_ * rfoot_to_origin_pose_;
00679       }
00680       else {
00681         ROS_INFO_THROTTLE(1.0, "dual leg support phase but use LLEG");
00682         estimated_odom_pose_ = lfoot_pose_ * lfoot_to_origin_pose_;;
00683         rfoot_to_origin_pose_ = rfoot_pose_.inverse() * lfoot_pose_ * lfoot_to_origin_pose_;
00684       }
00685     }
00686     else if (odom_status_ == LLEG_SUPPORT && support_status_ == RLEG_GROUND) {
00687       ROS_INFO_THROTTLE(1.0, "detect RLEG support phase");
00688       odom_status_ = RLEG_SUPPORT;
00689       estimated_odom_pose_ = rfoot_pose_ * rfoot_to_origin_pose_;
00690     }
00691     if (support_status_ == AIR) {
00692       ROS_INFO_THROTTLE(1.0, "resetting");
00693       odom_status_ = UNINITIALIZED;
00694     }
00695   }
00696 
00697 
00698 
00699   void Footcoords::publishState(const std::string& state)
00700   {
00701     std_msgs::String state_msg;
00702     state_msg.data = state;
00703     pub_state_.publish(state_msg);
00704   }
00705   
00706   void Footcoords::publishContactState(const ros::Time& stamp)
00707   {
00708     GroundContactState contact_state;
00709     contact_state.header.stamp = stamp;
00710     if (support_status_ == AIR) {
00711       contact_state.contact_state
00712         = GroundContactState::CONTACT_AIR;
00713     }
00714     else if (support_status_ == LLEG_GROUND) {
00715       contact_state.contact_state 
00716         = GroundContactState::CONTACT_LLEG_GROUND;
00717     }
00718     else if (support_status_ == RLEG_GROUND) {
00719       contact_state.contact_state 
00720         = GroundContactState::CONTACT_RLEG_GROUND;
00721     }
00722     else if (support_status_ == BOTH_GROUND) {
00723       contact_state.contact_state
00724         = GroundContactState::CONTACT_BOTH_GROUND;
00725     }
00726     try 
00727     {
00728       tf::StampedTransform foot_transform;
00729       tf_listener_->lookupTransform(
00730         lfoot_frame_id_, rfoot_frame_id_, stamp, foot_transform);
00731       double roll, pitch, yaw;
00732       foot_transform.getBasis().getRPY(roll, pitch, yaw);
00733       contact_state.error_pitch_angle = std::abs(pitch);
00734       contact_state.error_roll_angle = std::abs(roll);
00735       contact_state.error_yaw_angle = std::abs(yaw);
00736       contact_state.error_z = std::abs(foot_transform.getOrigin().z());
00737       pub_contact_state_.publish(contact_state);
00738     }
00739     catch (tf2::ConnectivityException &e)
00740     {
00741       ROS_ERROR("[Footcoords::publishContactState] transform error: %s", e.what());
00742     }
00743     catch (tf2::InvalidArgumentException &e)
00744     {
00745       ROS_ERROR("[Footcoords::publishContactState] transform error: %s", e.what());
00746     }
00747     catch (tf2::ExtrapolationException &e)
00748     {
00749       ROS_ERROR("[Footcoords::publishContactState] transform error: %s", e.what());
00750     }
00751     catch (tf2::LookupException &e)
00752     {
00753       ROS_ERROR("[Footcoords::publishContactState] transform error: %s", e.what());
00754     }
00755 
00756   }
00757 
00758   bool Footcoords::computeMidCoordsFromSingleLeg(const ros::Time& stamp,
00759                                                  bool use_left_leg)
00760   {
00761     if (!waitForEndEffectorTransformation(stamp)) {
00762       ROS_ERROR("[Footcoords::computeMidCoordsFromSingleLeg] Failed to lookup endeffector transformation");
00763       return false;
00764     }
00765     else {
00766       try
00767       {
00768         tf::StampedTransform foot_transform; 
00769         if (use_left_leg) {     
00770           tf_listener_->lookupTransform(
00771             root_frame_id_, lfoot_frame_id_, stamp, foot_transform);
00772         }
00773         else {                  
00774           tf_listener_->lookupTransform(
00775             root_frame_id_, rfoot_frame_id_, stamp, foot_transform);
00776         }
00777         midcoords_ = foot_transform.inverse();
00778         return true;
00779       }
00780       catch (tf2::ConnectivityException &e)
00781       {
00782         ROS_ERROR("[Footcoords::computeMidCoordsFromSingleLeg] transform error: %s", e.what());
00783         return false;
00784       }
00785       catch (tf2::InvalidArgumentException &e)
00786       {
00787         ROS_ERROR("[Footcoords::computeMidCoordsFromSingleLeg] transform error: %s", e.what());
00788         return false;
00789       }
00790       catch (tf2::ExtrapolationException &e)
00791       {
00792         ROS_ERROR("[Footcoords::computeMidCoordsFromSingleLeg] transform error: %s", e.what());
00793       }
00794       catch (tf2::LookupException &e)
00795       {
00796         ROS_ERROR("[Footcoords::computeMidCoordsFromSingleLeg] transform error: %s", e.what());
00797       }
00798 
00799 
00800     }
00801   }
00802   
00803   bool Footcoords::computeMidCoords(const ros::Time& stamp)
00804   {
00805     if (!waitForEndEffectorTransformation(stamp)) {
00806       ROS_ERROR("[Footcoords::computeMidCoords] Failed to lookup endeffector transformation");
00807       return false;
00808     }
00809     else {
00810       try 
00811       {
00812         tf::StampedTransform lfoot_transform;
00813         tf_listener_->lookupTransform(
00814           root_frame_id_, lfoot_frame_id_, stamp, lfoot_transform);
00815         tf::StampedTransform rfoot_transform;
00816         tf_listener_->lookupTransform(
00817           root_frame_id_, rfoot_frame_id_, stamp, rfoot_transform);
00818         tf::Quaternion lfoot_rot = lfoot_transform.getRotation();
00819         tf::Quaternion rfoot_rot = rfoot_transform.getRotation();
00820         tf::Quaternion mid_rot = lfoot_rot.slerp(rfoot_rot, 0.5);
00821         tf::Vector3 lfoot_pos = lfoot_transform.getOrigin();
00822         tf::Vector3 rfoot_pos = rfoot_transform.getOrigin();
00823         tf::Vector3 mid_pos = lfoot_pos.lerp(rfoot_pos, 0.5);
00824         midcoords_.setOrigin(mid_pos);
00825         midcoords_.setRotation(mid_rot);
00826         midcoords_ = midcoords_;
00827         return true;
00828       }
00829       catch (tf2::ConnectivityException &e)
00830       {
00831         ROS_ERROR("[Footcoords::computeMidCoords] transform error: %s", e.what());
00832         return false;
00833       }
00834       catch (tf2::InvalidArgumentException &e)
00835       {
00836         ROS_ERROR("[Footcoords::computeMidCoords] transform error: %s", e.what());
00837         return false;
00838       }
00839       catch (tf2::ExtrapolationException &e)
00840       {
00841         ROS_ERROR("[Footcoords::computeMidCoords] transform error: %s", e.what());
00842       }
00843       catch (tf2::LookupException &e)
00844       {
00845         ROS_ERROR("[Footcoords::computeMidCoords] transform error: %s", e.what());
00846       }
00847 
00848     }
00849   }
00850 
00851   bool Footcoords::waitForSensorFrameTransformation(const ros::Time& lstamp,
00852                                                     const ros::Time& rstamp,
00853                                                    const std::string& lsensor_frame,
00854                                                    const std::string& rsensor_frame)
00855   {
00856     
00857     if (!tf_listener_->waitForTransform(
00858           lsensor_frame, lfoot_sensor_frame_, lstamp, ros::Duration(1.0))) {
00859       ROS_ERROR("[Footcoords::waitForSensorFrameTransformation] failed to lookup transform between %s and %s",
00860                 lsensor_frame.c_str(),
00861                 lfoot_sensor_frame_.c_str());
00862       return false;
00863     }
00864     if (!tf_listener_->waitForTransform(
00865           rsensor_frame, rfoot_sensor_frame_, rstamp, ros::Duration(1.0))) {
00866       ROS_ERROR("[Footcoords::waitForSensorFrameTransformation] failed to lookup transform between %s and %s",
00867                 rsensor_frame.c_str(),
00868                 rfoot_sensor_frame_.c_str());
00869       return false;
00870     }
00871     return true;
00872   }
00873 
00874   bool Footcoords::waitForEndEffectorTransformation(const ros::Time& stamp)
00875   {
00876     
00877     if (!tf_listener_->waitForTransform(
00878           root_frame_id_, lfoot_frame_id_, stamp, ros::Duration(1.0))) {
00879       ROS_ERROR("[Footcoords::waitForEndEffectorTrasnformation] failed to lookup transform between %s and %s",
00880                 root_frame_id_.c_str(),
00881                 lfoot_frame_id_.c_str());
00882       return false;
00883     }
00884     
00885     else if (!tf_listener_->waitForTransform(
00886                root_frame_id_, rfoot_frame_id_, stamp, ros::Duration(1.0))) {
00887       ROS_ERROR("[Footcoords::waitForEndEffectorTrasnformation]failed to lookup transform between %s and %s",
00888                 root_frame_id_.c_str(),
00889                 rfoot_frame_id_.c_str());
00890       return false;
00891     }
00892     
00893     else if (!tf_listener_->waitForTransform(
00894                lfoot_frame_id_, rfoot_frame_id_, stamp, ros::Duration(1.0))) {
00895       ROS_ERROR("[Footcoords::waitForEndEffectorTrasnformation]failed to lookup transform between %s and %s",
00896                 lfoot_frame_id_.c_str(),
00897                 rfoot_frame_id_.c_str());
00898       return false;
00899     }
00900     return true;
00901   }
00902 
00903   bool Footcoords::updateGroundTF()
00904   {
00905     
00906     
00907     
00908     
00909     
00910     if (false && support_status_ == BOTH_GROUND) {
00911       
00912       ground_transform_ = midcoords_ * locked_midcoords_to_odom_on_ground_;
00913     }
00914     else {
00915       Eigen::Affine3d odom_to_midcoords;
00916       tf::transformTFToEigen(midcoords_, odom_to_midcoords);
00917       Eigen::Affine3d midcoords_to_odom = odom_to_midcoords.inverse();
00918       Eigen::Affine3d midcoords_to_odom_on_ground = midcoords_to_odom;
00919       midcoords_to_odom_on_ground.translation().z() = 0.0;
00920       Eigen::Vector3d zaxis;
00921       zaxis[0] = midcoords_to_odom_on_ground(0, 2);
00922       zaxis[1] = midcoords_to_odom_on_ground(1, 2);
00923       zaxis[2] = midcoords_to_odom_on_ground(2, 2);
00924       Eigen::Quaterniond rot;
00925       rot.setFromTwoVectors(zaxis, Eigen::Vector3d(0, 0, 1));
00926       midcoords_to_odom_on_ground.rotate(rot);
00927       Eigen::Affine3d odom_to_odom_on_ground
00928         = odom_to_midcoords * midcoords_to_odom_on_ground;
00929       tf::transformEigenToTF(odom_to_odom_on_ground,
00930                              ground_transform_);
00931     }
00932   }
00933 
00934   void Footcoords::getRollPitch(const Eigen::Affine3d& pose, float& roll, float& pitch)
00935   {
00936     Eigen::Affine3f posef;
00937     jsk_pcl_ros::convertEigenAffine3(pose, posef);
00938     float yaw;
00939     pcl::getEulerAngles(posef, roll, pitch, yaw);
00940   }
00941 
00942   float Footcoords::getYaw(const Eigen::Affine3d& pose)
00943   {
00944     Eigen::Affine3f posef;
00945     jsk_pcl_ros::convertEigenAffine3(pose, posef);
00946     float roll, pitch, yaw;
00947     pcl::getEulerAngles(posef, roll, pitch, yaw);
00948     return yaw;
00949   }
00950 
00951   void Footcoords::publishTF(const ros::Time& stamp)
00952   {
00953     
00954     geometry_msgs::TransformStamped ros_midcoords, 
00955       ros_ground_coords, ros_odom_to_body_coords,
00956       ros_body_on_odom_coords, ros_odom_init_coords;
00957     
00958     
00959     
00960     
00961     std_msgs::Header header;
00962     header.stamp = stamp;
00963     header.frame_id = parent_frame_id_;
00964     ros_midcoords.header.stamp = stamp;
00965     ros_midcoords.header.frame_id = root_frame_id_;
00966     ros_midcoords.child_frame_id = midcoords_frame_id_;
00967     ros_ground_coords.header.stamp = stamp;
00968     ros_ground_coords.header.frame_id = parent_frame_id_;
00969     ros_ground_coords.child_frame_id = output_frame_id_;
00970     ros_odom_to_body_coords.header.stamp = stamp;
00971     ros_odom_to_body_coords.header.frame_id = parent_frame_id_;
00972     ros_odom_to_body_coords.child_frame_id = root_frame_id_;
00973     ros_body_on_odom_coords.header.stamp = stamp;
00974     ros_body_on_odom_coords.header.frame_id = root_frame_id_;
00975     ros_body_on_odom_coords.child_frame_id = body_on_odom_frame_;
00976     ros_odom_init_coords.header.stamp = stamp;
00977     if (invert_odom_init_) {
00978       ros_odom_init_coords.header.frame_id = odom_init_frame_id_;
00979       ros_odom_init_coords.child_frame_id = parent_frame_id_;
00980     } else {
00981       ros_odom_init_coords.header.frame_id = parent_frame_id_;
00982       ros_odom_init_coords.child_frame_id = odom_init_frame_id_;
00983     }
00984     Eigen::Affine3d identity = Eigen::Affine3d::Identity();
00985     float roll, pitch;
00986     getRollPitch(odom_pose_, roll, pitch);
00987     Eigen::Affine3d body_on_odom_pose = (Eigen::Translation3d(0,
00988                                                               0,
00989                                                               odom_pose_.translation()[2]) * 
00990                                          Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX()) *
00991                                          Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()));
00992     midcoords_.getRotation().normalize();
00993     Eigen::Affine3d odom_init_pose = (Eigen::Translation3d(odom_init_pose_.translation()[0],
00994                                                            odom_init_pose_.translation()[1],
00995                                                            odom_init_pose_.translation()[2]) * 
00996                                       Eigen::AngleAxisd(getYaw(odom_init_pose_), Eigen::Vector3d::UnitZ()));
00997 
00998     tf::transformTFToMsg(midcoords_, ros_midcoords.transform);
00999     tf::transformEigenToMsg(identity, ros_ground_coords.transform);
01000     tf::transformEigenToMsg(body_on_odom_pose.inverse(), ros_body_on_odom_coords.transform);
01001     tf::transformEigenToMsg(odom_pose_, ros_odom_to_body_coords.transform);
01002     if (invert_odom_init_) {
01003       tf::transformEigenToMsg(odom_init_pose.inverse(), ros_odom_init_coords.transform);
01004     } else {
01005       tf::transformEigenToMsg(odom_init_pose, ros_odom_init_coords.transform);
01006     }
01007     std::vector<geometry_msgs::TransformStamped> tf_transforms;
01008     tf_transforms.push_back(ros_midcoords);
01009     tf_transforms.push_back(ros_ground_coords);
01010     if (publish_odom_tf_) {
01011       tf_transforms.push_back(ros_odom_to_body_coords);
01012     }
01013     tf_transforms.push_back(ros_body_on_odom_coords);
01014     tf_transforms.push_back(ros_odom_init_coords);
01015     tf_broadcaster_.sendTransform(tf_transforms);
01016   }
01017 
01018   void Footcoords::odomInitTriggerCallback(const std_msgs::Empty& trigger)
01019   {
01020     boost::mutex::scoped_lock lock(mutex_);
01021     
01022     jsk_recognition_utils::Plane floor_plane(floor_coeffs_);
01023     floor_plane.project(odom_pose_, odom_init_pose_); 
01024     odom_init_pose_ = (Eigen::Translation3d(odom_init_pose_.translation()) *
01025                        Eigen::AngleAxisd(getYaw(odom_pose_), Eigen::Vector3d::UnitZ())); 
01026     
01027     
01028     
01029     geometry_msgs::TransformStamped ros_odom_init_coords;
01030     geometry_msgs::PoseStamped ros_odom_init_pose_stamped;
01031     Eigen::Affine3d odom_init_pose = (Eigen::Translation3d(odom_init_pose_.translation()[0],
01032                                                            odom_init_pose_.translation()[1],
01033                                                            odom_init_pose_.translation()[2]) * 
01034                                       Eigen::AngleAxisd(getYaw(odom_init_pose_), Eigen::Vector3d::UnitZ()));
01035     ros_odom_init_coords.header.stamp = ros::Time::now();
01036     ros_odom_init_coords.header.frame_id = parent_frame_id_;
01037     ros_odom_init_coords.child_frame_id = odom_init_frame_id_;
01038     tf::transformEigenToMsg(odom_init_pose, ros_odom_init_coords.transform);
01039     pub_odom_init_transform_.publish(ros_odom_init_coords);
01040     ros_odom_init_pose_stamped.header = ros_odom_init_coords.header;
01041     ros_odom_init_pose_stamped.pose.position.x = ros_odom_init_coords.transform.translation.x;
01042     ros_odom_init_pose_stamped.pose.position.y = ros_odom_init_coords.transform.translation.y;
01043     ros_odom_init_pose_stamped.pose.position.z = ros_odom_init_coords.transform.translation.z;
01044     ros_odom_init_pose_stamped.pose.orientation = ros_odom_init_coords.transform.rotation;
01045     pub_odom_init_pose_stamped_.publish(ros_odom_init_pose_stamped);
01046   }
01047 
01048   void Footcoords::floorCoeffsCallback(const pcl_msgs::ModelCoefficients& coeffs)
01049   {
01050     boost::mutex::scoped_lock lock(mutex_);
01051     tf::StampedTransform floor_transform;
01052 
01053     
01054     if (coeffs.header.frame_id != parent_frame_id_) {
01055       try {
01056         tf_listener_->lookupTransform(odom_init_frame_id_, coeffs.header.frame_id, coeffs.header.stamp, floor_transform);
01057       } catch (tf2::ConnectivityException &e) {
01058         ROS_ERROR("[Footcoords::floorCoeffsCallback] transform error: %s", e.what());
01059         return;
01060       } catch (tf2::InvalidArgumentException &e) {
01061         ROS_ERROR("[Footcoords::floorCoeffsCallback] transform error: %s", e.what());
01062         return;
01063       } catch (tf2::ExtrapolationException &e) {
01064         ROS_ERROR("[Footcoords::floorCoeffsCallback] transform error: %s", e.what());
01065         return;
01066       } catch (tf2::LookupException &e) {
01067         ROS_ERROR("[Footcoords::floorCoeffsCallback] transform error: %s", e.what());
01068         return;
01069       }
01070       Eigen::Affine3d floor_transform_eigen;
01071       jsk_recognition_utils::Plane tmp_plane(coeffs.values);
01072       tf::transformTFToEigen(floor_transform, floor_transform_eigen);
01073       tmp_plane.transform(floor_transform_eigen);
01074       floor_coeffs_ = tmp_plane.toCoefficients();
01075     } else {
01076       floor_coeffs_ = coeffs.values;
01077     }
01078   }
01079 
01080   void Footcoords::odomImuCallback(const nav_msgs::Odometry::ConstPtr& odom_msg,
01081                                    const sensor_msgs::Imu::ConstPtr& imu_msg)
01082   {
01083     boost::mutex::scoped_lock lock(mutex_);
01084     if (use_imu_) {
01085       Eigen::Affine3d odom_pose;
01086       tf::poseMsgToEigen(odom_msg->pose.pose, odom_pose);
01087       Eigen::Quaterniond imu_orientation;
01088       tf::quaternionMsgToEigen(imu_msg->orientation, imu_orientation);
01089       if (use_imu_yaw_) {
01090         odom_pose_ = Eigen::Translation3d(odom_pose.translation()) * imu_orientation;
01091       }
01092       else {
01093         float roll, pitch;
01094         getRollPitch(Eigen::Affine3d::Identity() * imu_orientation, roll, pitch);
01095         odom_pose_ = (Eigen::Translation3d(odom_pose.translation()) *
01096                       Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX()) *
01097                       Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()));
01098       }
01099     }
01100     else {
01101       tf::poseMsgToEigen(odom_msg->pose.pose, odom_pose_);
01102     }
01103   }
01104 }
01105 
01106 int main(int argc, char** argv)
01107 {
01108   ros::init(argc, argv, "footcoords");
01109   jsk_footstep_controller::Footcoords c;
01110   ros::spin();
01111 }