00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 *
00004 *  Copyright (c) 2010, Rice University
00005 *  All rights reserved.
00006 *
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 *
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Rice University nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 *
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00035 /* Author: Mark Moll */
00036 
00037 #include <ompl/extensions/vortex/VortexSimpleSetup.h>
00038 #include <ompl/base/GoalRegion.h>
00039 
00040 #include <Vx/VxBox.h>
00041 #include <Vx/VxPart.h>
00042 #include <Vx/VxAssembly.h>
00043 #include <Vx/VxState.h>
00044 
00045 #include <ompl/config.h>
00046 #include <iostream>
00047 
00048 namespace ob = ompl::base;
00049 namespace og = ompl::geometric;
00050 namespace oc = ompl::control;
00051 
00053 
00054 class RigidBodyEnvironment : public oc::VortexEnvironment
00055 {
00056 public:
00057 
00058     RigidBodyEnvironment(void) : oc::VortexEnvironment()
00059     {
00060         createWorld();
00061     }
00062     ~RigidBodyEnvironment()
00063     {
00064         visualizer_->stopViewer();
00065     }
00066 
00067     /**************************************************
00068      * Implementation of functions needed by planning *
00069      **************************************************/
00070 
00071     virtual unsigned int getControlDimension(void) const
00072     {
00073         return 3;
00074     }
00075 
00076     virtual void getControlBounds(std::vector<double> &lower, std::vector<double> &upper) const
00077     {
00078         static double maxForce = 1.;
00079         lower.resize(3);
00080         lower[0] = -maxForce;
00081         lower[1] = -maxForce;
00082         lower[2] = 9.81 - maxForce;
00083 
00084         upper.resize(3);
00085         upper[0] = maxForce;
00086         upper[1] = maxForce;
00087         upper[2] = 9.81 + maxForce;
00088     }
00089 
00090     virtual void applyControl(const double *control) const
00091     {
00092         Vx::VxReal3 force = { control[0], control[1], control[2] };
00093         static_cast<Vx::VxPart*>(assembly_->findEntityFromName("moving box"))->addForce(force);
00094     }
00095 
00096     /**************************************************/
00097 
00098     // OMPL does not require this function here; we implement it here
00099     // for convenience. This function is only Vortex code to create a
00100     // simulation environment. At the end of the function, there is a
00101     // call to setPlanningParameters(), which configures members of
00102     // the base class needed by planners.
00103     void createWorld(void);
00104 
00105     // Set parameters needed by the base class (such as the bodies
00106     // that make up to state of the system we are planning for)
00107     void setPlanningParameters(void);
00108 
00109     // convenience function to get the position of the box
00110     const Vx::VxVector3& getPosition(const ob::State* st) const;
00111 };
00112 
00113 
00114 // Define the goal we want to reach
00115 class RigidBodyGoal : public ob::GoalRegion
00116 {
00117 public:
00118     RigidBodyGoal(const ob::SpaceInformationPtr &si) : ob::GoalRegion(si)
00119     {
00120         threshold_ = 1.;
00121     }
00122 
00123     virtual double distanceGoal(const ob::State *st) const
00124     {
00125         static const Vx::VxVector3 goalPos(30, 55, 35);
00126         const Vx::VxVector3& pos =
00127             si_->getStateSpace()->as<oc::VortexStateSpace>()->getEnvironment()->as<RigidBodyEnvironment>()->getPosition(st);
00128         return (goalPos - pos).norm();
00129     }
00130 };
00131 
00132 
00133 // Define how we project a state
00134 class RigidBodyStateProjectionEvaluator : public ob::ProjectionEvaluator
00135 {
00136 public:
00137 
00138     RigidBodyStateProjectionEvaluator(const ob::StateSpace *space) : ob::ProjectionEvaluator(space)
00139     {
00140         cellSizes_.resize(3);
00141         cellSizes_[0] = 1;
00142         cellSizes_[1] = 1;
00143         cellSizes_[2] = 1;
00144     }
00145 
00146     virtual unsigned int getDimension(void) const
00147     {
00148         return 3;
00149     }
00150 
00151     virtual void project(const ob::State *state, ob::EuclideanProjection &projection) const
00152     {
00153         const Vx::VxVector3& pos =
00154             space_->as<oc::VortexStateSpace>()->getEnvironment()->as<RigidBodyEnvironment>()->getPosition(state);
00155         projection[0] = pos[0];
00156         projection[1] = pos[1];
00157         projection[2] = pos[2];
00158     }
00159 
00160 };
00161 
00162 // Define our own state space, to include a distance function we want and register a default projection
00163 class RigidBodyStateSpace : public oc::VortexStateSpace
00164 {
00165 public:
00166     RigidBodyStateSpace(const oc::VortexEnvironmentPtr &env) : oc::VortexStateSpace(env)
00167     {
00168     }
00169 
00170     virtual double distance(const ob::State *s1, const ob::State *s2) const
00171     {
00172         return (env_->as<RigidBodyEnvironment>()->getPosition(s1) 
00173               - env_->as<RigidBodyEnvironment>()->getPosition(s2)).norm();
00174     }
00175 
00176     virtual void registerProjections(void)
00177     {
00178         registerDefaultProjection(ob::ProjectionEvaluatorPtr(new RigidBodyStateProjectionEvaluator(this)));
00179     }
00180 };
00181 
00183 
00184 int main(int, char **)
00185 {
00186     // create the Vortex environment
00187     oc::VortexEnvironmentPtr env(new RigidBodyEnvironment());
00188 
00189     // create the state space and the control space for planning
00190     ob::StateSpacePtr stateSpacePtr = ob::StateSpacePtr(new RigidBodyStateSpace(env));
00191 
00192     // this will take care of setting a proper collision checker and the
00193     // starting state for the planner as the initial Vortex state
00194     oc::VortexSimpleSetup ss(stateSpacePtr);
00195 
00196     // set the goal we would like to reach
00197     ss.setGoal(ob::GoalPtr(new RigidBodyGoal(ss.getSpaceInformation())));
00198 
00199     ob::RealVectorBounds bounds(3);
00200     bounds.setLow(-1);
00201     bounds.setHigh(70);
00202     stateSpacePtr->as<RigidBodyStateSpace>()->setWorkspaceBounds(bounds);
00203 
00204 
00205     ss.setup();
00206     ss.print();
00207     
00208     // ss.simulate(10);
00209     // return 0;
00210 
00211     if (ss.solve(30))
00212     {
00213         bool running;
00214         oc::PathControl p(ss.getSolutionPath());
00215         //p.interpolate(); // uncomment if you want to plot the path
00216 
00217         // print out box positions along the path
00218         for (unsigned int i = 0 ; i < p.states.size() ; ++i)
00219         {
00220             const Vx::VxVector3 pos = env->as<RigidBodyEnvironment>()->getPosition(p.states[i]);
00221             std::cout << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ' ';
00222             if (i==0)
00223                 // null controls applied for zero seconds to get to start state
00224                 std::cout << "0 0 0 0";
00225             else
00226             {
00227                 // print controls and control duration needed to get from state i-1 to state i
00228                 const double* c = p.controls[i-1]->as<oc::RealVectorControlSpace::ControlType>()->values;
00229                 std::cout << c[0] << ' ' << c[1] << ' ' << c[2] <<' ' << p.controlDurations[i-1];
00230             }
00231             std::cout << std::endl;
00232         }
00233         // loop over the box's motion
00234         do
00235         {
00236             running = ss.playSolutionPath();
00237         } while (running);
00238     }
00239     return 0;
00240 }
00241 
00242 
00243 
00244 
00245 
00246 
00248 
00249 /***********************************************
00250  * Member function implementations             *
00251  ***********************************************/
00252 
00253 void RigidBodyEnvironment::createWorld(void)
00254 {
00255     // BEGIN SETTING UP A VORTEX ENVIRONMENT
00256     // ***********************************
00257     Vx::VxUniverse* universe = new Vx::VxUniverse();
00258     universe->setGravity(0., 0., -9.81);
00259     world_->addUniverse(universe);
00260 
00261     visualizer_->addDataFilePathList(VORTEX_RESOURCE_DIR);
00262     visualizer_->createDefaultWindow(0, NULL, "Vortex Rigid Body Planning Demo");
00263     visualizer_->setUniverse(world_->getUniverse(0));
00264     visualizer_->setFrameRateLock(true);
00265     visualizer_->createHelp();
00266     visualizer_->toggleHelp();
00267 
00268     Vx::VxAssembly* assembly = new Vx::VxAssembly();
00269     Vx::VxPart* box = new Vx::VxPart(1);
00270     Vx::VxReal3 boxSize = {.2, .2, .1};
00271     float boxColor[4] = {1., .1, .1, 1.};
00272 
00273     box->setName("moving box");
00274     box->addGeometry(new Vx::VxBox(boxSize), 0);
00275     assembly->addEntity(box);
00276     assembly_ = assembly; // assembly_ contains all movable parts
00277     universe->addAssembly(assembly_);
00278     Vx::VxNode boxNode = visualizer_->createBox(boxSize, boxColor);
00279     box->setNode(boxNode);
00280     box->setPosition(0., 0., 0.);
00281     box->setOrientationQuaternion(1., 0., 0., 0.);
00282 
00283     visualizer_->setCameraLookAtAndPosition(Vx::VxVector3(30,55,20), Vx::VxVector3(-5,-5,-5));
00284     // *********************************
00285     // END SETTING UP AN Vortex ENVIRONMENT
00286 
00287     setPlanningParameters();
00288 }
00289 
00290 void RigidBodyEnvironment::setPlanningParameters(void)
00291 {
00292     // Fill in parameters for OMPL:
00293     stepSize_ = 0.05;
00294     minControlSteps_ = 5;
00295     maxControlSteps_ = 50;
00296 }
00297 
00298 const Vx::VxVector3& RigidBodyEnvironment::getPosition(const ob::State* st) const
00299 {
00300     const Vx::VxState* vxstate = st->as<oc::VortexStateSpace::StateType>()->vxstate_;
00301     vxstate->restoreState(assembly_);
00302     return static_cast<Vx::VxAssembly*>(assembly_)->getEntity(0)->getPosition();
00303 }
00304