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


descartes_planner
Author(s): Jorge Nicho
autogenerated on Thu Jun 6 2019 21:36:12