footcoords.cpp
Go to the documentation of this file.
00001 // -*- mode: C++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2013, Ryohei Ueda and JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Willow Garage nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
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     // read parameter
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     // pnh.param("lfoot_sensor_frame", lfoot_sensor_frame_, std::string("lfsensor"));
00106     // pnh.param("rfoot_sensor_frame", rfoot_sensor_frame_, std::string("rfsensor"));
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     // air -> warn
00156     // single leg, dual leg -> ok
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       // cancel translation
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       // lfoot_force = lfoot_rotation * lfoot_local;
00225       // rfoot_force = rfoot_rotation * rfoot_local;
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     //if (success_to_update) {
00262     tf::StampedTransform root_transform;
00263     try {
00264       // tf_listener_->lookupTransform(parent_frame_id_, root_frame_id_, event.current_real, root_transform);
00265       // root_link_pose_.setOrigin(root_transform.getOrigin());
00266       // root_link_pose_.setRotation(root_transform.getRotation());
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       // midcoords is a center coordinates of two feet
00283       // compute root_link -> midcoords
00284       // root_link_pose_ := odom -> root_link
00285       // midcoords_ := odom -> midcoords
00286       // root_link_pose_ * T = midcoords_
00287       // T = root_link_pose_^-1 * midcoords_
00288     //ground_transform_ = root_link_pose_.inverse() * midcoords_;
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     // Just for visualization
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        * if (chain.getSegment(i).getJoint().getType() == KDL::Joint::None)
00333        *   continue;
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     // lowpass filter
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     // resolve tf
00423     double lfoot_force = applyLowPassFilter(lfoot_force_vector[2], prev_lforce_);
00424     double rfoot_force = applyLowPassFilter(rfoot_force_vector[2], prev_rforce_);
00425 
00426     // publish lowlevel info
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       // only left
00446       support_status_ = LLEG_GROUND;
00447     }
00448     else if (rfoot_force >= force_thr_) {
00449       // only right
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     /* tf for debug*/
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     //estimateOdometryMainSupportLeg();
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       /* Update odom origin */
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       /* Update odom origin */
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         /* switch to lleg */
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       /* Update odom origin */
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         /* switch to lleg */
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; // parent -> foot
00769         if (use_left_leg) {     // left on the ground
00770           tf_listener_->lookupTransform(
00771             root_frame_id_, lfoot_frame_id_, stamp, foot_transform);
00772         }
00773         else {                  // right on the ground
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     // lfsensor -> lleg_end_coords
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     // odom -> lfoot
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     // odom -> rfoot
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     // lfoot -> rfoot
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     // project `/odom` on the plane of midcoords_
00906     // odom -> midcoords is available as `midcoords_`
00907     // we need odom -> odom_on_ground
00908     // 1. in order to get translation,
00909     //    project odom point to
00910     if (false && support_status_ == BOTH_GROUND) {
00911       // use locked_midcoords_to_odom_on_ground_ during dual stance phase
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     // publish midcoords_ and ground_cooords_
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     // ros_midcoords: ROOT -> ground
00958     // ros_ground_coords: odom -> odom_on_ground = identity
00959     // ros_odom_root_coords: odom -> odom_root = identity
00960     // ros_ground_coords: odom_root -> odom_on_ground = identity
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     // Update odom_init_pose
01022     jsk_recognition_utils::Plane floor_plane(floor_coeffs_);
01023     floor_plane.project(odom_pose_, odom_init_pose_); // this projection do not consider yaw orientations
01024     odom_init_pose_ = (Eigen::Translation3d(odom_init_pose_.translation()) *
01025                        Eigen::AngleAxisd(getYaw(odom_pose_), Eigen::Vector3d::UnitZ())); // assuming that projected plane is horizontal
01026     
01027     // publish odom_init topics
01028     // whether invert_odom_init is true or not odom_init_pose_stamped and odom_init_transform is described in odom coordinates.
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     // floor_coords is expected to be described in parent_frame_id_ relative coordinate
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 }


jsk_footstep_controller
Author(s):
autogenerated on Fri Apr 19 2019 03:45:37