Source code for klampt.plan.contactcspace

from .. import TerrainModel,RobotModel
from ..model import contact,collide
from ..model.contact import ContactPoint,Hold
from ..math import vectorops
from .cspaceutils import CompositeCSpace
from .robotcspace import ClosedLoopRobotCSpace
from .rigidobjectcspace import RigidObjectCSpace

[docs]class StanceCSpace(ClosedLoopRobotCSpace): """A cspace with contacts that impose closed-chain constraints between a robot and zero or more objects. Stability of the robot is also enforced. Collisions are not checked between the world and fixed robot links, or contacting links that are initially already colliding with the world. Attributes: robot, collider, solver, tol, maxIters: inherited from :class:`ClosedLoopRobotCSpace` gravity: the gravity vector (default [0,0,-9.8] -- currently cannot accept anything else) holds (list of :class:`Hold`): a list of Holds associated with the contacts. sp (list): the support polygon planes resulting from ``contact.supportPolygon(holds)`` equilibriumMargin (float): Can enforce that the COM needs to be within the support polygon shrunk by some safety margin. default value is 0. """ def __init__(self,robot,holds,collider=None,world=None,checkTorqueLimits=False): if collider is None and world is not None: ignoreCollisions = [robot.link(h.link) for h in holds] collider = collide.WorldCollider(world,ignore=ignoreCollisions) ClosedLoopRobotCSpace.__init__(self,robot,[h.ikConstraint for h in holds],collider) self.holds = holds self.gravity = (0,0,-9.8) sp = contact.supportPolygon(holds) self.sp = sp self.equilibriumMargin = 0.0 self.addFeasibilityTest(self.testSupportPolygon,"suppPoly") if checkTorqueLimits: raise NotImplementedError("Torque limit testing")
[docs] def testSupportPolygon(self,q): """Returns True if the robot's COM is in the support polygon at configuration q. """ self.robot.setConfig(q) x = self.robot.getCom() for plane in self.sp: if vectorops.dot(plane[:2],(x[0],x[1])) > plane[2] - self.equilibriumMargin: #print("COM",x[:2],"out of support polygon size",len(sp)) #for plane in sp: # print(" ",vectorops.dot(plane[:2],(x[0],x[1])) - plane[2]) return False return True
[docs]class TransitionCSpace(ClosedLoopRobotCSpace): """A configuration space for a transition between stances. For this to be meaningful, the holds of one stance must be a superset of the holds of the other. Args: space1 (StanceCSpace): the first stance. space2 (StanceCSpace): the second stance. """ def __init__(self,space1,space2): assert isinstance(space1,StanceCSpace) assert isinstance(space2,StanceCSpace) if len(space1.holds) > len(space2.holds): space1,space2 = space2,space1 self.space1,self.space2 = space1,space2 ClosedLoopRobotCSpace.__init__(self,space1.robot,[h.ikConstraint for h in space2.holds],space2.collider) self.addFeasibilityTest(space1.testSupportPolygon,"suppPoly")
[docs]class MultiContactCSpace(CompositeCSpace): """A cspace with contacts that impose closed-chain constraints between a robot and zero or more objects. .. warning:: NOT IMPLEMENTED YET Collisions are not checked between the world and fixed robot links, or contacting links that are initially already colliding with the world. Attributes: gravity: the gravity vector (default [0,0,-9.8]) contactMap (dict): a dictionary mapping (obj1,obj2) pairs to lists of contacts. Same structures that results from :func:`contactMap`. holds (list of :class:`Hold`): a list of Holds associated with the contacts. robotCSpace (ClosedLoopRobotCSpace): a ClosedLoopRobotCSpace for the robot objectCSpaces (list of :class:`RigidObjectCSpace`): a list of RigidObjectCSpace's for each moving object. movingObjects (list): a list of moving robots and rigid objects. stabilityTestObjects (list): a list of moving robots and rigid objects that will be stability tested. supportPolygon (list): a list of supportPolygon planes (result from :func:`contact.supportPolygon`). supportPolygonVerts (list): a list of support polygon vertices. """ def __init__(self,robot,contacts,stabilityTestObjects=None,collider=None): """Initializes the ContactCSpace. The members contactMap, and objectives are constructed from the contacts argument. Args: robot (RobotModel): the moving robot contacts: a list of :class:`Hold`, or :class:`ContactPoint` objects with the ``object1`` and/or ``object2`` elements filled out. stabilityTestObjects (list, optional): if provided, specifies which objects are stability tested (either type :class:`RobotModel` or :class:`RigidObjectModel`). Otherwise, all objects and free-floating robots in contact are stability tested. """ self.gravity = (0,0,-9.8) #construct contact structures if len(contacts)==0: self.contactMap = dict() self.holds = [] elif isinstance(contacts[0],ContactPoint): self.contactMap = contact.contactMap(contacts,lambda x:x is None or isinstance(x,TerrainModel)) self.holds = contact.contactMapHolds(self.contactMap) else: self.contactMap = dict() self.holds = contacts ikobjectives = [h.ikObjective for h in self.holds] self.robotCSpace = ClosedLoopRobotCSpace(robot,ikobjectives,collider) self.objectCSpaces = [] numRobots = 0 objs = set() for (obj1,obj2) in self.contactMap(): if obj1 is not None and not isinstance(obj1,TerrainModel): objs.add(obj1) if obj2 is not None and not isinstance(obj2,TerrainModel): objs.add(obj2) for o in objs: if isinstance(o,RobotModel): numRobots+=1 else: self.objectCSpaces.append(RigidObjectCSpace(o,collider)) assert numRobots == 1,"ContactCSpace: Can only handle one robot in contact" #Check and create vector indexing list objs = set() for (o1,o2) in self.contactMap.iterKeys(): if hasattr(o1,'robot'): #it's a RobotModelLink objs.insert(o1.robot()) elif o1 != None: objs.insert(o1) if hasattr(o2,'robot'): #it's a RobotModelLink objs.insert(o2.robot()) elif o2 != None: objs.insert(o2) self.movingObjects = list(objs) if stabilityTestObjects == None: #construct from the contact list stabilityTestObjects = [] for o in objs: if isinstance(o,RobotModel): #HACK: need a better test for floating bases if o.numDrivers() + 6 <= o.numLinks(): print("ContactCSpace: Robot",o.getName(),"is being treated as a floating-base robot") stabilityTestObjects.append(o) else: print("ContactCSpace: Robot",o.getName(),"is being treated as a fixed-base robot") else: stabilityTestObjects.append(o) else: for o in stabilityTestObjects: assert o in objs self.stabilityTestObjects = stabilityTestObjects self.supportPolygon = None self.supportPolygonVerts = None CompositeCSpace.__init__(self,[self.robotCSpace] + self.objectCSpaces)
#TODO: add stability tests