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 
00037 #include "pr2_plugs_actions/align_base.h"
00038 
00039 using namespace ros;
00040 using namespace std;
00041 
00042 static const string fixed_frame = "odom_combined";
00043 
00044 
00045 namespace pr2_plugs_actions{
00046 
00047 AlignBaseAction::AlignBaseAction() :
00048   wall_detector_("detect_wall_norm", true),
00049   move_base_omnidirectional_("move_base_omnidirectional", true),
00050   action_server_(ros::NodeHandle(), 
00051                  "align_base", 
00052                  boost::bind(&AlignBaseAction::execute, this, _1),
00053                  true)
00054 {
00055   ROS_INFO("Waiting for action servers");
00056   wall_detector_.waitForServer();
00057   move_base_omnidirectional_.waitForServer();
00058 };
00059 
00060 
00061 AlignBaseAction::~AlignBaseAction()
00062 {};
00063 
00064 
00065 void AlignBaseAction::execute(const pr2_plugs_msgs::AlignBaseGoalConstPtr& goal)
00066 { 
00067   ROS_INFO("AlignBaseAction: execute");
00068 
00069   
00070   pr2_plugs_msgs::DetectWallNormGoal wall_norm_goal;
00071   wall_norm_goal.look_point = goal->look_point;
00072   wall_norm_goal.look_point.point.y = -fabs(goal->desired_distance);
00073   while (ros::ok() && wall_detector_.sendGoalAndWait(wall_norm_goal, ros::Duration(100.0), ros::Duration(5.0)) != actionlib::SimpleClientGoalState::SUCCEEDED)
00074     ROS_INFO("AlignBaseAction: try again to get wall norm");
00075   
00076   
00077   geometry_msgs::PointStamped wall_point_msg = wall_detector_.getResult()->wall_point;
00078   geometry_msgs::Vector3Stamped wall_norm_msg = wall_detector_.getResult()->wall_norm;
00079   if (!tf_.waitForTransform(fixed_frame, wall_norm_msg.header.frame_id, wall_norm_msg.header.stamp, ros::Duration(2.0))){
00080     ROS_ERROR("AlignBaseAction: failed to transform from frame %s to %s at time %f", fixed_frame.c_str(), wall_norm_msg.header.frame_id.c_str(), wall_norm_msg.header.stamp.toSec());
00081     action_server_.setAborted();
00082     return;
00083   }
00084   tf_.transformPoint(fixed_frame, wall_point_msg, wall_point_msg);
00085   tf_.transformVector(fixed_frame, wall_norm_msg, wall_norm_msg);
00086   tf::Vector3 wall_norm = fromVector(wall_norm_msg.vector);
00087   tf::Vector3 wall_point = fromPoint(wall_point_msg.point);
00088   ROS_INFO("AlignBaseAction: wall norm  %f %f %f", wall_norm.x(), wall_norm.y(), wall_norm.z());
00089   ROS_INFO("AlignBaseAction: wall point %f %f %f", wall_point.x(), wall_point.y(), wall_point.z());
00090 
00091   
00092   if (fabs(wall_norm.z()) > 0.3){
00093     ROS_ERROR("A wall should be vertical. This vector (%f, %f, %f) is not vertical", wall_norm.x(), wall_norm.y(), wall_norm.z());
00094     action_server_.setAborted();
00095     return;
00096   }
00097   
00098   
00099   tf::StampedTransform robot_pose;
00100   if (!tf_.waitForTransform(fixed_frame, "base_link", ros::Time(), ros::Duration(2.0))){
00101     ROS_ERROR("AlignBaseAction: failed to transform from frame %s to base_link", fixed_frame.c_str());
00102     action_server_.setAborted();
00103     return;
00104   }
00105   tf_.lookupTransform(fixed_frame, "base_link", ros::Time(), robot_pose);
00106   ROS_INFO("AlignBaseAction: current robot pose %f %f ==> %f", robot_pose.getOrigin().x(), robot_pose.getOrigin().y(), tf::getYaw(robot_pose.getRotation()));
00107   
00108   
00109   tf::Pose desired_pose;
00110   desired_pose.setOrigin(robot_pose.getOrigin() + (wall_norm * (wall_norm.dot(wall_point-robot_pose.getOrigin()) - goal->desired_distance)));
00111   desired_pose.setRotation(tf::createQuaternionFromYaw(getVectorAngle(tf::Vector3(0,1,0), wall_norm*-1)));
00112   desired_pose = desired_pose * tf::Pose(tf::Quaternion::getIdentity(), tf::Vector3(goal->offset, 0.0, 0.0));
00113   ROS_INFO("AlignBaseAction: desired robot pose %f %f ==> %f", desired_pose.getOrigin().x(), desired_pose.getOrigin().y(), tf::getYaw(desired_pose.getRotation()));
00114     
00115   
00116   move_base_msgs::MoveBaseGoal move_base_goal;
00117   tf::poseStampedTFToMsg(tf::Stamped<tf::Pose>(desired_pose, ros::Time::now(), fixed_frame), move_base_goal.target_pose);
00118   if (move_base_omnidirectional_.sendGoalAndWait(move_base_goal, ros::Duration(20.0), ros::Duration(5.0)) != actionlib::SimpleClientGoalState::SUCCEEDED){
00119     ROS_ERROR("AlignBaseAction: failed to move base to desired pose");
00120     action_server_.setAborted();
00121     return;
00122   }
00123   pr2_plugs_msgs::AlignBaseResult  align_result;
00124   align_result.base_pose = move_base_goal.target_pose;
00125   align_result.wall_norm = wall_norm_msg;
00126   action_server_.setSucceeded(align_result);
00127 }
00128 
00129 
00130 
00131 geometry_msgs::Point AlignBaseAction::toPoint(const tf::Vector3& pnt)
00132 {
00133   geometry_msgs::Point res;
00134   res.x = pnt.x();
00135   res.y = pnt.y();
00136   res.z = pnt.z();
00137   return res;
00138 }
00139 
00140 geometry_msgs::Vector3 AlignBaseAction::toVector(const tf::Vector3& pnt)
00141 {
00142   geometry_msgs::Vector3 res;
00143   res.x = pnt.x();
00144   res.y = pnt.y();
00145   res.z = pnt.z();
00146   return res;
00147 }
00148 
00149 tf::Vector3 AlignBaseAction::fromVector(const geometry_msgs::Vector3& pnt)
00150 {
00151   return tf::Vector3(pnt.x, pnt.y, pnt.z);
00152 }
00153 
00154 tf::Vector3 AlignBaseAction::fromPoint(const geometry_msgs::Point& pnt)
00155 {
00156   return tf::Vector3(pnt.x, pnt.y, pnt.z);
00157 }
00158 
00159 
00160 double AlignBaseAction::getVectorAngle(const tf::Vector3& v1, const tf::Vector3& v2)
00161 {
00162   tf::Vector3 vec1 = v1; vec1 = vec1.normalize();
00163   tf::Vector3 vec2 = v2; vec2 = vec2.normalize();
00164   double dot      = vec2.x() * vec1.x() + vec2.y() * vec1.y();
00165   double perp_dot = vec2.y() * vec1.x() - vec2.x() * vec1.y();
00166   return atan2(perp_dot, dot);
00167 }
00168 
00169 }
00170 
00171 
00172 
00173 int main(int argc, char** argv)
00174 {
00175   ros::init(argc, argv, "align_base");
00176 
00177   pr2_plugs_actions::AlignBaseAction action_server;
00178 
00179   ros::spin();
00180   return 0;
00181 }