cleaning_plan_alg.cpp
Go to the documentation of this file.
00001 #include "cleaning_plan_alg.h"
00002 
00003 using namespace cv;
00004 using namespace std;
00005 
00006 
00007 CleaningPlanAlgorithm::CleaningPlanAlgorithm(void)
00008 {
00009         // centimeters to move over the plane to dodge objects
00010         away_from_surface_distance = -0.1;
00011 }
00012 
00013 CleaningPlanAlgorithm::~CleaningPlanAlgorithm(void)
00014 {
00015 }
00016 
00017 void CleaningPlanAlgorithm::config_update(Config& new_cfg, uint32_t level)
00018 {
00019   this->lock();
00020 
00021   this->movements_offset     = new_cfg.movements_offset;
00022   this->small_objects_min    = new_cfg.small_objects_min;
00023   this->small_objects_max    = new_cfg.small_objects_max;
00024   this->pose_yaw             = new_cfg.pose_yaw;
00025   this->two_arms_version     = new_cfg.two_arms_version;
00026   this->board_plan           = new_cfg.board_plan;
00027   this->camera_frame         = new_cfg.camera_frame;
00028   this->rotate_hand          = new_cfg.rotate_hand;
00029   
00030   // save the current configuration
00031   this->config_=new_cfg;
00032   
00033   this->unlock();
00034 }
00035 
00036 
00037 bool CleaningPlanAlgorithm::getMovementFromAction(std::vector< estirabot_msgs::DirtyArea > dirty_areas,
00038                           string action, estirabot_msgs::ArrayIndexes target_ellipses, 
00039                                                   EllipsesRepresentation& ellipses_rep,
00040                                                   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, 
00041                                                   std::vector<float> plane_coeffs,
00042                                                   std::vector<geometry_msgs::PoseStamped> &poses,
00043                                                   std::vector<iri_perception_msgs::ImagePoint> &poses_img_coords,
00044                                                   std::vector<uint8_t> &secondary_arm)
00045 {
00046         std::vector< Point2f > img_coords;
00047         bool is_real_movement = true;
00048         uint8_t secondary_arm_movements = 0;
00049         double orientation_yaw = this->pose_yaw;        // some movements also set the yaw for the secondary arm
00050 //      // TODO ugly fix calibration
00051         for (size_t i = 0; i < dirty_areas.size(); i++) {
00052                 dirty_areas[i].ellipse.center.y -= 8;
00053         }
00054         RotatedRect ellipse1 = ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[0]);
00055         
00056         // BOARD MOVEMENTS
00057         if (action.compare("circularClean") == 0) {
00058                 img_coords = getPointsCircularClean(ellipse1);
00059         }
00060         else if (action.compare("straightClean") == 0) {
00061                 img_coords = getPointsStraightClean(ellipse1);
00062         }
00063         else if (action.compare("smallClean") == 0) {
00064                 if (dirty_areas.size() <= 2)
00065                         img_coords = getPointsLastSmallClean(ellipse1);
00066                 else
00067                         img_coords = getPointsSmallClean(ellipse1);
00068                 
00069         }
00070         else if (action.compare("move") == 0) { // move nowhere, just mark as moved
00071                 is_real_movement = false;
00072         }
00073         
00074         // SMALL OBJECTS MOVEMENTS
00075         else if (action.compare("group") == 0) {
00076                 img_coords = getPointsGroupObjects(ellipse1);
00077         }
00078         else if ( (action.compare("join") == 0) || (action.compare("joinTrav") == 0) ) {
00079                 // getPointsJoinGroups may rearrange order of the action
00080                 // if ellipse2 gets moved instead of ellipse1, 
00081                 //   then ellipse2 will be changed with ellipse1
00082                 vector<RotatedRect> ellipses;
00083                 ellipses.push_back(ellipse1);
00084                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[1]));
00085                 img_coords = getPointsJoinGroups(ellipses);
00086         }
00087         else if (action.compare("join3") == 0) {
00088                 // getPointsJoinGroups may rearrange order of the action
00089                 // if ellipse2 gets moved instead of ellipse1, 
00090                 //   then ellipse2 will be changed to point at ellipse1 position
00091                 vector<RotatedRect> ellipses;
00092                 ellipses.push_back(ellipse1);
00093                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[1]));
00094                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[2]));
00095                 img_coords = getPointsJoinGroups(ellipses);
00096         }
00097         else if (action.compare("join4") == 0) {
00098                 // getPointsJoinGroups may rearrange order of the action
00099                 // if ellipse2 gets moved instead of ellipse1, 
00100                 //   then ellipse2 will be changed with ellipse1
00101                 vector<RotatedRect> ellipses;
00102                 ellipses.push_back(ellipse1);
00103                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[1]));
00104                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[2]));
00105                 ellipses.push_back(ellipses_rep.getEllipseFromRosDirtyAreas(dirty_areas, target_ellipses.indexes[3]));
00106                 img_coords = getPointsJoinGroups(ellipses);
00107         }
00108         else if (action.compare("pickUp") == 0) {
00109                 if (this->two_arms_version) {
00110                         img_coords = getPointsPickUp(ellipse1);
00111                         secondary_arm_movements = 2;
00112                         //orientation_yaw = ellipse1.angle * M_PI / 180;
00113                         //orientation_yaw = M_PI/2; // only for secondary arm! TODO
00114                 }
00115                 else {
00116                         // DEPRECATED compatibility with old plans
00117                         // ellipse1 position will be updated
00118                         img_coords = getPointsMoveToContainer(ellipse1);
00119                 }
00120         }
00121         else if (action.compare("moveToContainerLong") == 0) {
00122                 img_coords = getPointsMoveToContainer(ellipse1, 1);
00123         }
00124         else if (action.compare("moveToContainerShort") == 0) { // DEPRECATED
00125                 img_coords = getPointsMoveToContainer(ellipse1, 1);
00126         }
00127         else if ( (action.compare("moveToContainerStraight") == 0) || (action.compare("moveToContainerStraightTrav") == 0)){
00128                 img_coords = getPointsMoveToContainer(ellipse1, 3);
00129         }
00130         else if (action.compare("preparePickUp") == 0) {
00131                 // Nothing
00132                 is_real_movement = false;
00133         }
00134         else if (action.compare("None") == 0) {
00135                 // TODO
00136                 is_real_movement = false;
00137         }
00138         else if (action.compare("NoPerception") == 0) {
00139                 img_coords = getNoPerceptionPoints(ellipses_rep.state_image);
00140                 processedPosesFromImageCoordinates(ellipses_rep, cloud, img_coords, plane_coeffs, secondary_arm_movements, orientation_yaw, poses, poses_img_coords, secondary_arm);
00141                 for (size_t i = 4; i < poses.size(); i=i+4) {
00142                         this->movePoseAwayFromSurface(poses[i], plane_coeffs); // first point of each movement
00143                         this->movePoseAwayFromSurface(poses[i-1], plane_coeffs); // last point of each movement
00144                 }
00145                 return true;
00146         }
00147         else {
00148                 ROS_ERROR_STREAM("CleaningPlanAlgorithm::getImageCoordsFromAction - ACTION NOT FOUND: " << action);
00149         }
00150         
00151         if (is_real_movement) {
00152                 processedPosesFromImageCoordinates(ellipses_rep, cloud, img_coords, plane_coeffs, secondary_arm_movements, orientation_yaw, poses, poses_img_coords, secondary_arm);
00153         }
00154         
00155         return is_real_movement;
00156 }
00157 
00158 // TODO this should be called in the upper function
00159 void CleaningPlanAlgorithm::processedPosesFromImageCoordinates(EllipsesRepresentation& ellipses_rep,
00160                                                                 const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, 
00161                                                                 const std::vector< Point2f > img_coords,
00162                                                                 const std::vector<float> plane_coeffs,
00163                                                                 const uint8_t secondary_arm_movements,
00164                                                                 const double orientation_yaw,
00165                                                                 std::vector<geometry_msgs::PoseStamped> &poses,
00166                                                                 std::vector<iri_perception_msgs::ImagePoint> &poses_img_coords,
00167                                                                 std::vector<uint8_t> &secondary_arm
00168                                                                 )
00169 {
00170         this->posesFromImageCoordinates(cloud, img_coords, 
00171                                         plane_coeffs, orientation_yaw, 
00172                                         poses, poses_img_coords, 
00173                                         secondary_arm_movements, secondary_arm);
00174         
00175         if (not this->board_plan) { // when cleaning small objects
00176                 ROS_DEBUG("CleaningPlan - moving away movements");
00177                 
00178                 // move away first pose of current movement
00179                 this->movePoseAwayFromSurface(poses[poses.size() - img_coords.size() + secondary_arm_movements], plane_coeffs);
00180                 
00181                 // move away last pose of current movement
00182                 this->movePoseAwayFromSurface(poses[poses.size() - 1], plane_coeffs);
00183                 
00184                 if (secondary_arm_movements > 0) {
00185                         this->movePoseAwayFromSurface(poses[poses.size() - img_coords.size()], plane_coeffs);
00186                         //this->movePoseAwayFromSurface(poses[poses.size() - img_coords.size() + secondary_arm_movements - 1], plane_coeffs);
00187                 }
00188         }
00189         
00190         ellipses_rep.drawPoints(img_coords);
00191 }
00192 
00193 
00194 std::vector< Point2f > CleaningPlanAlgorithm::getNoPerceptionPoints(cv::Mat image)
00195 {
00196         // Moving objects from left to right
00197         std::vector< Point2f > img_coords;
00198         int step = 20;
00199         int left_margin = 25; // leave a margin of 25 pixels on the right to make sure that the cloth picks lentils
00200         int right_edge = 50; // position in x-axis where the arm will try to move the objects
00201         
00202         // auxiliar opencv vars
00203         cv::Rect bounding_box;
00204         std::vector<std::vector<Point> > contours;
00205         std::vector<Point> contours_points;
00206         std::vector<cv::Vec4i> hierarchy;
00207         
00208         // opencv stuff
00209         
00210         findContours( image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
00211         for (size_t i = 0; i < contours.size(); i++)
00212                 for (size_t j = 0; j < contours[i].size(); j++)
00213                         contours_points.push_back(contours[i][j]);
00214         bounding_box = boundingRect(contours_points);
00215         
00216         // set points every step points
00217         int y_offset=-10;
00218         // initial point
00219         Point2f start_point = Point2f(bounding_box.x - left_margin, bounding_box.y + y_offset);
00220         Point2f end_point;
00221         while (y_offset < (bounding_box.height + step)) {
00222                 img_coords.push_back(start_point);
00223                 
00224                 // Every point is repeated so it starts and ends the movement away from the surface
00225                 start_point = Point2f(bounding_box.x - left_margin, bounding_box.y + y_offset);
00226                 // first value is very low so it is farther than the edge of the surface
00227                 // the last surface position will be obtained by posesFromImageCoordinates
00228                 Point2f end_point = Point2f(image.size().width - right_edge, bounding_box.y + y_offset);
00229                 
00230                 img_coords.push_back(start_point);
00231                 img_coords.push_back(end_point);
00232                 img_coords.push_back(end_point);
00233                 
00234                 y_offset+=step;
00235         }
00236         // final point
00237         return img_coords;
00238 }
00239 
00240 
00241 std::vector< Point2f > CleaningPlanAlgorithm::getPointsSmallClean(RotatedRect ellipse)
00242 {
00243         ROS_DEBUG("CleaningPlan - Generating points for small move");
00244         std::vector< Point2f > result;
00245                 
00246         ROS_DEBUG_STREAM("Center is " << ellipse.center);
00247         
00248         result.push_back(ellipse.center);
00249         
00250         return result;
00251 }
00252 
00253 
00254 std::vector< Point2f > CleaningPlanAlgorithm::getPointsLastSmallClean(RotatedRect ellipse)
00255 {
00256         ROS_DEBUG("CleaningPlan - Generating points for one of the last small moves");
00257         std::vector< Point2f > result;
00258         Point2f point;
00259         
00260         ROS_DEBUG_STREAM("Center is " << ellipse.center);
00261         
00262         point = ellipse.center;
00263         point.y = point.y + 15;
00264         
00265         result.push_back(point);
00266         
00267         point = ellipse.center;
00268         point.y = point.y - 15;
00269         
00270         result.push_back(point);
00271         
00272         return result;
00273 }
00274 
00275 
00276 std::vector< Point2f > CleaningPlanAlgorithm::getPointsCircularClean(RotatedRect ellipse)
00277 {
00278         ROS_DEBUG("CleaningPlan - Generating points for circular move");
00279         
00280         std::vector< Point2f > result;
00281         Point2f firstPoint, secondPoint, thirdPoint, fourthPoint;
00282         float angle = ellipse.angle;
00283         if (angle > 180)
00284                 angle -=180;
00285         // to rads
00286         angle = (angle / 180) * M_PI;
00287         float x_inc1, y_inc1, x_inc2, y_inc2;
00288         
00289         // TODO ROS_ASSERT(ellipse.size.height > ellipse.size.width);
00290         
00291         x_inc1 = sin(angle)  * ellipse.size.height / 2;
00292         y_inc1 = -cos(angle) * ellipse.size.height / 2;
00293         x_inc2 = cos(angle)  * ellipse.size.width / 2;
00294         y_inc2 = sin(angle)  * ellipse.size.width / 2;
00295         
00296         firstPoint.x = ellipse.center.x + x_inc1;
00297         firstPoint.y = ellipse.center.y + y_inc1;
00298         
00299         secondPoint.x = ellipse.center.x - x_inc1;
00300         secondPoint.y = ellipse.center.y - y_inc1;
00301         
00302         thirdPoint.x = ellipse.center.x + x_inc2;
00303         thirdPoint.y = ellipse.center.y + y_inc2;
00304         
00305         fourthPoint.x = ellipse.center.x - x_inc2;
00306         fourthPoint.y = ellipse.center.y - y_inc2;
00307         
00308         ROS_DEBUG_STREAM("Center is " << ellipse.center);
00309         ROS_DEBUG_STREAM("Angle is " << angle);
00310         ROS_DEBUG_STREAM("Width is " << ellipse.size.width);
00311         ROS_DEBUG_STREAM("Height is " << ellipse.size.height);
00312         ROS_DEBUG_STREAM("First point " << firstPoint);
00313         ROS_DEBUG_STREAM("Second point " << secondPoint);
00314         ROS_DEBUG_STREAM("Third point " << thirdPoint);
00315         ROS_DEBUG_STREAM("Fourth point " << fourthPoint);
00316         
00317         // Define more points if ellipse is too big
00318         if (ellipse.size.width * ellipse.size.height > 5000) {
00319                 Point2f point5, point6, point7, point8;
00320                 // rotate M_PI/4 to generate 4 new points
00321                 //if (angle > (M_PI/4))
00322                         angle -= M_PI/4;
00323                 //else
00324                 //      angle += M_PI/4;
00325                 
00326                 x_inc1 =  sin(angle) * (ellipse.size.height + ellipse.size.width) / 4;
00327                 y_inc1 = -cos(angle) * (ellipse.size.height + ellipse.size.width) / 4;
00328                 x_inc2 =  cos(angle) * (ellipse.size.height + ellipse.size.width) / 4;
00329                 y_inc2 =  sin(angle) * (ellipse.size.height + ellipse.size.width) / 4;
00330                 
00331                 point5.x = ellipse.center.x + x_inc1;
00332                 point5.y = ellipse.center.y + y_inc1;
00333                 
00334                 point6.x = ellipse.center.x - x_inc1;
00335                 point6.y = ellipse.center.y - y_inc1;
00336                 
00337                 point7.x = ellipse.center.x + x_inc2;
00338                 point7.y = ellipse.center.y + y_inc2;
00339                 
00340                 point8.x = ellipse.center.x - x_inc2;
00341                 point8.y = ellipse.center.y - y_inc2;
00342                 
00343                 result.push_back(firstPoint);
00344                 result.push_back(point7);
00345                 result.push_back(thirdPoint);
00346                 result.push_back(point6);
00347                 result.push_back(secondPoint);
00348                 result.push_back(point8);
00349                 result.push_back(fourthPoint);
00350                 result.push_back(point5);
00351         }
00352         else {
00353                 result.push_back(firstPoint);
00354                 result.push_back(thirdPoint);
00355                 result.push_back(secondPoint);
00356                 result.push_back(fourthPoint);
00357         }
00358         
00359         // TODO needs current position of the arm
00360         // We should start cleaning at the nearest point
00361         //if ( getDistance(current_arm_position, result.front()) > getDistance(current_arm_position, result.back()) )
00362         //      std::reverse(result.begin(), result.end());
00363         
00364         return result;
00365 }
00366 
00367 
00368 std::vector< Point2f > CleaningPlanAlgorithm::getPointsStraightClean(RotatedRect ellipse)
00369 {
00370         ROS_DEBUG("CleaningPlan - Generating points for straight move");
00371         std::vector< Point2f > result;
00372         Point2f firstPoint, secondPoint;
00373         float angle = (ellipse.angle / 180) * M_PI;
00374         float x_inc, y_inc;
00375         
00376         // TODO ROS_ASSERT(ellipse.size.height > ellipse.size.width);
00377         
00378         x_inc =  sin(angle) * (ellipse.size.height / 2 + this->movements_offset);
00379         y_inc = -cos(angle) * (ellipse.size.height / 2 + this->movements_offset);
00380         
00381         firstPoint.x = ellipse.center.x + x_inc;
00382         firstPoint.y = ellipse.center.y + y_inc;
00383         secondPoint.x = ellipse.center.x - x_inc;
00384         secondPoint.y = ellipse.center.y - y_inc;
00385         
00386         ROS_DEBUG_STREAM("Center is " << ellipse.center);
00387         ROS_DEBUG_STREAM("Angle is " << angle);
00388         ROS_DEBUG_STREAM("Width is " << ellipse.size.width);
00389         ROS_DEBUG_STREAM("Height is " << ellipse.size.height);
00390         ROS_DEBUG_STREAM("First point " << firstPoint.x << "," << firstPoint.y);
00391         ROS_DEBUG_STREAM("Second point " << secondPoint.x << "," << secondPoint.y);
00392         
00393         result.push_back(firstPoint);
00394         result.push_back(secondPoint);
00395         
00396         // TODO needs current position of the arm
00397         // We should start cleaning at the nearest point
00398         //if ( getDistance(current_arm_position, result.front()) > getDistance(current_arm_position, result.back()) )
00399         //      std::reverse(result.begin(), result.end());
00400         
00401         return result;
00402 }
00403 
00409 std::vector< Point2f > CleaningPlanAlgorithm::getPointsGroupObjects(RotatedRect ellipse)
00410 {
00411         ROS_DEBUG("CleaningPlan - Generating points for group move");
00412         // Should be: height > width
00413         std::vector< Point2f > result;
00414         Point2f firstPoint, secondPoint;
00415         float angle = ellipse.angle;
00416         float x_inc, y_inc; // distance center -> end of the ellipse
00417         
00418         if (angle > 180)
00419                 angle -=180;
00420         angle = (angle / 180) * M_PI; // degrees to rads
00421         
00422         // TODO ROS_ASSERT(ellipse.size.height > ellipse.size.width);
00423         
00424         // if the ellipse is in the upper side and the movement points up
00425         if ((ellipse.center.y < (IMAGE_HEIGHT*small_objects_min)) && (angle > 3*M_PI/4))
00426                 angle = angle + M_PI; // make it point down left
00427         
00428         // if the ellipse is in the lower side and the movement points down
00429         if ((ellipse.center.y > (IMAGE_HEIGHT*small_objects_max)) && (angle < M_PI/4))
00430                 angle = angle + M_PI; // make it point up left
00431         
00432         // else it is already moving to the left
00433         
00434         x_inc = sin(angle) * ellipse.size.height / 2;
00435         y_inc = -cos(angle) * ellipse.size.height / 2;
00436         
00437         firstPoint.x  = ellipse.center.x + x_inc;
00438         firstPoint.y  = ellipse.center.y + y_inc;
00439         secondPoint.x = ellipse.center.x - x_inc;
00440         secondPoint.y = ellipse.center.y - y_inc;
00441         
00442         // add offset to the points so the arm touches the table with enough space to move them
00443         firstPoint.x  = firstPoint.x  + ( this->movements_offset *  sin(angle) );
00444         secondPoint.x = secondPoint.x + ( this->movements_offset *  sin(angle) );
00445         firstPoint.y  = firstPoint.y  + ( this->movements_offset * -cos(angle) );
00446         secondPoint.y = secondPoint.y + ( this->movements_offset * -cos(angle) );
00447         
00448         ROS_DEBUG_STREAM("Center is " << ellipse.center);
00449         ROS_DEBUG_STREAM("Angle is " << angle);
00450         ROS_DEBUG_STREAM("Width is " << ellipse.size.width);
00451         ROS_DEBUG_STREAM("Height is " << ellipse.size.height);
00452         ROS_DEBUG_STREAM("First point " << firstPoint.x << "," << firstPoint.y);
00453         ROS_DEBUG_STREAM("Second point " << secondPoint.x << "," << secondPoint.y);
00454         
00455         result.push_back(firstPoint);
00456         result.push_back(firstPoint);
00457         result.push_back(secondPoint);
00458         
00459         
00460         if (this->two_arms_version) {
00461                 // already finished
00462                 // only has to group them
00463                 result.push_back(secondPoint); 
00464         }
00465         else {
00466                 // Also move the objects to the edge (left)
00467                 Point2f thirdPoint;
00468                 thirdPoint = secondPoint;
00469                 thirdPoint.x = thirdPoint.x - this->movements_offset;
00470                 result.push_back(thirdPoint);
00471                 result.push_back(thirdPoint);
00472         }
00473         
00474         //if (firstPoint.x < secondPoint.x)
00475         //      std::reverse(result.begin(), result.end());
00476         
00477         return result;
00478 }
00479 
00480 
00481 std::vector< Point2f > CleaningPlanAlgorithm::getPointsJoinGroups(vector<RotatedRect> ellipses)
00482 {
00483         std::vector< Point2f > result;
00484         std::vector< Point2f > firstEllipsePoints, secondEllipsePoints;
00485         Point2f firstPoint, secondPoint, awayDirection;
00486         size_t first_ellipse_nearest, last_ellipse_nearest, first_ellipse_farthest;
00487 //      double first_ellipse_size = ellipses.front().size.width * ellipses.front().size.height;
00488 //      double last_ellipse_size = ellipses.back().size.width * ellipses.back().size.height;
00489         
00490         ROS_DEBUG("CleaningPlan - Generating points for join move");
00491         
00492 //      if ((this->two_arms_version) && (3 * first_ellipse_size < last_ellipse_size)) { // first_ellipse <<< last_ellipse
00493 //              // nothing
00494 //      }
00495 //      else if ((this->two_arms_version) && (3 * last_ellipse_size < first_ellipse_size)) { // last_ellipse <<< first_ellipse
00496 //              RotatedRect ellipse_aux;
00497 //              
00498 //              // Swap ellipses positions 
00499 //              //  - changes ellipses values so they will be changed in the original vector
00500 //              for (size_t i = 0; i < floor(ellipses.size() / 2); i++){
00501 //                      ellipse_aux = ellipses.at(i);
00502 //                      ellipses.at(i) = ellipses.at(ellipses.size() - i - 1);
00503 //                      ellipses.at(ellipses.size() - i - 1) = ellipse_aux;
00504 //              }
00505 //      }
00506 //      else if (ellipses.front().center.x > ellipses.back().center.x) {  // Prefer moving to the right (container on the right)
00507 //              RotatedRect ellipse_aux;
00508 //              
00509 //              for (size_t i = 0; i < floor(ellipses.size() / 2); i++){
00510 //                      ellipse_aux = ellipses.at(i);
00511 //                      ellipses.at(i) = ellipses.at(ellipses.size() - i - 1);
00512 //                      ellipses.at(ellipses.size() - i - 1) = ellipse_aux;
00513 //              }
00514 //      }
00515         // else not needed
00516         
00517         for (size_t i = 0; i < (ellipses.size() - 1); i++){
00518                 firstEllipsePoints  = getPointsCircularClean(ellipses.at(i));
00519                 secondEllipsePoints = getPointsCircularClean(ellipses.at(i+1));
00520                 
00521                 first_ellipse_nearest  = getNearestPoint(firstEllipsePoints,  secondEllipsePoints);
00522                 last_ellipse_nearest  = getNearestPoint(secondEllipsePoints, firstEllipsePoints);
00523                 
00524                 if (firstEllipsePoints.size() == 8)
00525                         first_ellipse_farthest = (first_ellipse_nearest + 4) % 8;
00526                 else
00527                         first_ellipse_farthest = (first_ellipse_nearest + 2) % 4;
00528                 
00529                 firstPoint = firstEllipsePoints[first_ellipse_farthest];
00530                 secondPoint = firstEllipsePoints[first_ellipse_nearest];
00531                 
00532                 ROS_DEBUG_STREAM("Nearest " << first_ellipse_nearest);
00533                 ROS_DEBUG_STREAM("Farthest " << first_ellipse_farthest);
00534                 
00535                 awayDirection.x = firstPoint.x - secondPoint.x;
00536                 awayDirection.y = firstPoint.y - secondPoint.y;
00537                 ROS_DEBUG_STREAM("Away direction is " << awayDirection);
00538                 awayDirection.x = awayDirection.x / sqrt(awayDirection.x*awayDirection.x + awayDirection.y*awayDirection.y);
00539                 awayDirection.y = awayDirection.y / sqrt(awayDirection.x*awayDirection.x + awayDirection.y*awayDirection.y);
00540                 ROS_DEBUG_STREAM("Away direction is " << awayDirection);
00541                 
00542                 if (i == 0) { // only first movement
00543                         firstPoint.x = firstPoint.x + awayDirection.x * this->movements_offset;
00544                         firstPoint.y = firstPoint.y + awayDirection.y * this->movements_offset;
00545                         
00546                         result.push_back(firstPoint);
00547                         result.push_back(firstPoint);
00548                 }
00549                 
00550                 result.push_back(secondPoint);
00551                 result.push_back(secondEllipsePoints[last_ellipse_nearest]);
00552                 
00553         }
00554 //      result.push_back(ellipses.at(ellipses.size() - 1).center);
00555         
00556         // repeat last movement to move away from the surface
00557         result.push_back(result.back());
00558         
00559         return result;
00560 }
00561 
00562 
00563 std::vector< Point2f > CleaningPlanAlgorithm::getPointsPickUp(RotatedRect ellipse)
00564 {
00565         ROS_DEBUG("CleaningPlan - Generating points for pick up");
00566         std::vector< Point2f > result;
00567         Point2f firstPoint, secondPoint;
00568         float angle = ellipse.angle;
00569         float x_inc1, x_inc2, x_biggest;
00570         
00571         if (angle > 180)
00572                 angle -=180;
00573         angle = (angle / 180) * M_PI; // to rads
00574         
00575         // TODO ROS_ASSERT(ellipse.size.height > ellipse.size.width);
00576         
00577         x_inc1 = abs(sin(angle)  * ellipse.size.height / 2);
00578         x_inc2 = abs(cos(angle)  * ellipse.size.width / 2);
00579         x_biggest = max(x_inc1, x_inc2);
00580         
00581         /* First 
00582          * Place secondary arm on the right
00583          */
00584         firstPoint.x  = ellipse.center.x + x_biggest + this->movements_offset;
00585         firstPoint.y  = ellipse.center.y;
00586         
00587         result.push_back(firstPoint);
00588         result.push_back(firstPoint);
00589         
00590         /* Second 
00591          * Place main arm on the left
00592          */
00593         firstPoint.x  = ellipse.center.x - x_biggest - this->movements_offset;
00594         firstPoint.y  = ellipse.center.y;
00595         secondPoint.x  = ellipse.center.x + x_biggest;
00596         secondPoint.y  = ellipse.center.y;
00597         
00598         result.push_back(firstPoint);
00599         result.push_back(firstPoint);
00600         result.push_back(secondPoint);
00601         result.push_back(secondPoint);
00602         
00603         ROS_DEBUG("CleaningPlan - Pick up generated");
00604         
00605         return result;
00606 }
00607 
00608 
00609 std::vector< Point2f > CleaningPlanAlgorithm::getPointsMoveToContainer(RotatedRect& ellipse, int max_steps)
00610 {
00611         ROS_DEBUG("CleaningPlan - Generating points for move right");
00612         std::vector< Point2f > result;
00613         Point2f firstPoint, secondPoint;
00614         float angle = ellipse.angle;
00615         float x_inc1, x_inc2, x_biggest;
00616         float y_inc1, y_inc2, y_biggest;
00617         if (angle > 180)
00618                 angle -=180;
00619         angle = (angle / 180) * M_PI; // to rads
00620         
00621         // TODO ROS_ASSERT(ellipse.size.height > ellipse.size.width);
00622         
00623         x_inc1 = abs(sin(angle)  * ellipse.size.height / 2);
00624         x_inc2 = abs(cos(angle)  * ellipse.size.width / 2);
00625         x_biggest = max(x_inc1, x_inc2);
00626         
00627         y_inc1 = abs(cos(angle)  * ellipse.size.height / 2);
00628         y_inc2 = abs(sin(angle)  * ellipse.size.width / 2);
00629         y_biggest = max(y_inc1, y_inc2);
00630         
00631         // if the ellipse is in the upper side -> the movement points up
00632         if (ellipse.center.y < (IMAGE_HEIGHT*small_objects_min) ) {
00633                 firstPoint.x  = ellipse.center.x;
00634                 firstPoint.y  = ellipse.center.y - (y_biggest + this->movements_offset);
00635                 secondPoint.x = ellipse.center.x;
00636                 secondPoint.y = ellipse.center.y + (y_biggest + this->movements_offset);
00637                 
00638                 result.push_back(firstPoint);
00639                 result.push_back(firstPoint);
00640                 result.push_back(secondPoint);
00641                 result.push_back(secondPoint);
00642         }
00643         
00644         // if the ellipse is in the lower side -> the movement points down
00645         else if (ellipse.center.y > (IMAGE_HEIGHT*small_objects_max) ) {
00646                 firstPoint.x  = ellipse.center.x;
00647                 firstPoint.y  = ellipse.center.y + (y_biggest + this->movements_offset);
00648                 secondPoint.x = ellipse.center.x;
00649                 secondPoint.y = ellipse.center.y - (y_biggest + this->movements_offset);
00650                 
00651                 result.push_back(firstPoint);
00652                 result.push_back(firstPoint);
00653                 result.push_back(secondPoint);
00654                 result.push_back(secondPoint);
00655         }
00656         
00657         else { // move to the right
00658                 int steps, step_size, max_x, current_x, max_steps_by_distance;
00659                 firstPoint.y  = ellipse.center.y;
00660                 firstPoint.x  = ellipse.center.x - (x_biggest + this->movements_offset);
00661                 
00662                 max_x = IMAGE_WIDTH - 40;
00663                 current_x = firstPoint.x;
00664                 max_steps_by_distance = std::floor((max_x - current_x) / this->movements_offset);
00665                 steps = std::min(max_steps, max_steps_by_distance);
00666                 step_size = std::floor((max_x - current_x) / steps);
00667                 
00668 //              secondPoint.y = ellipse.center.y;
00669 //              secondPoint.x = ellipse.center.x - (x_biggest + (max_multiplier*this->movements_offset));
00670 //              if (secondPoint.x < 10) {
00671 //                      secondPoint.x = 10; // force it to be in the image
00672 //              }
00673                 
00674                 result.push_back(firstPoint);
00675                 result.push_back(firstPoint);
00676                 
00677                 for (int i = 1; i <= steps; i++) {
00678                         current_x += step_size;
00679                         secondPoint.x = current_x;
00680                         secondPoint.y = ellipse.center.y;
00681                         
00682                         result.push_back(secondPoint);
00683                 }
00684                 result.push_back(secondPoint);
00685 //              for (int i = 1; i <= steps; i++) {
00686 //                      float new_distance_multiplier = (distance_multiplier / steps) * i;
00687 //                      secondPoint.x = ellipse.center.x - (x_biggest + (new_distance_multiplier*this->movements_offset));
00688 //                      secondPoint.y = ellipse.center.y;
00689 //                      
00690 //                      result.push_back(secondPoint);
00691 //                      result.push_back(secondPoint);
00692 //              }
00693         }
00694         
00695         // update ellipse position
00696         ellipse.center.x = secondPoint.x;
00697         ellipse.center.y = secondPoint.y;
00698         
00699         ROS_DEBUG("CleaningPlan - Move right generated");
00700         
00701         return result;
00702 }
00703 
00704 
00705 int32_t CleaningPlanAlgorithm::getNearestPoint(std::vector< Point2f > points1, std::vector< Point2f > points2)
00706 {
00707         double min = 10000;
00708         int32_t min_idx = -1;
00709         
00710         for (size_t i=0; i < points1.size(); i++) {
00711                 for (size_t j=0; j < points2.size(); j++) {
00712                         double dist = getDistance(points1[i], points2[j]);
00713                         if (dist < min) {
00714                                 min = dist;
00715                                 min_idx = i;
00716                         }
00717                 }
00718         }
00719         
00720         ROS_DEBUG_STREAM("Minimun distance is: " << min);
00721         
00722         return min_idx;
00723 }
00724 
00725 
00726 void CleaningPlanAlgorithm::posesFromImageCoordinates(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, 
00727                                                          std::vector< cv::Point2f > img_coords,
00728                                                          std::vector<float> plane_coeffs,
00729                                                          double orientation_yaw,
00730                                                          std::vector<geometry_msgs::PoseStamped> &poses,
00731                                                          std::vector<iri_perception_msgs::ImagePoint> &poses_coords,
00732                                                          uint8_t secondary_arm_movements,
00733                                                          std::vector<uint8_t> &secondary_arm)
00734 {
00735         geometry_msgs::PoseStamped a_pose;
00736         iri_perception_msgs::ImagePoint a_pose_coords;
00737         pcl::PointXYZ point;
00738         geometry_msgs::Quaternion orientation;
00739         
00740         double prev_yaw_increment = orientation_yaw, yaw_increment = orientation_yaw, diff_yaw;
00741         
00742         ROS_DEBUG("CleaningPlan - Transforming coords to poses");
00743         
00744         for (size_t i = 0; i < img_coords.size(); i++) {
00745                 if (img_coords[i].x < 0)
00746                         img_coords[i].x = 0;
00747                 if (img_coords[i].y < 0) 
00748                         img_coords[i].y = 0;
00749                 if (img_coords[i].x > cloud->width)
00750                         img_coords[i].x = cloud->width - 1;
00751                 if (img_coords[i].y > cloud->height)
00752                         img_coords[i].y = cloud->height - 1;
00753                         
00754                         
00755                 a_pose.header.stamp = ros::Time::now();
00756                 a_pose.header.frame_id = this->camera_frame;
00757                 
00758                 point = cloud->at(img_coords[i].x,img_coords[i].y);
00759                 
00760                 // TODO check
00761                 if ((not this->board_plan) && (not this->two_arms_version)) {
00762                         // Quick and ugly fix for getPointsMoveToContainer(RotatedRect ellipse) being always in the table
00763                         //
00764                         // Until std::isNan (c++11 feature) reach compilers, we use the Nan propiety
00765                         // of not returning true when comparing against itself
00766                         while (((point.x != point.x) || (pointToPlaneDistance(point, plane_coeffs) > 0.02 )) && (img_coords[i].x > (IMAGE_WIDTH/2)) ) { // while ( ((point is NaN) || ( (point not in plane)) && (not infinite loop) ) ) 
00767                                 img_coords[i].x -= 1;
00768                                 ROS_DEBUG("NaN point! Trying to fix...");
00769                                 ROS_DEBUG_STREAM("Coords are now " << img_coords[i].x);
00770                                 ROS_DEBUG_STREAM("Point to plane distance is " << pointToPlaneDistance(point, plane_coeffs));
00771                                 point = cloud->at(img_coords[i].x,img_coords[i].y);
00772                         }
00773                 }
00774                 
00775                 // REMOVE NaNs
00776                 if (point.x != point.x) {
00777                         point.x = 0;
00778                         point.y = 0;
00779                         point.z = 0;
00780                 }
00781                 
00782                 /* Change orientations on the go
00783                         * Too many rotations, needs more work
00784                         */
00785                 yaw_increment = prev_yaw_increment;
00786                 
00787                 if (not this->board_plan && this->rotate_hand) {
00788                         if ( ((i+1) < img_coords.size()) && (img_coords[i].x != img_coords[i+1].x) ) {
00789                                 yaw_increment = orientation_yaw;
00790                                 yaw_increment += getAngle2DwithAxisX(img_coords[i], img_coords[i+1]);
00791                         }
00792                 }
00793                 
00794 //                      if (yaw_increment > M_PI)
00795 //                              yaw_increment -= M_PI;
00796 //                      if (yaw_increment < 0)
00797 //                              yaw_increment += M_PI;
00798                 
00799                 diff_yaw = yaw_increment - prev_yaw_increment;
00800                 if (diff_yaw > M_PI/2)
00801                         yaw_increment -= M_PI;
00802                 else if (diff_yaw < - M_PI/2)
00803                         yaw_increment += M_PI;
00804                 
00805                 if (yaw_increment > 2*M_PI)
00806                         yaw_increment -= 2*M_PI;
00807                 if (yaw_increment < 0)
00808                         yaw_increment += 2*M_PI;
00809                 
00810                 prev_yaw_increment = yaw_increment;
00811                 ROS_DEBUG_STREAM("Yaw movement orientation increments " << yaw_increment);
00812                 
00813                 orientation = quaternionFrom3dVector(plane_coeffs, yaw_increment);
00814                 
00815                 // TODO improve secondary arm movements
00816                 /* if (secondary_arm_movements > 1) {
00817                         if (i < 2)
00818                                 secondary_arm.push_back(true);
00819                         if (i==5)
00820                                 secondary_arm.push_back(true);
00821                 }
00822                 */
00823                 if (i < secondary_arm_movements)
00824                         secondary_arm.push_back(true);
00825                 else
00826                         secondary_arm.push_back(false);
00827                 
00828                 a_pose.pose.position.x = point.x;
00829                 a_pose.pose.position.y = point.y;
00830                 a_pose.pose.position.z = point.z;
00831                 a_pose.pose.orientation = orientation;
00832                 a_pose_coords.x = img_coords[i].x;
00833                 a_pose_coords.y = img_coords[i].y;
00834                 
00835                 poses.push_back(a_pose);
00836                 poses_coords.push_back(a_pose_coords);
00837         }
00838         
00839         ROS_DEBUG("CleaningPlan - Poses generated");
00840 }
00841 
00842 
00843 void CleaningPlanAlgorithm::movePoseAwayFromSurface(geometry_msgs::PoseStamped &pose, std::vector<float> plane_coeffs)
00844 {
00845         pose.pose.position.x += (this->away_from_surface_distance * plane_coeffs[0]);
00846         pose.pose.position.y += (this->away_from_surface_distance * plane_coeffs[1]);
00847         pose.pose.position.z += (this->away_from_surface_distance * plane_coeffs[2]);
00848 }
00849 
00850 
00851 geometry_msgs::Quaternion CleaningPlanAlgorithm::quaternionFrom3dVector(std::vector<float> plane_coefs, double new_yaw)
00852 {
00853         using namespace Eigen;
00854         geometry_msgs::Quaternion q_msg;
00855         
00856         Vector2f vbase(1,0);
00857         Vector2f vbase2(0,1);
00858         Vector2f vroll(plane_coefs[1], plane_coefs[2]);
00859         Vector2f vpitch(plane_coefs[2], plane_coefs[0]);
00860         Vector2f vyaw(plane_coefs[0], plane_coefs[1]);
00861         
00862         double roll = getAngle2D(vroll,vbase2); // rojo (verde -> azul)
00863         double pitch = getAngle2D(vpitch,vbase); // verde (azul -> rojo)
00864         double yaw = 0; //getAngle2D(vyaw, vbase); // azul (rojo -> verde)
00865         //ROS_DEBUG_STREAM("roll " << roll);
00866         //ROS_DEBUG_STREAM("pitch " << pitch);
00867         //ROS_DEBUG_STREAM("yaw" << yaw);
00868         
00869         if (plane_coefs[2] * plane_coefs[0] < 0)
00870                 pitch = - pitch;
00871 
00872         if (plane_coefs[2] * plane_coefs[1] > 0)
00873                 roll = - roll;
00874         
00875         q_msg = tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);
00876         
00877         Quaternion<float> qe1(q_msg.w, q_msg.x, q_msg.y, q_msg.z);
00878         Quaternion<float> q_rot(AngleAxis<float>(M_PI + new_yaw, Vector3f(0,0,1)));
00879         Quaternion<float> q_dest;
00880         q_dest = qe1 * q_rot;
00881         q_msg.x = q_dest.x();
00882         q_msg.y = q_dest.y();
00883         q_msg.z = q_dest.z();
00884         q_msg.w = q_dest.w();
00885         
00886         return q_msg;
00887 }


iri_clean_board
Author(s): David Martinez
autogenerated on Fri Dec 6 2013 23:52:37