planners/atace/PL_PRM_Constrained.cpp

Go to the documentation of this file.
00001 
00002 #include "math/vector4.h"
00003 #include "math/matrixmxn.h"
00004 #include "synchronization/semaphore.h"
00005 #include "robots/R_OpenChain.h"
00006 #include "CollisionDetectors/CD_Swiftpp.h"
00007 #include <assert.h>
00008 #include "planners/ik_mpep/IK_Jacobian.h"
00009 #include "PL_PRM_ClosedChain.h"
00010 #include <gl/gl.h>
00011 #include <opengl/gl_sphere.h>
00012 #include <opengl/gl_group.h>
00013 
00014 #define MAX_ITERATION        30
00015 #define MAX_RETRY            30
00016 #define MAX_RETRY2           30
00017 #define DEF_NEIGHBOR         (2)
00018 #define DEF_DIST_TOLERANCE   (3)
00019 #define DEF_ERR_TOLERANCE    (1e-3)
00020 
00021 double (PL_PRM_ClosedChain::*costFunc)(const Configuration &p1, const Frame &pose) const = &PL_PRM_ClosedChain::Error1;
00022 
00023 PL_PRM_ClosedChain::PL_PRM_ClosedChain()
00024 {
00025         edgePath.init(G);
00026         edgeFrag = new Fragment;
00027         //int dof = collisionDetector->DOF();
00028         //distTolerance = DEF_NEIGHBOR * dof;
00029         planner = new LocalPlannerClosed;
00030         pCollisionDetector = NULL;
00031         useJacobian = false;
00032         usePlanarConstraint = false;
00033         useOrientConstraint = false;
00034         useGoalPose = false;
00035 }       
00036 
00037 PL_PRM_ClosedChain::~PL_PRM_ClosedChain()
00038 {
00039         if(pCollisionDetector)
00040         {
00041                 delete pCollisionDetector;
00042         }
00043         delete planner;
00044 
00045         edgeFrag->clear();
00046         delete edgeFrag;
00047 }
00048 
00049 void PL_PRM_ClosedChain::SetCollisionDetector(CD_BasicStyle* collisionDetector)
00050 {
00051         // Call Parent's Collision Detector and assign the collision detector
00052         PL_PRM::SetCollisionDetector( collisionDetector );
00053 
00054         if (pCollisionDetector != NULL)
00055                 delete pCollisionDetector;
00056 
00057         pCollisionDetector = new CD_Swiftpp( *(collisionDetector->GetUniverse()) );
00058         planner->SetCollisionDetector(pCollisionDetector);
00059         pCollisionDetector->DeactivateFrames(1, pCollisionDetector->DOF());
00060 }
00061 
00062 bool PL_PRM_ClosedChain::Plan ()
00063 {
00064         srand( (unsigned)time( NULL ) );
00065 
00066         StartTimer();
00067         if (usePlanarConstraint)
00068         {
00069                 UpdatePlanarConstraint();
00070         }
00071         else if (useOrientConstraint)
00072         {
00073                 UpdateOrientConstraint();
00074         }
00075 
00076         if (useJacobian)
00077         {
00078                 planner->SetTimeLimitInSeconds(100);
00079                 Configuration q1 = GetStartConfig();
00080                 Configuration q2 = GetGoalConfig();
00081                 planner->SetStartConfig(q1);
00082                 planner->SetGoalConfig(q2);
00083 
00084                 double dObstacleTol = 0.01;
00085                 double dHomogain = 2.0;
00086                 double dPathTol = 0.5;
00087                 int nObstacleNum = 2;
00088 
00089                 planner->SetObstacleTolerance(dObstacleTol);
00090                 planner->SetNumObstaclePt(nObstacleNum);
00091                 planner->SetHomogeneousGain(dHomogain);
00092                 planner->SetPathTolerence(dPathTol);
00093                 planner->SetOrientation(false);
00094                 planner->SetPosition(true);
00095 
00096                 //if (planner->Plan())
00097                 bool result = planner->Plan();
00098 
00099                 PA_Points *plannerPath = (PA_Points *)planner->GetPath();
00100                 path = *plannerPath;
00101 
00102                 //To take a look at where planner fail to go on,
00103                 //the path will be returned no matter the planing is success or not.
00104                 return result;
00105         }
00106         else if (useGoalPose)
00107         {
00108                 Configuration conf;
00109                 Frame goalPose = GetToolFrame( GetGoalConfig() );
00110                 bool Result = false;
00111                 double oldTimeLimit = GetTimeLimitInSeconds();
00112                 double timeLimit = 100;
00113                 
00114                 while (Result == false)
00115                 {
00116                         Result = GenerateRandomConfigForPose(conf, goalPose);
00117                         if (Result)
00118                         {
00119                                 timeLimit = GetTimeElapsedInSeconds() + 20;
00120                                 oldTimeLimit = GetTimeLimitInSeconds();
00121                                 if (timeLimit > oldTimeLimit)
00122                                         timeLimit = oldTimeLimit;
00123                                 SetTimeLimitInSeconds( timeLimit );
00124                                 PL_PRM::SetGoalConfig(conf);
00125                                 Result = Plan_As_Usual();
00126                                 if (GetTimeLimitInSeconds() != timeLimit)
00127                                         break;
00128                                 else
00129                                         SetTimeLimitInSeconds( oldTimeLimit );
00130                         }
00131                         if (Result)
00132                                 return true;
00133                         if ( HasTimeLimitExpired() )
00134                         {
00135                                 return false;
00136                         }
00137                 }
00138                 return false;
00139                 //return Plan_As_Usual();
00140                 //return PL_PRM::Plan();
00141         }
00142         else
00143         {
00144                 return Plan_As_Usual();
00145         }
00146 
00147 /*
00148         Configuration q_last = q1;
00149         Configuration q_end = q2;
00150         path.AppendPoint(q1);
00151         int MAX_I = MAX_ITERATION * MAX_RETRY * MAX_RETRY2;
00152         int MAX_J = MAX_RETRY;
00153         int MAX_K = MAX_RETRY2;
00154         double distToLast = sqrt(Distance(q_last, q2));
00155         while ((i<MAX_I) && (j<MAX_J) && (k<MAX_K) && (distToLast>DEF_DIST_TOLERANCE))
00156         {
00157                 i++;  j++;
00158                 Configuration q_mid = PL_PRM::GenerateRandomConfig(q_last, DEF_NEIGHBOR*0.2);
00159                 if (MakeItClosed(q_mid))  //if (Error(q_mid)<DEF_ERR_TOLERANCE)
00160                 {
00161                         j = 0; k++;
00162                         if (Distance(q_mid, q_end) < Distance(q_last, q_end))
00163                         {
00164                                 k = 0;
00165                                 path.AppendPoint(q_mid);
00166                                 q_last = q_mid;
00167                                 distToLast = sqrt(Distance(q_last, q2));
00168                         }
00169                 }
00170         }
00171 
00172         if (sqrt(Distance(q_last, q_end))<DEF_DIST_TOLERANCE)
00173         {
00174                 path.AppendPoint(q2);
00175                 return true;
00176         }
00177         else
00178         {
00179                 return false;
00180         }
00181 */
00182 //      return PL_PRM::Plan();
00183 }
00184 
00185 //****************************************************************************
00186 //             Function to Get Tool Frame: End-effector Frame.
00187 //****************************************************************************
00188 Frame PL_PRM_ClosedChain::GetToolFrame( const Configuration& config ) const
00189 {
00190         Frame toolFrame = Matrix4x4();
00191         if ( collisionDetector != NULL )
00192         {
00193                 FrameManager* frameManager = collisionDetector->GetFrameManager();
00194                 collisionDetector->SetConfiguration( config );
00195                 R_OpenChain * robot = (R_OpenChain *)collisionDetector->GetRobot(0);
00196                 int toolFrameID = robot->GetToolFrame(0);
00197                 if (toolFrameID == -1)
00198                 {
00199                         toolFrameID = collisionDetector->JointFrameNum(collisionDetector->DOF()-1);
00200                         toolFrame = frameManager->GetWorldFrame( toolFrameID );
00201                 }
00202                 else
00203                 {
00204                         toolFrame = *(frameManager->GetFrameRef(toolFrameID));
00205                         toolFrame = frameManager->GetTransformRelative(collisionDetector->DOF(), 0) * toolFrame;
00206                 }
00207         }
00208         return toolFrame;
00209 }
00210 
00211 bool PL_PRM_ClosedChain::Plan_As_Usual ()
00212 {
00213         PRM_StateMachineType currentState = lastPlanningState;
00214 
00215         // Nodes may have been added since last plan.  Allow planner to check roadmap again
00216         // IMPROVE:  Is this still needed?
00217         if ( lastPlanningState == PRM_FAILURE )
00218         {
00219                 currentState = PRM_START;
00220         }
00221 
00222         // Start the timer
00223         //StartTimer();
00224 
00225         // Establish the semaphore
00226         Semaphore semaphore( guid );
00227         if( this->m_UseSemaphores == true )
00228         {
00229                 semaphore.Lock();
00230         }
00231         
00232 
00233         // Some quick checks to determine if we really need to plan
00234         if ( (currentState != PRM_DONE ) && (currentState != PRM_FAILURE) ) 
00235         {
00236                 if ( startNode == goalNode )
00237                 {
00238                         // start and goal are the same.  Do not plan.
00239                         currentState = PRM_DONE;
00240 
00241                         // Assign a small path.
00242                         path.Clear();
00243                         path.AppendPoint( GetStartConfig() );
00244                 }
00245                 else if ( (PL_PRM::IsInterfering(startNode)) || (PL_PRM::IsInterfering(goalNode)) )
00246                 {
00247                         // either the start or goal are already interfering.  Plan will
00248                         // automatically fail.
00249                         currentState = PRM_FAILURE;
00250                 }
00251         }
00252         if( this->m_UseSemaphores == true )
00253         {
00254                 semaphore.Unlock();
00255         }
00256 
00257         // Ensure the diagonal length is correct
00258         diagonal_squared = GetCspaceRange();
00259         
00260         // State Machine
00261         while (( currentState != PRM_DONE ) && ( currentState != PRM_FAILURE )) 
00262                 // NOTE:  The PRM_FAILURE state should eventually be removed!
00263         {
00264                 SuccessResultType success;
00265 
00266                 if( this->m_UseSemaphores == true )
00267                 {
00268                         semaphore.Lock();
00269                 }
00270                 // Determine the State function to call for this iteration
00271                 switch ( currentState )
00272                 {
00273                         case PRM_BUILD_INIT_ROADMAP :
00274                                 success = BuildInitRoadMap();
00275                                 break;
00276                         case PRM_FIND_PATH :
00277                                 success = FindPath();
00278                                 break;
00279                         case PRM_VERIFY_PATH :
00280                                 success = VerifyPath();
00281                                 break;
00282                         case PRM_TRANSLATE_PATH :
00283                                 success = TranslatePath();
00284                                 break;
00285                         case PRM_ENHANCE_ROADMAP :
00286                                 success = EnhanceRoadMap();
00287                                 break;
00288                         default :
00289                                 // No state functions are associated with this state.
00290                                 // Do nothing except prepare for next iteration.
00291                                 success = PASS;
00292                 }  // end SWITCH
00293 
00294 
00295                 // Check if timer has expired and one of the state functions had returned early.
00296                 if ( success == TIMER_EXPIRED )
00297                 {
00298                         // Escape the state machine.
00299                         break;
00300                 }
00301 
00302                 // Determine the State Function to call for the next iteration
00303                 switch ( currentState )
00304                 {
00305                         case PRM_START :
00306                                 // Start by building the initial roadmap.
00307                                 currentState = PRM_BUILD_INIT_ROADMAP;  
00308                                 break;
00309                         case PRM_BUILD_INIT_ROADMAP :
00310                                 // Search current road map for a short path.
00311                                 currentState = PRM_FIND_PATH;                   
00312                                 break;
00313                         case PRM_FIND_PATH :
00314                                 if ( success == PASS )
00315                                 {
00316                                         // A path has been found, verify it has no collision.
00317                                         currentState = PRM_VERIFY_PATH;
00318                                 }
00319                                 else
00320                                 {
00321                                         // No path was found.  Enhance some of the trouble areas.
00322                                         currentState = PRM_ENHANCE_ROADMAP;
00323                                         //currentState = PRM_FAILURE;           // NOTE:  Once EnhanceRoadmap is working,
00324                                                                                                         //                the PRM_FAILURE state should be removed.
00325                                 }
00326                                 break;
00327                         case PRM_VERIFY_PATH :
00328                                 if ( success == PASS )
00329                                 {
00330                                         // Path represented by valid nodes is successful. Translate it so the
00331                                         // main program can implement it.
00332                                         currentState = PRM_TRANSLATE_PATH;
00333                                 }
00334                                 else
00335                                 {
00336                                         // Path was not collision free.  Need to find a new path now that the troublesome
00337                                         // nodes/edges have been removed.
00338                                         currentState = PRM_FIND_PATH;
00339                                 }
00340                                 break;
00341                         case PRM_TRANSLATE_PATH :
00342                                 // We are done.  Escape state machine and report success.
00343                                 currentState = PRM_DONE;
00344                                 break;
00345                         case PRM_ENHANCE_ROADMAP :
00346                                 // Try finding a path again with the new nodes and edges added.
00347                                 currentState = PRM_FIND_PATH;
00348                                 break;
00349                         default :
00350                                 // an unexpected or invalid state has occurred.  Crash the program!
00351                                 ASSERT( FALSE );
00352                 } // end SWITCH.
00353 
00354                 // Release semaphore temporary.
00355                 if( this->m_UseSemaphores == true )
00356                 {
00357                         semaphore.Unlock();
00358                 }
00359         }  // END State Machine
00360 
00361 
00362         // save the current state of the machine for the next time the planner is called.
00363         lastPlanningState = currentState;
00364 
00365         // Report the success of the planner.
00366         if ( currentState == PRM_DONE )
00367         {
00368                 // planner has completed.  A path has been found and saved.
00369                         
00370                 // Release semaphore permanetly.
00371                 if( this->m_UseSemaphores == true )
00372                 {
00373                         semaphore.Unlock();
00374                 }
00375 
00376                 return true;
00377         }
00378         else
00379         {
00380                 // planner has not completed and has terminated early
00381                 graphPath.clear();
00382 
00383                 // Assign a small path.
00384                 path.Clear();
00385                 path.AppendPoint( GetStartConfig() );
00386 
00387                 // Release semaphore permanetly.
00388                 if( this->m_UseSemaphores == true )
00389                 {
00390                         semaphore.Unlock();
00391                 }
00392 
00393                 return false;
00394         }
00395 }  // END Plan
00396 
00397 bool PL_PRM_ClosedChain::GetSatisfactoryConfiguration(Configuration &conf, Frame &pose) const
00398 {
00399         int i,j;
00400         Configuration q;
00401         q = conf;
00402         i = 0; j = 0;
00403         int MAX_I = MAX_ITERATION * MAX_RETRY;
00404         int MAX_J = MAX_RETRY;
00405         double err_q = (this->*costFunc)(q, pose);
00406         while ((i<MAX_I) && (j<MAX_J) && (err_q>DEF_ERR_TOLERANCE))
00407         {
00408                 i++;   j++;
00409                 double deviation = DEF_NEIGHBOR;
00410                 if (err_q < 1)
00411                         deviation *= err_q;
00412                 Configuration q_next = PL_PRM::GenerateRandomConfig(q, deviation);
00413                 if ((this->*costFunc)(q_next, pose) < err_q)
00414                 {
00415                         j = 0; 
00416                         q = q_next;
00417                         err_q = (this->*costFunc)(q, pose);
00418                 }
00419                 if ( HasTimeLimitExpired() )
00420                 {
00421                         return false;
00422                 }
00423         }
00424 
00425         conf = q;
00426         return (err_q <= DEF_ERR_TOLERANCE);
00427 }
00428 
00429 bool PL_PRM_ClosedChain::GetClosedConfiguration(Configuration &conf)
00430 {
00431         UpdatePlanarConstraint();
00432         UpdateOrientConstraint();
00433 
00434         int i,j;
00435         Configuration q;
00436         q = conf;
00437         i = 0; j = 0;
00438         int MAX_I = MAX_ITERATION * MAX_RETRY;
00439         int MAX_J = MAX_RETRY;
00440         double err_q = Error(q);
00441         while ((i<MAX_I) && (j<MAX_J) && (err_q>DEF_ERR_TOLERANCE))
00442         {
00443                 i++;   j++;
00444                 double deviation = DEF_NEIGHBOR;
00445                 if (err_q < 1)
00446                         deviation *= err_q;
00447                 Configuration q_next = PL_PRM::GenerateRandomConfig(q, deviation);
00448                 if (Error(q_next) < err_q)
00449                 {
00450                         j = 0; 
00451                         q = q_next;
00452                         err_q = Error(q);
00453                 }
00454         }
00455 
00456         conf = q;
00457         return (err_q <= DEF_ERR_TOLERANCE);
00458 }
00459 
00460 bool PL_PRM_ClosedChain::GenerateRandomConfigForPose (Configuration &conf, Frame &endEffPose)
00461 {
00462         conf = PL_PRM::GenerateRandomConfig();
00463         costFunc = &PL_PRM_ClosedChain::Error1;
00464 
00465         bool Result = GetSatisfactoryConfiguration(conf, endEffPose);
00466         if (Result)
00467         {
00468                 Result = !IsInterfering(conf);
00469         }
00470         return Result;
00471 }
00472 
00473 Configuration PL_PRM_ClosedChain::GenerateRandomConfig () const
00474 {
00475         Configuration conf;
00476         Frame endEffPose;
00477         conf = PL_PRM::GenerateRandomConfig();
00478         if (usePlanarConstraint)
00479         {
00480                 endEffPose = planeDesired;
00481                 costFunc = &PL_PRM_ClosedChain::Error3;
00482         }
00483         else if (useOrientConstraint)
00484         {
00485                 endEffPose = orientDesired;
00486                 costFunc = &PL_PRM_ClosedChain::Error4;
00487         }
00488         else
00489         {
00490                 costFunc = &PL_PRM_ClosedChain::Error2;
00491         }
00492 
00493         GetSatisfactoryConfiguration(conf, endEffPose);
00494         //MakeItClosed(conf);
00495         return conf;
00496 }
00497 
00498 Configuration PL_PRM_ClosedChain::GenerateRandomConfig ( const Configuration& seed, const double& std_dev ) const
00499 {
00500         Configuration conf;
00501         Frame endEffPose;
00502         conf = PL_PRM::GenerateRandomConfig(seed, std_dev);
00503         if (usePlanarConstraint)
00504         {
00505                 endEffPose = planeDesired;
00506                 costFunc = &PL_PRM_ClosedChain::Error3;
00507         }
00508         else if (useOrientConstraint)
00509         {
00510                 endEffPose = orientDesired;
00511                 costFunc = &PL_PRM_ClosedChain::Error4;
00512         }
00513         else
00514         {
00515                 costFunc = &PL_PRM_ClosedChain::Error2;
00516         }
00517 
00518         GetSatisfactoryConfiguration(conf, endEffPose);
00519         return conf;
00520 }
00521 
00522 void PL_PRM_ClosedChain::ConnectEdgesFull( const node& newnode, const double& radius_squared )
00523 {
00524         // verify connectIDp is valid.
00525         assert( connectIDp != NULL );
00526 
00527         // Save calculation time by determining configuration of the node once intstead of in each iteration
00528         Configuration nodeconfig = G.inf(newnode);
00529 
00530         node n1;
00531 
00532         // create a list of neighbour nodes to connect to within the given radius.
00533         node_pq<double> neighbours(G);
00534         forall_nodes( n1, G)
00535         {
00536                 if ( newnode != n1)
00537                 {
00538                         double edgelength_squared = Distance( nodeconfig, G.inf(n1) );  // returns the squared distance
00539                         // Check if the two nodes are within radius
00540                         if (  edgelength_squared <= radius_squared )  // can compare squares since a^2<b^2 if |a|<|b|
00541                         {
00542                                 // node is within radius, add it as a neighbour with its distance as its priority.
00543                                 neighbours.insert( n1, edgelength_squared );
00544                         }
00545                 }
00546         }
00547 
00548         // New node is currently not connected to anyone, assign it the NIL_ID.
00549         (*connectIDp)[newnode] = NIL_ID;
00550 
00551         // Create a running list of graph connected components new node is attached to.
00552         list<int> connectIDs;
00553 
00554         // While the list of neighbour is not empty, connect the node to the closests nodes, not already graph
00555         // connected to.
00556         while ( !neighbours.empty() )
00557         {
00558                 // get closest neighbour and remove it from the list
00559                 node neighbour = neighbours.find_min();
00560                 double dist_sq = neighbours.inf( neighbour );
00561                 neighbours.del( neighbour );
00562 
00563                 // connect the neighbour to the new node if it is not already graph connected.
00564                 // A node is graph connected if its current connectID is in the running list of
00565                 // connected graph components or has the same connectID as the new node.
00566                 if ( ((*connectIDp)[neighbour] == NIL_ID) ||
00567                          ( ((*connectIDp)[neighbour] != (*connectIDp)[newnode]) &&
00568                            ( !NodeInConnectionList(neighbour, connectIDs) ) )
00569                    )
00570                 {
00571                         edgeFrag->clear();
00572                         // nodes are not aleady connected.  Connect them now if there is a collision free path.
00573                         if ( !IsInterfering( nodeconfig, G.inf(neighbour) ) )
00574                         {
00575                                 double edgelength = sqrt( dist_sq );
00576                                 edge newedge = G.new_edge( newnode, neighbour, edgelength );
00577                                 edgeChecked[newedge] = TRUE;
00578                                 edgePath[newedge] = *edgeFrag;
00579 
00580                                 //LogMessage("closedchain.log", "Configurations checked in fragment");
00581                                 //for (int testj=0; testj<edgePath[newedge].size(); testj++)
00582                                 //{
00583                                 //      Fragment& E= edgePath[newedge];
00584                                 //      list_item itt = E.get_item(testj);
00585                                 //      Configuration conf = (E[itt]);
00586                                 //      LogVector("closedchain.log", conf, "Conf: ");
00587                                 //}
00588 
00589                                 // update the connectionIDs to show these two nodes are now graph connected.
00590                                 if ( (*connectIDp)[neighbour] != NIL_ID )
00591                                 // neighbour node has been previously connected to a graph component.
00592                                 {
00593                                         if ( (*connectIDp)[newnode] == NIL_ID )
00594                                         {
00595                                                 // node has not been previously connected, assign it the connect ID of its new neighbour.
00596                                                 (*connectIDp)[newnode] = (*connectIDp)[neighbour];
00597                                         }
00598                                         else if ( (*connectIDp)[neighbour] < (*connectIDp)[newnode] )
00599                                         {
00600                                                 // the neighbour node has the smaller ID.  Select this as the new ID for the two
00601                                                 // newly connected graph components (one from the new neighbour, one from the new node).
00602 
00603                                                 // save the old connectionID into the running list to be updated later.
00604                                                 connectIDs.push( (*connectIDp)[newnode] );
00605 
00606                                                 // assign the lower connection ID to the new node.
00607                                                 (*connectIDp)[newnode] = (*connectIDp)[neighbour];
00608                                         }
00609                                         else
00610                                         {
00611                                                 // the new node has the smaller ID.  Select this as the new ID for the two components.
00612 
00613                                                 // save the old connectionID into the running list to be updated later.
00614                                                 connectIDs.push( (*connectIDp)[neighbour] );
00615 
00616                                                 // assign the lower connection ID to the neighbour.
00617                                                 (*connectIDp)[neighbour] = (*connectIDp)[newnode];
00618                                         }
00619                                 }  // end if neighbour != NIL_ID
00620                                 else
00621                                 // neighbour has not been previously connected.
00622                                 {
00623                                         if ( (*connectIDp)[newnode] != NIL_ID )
00624                                         {
00625                                                 // new node has been previously connected, assign the neighbour its ID.
00626                                                 (*connectIDp)[neighbour] = (*connectIDp)[newnode];
00627                                         }
00628                                         else
00629                                         {
00630                                                 // both nodes have not been previously connected.  Create a new graph connected
00631                                                 // component by assigning these two nodes the baseConnectID.
00632                                                 (*connectIDp)[newnode] = baseConnectID;
00633                                                 (*connectIDp)[neighbour] = baseConnectID;
00634 
00635                                                 // Update the base connect ID to ensure a new unique ID is available for next new node.
00636                                                 baseConnectID++;
00637                                         }
00638                                 }  // end update connectIDs.
00639 
00640                         } // end if interfering
00641                         else
00642                         {
00643                                 edgeFrag->clear();
00644                                 // nodes have a collision path.  Use the midpoint between these two nodes as a seed for enhancing.
00645                                 // Add the midpoint of this potential edge as a seed, if requested
00646                                 if ( useMidPts )
00647                                 {
00648                                         Configuration midpt = GetMidPoint( nodeconfig, G.inf(neighbour) );
00649                                         config_seeds.append( midpt );
00650                                 }
00651                         }  // end if interfering else.
00652 
00653                 }       // end if not already graph connected.
00654 
00655         } // end while !neighbours.empty().
00656 
00657         // Search the entire graph, if required, updating connectIDs to reflect how new node has graph connected
00658         // different components of the graph.
00659         if ( ((*connectIDp)[newnode] != NIL_ID) && ( !connectIDs.empty() ) )
00660         {
00661                 // new node is connected to more than one graph connected component.  Update the connect IDs of
00662                 // affected nodes.
00663                 int newID = (*connectIDp)[newnode];
00664 
00665                 forall_nodes( n1, G )
00666                 {
00667                         if ( ((*connectIDp)[n1] != newID ) && (NodeInConnectionList( n1, connectIDs )) )
00668                         {
00669                                 (*connectIDp)[n1] = newID;
00670                         }
00671                 }
00672         }  // end update connectIDs of entire graph
00673 
00674         return;
00675 }
00676 
00677 bool PL_PRM_ClosedChain::MakeItClosed(Configuration &conf) const
00678 {
00679         int i,j;
00680         Configuration q;
00681         q = conf;
00682         i = 0; j = 0;
00683         int MAX_I = MAX_ITERATION * MAX_RETRY;
00684         int MAX_J = MAX_RETRY;
00685         double err_q = Error(q);
00686         while ((i<MAX_I) && (j<MAX_J) && (err_q>DEF_ERR_TOLERANCE))
00687         {
00688                 i++;   j++;
00689                 double deviation = DEF_NEIGHBOR;
00690                 if (err_q < 1)
00691                         deviation *= err_q;
00692                 Configuration q_next = PL_PRM::GenerateRandomConfig(q, deviation);
00693                 if (Error(q_next) < err_q)
00694                 {
00695                         j = 0; 
00696                         q = q_next;
00697                         err_q = Error(q);
00698                 }
00699                 if ( HasTimeLimitExpired() )
00700                 {
00701                         return false;
00702                 }
00703         }
00704 
00705         conf = q;
00706         return (err_q <= DEF_ERR_TOLERANCE);
00707 }
00708 
00709 bool PL_PRM_ClosedChain::IsClosed(const Configuration &conf) const
00710 {
00711         return (Error(conf) <= DEF_ERR_TOLERANCE);
00712 }
00713 
00714 bool PL_PRM_ClosedChain::IsInterfering ( const Configuration& q1, const Configuration& q2 ) const
00715 {
00716         int i, j, k;
00717         i = 0;  j = 0;  k = 0;
00718         Configuration q_last = q1;
00719         //Configuration q_end = q2;
00720         edgeFrag->append(q1);
00721         int MAX_I = MAX_ITERATION * MAX_RETRY * MAX_RETRY2;
00722         int MAX_J = MAX_RETRY;
00723         int MAX_K = MAX_RETRY2;
00724         double distToLast = sqrt(Distance(q_last, q2));
00725         bool result = false;
00726         while ((i<MAX_I) && (j<MAX_J) && (k<MAX_K) && (distToLast>DEF_DIST_TOLERANCE))
00727         {
00728                 i++;  j++;
00729                 //Configuration q_mid = PL_PRM::GenerateRandomConfig(q_last, DEF_NEIGHBOR*0.2);
00730                 Configuration q_mid = q_last*(1-(DEF_DIST_TOLERANCE/distToLast)) + q2*(DEF_DIST_TOLERANCE/distToLast);
00731                 if (MakeItClosed(q_mid))  //if (Error(q_mid)<DEF_ERR_TOLERANCE)
00732                 {
00733                         j = 0; k++;
00734                         if (PL_PRM::IsInterfering(q_mid))
00735                         {
00736                                 result = true;
00737                                 break;
00738                         }
00739                         if (Distance(q_mid, q2) < distToLast*distToLast)
00740                         {
00741                                 k = 0;
00742                                 edgeFrag->append(q_mid);
00743                                 q_last = q_mid;
00744                                 distToLast = sqrt(Distance(q_last, q2));
00745                         }
00746                 }
00747                 if ( HasTimeLimitExpired() )
00748                 {
00749                         result = true;
00750                         break;
00751                 }
00752         }
00753 
00754         //LogMessage("closedchain.log", "Configurations added into fragment");
00755         //for (int testj=0; testj<edgeFrag->size(); testj++)
00756         //{
00757         //      list_item itt = edgeFrag->get_item(testj);
00758         //      Configuration conf = edgeFrag->contents(itt);
00759         //      LogVector("closedchain.log", conf, "Conf: ");
00760         //}
00761 
00762         if ((!result) && (distToLast<=DEF_DIST_TOLERANCE))
00763         {
00764                 edgeFrag->append(q2);
00765                 return false;
00766         }
00767         else
00768         {
00769                 edgeFrag->clear();
00770                 return true;
00771         }
00772 }
00773 
00774 bool PL_PRM_ClosedChain::IsInterfering ( const Configuration& c1 ) const
00775 {
00776         if (!IsClosed(c1)) 
00777                 return true;
00778         if (PL_PRM::IsInterfering(c1))
00779                 return true;
00780         return false;
00781 }
00782 
00783 
00784 void PL_PRM_ClosedChain::UpdatePlanarConstraint() 
00785 {
00786         planeDesired = GetToolFrame( GetStartConfig() );
00787 }
00788 
00789 void PL_PRM_ClosedChain::UpdateOrientConstraint()
00790 {
00791         //orientDesired = GetToolFrame( GetStartConfig() );
00792         orientDesired = Matrix4x4::Identity();
00793         orientDesired.Rotate(Vector4(1, 0, 0), -90);
00794         //orientDesired.Rotate(Vector4(0, 1, 0), 0);
00795         //orientDesired.Rotate(Vector4(0, 0, 1), 0);
00796 }
00797 
00798 //Distance between a configuration to a pose
00799 double PL_PRM_ClosedChain::Error1(const Configuration &p1, const Frame &pose) const
00800 {
00801         double distance;
00802 
00803         Frame toolFrame = GetToolFrame( p1 );
00804         if (!useOrientConstraint)
00805         {
00806                 Vector4 offset = pose.GetTranslationVector() - toolFrame.GetTranslationVector();
00807                 distance = offset.Magnitude();
00808         }
00809         else
00810         {
00811                 /*
00812                 double distance_sq;
00813                 Vector4 offset = pose.GetTranslationVector() - toolFrame.GetTranslationVector();
00814                 distance_sq = offset.MagSquared();
00815                 Vector4 rot1, rot2;
00816                 GetRotAngles(toolFrame, rot1[0], rot1[1], rot1[2]);
00817                 GetRotAngles(pose, rot2[0], rot2[1], rot2[2]);
00818                 rot1 -= rot2;
00819                 distance_sq += Deg2Rad(1)*Deg2Rad(1)*rot1.MagSquared();
00820                 distance = sqrt(distance_sq);
00821                 */
00823                 Vector4 PX(1, 0, 0);
00824                 Vector4 PY(0, 1, 0);
00825                 Vector4 PZ(0, 0, 1);
00826                 // Generate vectors from base frame to each of the unit vector of the given frames.
00827                 Vector4 Pax = toolFrame * PX;
00828                 Vector4 Pay = toolFrame * PY;
00829                 Vector4 Paz = toolFrame * PZ;
00830 
00831                 Vector4 Pbx = pose * PX;
00832                 Vector4 Pby = pose * PY;
00833                 Vector4 Pbz = pose * PZ;
00834 
00835                 // Generate difference vectors that connect the corresponding unit vectors of the given frames
00836                 Vector4 dx = Pax - Pbx;
00837                 Vector4 dy = Pay - Pby;
00838                 Vector4 dz = Paz - Pbz;
00839 
00840                 // Calculate the value of the distance metric (square the magitude of each difference vectors and sum.
00841                 double distance_sq = dx.MagSquared() + dy.MagSquared() + dz.MagSquared();
00842                 distance = sqrt(distance_sq);
00843                 //*/
00844         }
00845 
00846         return distance;
00847 }
00848 
00849 //Distance between a configuration to a closure constraint
00850 double PL_PRM_ClosedChain::Error2(const Configuration &p1, const Frame &pose) const
00851 {
00852         Frame toolFrame = GetToolFrame( p1 );
00853         Vector4 offset = toolFrame.GetTranslationVector();
00854         offset[2] = 0;
00855         return offset.Magnitude();
00856 }
00857 
00858 //Distance between a configuration to a plane
00859 double PL_PRM_ClosedChain::Error3(const Configuration &p1, const Frame &pose) const
00860 {
00861         Frame toolFrame = GetToolFrame( p1 );
00862         //return fabs(toolFrame(1, 3)-planeDesired);
00863 #if 0 //plannar constraint
00864         return fabs(toolFrame(1, 3)-pose(1, 3));
00865 
00866 #ifdef ABCD //sphere constraint without constraint
00867         double cx, cy, cz, radius;
00868         cx=15;  cy=0;  cz=5;  //center
00869         radius = 12;
00870         Vector4 center(cx, cy, cz);
00871         Vector4 pos1 = toolFrame.GetTranslationVector();
00872         pos1 -= center;
00873         return sqrt((pos1.Magnitude() - radius)*(pos1.Magnitude() - radius));
00874 #endif
00875 
00876 #else //ifdef ABCD
00877         double cx, cy, cz, radius;
00878         cx=15;  cy=0;  cz=5;  //center
00879         radius = 12;
00880         Vector4 center(cx, cy, cz);
00881         //Get desired Z-axis
00882         Vector4 pos1 = pose.GetTranslationVector();
00883         Vector4 desiredZ = center;
00884         desiredZ -= pos1;
00885         desiredZ.Normalize();
00886         desiredZ *= -(radius-1);
00887         desiredZ += center;
00888         //Get current Z-axis
00889         Vector4 pos2 = toolFrame.GetTranslationVector();
00890         Vector4 currentZ;
00891         currentZ[0] = toolFrame(0, 2);
00892         currentZ[1] = toolFrame(1, 2);
00893         currentZ[2] = toolFrame(2, 2);
00894         currentZ += pos2;
00895 
00896         desiredZ -= currentZ;
00897         return desiredZ.Magnitude();
00898 #endif
00899 }
00900 
00901 //Distance between a configuration to a plane
00902 double PL_PRM_ClosedChain::Error4(const Configuration &p1, const Frame &pose) const
00903 {
00904         Frame toolFrame = GetToolFrame( p1 );
00905         double yaw1, pitch1, roll1;
00906         double yaw2, pitch2, roll2;
00907         GetRotAngles(toolFrame, roll1, pitch1, yaw1);
00908         GetRotAngles(pose, roll2, pitch2, yaw2);
00909         return ((roll1-roll2)*(roll1-roll2) + (yaw1-yaw2)*(yaw1-yaw2)
00910                 /*+ (pitch1-pitch2)*(pitch1-pitch2)*/);
00911 }
00912 
00913 double PL_PRM_ClosedChain::Error(const Configuration &p1) const
00914 {
00915         Frame toolFrame = GetToolFrame( p1 );
00916 
00917         if (usePlanarConstraint)
00918         {
00919                 //Before adding the sphere.
00920                 //return fabs(toolFrame(1, 3)-planeDesired(1, 3));
00921                 return Error3(p1, toolFrame);
00922         }
00923         else if (useOrientConstraint)
00924         {
00925                 double yaw1, pitch1, roll1;
00926                 double yaw2, pitch2, roll2;
00927                 GetRotAngles(toolFrame, roll1, pitch1, yaw1);
00928                 GetRotAngles(orientDesired, roll2, pitch2, yaw2);
00929                 //return ((roll1-roll2)*(roll1-roll2) + (yaw1-yaw2)*(yaw1-yaw2));
00930                 return ((roll1-roll2)*(roll1-roll2) + (yaw1-yaw2)*(yaw1-yaw2) 
00931                         /*+ (pitch1-pitch2)*(pitch1-pitch2)*/);
00932         }
00933         else
00934         {
00935                 //here we're only working on 2D case, and assume the base is the origin
00936                 Vector4 offset = toolFrame.GetTranslationVector();
00937                 offset[2] = 0;
00938                 return offset.Magnitude();
00939         }
00940 }
00941 
00942 void PL_PRM_ClosedChain::GetRotAngles( const Matrix4x4& frame, double& roll, double& pitch, double& yaw ) const
00943 {
00944         // Declare the fixed angle variables.
00945         double alpha, beta, gamma;
00946         
00947         // Calculate beta and cache the cosine.
00948         beta = atan2( -frame(2,0) , sqrt( Sqr(frame(0,0)) + Sqr(frame(1,0)) ) );
00949         double cB = cos ( beta );
00950 
00951         // Calculate the other two rotations
00952         if ( cB == 0.0 )
00953         { 
00954                 alpha = 0;
00955                 if ( beta > 0 ) // if beta == PI/2
00956                 {
00957                         gamma = atan2( frame(0,1) , frame(1,1) );
00958                 }
00959                 else
00960                 {
00961                         gamma = -atan2( frame(0,1), frame(1,1) );
00962                 }
00963         }
00964         else
00965         {
00966                 alpha = atan2( frame(1,0) / cB , frame(0,0) / cB );
00967                 gamma = atan2( frame(2,1) / cB , frame(2,2) / cB );
00968         }
00969 
00970         // Convert angles to degrees and assign to appropriate parameters
00971         // NOTE:  These angles must correspond to same angles used in SetGoalFrame
00972         yaw   = Rad2Deg( alpha );
00973         pitch = Rad2Deg( beta );
00974         roll  = Rad2Deg( gamma );
00975 }
00976 
00977 SuccessResultType PL_PRM_ClosedChain::TranslatePath()
00978 {
00979         // Clear any current path.
00980         path.Clear();
00981 
00982         // Check if a graph path is available.
00983         if ( graphPath.empty() )
00984         {
00985                 // Path is empty.  Set start as the beginning of the path, and return.
00986                 path.AppendPoint( GetStartConfig() );
00987 
00988                 // no path exists.
00989                 return FAIL;
00990         }
00991 
00992         // If still in the function, there is a graphPath.
00993         // Go through all nodes stored in graphPath and assign the configuration they correspond to the
00994         // actual path.
00995         node n1;
00996         node n2;
00997         forall( n1, graphPath )
00998         {
00999                 Configuration conf = G.inf(n1);
01000                 path.AppendPoint( conf );
01001                 n2 = graphPath.succ(n1);
01002                 if (n2 == NULL)
01003                         continue;
01004 
01005                 edge e;
01006                 forall_inout_edges(e, n1)
01007                 //edge e = G.first_in_edge(n1);
01008                 //while(e)
01009                 {
01010                         if (G.opposite(n1, e) == n2)
01011                         {
01012                                 int nStep = 0;
01013                                 int dir = -1;
01014                                 Fragment& frag = edgePath[e];
01015                                 int nFirst = frag.size();
01016                                 if (conf == frag[frag[0]])
01017                                 {
01018                                         nFirst = 0;
01019                                         dir = 1;
01020                                 }
01021                                 for (int i=1; i<(frag.size()-1); i++)
01022                                 {
01023                                         nStep += dir;
01024                                         list_item it = frag[nFirst+nStep];
01025                                         conf = frag[it];
01026                                         //->get_item(i);//((*frag)[nFirst+dir]);
01027                                         path.AppendPoint( conf );
01028                                 }
01029                                 break;
01030                         }
01031                 }
01032         }
01033 
01034         // Path has been translated and is ready to be animated.
01035         return PASS;
01036 }
01037 
01038 double LocalPlannerClosed::Distance(Configuration &conf1, Configuration &conf2)
01039 {
01040         // Get the differences between each of the joints
01041         VectorN jointDiff;
01042         jointDiff = collisionDetector->JointDisplacement( conf1, conf2 );
01043 
01044         // Square and sum each of the joint differences
01045         double distance = 0;
01046         for( int i = 0; i < jointDiff.Length(); i++ )
01047         {
01048                 distance += Sqr(jointDiff[i] );
01049         }
01050 
01051         // Return the squared euclidean distance
01052         return sqrt(distance);
01053 }
01054 
01055 bool LocalPlannerClosed::Plan()
01056 {
01057     // check to see that SWIFTpp is the collision detector used
01058     const CD_Swiftpp* pSwiftpp = dynamic_cast< const CD_Swiftpp* >( collisionDetector );
01059     if (pSwiftpp == NULL)
01060     {
01061         return false;
01062     }
01063 
01064     // quick checks
01065         if ( collisionDetector->IsInterfering( GetStartConfig() ) )
01066         {
01067                 // there is a collision with the start configuration...report failure
01068         //MessageBox(NULL, "Collision detected while planning.","IK_Jacobian Planner Error", MB_OK);
01069                 return false;
01070         }
01071 
01072         // Start the timer
01073         StartTimer();
01074 
01075         // Establish the semaphore
01076         //Semaphore semaphore( guid );
01077         //semaphore.Lock();
01078 
01079     Configuration   currentConfig, goalConfig, nextConfig, jointVelocity;
01080     currentConfig.SetNumDOF(m_nDof);
01081     nextConfig.SetNumDOF(m_nDof);
01082     jointVelocity.SetNumDOF(m_nDof);
01083     for (int i = 0; i < m_nDof; i++)
01084     {
01085         jointVelocity[i] = 0;
01086     }
01087     currentConfig = GetStartConfig();
01088         goalConfig = GetGoalConfig();
01089     
01090     path.Clear();
01091     path.AppendPoint(currentConfig);
01092 
01093         //Initialize Jacobian, obstacle point and end-effector will share a Jacobian matrix.
01094         CJacobian jacobian(*m_pRobot);
01095         jacobian.SetConfiguration(currentConfig);
01096         //Frame frEndEffector = jacobian.GetJointFrame(m_nDof+1);
01097 
01098         bool abort = false;
01099 
01100         VectorN vEndEffVel(0, 0, 0);
01101     //for (int iViaPts = 0; iViaPts < (poses.size()-1); iViaPts++);
01102         double dist = Distance(currentConfig, goalConfig);
01103         while (dist > DEF_DIST_TOLERANCE )
01104     {
01105                 jacobian.SetInterestPoint(m_nDof-1, m_frEndEffector, m_bPosition, m_bOrientation);
01106                 //jacobian.GetJointVelocity(jointVelocity, vEndEffVel);
01107 
01108                 Matrixmxn mJEnd, mJEndInv;
01109                 mJEnd = *(jacobian.GetMatrix());
01110                 mJEnd.Inverse(mJEndInv);
01111 
01112                 Matrixmxn mTemp(m_nDof, m_nDof); 
01113                 mTemp -= mJEndInv * mJEnd;
01114 
01115                 //jointVelocity = currentConfig*(1-(DEF_DIST_TOLERANCE/dist)) + goalConfig*(DEF_DIST_TOLERANCE/dist);
01116                 jointVelocity = (goalConfig-currentConfig);
01117                 if (dist > DEF_DIST_TOLERANCE)
01118                         jointVelocity *= (DEF_DIST_TOLERANCE/dist);
01119                 for (int i=0; i<m_nDof; i++)
01120                 {
01121                         double dValue = jointVelocity[i];
01122                         jointVelocity[i] = Deg2Rad(dValue);
01123                 }
01124                 jointVelocity = mTemp * jointVelocity;
01125 
01126                 //============= Begin of obstacles =====================
01127         // Getting the homogeneous solutions for the obstacles (Jo's)
01128         // check for the closest points between robot/obstacles
01129         if (GetClosestValues(currentConfig) != false)
01130                 {
01131                         //LogMessage("Aborting.... Colliding when getting collision points!");
01132                         abort = true;
01133             break;
01134                 }
01135 
01136         double obsDirMag = 0;
01137         // if closest distance is critical, abort
01138         if (m_vClosestPoints[0].distance <= m_dObsTol)
01139         {                
01140             //MessageBox(NULL, "Collision detected while planning", "IK_Jacobian Planner Error", MB_OK);
01141                         //LogMessage("Aborting.... Colliding, too close to obstacles!");
01142             abort = true;
01143             break;
01144         }            
01145         //** no obstacle scenario handled by infinite distance
01146         else
01147         {
01148                         VectorN vHomogeneousSolns;
01149                         vHomogeneousSolns = ComputeHomogeneousTerm(jacobian, mJEnd, mJEndInv, vEndEffVel);
01150 
01151                         //LogVector(vHomogeneousSolns, "Homogeneous Term:");
01152                         
01153                         jointVelocity += vHomogeneousSolns;
01154         } // obstacles exist
01155 
01156                 //============= End of obstacles =====================
01157 
01158                 //Convert to degree representation;
01159         CheckJointVelocities(jointVelocity);
01160                 for (i=0; i<m_nDof; i++)
01161                 {
01162                         double dValue = jointVelocity[i];
01163                         jointVelocity[i] = Rad2Deg(dValue);
01164                 }
01165 
01166                 //LogVector(jointVelocity, "Joint Velocity");
01167         
01168                 // calculate where the new velocity takes us after time interval
01169                 nextConfig = currentConfig + jointVelocity;
01170         CheckJointLimits(nextConfig);
01171 
01172                 
01173  //               currentConfig = nextConfig;
01174 //                              path.AppendPoint(currentConfig);
01175 //              LogVector("ClosedLocal.log", nextConfig, "Next Configuration");                       
01176 
01177 
01178 
01179         // got next configuration, now need to see if it's valid               
01180         //if (collisionDetector->IsInterferingLinear(currentConfig, nextConfig ) == false)
01181                 if (collisionDetector->IsInterfering(nextConfig ) == false)
01182         {        
01183             // there's no point adding it if it's the same
01184             if (currentConfig != nextConfig)        
01185             {
01186                 currentConfig = nextConfig;
01187                 path.AppendPoint(currentConfig);
01188                                 dist = Distance(currentConfig, goalConfig);
01189                // GetEndEffVector(currentConfig, vCurPt);
01190             }
01191             jacobian.SetConfiguration(currentConfig);
01192         }
01193         else        // interfering
01194         {
01195             //MessageBox(NULL, "Obstacle in path could not be avoided","IK_Jacobian Planner Error", MB_OK);
01196                         //LogMessage("Aborting.... Colliding when checking next configuration!");
01197             abort = true;
01198                         break;
01199         }            
01200             //semaphore.Unlock();
01201             //semaphore.Lock();
01202 
01203         if (HasTimeLimitExpired() != false)
01204         {            
01205             //MessageBox(NULL, "Time's up!", "Plan() fail - Time's Up!", MB_OK);
01206                         //LogMessage("Aborting.... Time up!");
01207             abort = true;
01208                         break;
01209         }
01210     }
01211 
01212     //semaphore.Unlock();
01213         if (abort)
01214         {
01215                 //LogMessage("### Planning Failure");
01216         }
01217         else
01218         {
01219         if (collisionDetector->IsInterferingLinear(currentConfig, goalConfig ) == false)
01220                 {
01221             path.AppendPoint(goalConfig);
01222                 }
01223                 //LogMessage("### Planning Success");
01224         }
01225     return (abort == false);
01226 }
01227 
01228 //===========================================================================================
01229 

Generated on Sat Apr 1 21:30:41 2006 for Motion Planning Kernel by  doxygen 1.4.6-NO