door_functions.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2008, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 #include "pr2_doors_common/door_functions.h"
00036 #include <kdl/frames.hpp>
00037 
00038 using namespace ros;
00039 using namespace std;
00040 using namespace KDL;
00041 
00042 
00043 namespace pr2_doors_common
00044 {
00045   static const double eps_angle = 5.0*M_PI/180.0;
00046   static const double gripper_height = 0.8;
00047 
00048   tf::Stamped<tf::Pose> getRobotPose(const door_msgs::Door& door, double dist)
00049   {
00050     Vector x_axis(1,0,0);
00051     
00052     // get vector to center of frame
00053     Vector frame_1(door.frame_p1.x, door.frame_p1.y, door.frame_p1.z);
00054     Vector frame_2(door.frame_p2.x, door.frame_p2.y, door.frame_p2.z);
00055     Vector frame_center = (frame_2 + frame_1)/2.0;
00056     
00057     // get robot pos
00058     Vector frame_normal = getFrameNormal(door);
00059     Vector robot_pos = frame_center + (frame_normal * dist);
00060     tf::Stamped<tf::Pose> robot_pose;
00061     robot_pose.frame_id_ = door.header.frame_id;
00062     robot_pose.stamp_ = door.header.stamp;
00063     robot_pose.setOrigin( tf::Vector3(robot_pos(0), robot_pos(1), robot_pos(2)));
00064     robot_pose.setRotation( tf::createQuaternionFromRPY(getVectorAngle(x_axis, frame_normal), 0, 0) ); 
00065     
00066     return robot_pose;  
00067   }
00068   
00069   double getNearestDoorAngle(const tf::Pose& robot_pose, const door_msgs::Door& door, double robot_dist, double touch_dist)
00070   { 
00071     double angle = 0, step = 0;
00072     if (door.rot_dir == door.ROT_DIR_CLOCKWISE)
00073       step = -0.01;
00074     else if (door.rot_dir == door.ROT_DIR_COUNTERCLOCKWISE)
00075       step = 0.01;
00076     else{
00077       ROS_ERROR("Door rot dir is not specified");
00078       return 0.0;
00079     }
00080 
00081     while ((robot_pose.getOrigin() - getGripperPose(door, angle, touch_dist).getOrigin()).length() < robot_dist &&
00082            fabs(angle) < M_PI_2)
00083       angle += step;
00084 
00085     return angle;
00086   }
00087 
00088   tf::Stamped<tf::Pose> getGripperPose(const door_msgs::Door& door, double angle, double dist)
00089   {
00090     Vector x_axis(1,0,0);
00091     
00092     // get hinge point
00093     Vector hinge, frame_vec;
00094     if (door.hinge == door_msgs::Door::HINGE_P1){
00095       hinge = Vector(door.door_p1.x, door.door_p1.y, door.door_p1.z);
00096       frame_vec = Vector(door.frame_p2.x - door.frame_p1.x, door.frame_p2.y - door.frame_p1.y, door.frame_p2.z - door.frame_p1.z);
00097     }
00098     else if (door.hinge == door_msgs::Door::HINGE_P2){
00099       hinge = Vector(door.door_p2.x, door.door_p2.y, door.door_p2.z);
00100       frame_vec = Vector(door.frame_p1.x - door.frame_p2.x, door.frame_p1.y - door.frame_p2.y, door.frame_p1.z - door.frame_p2.z);
00101     }
00102 
00103     // get gripper pos
00104     frame_vec.Normalize();
00105     frame_vec = frame_vec * dist;
00106     Rotation rot_angle = Rotation::RotZ(angle);
00107     Vector gripper_pos = hinge + (rot_angle * frame_vec);
00108     
00109     tf::Stamped<tf::Pose> gripper_pose;
00110     Vector normal_frame = getFrameNormal(door);
00111     gripper_pose.frame_id_ = door.header.frame_id;
00112     gripper_pose.stamp_ = door.header.stamp;
00113     gripper_pose.setOrigin( tf::Vector3(gripper_pos(0), gripper_pos(1), gripper_height));
00114     gripper_pose.setRotation( tf::createQuaternionFromRPY(getVectorAngle(x_axis, normal_frame)+angle, 0, 0) ); 
00115     
00116     return gripper_pose;  
00117   }
00118 
00119   tf::Stamped<tf::Pose> getGripperPose(const door_msgs::Door& door, double angle, double dist, int side)
00120   {
00121     Vector x_axis(1,0,0);
00122     
00123     // get hinge point
00124     Vector hinge, frame_vec;
00125     if (door.hinge == door_msgs::Door::HINGE_P1){
00126       hinge = Vector(door.door_p1.x, door.door_p1.y, door.door_p1.z);
00127       frame_vec = Vector(door.frame_p2.x - door.frame_p1.x, door.frame_p2.y - door.frame_p1.y, door.frame_p2.z - door.frame_p1.z);
00128     }
00129     else if (door.hinge == door_msgs::Door::HINGE_P2){
00130       hinge = Vector(door.door_p2.x, door.door_p2.y, door.door_p2.z);
00131       frame_vec = Vector(door.frame_p1.x - door.frame_p2.x, door.frame_p1.y - door.frame_p2.y, door.frame_p1.z - door.frame_p2.z);
00132     }
00133 
00134     // get gripper pos
00135     frame_vec.Normalize();
00136     frame_vec = frame_vec * dist;
00137     Rotation rot_angle = Rotation::RotZ(angle);
00138     Vector gripper_pos = hinge + (rot_angle * frame_vec);
00139     
00140     tf::Stamped<tf::Pose> gripper_pose;
00141     Vector normal_frame = getFrameNormal(door);
00142     gripper_pose.frame_id_ = door.header.frame_id;
00143     gripper_pose.stamp_ = door.header.stamp;
00144     gripper_pose.setOrigin( tf::Vector3(gripper_pos(0), gripper_pos(1), gripper_height));
00145     if(side == door_msgs::DoorCmd::PULL)
00146     {
00147       gripper_pose.setRotation( tf::createQuaternionFromRPY(getVectorAngle(-x_axis, normal_frame)+angle, 0, 0) ); 
00148     }
00149     else
00150     {
00151       gripper_pose.setRotation( tf::createQuaternionFromRPY(getVectorAngle(x_axis, normal_frame)+angle, 0, 0) ); 
00152     }
00153     return gripper_pose;  
00154   }
00155 
00156 
00157   geometry_msgs::Point32 getHingeAxisPoint(const door_msgs::Door& door)
00158   {
00159     geometry_msgs::Point32 hinge;
00160     if (door.hinge == door_msgs::Door::HINGE_P1){
00161       hinge = door.door_p1;
00162     }
00163     else if (door.hinge == door_msgs::Door::HINGE_P2){
00164       hinge = door.door_p2;
00165     }
00166     return hinge;
00167   }
00168 
00169   geometry_msgs::Point32 getEdgePoint(const door_msgs::Door& door)
00170   {
00171     geometry_msgs::Point32 edge;
00172     if (door.hinge == door_msgs::Door::HINGE_P1){
00173       edge = door.door_p2;
00174     }
00175     else if (door.hinge == door_msgs::Door::HINGE_P2){
00176       edge = door.door_p1;
00177     }
00178     return edge;
00179   }
00180 
00181   tf::Stamped<tf::Pose> getHandlePose(const door_msgs::Door& door, int side)
00182   {
00183     Vector x_axis(1,0,0);
00184     
00185     double dist = sqrt(pow(door.frame_p1.x - door.handle.x,2)+pow(door.frame_p1.y - door.handle.y,2));
00186     if(door.hinge == door_msgs::Door::HINGE_P2)
00187     {
00188       dist = sqrt(pow(door.frame_p2.x - door.handle.x,2)+pow(door.frame_p2.y - door.handle.y,2));
00189     }
00190     double angle = getDoorAngle(door);
00191 
00192     // get hinge point
00193     Vector hinge, frame_vec;
00194     if (door.hinge == door_msgs::Door::HINGE_P1){
00195       hinge = Vector(door.door_p1.x, door.door_p1.y, door.door_p1.z);
00196       frame_vec = Vector(door.frame_p2.x - door.frame_p1.x, door.frame_p2.y - door.frame_p1.y, door.frame_p2.z - door.frame_p1.z);
00197     }
00198     else if (door.hinge == door_msgs::Door::HINGE_P2){
00199       hinge = Vector(door.door_p2.x, door.door_p2.y, door.door_p2.z);
00200       frame_vec = Vector(door.frame_p1.x - door.frame_p2.x, door.frame_p1.y - door.frame_p2.y, door.frame_p1.z - door.frame_p2.z);
00201     }
00202 
00203     // get gripper pos
00204     frame_vec.Normalize();
00205     frame_vec = frame_vec * dist;
00206     Rotation rot_angle = Rotation::RotZ(angle);
00207     Vector handle_pos = hinge + (rot_angle * frame_vec);
00208     
00209     tf::Stamped<tf::Pose> handle_pose;
00210     Vector normal_frame = getFrameNormal(door);
00211     if(side == -1)
00212     {
00213       normal_frame = -normal_frame;
00214     }
00215     handle_pose.frame_id_ = door.header.frame_id;
00216     handle_pose.stamp_ = door.header.stamp;
00217     handle_pose.setOrigin( tf::Vector3(handle_pos(0), handle_pos(1), gripper_height));
00218     handle_pose.setRotation( tf::createQuaternionFromRPY(getVectorAngle(x_axis, normal_frame)+angle, 0, 0) ); 
00219     
00220     tf::Pose gripper_rotate(tf::createQuaternionFromRPY(0.0,0.0,M_PI/2.0),tf::Vector3(0.0,0.0,0.0));
00221     handle_pose.mult(handle_pose,gripper_rotate);
00222     return handle_pose;  
00223   }
00224 
00225   double getDoorAngle(const door_msgs::Door& door)
00226   {
00227     Vector frame_vec(door.frame_p1.x-door.frame_p2.x, door.frame_p1.y-door.frame_p2.y, door.frame_p1.z-door.frame_p2.z);
00228     Vector door_vec(door.door_p1.x-door.door_p2.x, door.door_p1.y-door.door_p2.y, door.door_p1.z-door.door_p2.z);
00229     double angle = getVectorAngle(frame_vec, door_vec);
00230 
00231     // validity check
00232     if (door.rot_dir == door_msgs::Door::ROT_DIR_CLOCKWISE && angle > eps_angle)
00233       ROS_DEBUG("Door angle is positive, but door message specifies it turns clockwise");
00234 
00235     if (door.rot_dir == door_msgs::Door::ROT_DIR_COUNTERCLOCKWISE && angle < -eps_angle)
00236       ROS_DEBUG("Door angle is negative, but door message specifies it turns counter-clockwise");
00237 
00238     return angle;
00239   }
00240 
00241   double getVectorAngle(const Vector& v1, const Vector& v2)
00242   {
00243     Vector vec1 = v1; vec1.Normalize();
00244     Vector vec2 = v2; vec2.Normalize();
00245     double dot      = vec2(0) * vec1(0) + vec2(1) * vec1(1);
00246     double perp_dot = vec2(1) * vec1(0) - vec2(0) * vec1(1);
00247     return atan2(perp_dot, dot);
00248   }
00249 
00250   Vector getDoorNormal(const door_msgs::Door& door)
00251   {
00252     Vector frame_normal = getFrameNormal(door);
00253     Rotation rot_frame_door = Rotation::RotZ(getDoorAngle(door));
00254     return rot_frame_door * frame_normal;
00255   }
00256 
00257   Vector getFrameNormal(const door_msgs::Door& door)
00258   {
00259     // normal on frame
00260     Vector p12(door.frame_p1.x-door.frame_p2.x, door.frame_p1.y-door.frame_p2.y, door.frame_p1.z-door.frame_p2.z);
00261     p12.Normalize();
00262     Vector z_axis(0,0,1);
00263     Vector normal = p12 * z_axis;
00264 
00265     // make normal point in direction we travel through door
00266     Vector dir(door.travel_dir.x, door.travel_dir.y, door.travel_dir.z);
00267     if (dot(dir, normal) < 0)
00268       normal = normal * -1.0;
00269 
00270     return normal;
00271   }
00272 
00273   bool transformTo(const tf::Transformer& tf, const string& goal_frame, const door_msgs::Door& door_in, door_msgs::Door& door_out, const std::string& fixed_frame)
00274   {
00275     door_out = door_in;
00276     ros::Time time_now = ros::Time::now();
00277     if (!transformPointTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.frame_p1, door_out.frame_p1, fixed_frame, time_now)) return false;
00278     if (!transformPointTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.frame_p2, door_out.frame_p2, fixed_frame, time_now)) return false;
00279     if (!transformPointTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.door_p1, door_out.door_p1, fixed_frame, time_now)) return false;
00280     if (!transformPointTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.door_p2, door_out.door_p2, fixed_frame, time_now)) return false;
00281     if (!transformPointTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.handle, door_out.handle, fixed_frame, time_now)) return false;
00282     if (!transformVectorTo(tf, door_in.header.frame_id, goal_frame, door_in.header.stamp, door_in.travel_dir, door_out.travel_dir, fixed_frame, time_now)) return false;
00283     door_out.header.frame_id = goal_frame;
00284     door_out.header.stamp = time_now;
00285     return true;
00286   }
00287 
00288   bool transformPointTo(const tf::Transformer& tf, const string& source_frame, const string& goal_frame, const Time& time_source,
00289                         const geometry_msgs::Point32& point_in, geometry_msgs::Point32& point_out, const std::string& fixed_frame, const Time& time_goal)
00290   {
00291     ros::Duration timeout = Duration().fromSec(5.0);
00292     if (!tf.waitForTransform(source_frame, time_source, goal_frame, time_goal, fixed_frame, timeout)) return false;
00293     tf::Stamped<tf::Point> pnt(tf::Vector3(point_in.x, point_in.y, point_in.z), time_source, source_frame);
00294     tf.transformPoint(goal_frame, time_goal, pnt, fixed_frame, pnt);
00295     point_out.x = pnt[0];
00296     point_out.y = pnt[1];
00297     point_out.z = pnt[2];
00298 
00299     return true;
00300   }
00301 
00302   bool transformVectorTo(const tf::Transformer& tf, const string& source_frame, const string& goal_frame, const Time& time_source,
00303                          const geometry_msgs::Vector3& point_in, geometry_msgs::Vector3& point_out, const std::string& fixed_frame, const Time& time_goal)
00304   {
00305     ros::Duration timeout = Duration().fromSec(2.0);
00306     if (!tf.waitForTransform(source_frame, time_source, goal_frame, time_goal, fixed_frame, timeout)) return false;
00307     tf::Stamped<tf::Point> pnt(tf::Vector3(point_in.x, point_in.y, point_in.z), time_source, source_frame);
00308     tf.transformVector(goal_frame, time_goal, pnt, fixed_frame, pnt);
00309     point_out.x = pnt[0];
00310     point_out.y = pnt[1];
00311     point_out.z = pnt[2];
00312 
00313     return true;
00314   }
00315 
00316   std::vector<geometry_msgs::Point> getPolygon(const door_msgs::Door& door, const double &door_thickness)
00317   {
00318     std::vector<geometry_msgs::Point> door_polygon;
00319     geometry_msgs::Point tmp;
00320     Vector door_normal = getDoorNormal(door);
00321     tmp.x = door.frame_p1.x + door_normal(0) * door_thickness/2.0;
00322     tmp.y = door.frame_p1.y + door_normal(1) * door_thickness/2.0;
00323     door_polygon.push_back(tmp);
00324 
00325     tmp.x = door.frame_p1.x - door_normal(0) * door_thickness/2.0;
00326     tmp.y = door.frame_p1.y - door_normal(1) * door_thickness/2.0;
00327     door_polygon.push_back(tmp);
00328 
00329     tmp.x = door.frame_p2.x - door_normal(0) * door_thickness/2.0;
00330     tmp.y = door.frame_p2.y - door_normal(1) * door_thickness/2.0;
00331     door_polygon.push_back(tmp);
00332 
00333     tmp.x = door.frame_p2.x + door_normal(0) * door_thickness/2.0;
00334     tmp.y = door.frame_p2.y + door_normal(1) * door_thickness/2.0;
00335     door_polygon.push_back(tmp);
00336     return door_polygon;
00337   }
00338 
00339   door_msgs::Door rotateDoor(const door_msgs::Door& door, const double &angle)
00340   {
00341     door_msgs::Door result = door;
00342     geometry_msgs::Point32 hinge = door.frame_p1;
00343     geometry_msgs::Point32 edge = door.frame_p2;
00344     if(door.hinge == door.HINGE_P2)
00345     {
00346       hinge = door.frame_p2;
00347       edge = door.frame_p1;
00348     }
00349     double handle_distance = sqrt(pow(door.handle.y-hinge.y,2) + pow(door.handle.x-hinge.x,2)); //assumes handle is flush with door
00350     double door_frame_global_yaw = atan2(edge.y-hinge.y,edge.x-hinge.x);
00351     double door_length = sqrt(pow(edge.y-hinge.y,2) + pow(edge.x-hinge.x,2));
00352 
00353     double sth = sin(door_frame_global_yaw+angle);
00354     double cth = cos(door_frame_global_yaw+angle);
00355 
00356     geometry_msgs::Point32 new_edge;
00357     new_edge.x = hinge.x + cth *door_length;
00358     new_edge.y = hinge.y + sth *door_length;
00359     geometry_msgs::Point32 new_handle = door.handle;
00360     new_handle.x = hinge.x + cth*handle_distance;
00361     new_handle.y = hinge.y + sth*handle_distance;
00362 
00363     result.door_p1 = hinge;
00364     result.door_p2 = new_edge;
00365     if(door.hinge == door.HINGE_P2)
00366     {
00367       result.door_p2 = hinge;
00368       result.door_p1 = new_edge;
00369     }
00370     result.handle = new_handle;
00371     return result;
00372   }
00373 
00374   double getFrameAngle(const door_msgs::Door& door)
00375   {
00376     double result;
00377     if(door.hinge == door.HINGE_P1)
00378     {   
00379       result =  atan2(door.frame_p2.y - door.frame_p1.y, door.frame_p2.x - door.frame_p1.x);
00380     }
00381     else
00382     {
00383       result =  atan2(door.frame_p1.y - door.frame_p2.y, door.frame_p1.x - door.frame_p2.x);
00384     }
00385     return result;
00386   }
00387 
00388   double getHandleDir(const door_msgs::Door& d)
00389   {
00390     Vector normal = getFrameNormal(d);
00391     Vector frame_vec;
00392     if (d.hinge == door_msgs::Door::HINGE_P1)
00393       frame_vec = Vector(d.frame_p2.x - d.frame_p1.x, d.frame_p2.y - d.frame_p1.y, d.frame_p2.z - d.frame_p1.z);
00394     else if (d.hinge == door_msgs::Door::HINGE_P2)
00395       frame_vec = Vector(d.frame_p1.x - d.frame_p2.x, d.frame_p1.y - d.frame_p2.y, d.frame_p1.z - d.frame_p2.z);
00396     else
00397       ROS_ERROR("Hinge side is not defined");
00398 
00399     Vector rot_vec = frame_vec * normal;
00400     if (rot_vec(2) > 0)
00401       return -1.0;
00402     else
00403       return 1.0;
00404   }
00405 
00406   double getDoorDir(const door_msgs::Door& d)
00407   {
00408     // get frame vector
00409     Vector frame_vec;
00410     if (d.hinge == door_msgs::Door::HINGE_P1)
00411       frame_vec = Vector(d.frame_p2.x - d.frame_p1.x, d.frame_p2.y - d.frame_p1.y, d.frame_p2.z - d.frame_p1.z);
00412     else if (d.hinge == door_msgs::Door::HINGE_P2)
00413       frame_vec = Vector(d.frame_p1.x - d.frame_p2.x, d.frame_p1.y - d.frame_p2.y, d.frame_p1.z - d.frame_p2.z);
00414     else
00415       ROS_ERROR("Hinge side is not defined");
00416 
00417     // rotate frame vector
00418     if (d.rot_dir == door_msgs::Door::ROT_DIR_CLOCKWISE)
00419       frame_vec = Rotation::RotZ(-M_PI_2) * frame_vec;
00420     else if (d.rot_dir == door_msgs::Door::ROT_DIR_COUNTERCLOCKWISE)
00421       frame_vec = Rotation::RotZ(M_PI_2) * frame_vec;
00422     else
00423       ROS_ERROR("Rot dir is not defined");
00424 
00425     if (dot(frame_vec, getFrameNormal(d)) < 0)
00426       return -1.0; 
00427     else
00428       return 1.0;
00429   }
00430 
00431   std::ostream& operator<< (std::ostream& os, const door_msgs::Door& d)
00432   {
00433     os << "Door message in " << d.header.frame_id << " at time " << d.header.stamp.toSec() << endl;
00434     os << " - frame (" 
00435        << d.frame_p1.x << " " << d.frame_p1.y << " "<< d.frame_p1.z << ") -- (" 
00436        << d.frame_p2.x << " " << d.frame_p2.y << " "<< d.frame_p2.z << ")" << endl;
00437 
00438     os << " - door (" 
00439        << d.door_p1.x << " " << d.door_p1.y << " "<< d.door_p1.z << ") -- (" 
00440        << d.door_p2.x << " " << d.door_p2.y << " "<< d.door_p2.z << ")" << endl;
00441 
00442     os << " - handle (" 
00443        << d.handle.x << " " << d.handle.y << " "<< d.handle.z << ")" << endl;
00444 
00445     os << " - travel_dir (" 
00446        << d.travel_dir.x << " " << d.travel_dir.y << " "<< d.travel_dir.z << ")" << endl;
00447 
00448     os << " - latch_state " << d.latch_state << endl;
00449     os << " - hinge side " << d.hinge << endl;
00450     os << " - rot_dir " << d.rot_dir << endl;
00451     os << " - angle [deg] " << getDoorAngle(d)*180.0/M_PI << endl;
00452     return os;
00453   }
00454 
00455 
00456 }


pr2_doors_common
Author(s): Wim Meeussen
autogenerated on Wed Dec 11 2013 14:16:50