From 2d4f94bb83c235b4cce8f959ef3ce00c5bea6586 Mon Sep 17 00:00:00 2001
From: Steve Tonneau <stonneau@laas.fr>
Date: Tue, 16 Jun 2015 17:12:29 +0200
Subject: [PATCH] managed python bindings, can plan with a rbprmdevice

---
 src/CMakeLists.txt                          |   1 +
 src/hpp/corbaserver/rbprm/problem_solver.py | 376 ++++++++++++++++++++
 src/hpp/corbaserver/rbprm/rbprmbuilder.py   |  32 +-
 3 files changed, 402 insertions(+), 7 deletions(-)
 create mode 100644 src/hpp/corbaserver/rbprm/problem_solver.py

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a043a323..38f58e75 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -119,6 +119,7 @@ INSTALL(
   FILES
 	${CMAKE_CURRENT_SOURCE_DIR}/hpp/corbaserver/rbprm/client.py
 	${CMAKE_CURRENT_SOURCE_DIR}/hpp/corbaserver/rbprm/rbprmbuilder.py
+	${CMAKE_CURRENT_SOURCE_DIR}/hpp/corbaserver/rbprm/problem_solver.py
   DESTINATION ${PYTHON_SITELIB}/hpp/corbaserver/rbprm
   )
 
diff --git a/src/hpp/corbaserver/rbprm/problem_solver.py b/src/hpp/corbaserver/rbprm/problem_solver.py
new file mode 100644
index 00000000..35ad1dd6
--- /dev/null
+++ b/src/hpp/corbaserver/rbprm/problem_solver.py
@@ -0,0 +1,376 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 CNRS
+# Author: Florent Lamiraux
+#
+# This file is part of hpp-corbaserver.
+# hpp-corbaserver is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either version
+# 3 of the License, or (at your option) any later version.
+#
+# hpp-corbaserver is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Lesser Public License for more details.  You should have
+# received a copy of the GNU Lesser General Public License along with
+# hpp-corbaserver.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+## Definition of a path planning problem
+#
+#  This class wraps the Corba client to the server implemented by
+#  libhpp-corbaserver.so
+#
+#  Some method implemented by the server can be considered as private. The
+#  goal of this class is to hide them and to expose those that can be
+#  considered as public.
+class ProblemSolver (object):
+    def __init__ (self, robot):
+        self.client = robot.client.basic
+        self.robot = robot
+
+    ## \name Initial and goal configurations
+    # \{
+
+    ## Set initial configuration of specified problem.
+    #	\param dofArray Array of degrees of freedom
+    #	\throw Error.
+    def setInitialConfig (self, dofArray):
+        return self.client.problem.setInitialConfig (dofArray)
+
+    ## Get initial configuration of specified problem.
+    #	\return Array of degrees of freedom
+    def getInitialConfig (self):
+        return self.client.problem.getInitialConfig ()
+
+    ## Add goal configuration to specified problem.
+    #	\param dofArray Array of degrees of freedom
+    #	\throw Error.
+    def addGoalConfig (self, dofArray):
+        return self.client.problem.addGoalConfig (dofArray)
+
+    ## Get goal configurations of specified problem.
+    #	\return Array of degrees of freedom
+    def getGoalConfigs (self):
+        return self.client.problem.getGoalConfigs ()
+
+    ## Reset goal configurations
+    def resetGoalConfigs (self):
+        return self.client.problem.resetGoalConfigs ()
+    ## \}
+
+    ## \name Obstacles
+    # \{
+
+    ## Load obstacle from urdf file
+    #  \param package Name of the package containing the model,
+    #  \param filename name of the urdf file in the package
+    #         (without suffix .urdf)
+    #  \param prefix prefix added to object names in case the same file is
+    #         loaded several times
+    #
+    #  The ros url is built as follows:
+    #  "package://${package}/urdf/${filename}.urdf"
+    #
+    #  The kinematic structure of the urdf file is ignored. Only the geometric
+    #  objects are loaded as obstacles.
+    def loadObstacleFromUrdf (self, package, filename, prefix):
+        return self.client.obstacle.loadObstacleModel (package, filename,
+                                                       prefix)
+
+    ## Remove an obstacle from outer objects of a joint body
+    #
+    #  \param objectName name of the object to remove,
+    #  \param jointName name of the joint owning the body,
+    #  \param collision whether collision with object should be computed,
+    #  \param distance whether distance to object should be computed.
+    #  \throw Error.
+    def removeObstacleFromJoint (self, objectName, jointName, collision,
+                                 distance):
+        return self.client.obstacle.removeObstacleFromJoint \
+            (objectName, jointName, collision, distance)
+
+    ## Move an obstacle to a given configuration.
+    #  \param objectName name of the polyhedron.
+    #  \param cfg the configuration of the obstacle.
+    #  \throw Error.
+    #
+    #  \note The obstacle is not added to local map
+    #  impl::Obstacle::collisionListMap.
+    #
+    #  \note Build the collision entity of polyhedron for KCD.
+    def moveObstacle (self, objectName, cfg):
+        return self.client.obstacle.moveObstacle (objectName, cfg)
+    ## Get the position of an obstacle
+    #
+    #  \param objectName name of the polyhedron.
+    #  \retval cfg Position of the obstacle.
+    #  \throw Error.
+    def getObstaclePosition (self, objectName):
+        return self.client.obstacle.getObstaclePosition (objectName)
+
+    ## Get list of obstacles
+    #
+    #  \param collision whether to return obstacle for collision,
+    #  \param distance whether to return obstacles for distance computation
+    # \return list of obstacles
+    def getObstacleNames (self, collision, distance):
+        return self.client.obstacle.getObstacleNames (collision, distance)
+
+    ##\}
+
+    ## \name Constraints
+    #  \{
+
+    ## Create orientation constraint between two joints
+    #
+    #  \param constraintName name of the constraint created,
+    #  \param joint1Name name of first joint
+    #  \param joint2Name name of second joint
+    #  \param p quaternion representing the desired orientation
+    #         of joint2 in the frame of joint1.
+    #  \param mask Select which axis to be constrained.
+    #  If joint1 or joint2 is "", the corresponding joint is replaced by
+    #  the global frame.
+    #  constraints are stored in ProblemSolver object
+    def createOrientationConstraint (self, constraintName, joint1Name,
+                                     joint2Name, p, mask):
+        return self.client.problem.createOrientationConstraint \
+            (constraintName, joint1Name, joint2Name, p, mask)
+
+    ## Create RelativeCom constraint between two joints
+    #
+    #  \param constraintName name of the constraint created,
+    #  \param comName name of CenterOfMassComputation
+    #  \param jointName name of joint
+    #  \param point point in local frame of joint.
+    #  \param mask Select axis to be constrained.
+    #  If jointName is "", the robot root joint is used.
+    #  Constraints are stored in ProblemSolver object
+    def createRelativeComConstraint (self, constraintName, comName, jointLName, point, mask):
+        return self.client.problem.createRelativeComConstraint \
+            (constraintName, comName, jointLName, point, mask)
+
+    ## Create ComBeetweenFeet constraint between two joints
+    #
+    #  \param constraintName name of the constraint created,
+    #  \param comName name of CenterOfMassComputation
+    #  \param jointLName name of first joint
+    #  \param jointRName name of second joint
+    #  \param pointL point in local frame of jointL.
+    #  \param pointR point in local frame of jointR.
+    #  \param jointRefName name of second joint
+    #  \param mask Select axis to be constrained.
+    #  If jointRef is "", the robot root joint is used.
+    #  Constraints are stored in ProblemSolver object
+    def createComBeetweenFeet (self, constraintName, comName, jointLName, jointRName,
+        pointL, pointR, jointRefName, mask):
+        return self.client.problem.createComBeetweenFeet \
+            (constraintName, comName, jointLName, jointRName, pointL, pointR, jointRefName, mask)
+
+    ## Add an object to compute a partial COM of the robot.
+    # \param name of the partial com
+    # \param jointNames list of joint name of each tree ROOT to consider.
+    # \note Joints are added recursively, it is not possible so far to add a
+    # joint without addind all its children.
+    def addPartialCom (self, comName, jointNames):
+        return self.client.robot.addPartialCom (comName, jointNames);
+
+    ## Create position constraint between two joints
+    #
+    #  \param constraintName name of the constraint created,
+    #  \param joint1Name name of first joint
+    #  \param joint2Name name of second joint
+    #  \param point1 point in local frame of joint1,
+    #  \param point2 point in local frame of joint2.
+    #  \param mask Select which axis to be constrained.
+    #  If joint1 of joint2 is "", the corresponding joint is replaced by
+    #  the global frame.
+    #  constraints are stored in ProblemSolver object
+    def createPositionConstraint (self, constraintName, joint1Name,
+                                  joint2Name, point1, point2, mask):
+        return self.client.problem.createPositionConstraint \
+            (constraintName, joint1Name, joint2Name, point1, point2, mask)
+
+    ## Reset Constraints
+    #
+    #  Reset all constraints, including numerical constraints and locked
+    #  joints
+    def resetConstraints (self):
+        return self.client.problem.resetConstraints ()
+
+    ## Set numerical constraints in ConfigProjector
+    #
+    #  \param name name of the resulting numerical constraint obtained
+    #         by stacking elementary numerical constraints,
+    #  \param names list of names of the numerical constraints as
+    #         inserted by method hpp::core::ProblemSolver::addNumericalConstraint.
+    def setNumericalConstraints (self, name, names):
+        return self.client.problem.setNumericalConstraints (name, names)
+
+    ## Apply constraints
+    #
+    #  \param q initial configuration
+    #  \return configuration projected in success,
+    #  \throw Error if projection failed.
+    def applyConstraints (self, q):
+        return self.client.problem.applyConstraints (q)
+
+    ## Create a vector of passive dofs.
+    #
+    #  \param name name of the vector in the ProblemSolver map.
+    #  \param dofNames list of names of DOF that may
+    def addPassiveDofs (self, name, dofNames):
+        return self.client.problem.addPassiveDofs (name, dofNames)
+
+    ## Generate a configuration satisfying the constraints
+    #
+    #  \param maxIter maximum number of tries,
+    #  \return configuration projected in success,
+    #  \throw Error if projection failed.
+    def generateValidConfig (self, maxIter):
+        return self.client.problem.generateValidConfig (maxIter)
+
+    ## Lock joint with given joint configuration
+    # \param jointName name of the joint
+    # \param value value of the joint configuration
+    def lockJoint (self, jointName, value):
+        return self.client.problem.lockJoint (jointName, value)
+
+    ## error threshold in numerical constraint resolution
+    def setErrorThreshold (self, threshold):
+        return self.client.problem.setErrorThreshold (threshold)
+
+    ## Set the maximal number of iterations
+    def setMaxIterations (self, iterations):
+	return self.client.problem.setMaxIterations (iterations)
+
+
+    ## \}
+
+    ## \name Solve problem and get paths
+    # \{
+
+    ## Select path planner type
+    #  \param Name of the path planner type, either "DiffusingPlanner",
+    #         "VisibilityPrmPlanner", or any type added by method
+    #         core::ProblemSolver::addPathPlannerType
+    def selectPathPlanner (self, pathPlannerType):
+        return self.client.problem.selectPathPlanner (pathPlannerType)
+
+    ## Add a path optimizer
+    #  \param Name of the path optimizer type, either "RandomShortcut" or
+    #   any type added by core::ProblemSolver::addPathOptimizerType
+    def addPathOptimizer (self, pathOptimizerType):
+        return self.client.problem.addPathOptimizer (pathOptimizerType)
+
+    ## Clear sequence of path optimizers
+    #
+    def clearPathOptimizers (self):
+        return self.client.problem.clearPathOptimizers ()
+
+    ## Select path validation method
+    #  \param Name of the path validation method, either "Discretized"
+    #  "Progressive", "Dichotomy", or any type added by
+    #  core::ProblemSolver::addPathValidationType,
+    #  \param tolerance maximal acceptable penetration.
+    def selectPathValidation (self, pathValidationType, tolerance):
+        return self.client.problem.selectPathValidation (pathValidationType,
+                                                         tolerance)
+
+    ## Select path projector method
+    #  \param Name of the path projector method, either "Discretized"
+    #  "Progressive", "Dichotomy", or any type added by
+    #  core::ProblemSolver::addPathProjectorType,
+    #  \param tolerance maximal acceptable penetration.
+    def selectPathProjector (self, pathProjectorType, tolerance):
+        return self.client.problem.selectPathProjector (pathProjectorType,
+                                                        tolerance)
+
+    ## Solve the problem of corresponding ChppPlanner object
+    def solve (self):
+        return self.client.problem.solve ()
+
+    ## Make direct connection between two configurations
+    #  \param startConfig, endConfig: the configurations to link.
+    #  \throw Error if steering method fails to create a direct path of if
+    #  direct path is not valid
+    def directPath (self, startConfig, endConfig):
+        return self.client.problem.directPath (startConfig, endConfig)
+
+    ## Get Number of paths
+    def numberPaths (self):
+        return self.client.problem.numberPaths ()
+
+    ## Optimize a given path
+    # \param inPathId Id of the path in this problem.
+    # \throw Error.
+    def optimizePath(self, inPathId):
+        return self.client.problem.optimizePath (inPathId)
+
+    ## Get length of path
+    # \param inPathId rank of the path in the problem
+    # \return length of path if path exists.
+    def pathLength(self, inPathId):
+        return self.client.problem.pathLength(inPathId)
+
+    ## Get the robot's config at param on the a path
+    # \param inPathId rank of the path in the problem
+    # \param atDistance : the user parameter choice
+    # \return dofseq : the config at param
+    def configAtParam (self, inPathId, atDistance):
+        return self.client.problem.configAtParam (inPathId, atDistance)
+
+    ## Get way points of a path
+    #  \param pathId rank of the path in the problem
+    def getWaypoints (self, pathId):
+        return self.client.problem.getWaypoints (pathId)
+
+    ## \name Interruption of a path planning request
+    #  \{
+
+    ## \brief Interrupt path planning activity
+    #   \note this method is effective only when multi-thread policy is used
+    #         by CORBA server.
+    #         See constructor of class Server for details.
+    def interruptPathPlanning (self):
+        return self.client.problem.interruptPathPlanning ()
+    # \}
+
+    ## \name exploring the roadmap
+    #  \{
+
+    ## Get nodes of the roadmap.
+    def nodes(self):
+      return self.client.problem.nodes ()
+
+    # the configuration of the node nodeId
+    def node(self,nodeId):
+      return self.client.problem.node(nodeId)
+
+    # the number of nodes in the roadmap
+    def numberNodes(self):
+      return self.client.problem.numberNodes ()
+
+    ## Number of edges
+    def numberEdges (self):
+        return self.client.problem.numberEdges ()
+
+    ## Edge at given rank
+    def edge (self, edgeId):
+        return self.client.problem.edge (edgeId)
+
+    ## Number of connected components
+    def numberConnectedComponents (self):
+        return self.client.problem.numberConnectedComponents ()
+
+    ## Nodes of a connected component
+    #  \param connectedComponentId index of connected component in roadmap
+    #  \return list of nodes of the connected component.
+    def nodesConnectedComponent (self, ccId):
+        return self.client.problem.nodesConnectedComponent (ccId)
+
+    ## Clear the roadmap
+    def clearRoadmap (self):
+        return self.client.problem.clearRoadmap ()
+    ## \}
diff --git a/src/hpp/corbaserver/rbprm/rbprmbuilder.py b/src/hpp/corbaserver/rbprm/rbprmbuilder.py
index 713cc3c3..141c6eb3 100644
--- a/src/hpp/corbaserver/rbprm/rbprmbuilder.py
+++ b/src/hpp/corbaserver/rbprm/rbprmbuilder.py
@@ -42,18 +42,36 @@ class Builder (object):
     # \param load whether to actually load urdf files. Set to no if you only
     #        want to initialize a corba client to an already initialized
     #        problem.
-    def __init__ (self, trunkName, romName, rootJointType, load = True):
+    def __init__ (self, load = True):
         self.tf_root = "base_link"
         self.rootJointType = dict()
-        self.name = trunkName
-        self.displayName = trunkName
         self.client = CorbaClient ()
         self.load = load
-        self.loadModel (trunkName, romName, rootJointType)
-
+        
     ## Virtual function to load the robot model
-    def loadModel (self, trunkName, romName, rootJointType):
-        self.client.rbprm.robot.create (trunkName, romName)
+    def loadModel (self, urdfName, rootJointType, packageName, meshPackageName, urdfSuffix, srdfSuffix):
+		self.client.rbprm.rbprm.loadRobotRomModel(urdfName, rootJointType, packageName, urdfName, urdfSuffix, srdfSuffix)
+		self.client.rbprm.rbprm.loadRobotCompleteModel(urdfName, rootJointType, packageName, urdfName, urdfSuffix, srdfSuffix)		
+		self.name = urdfName
+		self.displayName = urdfName
+		self.tf_root = "base_link"
+		self.rootJointType = rootJointType
+		self.jointNames = self.client.basic.robot.getJointNames ()
+		self.allJointNames = self.client.basic.robot.getAllJointNames ()
+		self.client.basic.robot.meshPackageName = meshPackageName
+		self.meshPackageName = meshPackageName
+		self.rankInConfiguration = dict ()
+		self.rankInVelocity = dict ()
+		self.packageName = packageName
+		self.urdfName = urdfName
+		self.urdfSuffix = urdfSuffix
+		self.srdfSuffix = srdfSuffix
+		rankInConfiguration = rankInVelocity = 0
+		for j in self.jointNames:
+			self.rankInConfiguration [j] = rankInConfiguration
+			rankInConfiguration += self.client.basic.robot.getJointConfigSize (j)
+			self.rankInVelocity [j] = rankInVelocity
+			rankInVelocity += self.client.basic.robot.getJointNumberDof (j)
 
    ## \name Degrees of freedom
     #  \{
-- 
GitLab