base_footprint.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  * Publish the Nao humanoid's base_footprint frame according to REP-120
00004  * Based on nao_common/remap_odometry.cpp
00005  *
00006  * Copyright 2013 Armin Hornung, Stefan Osswald, University of Freiburg
00007  * http://www.ros.org/wiki/nao
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions 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 copyright
00015  *       notice, this list of conditions and the following disclaimer in the
00016  *       documentation and/or other materials provided with the distribution.
00017  *     * Neither the name of the University of Freiburg nor the names of its
00018  *       contributors may be used to endorse or promote products derived from
00019  *       this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031  * POSSIBILITY OF SUCH DAMAGE.
00032  */
00033 
00034 #include <ros/ros.h>
00035 #include <message_filters/subscriber.h>
00036 #include <tf/transform_broadcaster.h>
00037 #include <tf/transform_datatypes.h>
00038 #include <tf/transform_listener.h>
00039 #include <tf/message_filter.h>
00040 #include <sensor_msgs/JointState.h>
00041 
00042 class BaseFootprint
00043 {
00044 public:
00045         BaseFootprint();
00046         ~BaseFootprint();
00047 
00048 
00049 private:
00050   void jsCallback(const sensor_msgs::JointState::ConstPtr & msg);
00051 
00052   ros::NodeHandle m_nh;
00053   ros::NodeHandle m_privateNh;
00054 
00055   // for base_footprint_frame: broadcasts frame between right and left foot, coinciding with the ground
00056   message_filters::Subscriber<sensor_msgs::JointState> * m_jsSub;
00057   tf::MessageFilter<sensor_msgs::JointState> * m_jsFilter;
00058   tf::TransformBroadcaster m_brBaseFootPrint;
00059   tf::TransformListener m_listener;
00060 
00061   std::string m_odomFrameId;
00062   std::string m_baseFrameId;
00063   std::string m_lfootFrameId;
00064   std::string m_rfootFrameId;
00065   std::string m_baseFootPrintID;
00066 
00067 };
00068 
00069 BaseFootprint::BaseFootprint()
00070   : m_privateNh("~"), m_odomFrameId("odom"), m_baseFrameId("base_link"),
00071     m_lfootFrameId("l_sole"), m_rfootFrameId("r_sole"),
00072     m_baseFootPrintID("base_footprint")
00073 {
00074   // Read parameters
00075   m_privateNh.param("odom_frame_id", m_odomFrameId, m_odomFrameId);
00076   m_privateNh.param("base_frame_id", m_baseFrameId, m_baseFrameId);
00077   m_privateNh.param("base_footprint_frame_id", m_baseFootPrintID, m_baseFootPrintID);
00078 
00079 
00080   // Resolve TF frames using ~tf_prefix parameter
00081 
00082   m_odomFrameId = m_listener.resolve(m_odomFrameId);
00083   m_baseFrameId = m_listener.resolve(m_baseFrameId);
00084   m_baseFootPrintID = m_listener.resolve(m_baseFootPrintID);
00085   m_lfootFrameId = m_listener.resolve(m_lfootFrameId);
00086   m_rfootFrameId = m_listener.resolve(m_rfootFrameId);
00087 
00088   // subscribe to joint_states to provide a clock signal for synchronization
00089   // since the frames are computed based on the joint state, all should be available
00090   // with the same time stamps
00091   m_jsSub = new message_filters::Subscriber<sensor_msgs::JointState>(m_nh, "joint_states", 50);
00092   m_jsFilter = new tf::MessageFilter<sensor_msgs::JointState>(*m_jsSub, m_listener, m_rfootFrameId, 50);
00093   std::vector<std::string> frames;
00094   frames.push_back(m_rfootFrameId);
00095   frames.push_back(m_odomFrameId);
00096   m_jsFilter->setTargetFrames(frames);
00097   m_jsFilter->registerCallback(boost::bind(&BaseFootprint::jsCallback, this, _1));
00098 }
00099 
00100 BaseFootprint::~BaseFootprint(){
00101   delete m_jsFilter;
00102   delete m_jsSub;
00103 }
00104 
00105 void BaseFootprint::jsCallback(const sensor_msgs::JointState::ConstPtr & ptr)
00106 {
00107   ros::Time time = ptr->header.stamp;
00108   tf::StampedTransform tf_odom_to_base, tf_odom_to_left_foot, tf_odom_to_right_foot;
00109 
00110   ROS_DEBUG("JointState callback function, computing frame %s", m_baseFootPrintID.c_str());
00111   try {
00112     m_listener.lookupTransform(m_odomFrameId, m_lfootFrameId, time, tf_odom_to_left_foot);
00113     m_listener.lookupTransform(m_odomFrameId, m_rfootFrameId, time, tf_odom_to_right_foot);
00114     m_listener.lookupTransform(m_odomFrameId, m_baseFrameId,  time, tf_odom_to_base);
00115   } catch (const tf::TransformException& ex){
00116     ROS_ERROR("%s",ex.what());
00117     return ;
00118   }
00119 
00120   tf::Vector3 new_origin = (tf_odom_to_right_foot.getOrigin() + tf_odom_to_left_foot.getOrigin())/2.0; // middle of both feet
00121   double height = std::min(tf_odom_to_left_foot.getOrigin().getZ(), tf_odom_to_right_foot.getOrigin().getZ()); // fix to lowest foot
00122   new_origin.setZ(height);
00123 
00124   // adjust yaw according to torso orientation, all other angles 0 (= in z-plane)
00125   double roll, pitch, yaw;
00126   tf_odom_to_base.getBasis().getRPY(roll, pitch, yaw);
00127 
00128   tf::Transform tf_odom_to_footprint(tf::createQuaternionFromYaw(yaw), new_origin);
00129   tf::Transform tf_base_to_footprint = tf_odom_to_base.inverse() * tf_odom_to_footprint;
00130 
00131   // publish transform with parent m_baseFrameId and new child m_baseFootPrintID
00132   // i.e. transform from m_baseFrameId to m_baseFootPrintID
00133   m_brBaseFootPrint.sendTransform(tf::StampedTransform(tf_base_to_footprint, time, m_baseFrameId, m_baseFootPrintID));
00134   ROS_DEBUG("Published Transform %s --> %s", m_baseFrameId.c_str(), m_baseFootPrintID.c_str());
00135 
00136   return;
00137 
00138 }
00139 
00140 int main(int argc, char** argv){
00141   ros::init(argc, argv, "base_footprint");
00142   BaseFootprint baseFootprint;
00143   ros::spin();
00144 
00145   return 0;
00146 }
00147 
00148 


nao_description
Author(s): Armin Hornung, Stefan Osswald
autogenerated on Sat Jun 8 2019 20:38:41