planning_graph.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Apache License)
00003  *
00004  * Copyright (c) 2014, Southwest Research Institute
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  * http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 /*
00019  * planning_graph.cpp
00020  *
00021  *  Created on: Jun 5, 2014
00022  *      Author: Dan Solomon
00023  */
00024 
00025 #include "descartes_planner/planning_graph.h"
00026 
00027 #include <stdio.h>
00028 #include <iomanip>
00029 #include <iostream>
00030 #include <utility>
00031 #include <algorithm>
00032 #include <fstream>
00033 
00034 #include <ros/console.h>
00035 
00036 #include <boost/graph/dijkstra_shortest_paths.hpp>
00037 
00038 using namespace descartes_core;
00039 using namespace descartes_trajectory;
00040 namespace descartes_planner
00041 {
00042 
00043 
00044 PlanningGraph::PlanningGraph(RobotModelConstPtr model)
00045   : robot_model_(std::move(model))
00046   , cartesian_point_link_(NULL)
00047 {}
00048 
00049 PlanningGraph::~PlanningGraph()
00050 {
00051   delete cartesian_point_link_;
00052 }
00053 
00054 CartesianMap PlanningGraph::getCartesianMap()
00055 {
00056   TrajectoryPt::ID cart_id = descartes_core::TrajectoryID::make_nil();
00057   for(std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator c_iter = cartesian_point_link_->begin();
00058       c_iter != cartesian_point_link_->end(); c_iter++)
00059   {
00060     ROS_DEBUG_STREAM("Checking for last TrajectoryID: " << c_iter->first);
00061     if(c_iter->second.links_.id_next.is_nil())
00062     {
00063       cart_id = c_iter->first;
00064       break;
00065     }
00066   }
00067 
00068   CartesianMap to_return = CartesianMap();
00069   bool done = false;
00070   while(!done)
00071   {
00072     to_return[cart_id] = (*cartesian_point_link_)[cart_id];
00073     cart_id = (*cartesian_point_link_)[cart_id].links_.id_previous;
00074     done = (cart_id.is_nil());
00075     ROS_DEBUG_STREAM("Next CID: " << cart_id);
00076   }
00077 
00078   return to_return;
00079 }
00080 
00081 descartes_core::RobotModelConstPtr PlanningGraph::getRobotModel()
00082 {
00083   return robot_model_;
00084 }
00085 
00086 bool PlanningGraph::insertGraph(const std::vector<TrajectoryPtPtr> *points)
00087 {
00088   // validate input
00089   if (!points)
00090   {
00091     // one or both are null
00092     ROS_ERROR_STREAM("points == null. Cannot initialize graph with null list.");
00093     return false;
00094   }
00095   if (points->size() == 0)
00096   {
00097     // one or both have 0 elements
00098     ROS_ERROR_STREAM("points.size == 0. Cannot initialize graph with 0 elements.");
00099     return false;
00100   }
00101 
00102   delete cartesian_point_link_; // remove the previous map before we start on a new one
00103   cartesian_point_link_ = new std::map<TrajectoryPt::ID, CartesianPointInformation>();
00104 
00105   // DEBUG
00106   //printMaps();
00107   TrajectoryPt::ID previous_id = descartes_core::TrajectoryID::make_nil();
00108 
00109   // input is valid, copy to local maps that will be maintained by the planning graph
00110   for (std::vector<TrajectoryPtPtr>::const_iterator point_iter = points->begin();
00111       point_iter != points->end(); point_iter++)
00112   {
00113     (*cartesian_point_link_)[point_iter->get()->getID()].source_trajectory_ = (*point_iter);
00114     CartesianPointRelationship point_link = CartesianPointRelationship();
00115     point_link.id = point_iter->get()->getID();
00116     point_link.id_next = descartes_core::TrajectoryID::make_nil(); // default to nil UUID
00117     point_link.id_previous = descartes_core::TrajectoryID::make_nil(); // default to nil UUID
00118 
00119     // if the previous_id exists, set it's next_id to the new id
00120     if (cartesian_point_link_->find(previous_id) != cartesian_point_link_->end())
00121     {
00122       (*cartesian_point_link_)[previous_id].links_.id_next = point_link.id;
00123       
00124       ROS_DEBUG_STREAM("PreviousID[" << previous_id << "].links_.id_next = " << point_link.id);
00125     }
00126     else
00127     {
00128       ROS_INFO_STREAM("PreviousID: " << previous_id << " was not found");
00129     }
00130 
00131     // set the new current point link
00132     point_link.id_previous = previous_id;
00133 
00134     // the new one becomes the previous_id
00135     previous_id = point_link.id;
00136 
00137     // save the point_link structure to the map
00138     (*cartesian_point_link_)[point_link.id].links_ = point_link;
00139   }
00140 
00141   // after populating maps above (presumably from cartesian trajectory points), calculate (or query) for all joint trajectories
00142   if (!calculateJointSolutions())
00143   {
00144     // failed to get joint trajectories
00145     ROS_ERROR_STREAM("unable to calculate joint trajectories for input points");
00146     return false;
00147   }
00148 
00149   if (!populateGraphVertices())
00150   {
00151     ROS_ERROR_STREAM("unable to populate graph from input points");
00152     return false;
00153   }
00154 
00155   // after obtaining joint trajectories, calculate each edge weight between adjacent joint trajectories
00156   // edge list can be local here, it needs to be passed to populate the graph but not maintained afterwards
00157   std::list<JointEdge> edges;
00158   if (!calculateAllEdgeWeights(edges))
00159   {
00160     // failed to get edge weights
00161     ROS_ERROR_STREAM("unable to calculate edge weight of joint transitions for joint trajectories");
00162     return false;
00163   }
00164 
00165   // from list of joint trajectories (vertices) and edges (edges), construct the actual graph
00166   if (!populateGraphEdges(edges))
00167   {
00168     // failed to create graph
00169     ROS_ERROR_STREAM("unable to populate graph from calculated edges");
00170     return false;
00171   }
00172 
00173   return true;
00174 }
00175 
00176 bool PlanningGraph::addTrajectory(TrajectoryPtPtr point, TrajectoryPt::ID previous_id, TrajectoryPt::ID next_id)
00177 {
00178   if (previous_id.is_nil() && next_id.is_nil())
00179   {
00180     // unable to add a point with no forward or backward connections
00181     ROS_ERROR_STREAM("unable to add a point that is not connected to one or more existing points");
00182     return false;
00183   }
00184 
00185   if (!previous_id.is_nil() && cartesian_point_link_->find(previous_id) == cartesian_point_link_->end())
00186   {
00187     // unable to find referenced previous_id
00188     ROS_ERROR_STREAM("unable to find previous point");
00189     return false;
00190   }
00191   if (!next_id.is_nil() && cartesian_point_link_->find(next_id) == cartesian_point_link_->end())
00192   {
00193     // unable to find referenced next_id
00194     ROS_ERROR_STREAM("unable to find next point");
00195   }
00196 
00197   CartesianPointRelationship point_link;
00198   point_link.id = point->getID();
00199   point_link.id_next = next_id;
00200   point_link.id_previous = previous_id;
00201 
00202   // save the new point_link structure to the map
00203   (*cartesian_point_link_)[point_link.id].links_ = point_link;
00204 
00205   // if not adding at the beginning, update the previous to point to the new point
00206   //if (cartesian_point_link_->find(previous_id) != cartesian_point_link_->end())
00207   if(!previous_id.is_nil())
00208   {
00209     (*cartesian_point_link_)[previous_id].links_.id_next = point_link.id;
00210   }
00211   // if not updating the end, update the next to point to the new point
00212   //if (cartesian_point_link_->find(next_id) != cartesian_point_link_->end())
00213   if(!next_id.is_nil())
00214   {
00215     (*cartesian_point_link_)[next_id].links_.id_previous = point_link.id;
00216   }
00217 
00218   ROS_DEBUG_STREAM("New ID: " << point_link.id);
00219   ROS_DEBUG_STREAM("New Next ID: " << point_link.id_next);
00220   ROS_DEBUG_STREAM("New Previous ID: " << point_link.id_previous);
00221 
00222   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00223   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00224 
00225   if(!previous_id.is_nil() && !next_id.is_nil())
00226   {
00227     // remove graph edges from each joint at [id_previous] to joint at [id_next]
00228     std::list<TrajectoryPt::ID> start_joint_ids = (*cartesian_point_link_)[previous_id].joints_;
00229     std::list<TrajectoryPt::ID> end_joint_ids = (*cartesian_point_link_)[next_id].joints_;
00230     for (std::list<TrajectoryPt::ID>::iterator start_joint_iter = start_joint_ids.begin();
00231         start_joint_iter != start_joint_ids.end(); start_joint_iter++)
00232     {
00233       for (std::list<TrajectoryPt::ID>::iterator end_joint_iter = end_joint_ids.begin();
00234           end_joint_iter != end_joint_ids.end(); end_joint_iter++)
00235       {
00236         ROS_DEBUG_STREAM("Removing edge: " << *start_joint_iter << " -> " << *end_joint_iter);
00237         boost::remove_edge(joint_vertex_map[*start_joint_iter], joint_vertex_map[*end_joint_iter], dg_);
00238       }
00239     }
00240   }
00241 
00242   // get joint poses from new trajectory point (unique id)
00243   std::vector<std::vector<double> > joint_poses;
00244   point.get()->getJointPoses(*robot_model_, joint_poses);
00245 
00246   if (joint_poses.size() == 0)
00247   {
00248     ROS_WARN_STREAM("no joint solution for this point... potential discontinuity in the graph");
00249   }
00250   else
00251   {
00252     for (std::vector<std::vector<double> >::iterator joint_pose_iter = joint_poses.begin();
00253         joint_pose_iter != joint_poses.end(); joint_pose_iter++)
00254     {
00255       //get UUID from JointTrajPt (convert from std::vector<double>)
00256       JointTrajectoryPt new_pt (*joint_pose_iter, point->getTiming());
00257       //traj_solutions->push_back(new_pt->getID());
00258       (*cartesian_point_link_)[point->getID()].joints_.push_back(new_pt.getID());
00259 
00260       // insert new vertices into graph
00261       JointGraph::vertex_descriptor v = boost::add_vertex(dg_);
00262       dg_[v].id = new_pt.getID();
00263 
00264       joint_solutions_map_[new_pt.getID()] = new_pt;
00265     }
00266   }
00267 
00268   // save the list of joint solutions
00269   std::list<TrajectoryPt::ID> traj_solutions = (*cartesian_point_link_)[point->getID()].joints_;
00270   // save the actual trajectory point into the map
00271   (*cartesian_point_link_)[point->getID()].source_trajectory_ = point;
00272 
00273   ROS_INFO_STREAM("SAVE CART POINT ID[" << point->getID() << "]: "
00274           << (*cartesian_point_link_)[point->getID()].source_trajectory_.get()->getID());
00275 
00276   std::list<JointEdge> edges;
00277   // recalculate edges(previous -> this; this -> next)
00278 
00279   if(!previous_id.is_nil())
00280   {
00281     std::list<TrajectoryPt::ID> previous_joint_ids = (*cartesian_point_link_)[previous_id].joints_;
00282     calculateEdgeWeights(previous_joint_ids, traj_solutions, edges);
00283   }
00284 
00285   if(!next_id.is_nil())
00286   {
00287     std::list<TrajectoryPt::ID> next_joint_ids = (*cartesian_point_link_)[next_id].joints_;
00288     calculateEdgeWeights(traj_solutions, next_joint_ids, edges);
00289   }
00290 
00291   // insert new edges
00292   populateGraphEdges(edges);
00293 
00294   // DEBUG LOGS
00295 //  printGraph();
00296 //  printMaps();
00297 
00298   //CartesianMap test_map = getCartesianMap();
00299 
00300   // simple test for now to see the new point is in the list
00301   return (cartesian_point_link_->find(point->getID()) != cartesian_point_link_->end());
00302 }
00303 
00304 bool PlanningGraph::modifyTrajectory(TrajectoryPtPtr point)
00305 {
00306   TrajectoryPt::ID modify_id = point.get()->getID();
00307   ROS_INFO_STREAM("Attempting to modify point:: " << modify_id);
00308 
00309 //  printMaps();
00310 
00311   if (modify_id.is_nil())
00312   {
00313     // unable to modify a point with nil ID
00314     ROS_ERROR_STREAM("unable to modify a point with nil ID");
00315     return false;
00316   }
00317 
00318   if (cartesian_point_link_->find(modify_id) == cartesian_point_link_->end())
00319   {
00320     // unable to find cartesian point with ID:
00321     ROS_ERROR_STREAM("unable to find cartesian point link with ID: " << modify_id);
00322     return false;
00323   }
00324   else
00325   {
00326     ROS_INFO_STREAM("Found ID: " << modify_id << " to modify.");
00327   }
00328 
00329   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00330   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00331 
00332   // identify joint points at this cartesian point
00333   std::list<TrajectoryPt::ID> start_joint_ids = (*cartesian_point_link_)[modify_id].joints_;
00334 
00335   ROS_INFO_STREAM("start_joint_ids.size = " << start_joint_ids.size());
00336 
00337   std::vector<JointGraph::edge_descriptor> to_remove_edges;
00338   std::vector<JointGraph::vertex_descriptor> to_remove_vertices;
00339   // remove edges
00340   for (std::list<TrajectoryPt::ID>::iterator start_joint_iter = start_joint_ids.begin();
00341       start_joint_iter != start_joint_ids.end(); start_joint_iter++)
00342   {
00343     // get the graph vertex descriptor
00344     JointGraph::vertex_descriptor jv = joint_vertex_map[*start_joint_iter];
00345 
00346     // NOTE: cannot print jv as int when using listS
00347     ROS_DEBUG_STREAM("jv: " << jv);
00348 
00349     // TODO: make this a standalone function to take a jv and return a list of edges to remove
00350     // remove out edges
00351     std::pair<OutEdgeIterator, OutEdgeIterator> out_ei = out_edges(jv, dg_);
00352 
00353     for (OutEdgeIterator out_edge = out_ei.first; out_edge != out_ei.second; ++out_edge)
00354     {
00355       JointGraph::edge_descriptor e = *out_edge;
00356       ROS_DEBUG_STREAM("REMOVE OUTEDGE: " << dg_[e].joint_start << " -> " << dg_[e].joint_end);
00357       to_remove_edges.push_back(e);
00358     }
00359 
00360     // remove in edges
00361     std::pair<InEdgeIterator, InEdgeIterator> in_ei = in_edges(jv, dg_);
00362     for (InEdgeIterator in_edge = in_ei.first; in_edge != in_ei.second; ++in_edge)
00363     {
00364       JointGraph::edge_descriptor e = *in_edge;
00365       ROS_DEBUG_STREAM("REMOVE INEDGE: " << dg_[e].joint_start << " -> " << dg_[e].joint_end);
00366       to_remove_edges.push_back(e);
00367     }
00368 
00369     to_remove_vertices.push_back(jv);
00370     joint_solutions_map_.erase(*start_joint_iter);
00371 //    printMaps();
00372   }
00373   for(std::vector<JointGraph::edge_descriptor>::iterator e_iter = to_remove_edges.begin(); e_iter != to_remove_edges.end(); e_iter++)
00374   {
00375     ROS_DEBUG_STREAM("REMOVE EDGE: " << dg_[*e_iter].joint_start << " -> " << dg_[*e_iter].joint_end);
00376     boost:remove_edge(*e_iter, dg_);
00377     //printGraph();
00378   }
00379   std::sort(to_remove_vertices.begin(), to_remove_vertices.end());
00380   std::reverse(to_remove_vertices.begin(), to_remove_vertices.end());
00381   for(std::vector<JointGraph::vertex_descriptor>::iterator v_iter = to_remove_vertices.begin(); v_iter != to_remove_vertices.end(); v_iter++)
00382   {
00383     // remove the graph vertex and joint point
00384     // NOTE: cannot print jv as int when using listS
00385     ROS_DEBUG_STREAM("REMOVE VERTEX: " << *v_iter);
00386     boost::remove_vertex(*v_iter, dg_);
00387 //    printGraph();
00388   }
00389   (*cartesian_point_link_)[modify_id].joints_.clear();
00390 
00391   // get new joint points for this cartesian
00392   std::vector<std::vector<double> > joint_poses;
00393   point.get()->getJointPoses(*robot_model_, joint_poses);
00394 
00395   if (joint_poses.size() == 0)
00396   {
00397     ROS_WARN_STREAM("no joint solution for this point... potential discontinuity in the graph");
00398   }
00399   else
00400   {
00401     for (std::vector<std::vector<double> >::iterator joint_pose_iter = joint_poses.begin();
00402         joint_pose_iter != joint_poses.end(); joint_pose_iter++)
00403     {
00404       //get UUID from JointTrajPt (convert from std::vector<double>)
00405       JointTrajectoryPt new_pt (*joint_pose_iter, point->getTiming());
00406       (*cartesian_point_link_)[modify_id].joints_.push_back(new_pt.getID());
00407 
00408       // insert new vertices into graph
00409       JointGraph::vertex_descriptor v = boost::add_vertex(dg_);
00410       dg_[v].id = new_pt.getID();
00411 
00412       joint_solutions_map_[new_pt.getID()] = new_pt;
00413       ROS_INFO_STREAM("Added New Joint: " << v);
00414     }
00415   }
00416 
00417   std::list<TrajectoryPt::ID> traj_solutions = (*cartesian_point_link_)[modify_id].joints_;
00418   (*cartesian_point_link_)[modify_id].source_trajectory_ = point;
00419   // don't need to modify links
00420 
00421   // recalculate edges(previous -> this; this -> next)
00422   TrajectoryPt::ID previous_cart_id = (*cartesian_point_link_)[modify_id].links_.id_previous; // should be equal to cart_link_iter->second.links_.id
00423   TrajectoryPt::ID next_cart_id = (*cartesian_point_link_)[modify_id].links_.id_next;
00424 
00425   std::list<JointEdge> edges;
00426   // recalculate edges(previous -> this; this -> next)
00427 
00428   if(!previous_cart_id.is_nil())
00429   {
00430     std::list<TrajectoryPt::ID> previous_joint_ids = (*cartesian_point_link_)[previous_cart_id].joints_;
00431     ROS_DEBUG_STREAM("Calculating previous -> new weights: " << previous_joint_ids.size() << " -> " << traj_solutions.size());
00432     calculateEdgeWeights(previous_joint_ids, traj_solutions, edges);
00433   }
00434 
00435   if(!next_cart_id.is_nil())
00436   {
00437     std::list<TrajectoryPt::ID> next_joint_ids = (*cartesian_point_link_)[next_cart_id].joints_;
00438     ROS_DEBUG_STREAM("Calculating new -> next weights: " << traj_solutions.size() << " -> " << next_joint_ids.size());
00439     calculateEdgeWeights(traj_solutions, next_joint_ids, edges);
00440   }
00441 
00442   ROS_INFO_STREAM("NEW EDGES: " << edges.size());
00443   // insert new edges
00444   return populateGraphEdges(edges);
00445 
00446   // DEBUG LOGS
00447 //  printGraph();
00448 //  printMaps();
00449 }
00450 
00451 bool PlanningGraph::removeTrajectory(TrajectoryPtPtr point)
00452 {
00453   TrajectoryPt::ID delete_id = point.get()->getID();
00454   ROS_INFO_STREAM("Attempting to delete ID: " << delete_id);
00455 
00456   if (delete_id.is_nil())
00457   {
00458     // unable to modify a point with nil ID
00459     ROS_ERROR_STREAM("unable to delete a point with nil ID");
00460     return false;
00461   }
00462   if (cartesian_point_link_->find(delete_id) == cartesian_point_link_->end())
00463   {
00464     // unable to find cartesian point with ID:
00465     ROS_ERROR_STREAM("unable to find cartesian point link with ID: " << delete_id);
00466     return false;
00467   }
00468   // identify joint points at this cartesian point
00469   std::list<TrajectoryPt::ID> start_joint_ids = (*cartesian_point_link_)[delete_id].joints_;
00470 
00471   ROS_INFO_STREAM("Attempting to delete edges from " << start_joint_ids.size() << " vertices");
00472 
00473   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00474   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00475 
00476   std::vector<JointGraph::edge_descriptor> to_remove_edges;
00477   std::vector<JointGraph::vertex_descriptor> to_remove_vertices;
00478   // remove edges
00479   for (std::list<TrajectoryPt::ID>::iterator start_joint_iter = start_joint_ids.begin();
00480       start_joint_iter != start_joint_ids.end(); start_joint_iter++)
00481   {
00482     // get the graph vertex descriptor
00483     JointGraph::vertex_descriptor jv = joint_vertex_map[*start_joint_iter];
00484 
00485     // remove out edges
00486     std::pair<OutEdgeIterator, OutEdgeIterator> out_ei = out_edges(jv, dg_);
00487 
00488     for (OutEdgeIterator out_edge = out_ei.first; out_edge != out_ei.second; ++out_edge)
00489     {
00490       JointGraph::edge_descriptor e = *out_edge;
00491       ROS_DEBUG_STREAM("REMOVE OUTEDGE: " << dg_[e].joint_start << " -> " << dg_[e].joint_end);
00492       to_remove_edges.push_back(e);
00493     }
00494 
00495     // remove in edges
00496     std::pair<InEdgeIterator, InEdgeIterator> in_ei = in_edges(jv, dg_);
00497     for (InEdgeIterator in_edge = in_ei.first; in_edge != in_ei.second; ++in_edge)
00498     {
00499       JointGraph::edge_descriptor e = *in_edge;
00500       ROS_DEBUG_STREAM("REMOVE INEDGE: " << dg_[e].joint_start << " -> " << dg_[e].joint_end);
00501       to_remove_edges.push_back(e);
00502     }
00503     to_remove_vertices.push_back(jv);
00504     // remove the graph vertex and joint point
00505 
00506     joint_solutions_map_.erase(*start_joint_iter);
00507   }
00508 
00509   for(std::vector<JointGraph::edge_descriptor>::iterator e_iter = to_remove_edges.begin(); e_iter != to_remove_edges.end(); e_iter++)
00510   {
00511     boost:remove_edge(*e_iter, dg_);
00512   }
00513 
00514   std::sort(to_remove_vertices.begin(), to_remove_vertices.end());
00515   std::reverse(to_remove_vertices.begin(), to_remove_vertices.end());
00516   for(std::vector<JointGraph::vertex_descriptor>::iterator v_iter = to_remove_vertices.begin(); v_iter != to_remove_vertices.end(); v_iter++)
00517   {
00518     // remove the graph vertex and joint point
00519     // NOTE: cannot print jv as int when using listS
00520     ROS_INFO_STREAM("REMOVE VERTEX: " << *v_iter);
00521     boost::remove_vertex(*v_iter, dg_);
00522 //    printGraph();
00523   }
00524   (*cartesian_point_link_)[delete_id].joints_.clear();
00525 
00526   // get previous_id and next_id from cartesian list
00527   CartesianPointRelationship links = (*cartesian_point_link_)[delete_id].links_;
00528   TrajectoryPt::ID previous_id = links.id_previous;
00529   TrajectoryPt::ID next_id = links.id_next;
00530 
00531   if(!previous_id.is_nil())
00532   {
00533     // change previous_cartesian link to next_id
00534     (*cartesian_point_link_)[previous_id].links_.id_next = next_id;
00535   }
00536   if(!next_id.is_nil())
00537   {
00538     // change next_cartesian link to previous_id
00539     (*cartesian_point_link_)[next_id].links_.id_previous = previous_id;
00540   }
00541 
00542   std::list<JointEdge> edges;
00543   // recalculate edges(previous -> this; this -> next)
00544 
00545   if(!previous_id.is_nil() && !next_id.is_nil())
00546   {
00547     std::list<TrajectoryPt::ID> previous_joint_ids = (*cartesian_point_link_)[previous_id].joints_;
00548     std::list<TrajectoryPt::ID> next_joint_ids = (*cartesian_point_link_)[next_id].joints_;
00549     calculateEdgeWeights(previous_joint_ids, next_joint_ids, edges);
00550   }
00551 
00552   // insert new edges
00553   populateGraphEdges(edges);
00554 
00555   // DEBUG LOGS
00556 //  printGraph();
00557 //  printMaps();
00558 
00559   return true;
00560 }
00561 
00562 bool PlanningGraph::findStartVertices(std::list<JointGraph::vertex_descriptor> &start_points)
00563 {
00564   // Create local id->vertex map  
00565   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00566   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00567 
00568   // Find the TrajectoryPt ID of the first point specified by the user
00569   TrajectoryPt::ID cart_id = descartes_core::TrajectoryID::make_nil();
00570 
00571   for(std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator c_iter = cartesian_point_link_->begin();
00572       c_iter != cartesian_point_link_->end(); c_iter++)
00573   {
00574     if(c_iter->second.links_.id_previous.is_nil())
00575     {
00576       cart_id = c_iter->first;
00577       break;
00578     }
00579   }
00580 
00581   // Test for error case
00582   if (cart_id.is_nil())
00583   {
00584     // Users can insert points with any given previous and next point using the addTrajectory
00585     // function.
00586     ROS_ERROR("Could not locate TrajectoryPt with nil previous point. Graph may be cyclic.");
00587     return false;
00588   }
00589 
00590   // Iterate through the JointSolutions for the last point
00591   const std::list<descartes_core::TrajectoryPt::ID>& ids = cartesian_point_link_->at(cart_id).joints_;
00592 
00593   for (const auto& id : ids)
00594   {
00595     JointGraph::vertex_descriptor v = joint_vertex_map.at(id); 
00596     start_points.push_back(v);
00597   }
00598 
00599   return !start_points.empty();
00600 }
00601 
00602 bool PlanningGraph::findEndVertices(std::list<JointGraph::vertex_descriptor> &end_points)
00603 {
00604   // Create local id->vertex map  
00605   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00606   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00607 
00608   // Find the TrajectoryPt ID of the last point specified by the user
00609   TrajectoryPt::ID cart_id = descartes_core::TrajectoryID::make_nil();
00610 
00611   for(std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator c_iter = cartesian_point_link_->begin();
00612       c_iter != cartesian_point_link_->end(); c_iter++)
00613   {
00614     if(c_iter->second.links_.id_next.is_nil())
00615     {
00616       cart_id = c_iter->first;
00617       break;
00618     }
00619   }
00620 
00621   // Test for error case
00622   if (cart_id.is_nil())
00623   {
00624     // Users can insert points with any given previous and next point using the addTrajectory
00625     // function.
00626     ROS_ERROR("Could not locate TrajectoryPt with nil next point. Graph may be cyclic.");
00627     return false;
00628   }
00629 
00630   // Iterate through the JointSolutions for the last point
00631   const std::list<descartes_core::TrajectoryPt::ID>& ids = cartesian_point_link_->at(cart_id).joints_;
00632 
00633   for (const auto& id : ids)
00634   {
00635     JointGraph::vertex_descriptor v = joint_vertex_map.at(id); 
00636     end_points.push_back(v);
00637   }
00638 
00639   return !end_points.empty();
00640 }
00641 
00642 
00643 bool PlanningGraph::getShortestPath(double &cost, std::list<JointTrajectoryPt> &path)
00644 {
00645   std::list<JointGraph::vertex_descriptor> start_points;
00646   findStartVertices(start_points);
00647   std::list<JointGraph::vertex_descriptor> end_points;
00648   findEndVertices(end_points);
00649 
00650   size_t num_vert = boost::num_vertices(dg_);
00651 
00652   std::vector<TrajectoryPt::ID> vertex_index_map(num_vert);
00653   std::pair<VertexIterator, VertexIterator> vi = boost::vertices(dg_);
00654   int i = 0;
00655   for (VertexIterator vert_iter = vi.first; vert_iter != vi.second; ++vert_iter)
00656   {
00657     JointGraph::vertex_descriptor jv = *vert_iter;
00658     vertex_index_map[i++] = dg_[jv].id;
00659   }
00660 
00661   cost = std::numeric_limits<double>::max();
00662 
00663   for (std::list<JointGraph::vertex_descriptor>::iterator start = start_points.begin(); start != start_points.end(); start++)
00664   {
00665     // initialize vectors to be used by dijkstra
00666     std::vector<JointGraph::vertex_descriptor> predecessors(num_vert);
00667     std::vector<double> weights(num_vert, std::numeric_limits<double>::max());
00668 
00669     dijkstra_shortest_paths(
00670         dg_,
00671         *start,
00672         weight_map(get(&JointEdge::transition_cost, dg_)).distance_map(
00673           boost::make_iterator_property_map(weights.begin(), get(boost::vertex_index, dg_))).predecessor_map(
00674           &predecessors[0]));
00675 
00676     for (std::list<JointGraph::vertex_descriptor>::iterator end = end_points.begin(); end != end_points.end(); end++)
00677     {
00678       // actual weight(cost) from start_id to end_id
00679       double weight = weights[*end];
00680 
00681       // if the weight of this path of less than a previous one, replace the return path
00682       if (weight < cost)
00683       {
00684         std::stringstream ss;
00685         ss << "New Shortest Path: ";
00686 
00687         cost = weight;
00688         path.clear();
00689         // Add the destination point.
00690         int current = *end;
00691         path.push_front(joint_solutions_map_[vertex_index_map[current]]);
00692 
00693         ss << current;
00694         // Starting from the destination point step through the predecessor map
00695         // until the source point is reached.
00696         while (current != *start)
00697         {
00698           current = predecessors[current];
00699           ss << " -> " << current;
00700           path.push_front(joint_solutions_map_[vertex_index_map[current]]);
00701         }
00702 
00703         ROS_INFO("With %lu - new best score: %f", path.size(), weight);
00704       }
00705     }
00706   }
00707 
00708   ROS_INFO("Lowest cost: %f", cost);
00709 
00710   if (cost < std::numeric_limits<double>::max())
00711   {
00712     ROS_INFO("FOUND A PATH");
00713     return true;
00714   }
00715   else
00716   {
00717     ROS_ERROR_STREAM("unable to find a valid path");
00718     return false;
00719   }
00720 }
00721 
00722 void PlanningGraph::printMaps()
00723 {
00724   ROS_DEBUG_STREAM("Number of points: " << cartesian_point_link_->size());
00725 
00726   for(std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator c_iter = cartesian_point_link_->begin();
00727       c_iter != cartesian_point_link_->end(); c_iter++)
00728   {
00729     ROS_DEBUG_STREAM("C_ID: " << c_iter->first << "[P_ID: " << c_iter->second.links_.id_previous << " -> N_ID: "
00730                       << c_iter->second.links_.id_next << "](Joints: " << c_iter->second.joints_.size() << ')');
00731   }
00732 }
00733 
00734 int PlanningGraph::recalculateJointSolutionsVertexMap(std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> &joint_map)
00735 {
00736   std::pair<VertexIterator, VertexIterator> vi = vertices(dg_);
00737 
00738   for (VertexIterator vert_iter = vi.first; vert_iter != vi.second; ++vert_iter)
00739   {
00740     JointGraph::vertex_descriptor jv = *vert_iter;
00741     joint_map[dg_[jv].id] = jv;
00742   }
00743 }
00744 
00745 // TODO: optionally output this to a .DOT file (viewable in GraphVIZ or comparable)
00746 void PlanningGraph::printGraph()
00747 {
00748   ROS_DEBUG_STREAM("\n\nPRINTING GRAPH\n\n");
00749   std::stringstream ss;
00750   ss << "GRAPH VERTICES (" << num_vertices(dg_) << "): ";
00751   ROS_DEBUG_STREAM(ss.str());
00752   std::pair<VertexIterator, VertexIterator> vi = vertices(dg_);
00753   ROS_DEBUG_STREAM("Graph OutEdges:");
00754   for (VertexIterator vert_iter = vi.first; vert_iter != vi.second; ++vert_iter)
00755   {
00756     JointGraph::vertex_descriptor jv = *vert_iter;
00757     ss.str("");
00758     ss << "Vertex: (" << jv << ")";
00759     ss << dg_[jv].id;
00760     std::pair<OutEdgeIterator, OutEdgeIterator> out_ei = out_edges(jv, dg_);
00761     ss << " -> {";
00762     for (OutEdgeIterator out_edge = out_ei.first; out_edge != out_ei.second; ++out_edge)
00763     {
00764       JointGraph::edge_descriptor e = *out_edge;
00765       ss << "[" << dg_[e].joint_end << "] , ";
00766     }
00767     ss << "}";
00768     ROS_DEBUG_STREAM(ss.str());
00769   }
00770 
00771   ROS_DEBUG_STREAM("Graph InEdges:");
00772   for (VertexIterator vert_iter = vi.first; vert_iter != vi.second; ++vert_iter)
00773   {
00774     JointGraph::vertex_descriptor jv = *vert_iter;
00775 
00776     std::pair<InEdgeIterator, InEdgeIterator> in_ei = in_edges(jv, dg_);
00777     ss.str("");
00778     ss << "{";
00779     for (InEdgeIterator in_edge = in_ei.first; in_edge != in_ei.second; ++in_edge)
00780     {
00781       JointGraph::edge_descriptor e = *in_edge;
00782       ss << source(e, dg_) << "[" << dg_[e].joint_start << "], ";
00783     }
00784     ss << "} -> ";
00785     ss << "Vertex (" << jv << "): " ;//<<  dg_[jv].id;
00786     ROS_DEBUG_STREAM(ss.str());
00787   }
00788 
00789   ROS_DEBUG_STREAM("GRAPH EDGES (" << num_edges(dg_) << "): ");
00790   //Tried to make this section more clear, instead of using tie, keeping all
00791   //the original types so it's more clear what is going on
00792   std::pair<EdgeIterator, EdgeIterator> ei = edges(dg_);
00793   for (EdgeIterator edge_iter = ei.first; edge_iter != ei.second; ++edge_iter)
00794   {
00795     JointGraph::vertex_descriptor jv = source(*edge_iter, dg_);
00796     JointGraph::edge_descriptor e = *out_edges(jv, dg_).first;
00797 
00798     JointGraph::edge_descriptor e2 = *edge_iter;
00799     ROS_DEBUG_STREAM("(" << source(*edge_iter, dg_) << ", " << target(*edge_iter, dg_) << "): cost: " << dg_[e2].transition_cost);
00800   }
00801   ROS_DEBUG_STREAM("\n\nEND PRINTING GRAPH\n\n");
00802 }
00803 
00804 bool PlanningGraph::calculateJointSolutions()
00805 {
00806   if (joint_solutions_map_.size() > 0)
00807   {
00808     // existing joint solutions... clear the list?
00809     ROS_WARN_STREAM("existing joint solutions found, clearing map");
00810     joint_solutions_map_.clear();
00811   }
00812 
00813   // for each TrajectoryPt, get the available joint solutions
00814   for (std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator trajectory_iter = cartesian_point_link_->begin();
00815       trajectory_iter != cartesian_point_link_->end(); trajectory_iter++)
00816   {
00817     // TODO: copy this block to a function that can be used by add and modify
00818     /*************************/
00819     std::list<TrajectoryPt::ID> traj_solutions;
00820     std::vector<std::vector<double> > joint_poses;
00821     trajectory_iter->second.source_trajectory_.get()->getJointPoses(*robot_model_, joint_poses);
00822     TrajectoryPt::ID tempID = trajectory_iter->first;
00823     ROS_INFO_STREAM("CartID: " << tempID << " JointPoses count: " << joint_poses.size());
00824 
00825     if (joint_poses.size() == 0)
00826     {
00827       ROS_WARN_STREAM("no joint solution for this point... potential discontinuity in the graph");
00828     }
00829     else
00830     {
00831       for (std::vector<std::vector<double> >::iterator joint_pose_iter = joint_poses.begin();
00832           joint_pose_iter != joint_poses.end(); joint_pose_iter++)
00833       {
00834         //get UUID from JointTrajPt (convert from std::vector<double>)
00835         JointTrajectoryPt new_pt (*joint_pose_iter, trajectory_iter->second.source_trajectory_.get()->getTiming());
00836         traj_solutions.push_back(new_pt.getID());
00837         joint_solutions_map_[new_pt.getID()] = new_pt;
00838       }
00839     }
00840     trajectory_iter->second.joints_ = traj_solutions;
00841     /*************************/
00842   }
00843 
00844   return true;
00845 }
00846 
00847 bool PlanningGraph::calculateAllEdgeWeights(std::list<JointEdge> &edges)
00848 {
00849   if (cartesian_point_link_->size() == 0)
00850   {
00851     // no linkings of cartesian points
00852     ROS_ERROR_STREAM("no trajectory point links defined");
00853     return false;
00854   }
00855   else
00856   {
00857     ROS_DEBUG_STREAM("Found %i " << cartesian_point_link_->size() << " trajectory point links");
00858   }
00859 
00860   if (joint_solutions_map_.size() == 0)
00861   {
00862     // no joint solutions to calculate transitions for
00863     ROS_ERROR_STREAM("no joint solutions available");
00864     return false;
00865   }
00866   else
00867   {
00868     ROS_INFO_STREAM("Found " << joint_solutions_map_.size() << " joint solutions available");
00869   }
00870 
00871   for (std::map<TrajectoryPt::ID, CartesianPointInformation>::iterator cart_link_iter = cartesian_point_link_->begin();
00872       cart_link_iter != cartesian_point_link_->end(); cart_link_iter++)
00873   {
00874     TrajectoryPt::ID start_cart_id = cart_link_iter->first; // should be equal to cart_link_iter->second.links_.id
00875     TrajectoryPt::ID end_cart_id = cart_link_iter->second.links_.id_next;
00876 
00877     if(!end_cart_id.is_nil())
00878     {
00879       std::list<TrajectoryPt::ID> start_joint_ids = cart_link_iter->second.joints_;
00880       std::list<TrajectoryPt::ID> end_joint_ids = (*cartesian_point_link_)[end_cart_id].joints_;
00881 
00882       if(!calculateEdgeWeights(start_joint_ids, end_joint_ids, edges))
00883       {
00884         ROS_WARN_STREAM("One or more joints lists in the cartesian point link is empty ID:" << start_cart_id << 
00885                         "[start ids:" << start_joint_ids.size() << "], ID:" << end_cart_id << "[end ids:" << end_joint_ids.size() << ']');
00886       }
00887     }
00888     else
00889     {
00890       // not going to try to calculate from point to nil
00891       ROS_INFO_STREAM("Not calculating edge weights to nil ID");
00892     }
00893   }
00894 
00895   return !edges.empty();
00896 }
00897 
00898 bool PlanningGraph::calculateEdgeWeights(const std::list<TrajectoryPt::ID> &start_joints,const std::list<TrajectoryPt::ID> &end_joints, std::list<JointEdge> &edge_results)
00899 {
00900   typedef std::list<TrajectoryPt::ID>::const_iterator TrajIdConstIter;
00901 
00902   if(start_joints.empty() || end_joints.empty())
00903   {
00904     ROS_WARN_STREAM("One or more joints lists is empty, Start Joints: " << start_joints.size() << " End Joints: " << end_joints.size());
00905     return false;
00906   }
00907 
00908   bool has_valid_transition = false;
00909 
00910   // calculate edges for previous vertices to this set of vertices
00911   for (TrajIdConstIter previous_joint_iter = start_joints.begin();
00912       previous_joint_iter != start_joints.end(); previous_joint_iter++)
00913   {
00914     // Look up the start_joint once per iteration of this loop
00915     const JointTrajectoryPt& start_joint = joint_solutions_map_[*previous_joint_iter];
00916 
00917     // Loop over the ending points -> look at each combination of start/end points
00918     for (TrajIdConstIter next_joint_iter = end_joints.begin();
00919         next_joint_iter != end_joints.end(); next_joint_iter++)
00920     {
00921       const JointTrajectoryPt& end_joint = joint_solutions_map_[*next_joint_iter];
00922 
00923       LinearWeightResult edge_result = linearWeight(start_joint, end_joint);
00924 
00925       // If the edge weight calculation returns false, do not create an edge
00926       if (!edge_result.first)
00927       {
00928         continue;
00929       }
00930 
00931       // If one edge exists, there is a valid transition from the previous TrajectoryPt
00932       // to the next
00933       has_valid_transition = true;
00934 
00935       JointEdge edge;
00936       edge.joint_start = *previous_joint_iter;
00937       edge.joint_end = *next_joint_iter;
00938       edge.transition_cost = edge_result.second;
00939       edge_results.push_back(edge);
00940     }
00941   }
00942 
00943   return has_valid_transition;
00944 }
00945 
00946 bool PlanningGraph::populateGraphVertices()
00947 {
00948   if (joint_solutions_map_.size() == 0)
00949   {
00950     // no joints (vertices)
00951     ROS_ERROR_STREAM("no joint solutions defined, thus no graph vertices");
00952     return false;
00953   }
00954 
00955   for (std::map<TrajectoryPt::ID, JointTrajectoryPt>::iterator joint_iter = joint_solutions_map_.begin();
00956       joint_iter != joint_solutions_map_.end(); joint_iter++)
00957   {
00958     JointGraph::vertex_descriptor v = boost::add_vertex(dg_);
00959     dg_[v].id = joint_iter->second.getID();
00960   }
00961 
00962   return true;
00963 }
00964 
00965 bool PlanningGraph::populateGraphEdges(const std::list<JointEdge> &edges)
00966 {
00967   if (edges.size() == 0)
00968   {
00969     // no edges
00970     ROS_ERROR_STREAM("no graph edges defined");
00971     return false;
00972   }
00973 
00974   std::map<TrajectoryPt::ID, JointGraph::vertex_descriptor> joint_vertex_map;
00975   int num_joints = recalculateJointSolutionsVertexMap(joint_vertex_map);
00976 
00977   for (std::list<JointEdge>::const_iterator edge_iter = edges.begin(); edge_iter != edges.end(); edge_iter++)
00978   {
00979     JointGraph::edge_descriptor e;
00980     bool b;
00981     // add graph links for structure
00982     boost::tie(e, b) = boost::add_edge(joint_vertex_map[edge_iter->joint_start],
00983                                        joint_vertex_map[edge_iter->joint_end], dg_);
00984     // populate edge fields
00985     dg_[e].transition_cost = edge_iter->transition_cost;
00986     dg_[e].joint_start = edge_iter->joint_start;
00987     dg_[e].joint_end = edge_iter->joint_end;
00988   }
00989 
00990   return true;
00991 }
00992 
00993 PlanningGraph::LinearWeightResult PlanningGraph::linearWeight(const JointTrajectoryPt& start,
00994                                                               const JointTrajectoryPt& end) const
00995 {
00996   LinearWeightResult result;
00997   result.first = false;
00998 
00999   const std::vector<double>& start_vector = start.nominal();
01000   const std::vector<double>& end_vector = end.nominal();
01001   if (start_vector.size() == end_vector.size())
01002   {
01003     // Check to see if time is specified and if so, check to see if the
01004     // joint motion is possible in the window provided
01005     if (end.getTiming().isSpecified() &&
01006         !robot_model_->isValidMove(start_vector, end_vector, end.getTiming().upper))
01007     {
01008       return result;
01009     }
01010 
01011     double vector_diff = 0;
01012     for (unsigned i = 0; i < start_vector.size(); i++)
01013     {
01014       double joint_diff = std::abs(end_vector[i] - start_vector[i]);
01015       vector_diff += joint_diff ;
01016     }
01017 
01018     result.first = true;
01019     result.second = vector_diff;
01020     return result;
01021   }
01022   else
01023   {
01024     ROS_WARN_STREAM("unequal joint pose vector lengths: "
01025                     << start_vector.size() << " != " << end_vector.size());
01026   }
01027 
01028   return result;
01029 }
01030 
01031 } /* namespace descartes_planner */


descartes_planner
Author(s): Jorge Nicho
autogenerated on Wed Aug 26 2015 11:21:35