Beispiel #1
0
def _make_canonical(robot, constraints, startConfig, endConfig, solver):
    if not hasattr(constraints, '__iter__'):
        constraints = [constraints]
    for c in constraints:
        if isinstance(c, (int, str)):
            newconstraints = []
            for d in constraints:
                if isinstance(d, (int, str)):
                    newconstraints.append(
                        ik.objective(robot, d, R=so3.identity(), t=[0, 0, 0]))
                else:
                    assert isinstance(d, IKObjective)
                    newconstraints.append(d)
            if solver:
                newSolver = IKSolver(solver)
                newSolver.clear()
                for d in newconstraints:
                    newSolver.add(d)
            else:
                newSolver = None
            constraints = newconstraints
            solver = newSolver
            break
    if solver is None:
        solver = ik.solver(constraints)
    if startConfig == 'robot':
        startConfig = robot.getConfig()
    if endConfig == 'robot':
        endConfig = robot.getConfig()
    return constraints, startConfig, endConfig, solver
def _make_canonical(robot,constraints,startConfig,endConfig,solver):
    if not hasattr(constraints,'__iter__'):
        constraints = [constraints]
    for c in constraints:
        if isinstance(c,(int,str)):
            newconstraints = []
            for d in constraints:
                if isinstance(d,(int,str)):
                    newconstraints.append(ik.objective(robot,d,R=so3.identity(),t=[0,0,0]))
                else:
                    assert isinstance(d,IKObjective)
                    newconstraints.append(d)
            if solver:
                newSolver = IKSolver(solver)
                newSolver.clear()
                for d in newconstraints:
                    newSolver.add(d)
            else:
                newSolver = None
            constraints = newconstraints
            solver = newSolver
            break
    if solver is None:
        solver = ik.solver(constraints)
    if startConfig=='robot':
        startConfig = robot.getConfig()
    if endConfig=='robot':
        endConfig = robot.getConfig()
    return constraints,startConfig,endConfig,solver
Beispiel #3
0
def cartesian_bump(robot,
                   js_path,
                   constraints,
                   bump_paths,
                   delta=1e-2,
                   solver=None,
                   ee_relative=False,
                   maximize=False,
                   closest=False,
                   maxDeviation=None):
    """Given the robot and a reference joint space trajectory, "bumps" the
    trajectory in Cartesian space using a given relative transform (or
    transform path).  The movement in joint space is approximately minimized
    to follow the bumped Cartesian path.

    For example, to translate the motion of an end effector by [dx,dy,dz]
    in world coordinates,  call::

        cartesian_bump(robot,traj,ik.fixed_objective(link),se3.from_translation([dx,dy,dz]))

    Args:
        robot (RobotModel or SubRobotModel): the robot for which the bump is
            applied.  
        js_path (Trajectory or RobotTrajectory): the reference joint space
            Trajectory of the robot.
        constraints: one or more link indices, link names, or IKObjective's
            giving the manner in which the Cartesian space is defined. 
            Interpreted as follows:

            * int or str: the specified link's entire pose is constrained
            * IKObjective: the links, constraint types, local positions, and
              local axes are used as constraints.  The world space elements
              are considered temporary and will change to match the
              Cartesian trajectory.
            * list of int, list of str, or list of IKObjective: concatenates
              the specified constraints together

        bump_paths: one or more transforms or transform paths specifying the
            world-space relative "bump" of each cartesian goal.  One bump per
            constraint must be given as input.  Each bump can either be a
            static klampt.se3 element or a SE3Trajectory.
        delta (float, optional): the maximum configuration space distance
            between points on the output path
        method: method used.  Can be 'any', 'pointwise', or 'roadmap'.
        solver (IKSolver, optional): if provided, an IKSolver configured with
            the desired parameters for IK constraint solving.
        ee_relative (bool, optional): if False (default), bumps are given in
            world coordinates.  If True, bumps are given in end-effector local
            coordinates.
        maximize (bool, optional): if true, goes as far as possible along the
            path.
        closest (bool, optional): if not resolved and this is True, the
            function returns the robot trajectory
            whose cartesian targets get as close as possible (locally) to the
            bumped trajectory
        maxDeviation (list of floats, optional): if not None, this is a vector
            giving the max joint space distance by which each active joint is
            allowed to move from `js_path`.

    Returns:
        RobotTrajectory or None: the bumped trajectory, or None if no path can
        be found.
    """
    #make into canonical form
    if not hasattr(constraints, '__iter__'):
        constraints = [constraints]
    if not hasattr(bump_paths, '__iter__'):
        bump_paths = [bump_paths]
    assert len(constraints) == len(
        bump_paths), "Must specify one bump per constraint"
    if maxDeviation != None:
        assert len(maxDeviation) == robot.numLinks()
    for c in constraints:
        if isinstance(c, (int, str)):
            newconstraints = []
            for d in constraints:
                if isinstance(d, (int, str)):
                    newconstraints.append(
                        ik.objective(robot, d, R=so3.identity(), t=[0, 0, 0]))
                else:
                    assert isinstance(d, IKObjective)
                    newconstraints.append(d)
    is1xform = any(isinstance(p, (int, float)) for p in bump_paths)
    if is1xform:
        bump_paths = [bump_paths]
    meshpts = []
    for i, p in enumerate(bump_paths):
        #it's a static transform, map it to a path
        if isinstance(p, (list, tuple)):
            bump_paths[i] = SE3Trajectory(times=[js_path.startTime()],
                                          milestones=[p])
        else:
            assert hasattr(p,
                           'times'), "bump_paths must contain SE3Trajectory's"
            meshpts += p.times
    if solver is None:
        solver = ik.solver(constraints)
    #now preprocess the joint space so that everything is initially within delta distance
    for i in xrange(len(js_path.milestones) - 1):
        d = robot.distance(js_path.milestones[i], js_path.milestones[i + 1])
        if d > delta:
            #add in subdividing mesh points
            a, b = js_path.times[i], js_path.times[i + 1]
            numdivs = int(math.ceil(d / delta))
            for j in xrange(1, numdivs):
                meshpts.append(a + float(j) / float(numdivs) * (b - a))
    #ensure that all the movements of the SE3 trajectories are captured
    if len(meshpts) > 0:
        js_path = js_path.remesh(meshpts)[0]
    qmin0, qmax0 = solver.getJointLimits()
    #OK, now move all the cartesian points
    numsolved = 0
    res = RobotTrajectory(robot)
    res.times = js_path.times
    closeIntervals = set()
    for i, q in enumerate(js_path.milestones):
        t = js_path.times[i]
        robot.setConfig(q)
        solver.clear()
        for c, p in zip(constraints, bump_paths):
            xform0 = robot.link(c.link()).getTransform()
            xformrel = p.eval_se3(t)
            xform = (se3.mul(xform0, xformrel) if ee_relative else se3.mul(
                xformrel, xform0))
            c.matchDestination(*xform)
            solver.add(c)
        if maxDeviation != None:
            qmin = [
                max(v - d, vmin)
                for (v, d, vmin) in zip(q, maxDeviation, qmin0)
            ]
            qmax = [
                min(v + d, vmax)
                for (v, d, vmax) in zip(q, maxDeviation, qmax0)
            ]
            solver.setJointLimits(qmin, qmax)
        if not solver.solve():
            print "cartesian_bump(): Unable to perform Cartesian solve on milestone at time", t
            if not closest:
                if maximize:
                    #going as far as possible, just clip the result
                    res.times = res.times[:len(res.milestones)]
                    break
                else:
                    solver.setJointLimits(qmin0, qmax0)
                    return None
            else:
                closeIntervals.add(i)
                #otherwise soldier on with an imperfect solution
        else:
            numsolved += 1
        res.milestones.append(robot.getConfig())
    print "cartesian_bump(): Solved %d/%d milestone configurations along path, now interpolating paths..." % (
        numsolved, len(res.milestones))
    numResolved = 0
    numTotalEdges = len(res.milestones) - 1
    solver.setJointLimits(qmin0, qmax0)
    i = 0
    while i + 1 < len(res.milestones):
        q = res.milestones[i]
        qnext = res.milestones[i + 1]
        d = robot.distance(q, qnext)
        if d > delta:
            if i in closeIntervals:
                i += 1
                continue
            #resolve cartesian path
            ta = res.times[i]
            tb = res.times[i + 1]
            robot.setConfig(q)
            for c, p in zip(constraints, bump_paths):
                xform0 = robot.link(c.link()).getTransform()
                c.matchDestination(*xform0)
            xa = config.getConfig(constraints)
            robot.setConfig(qnext)
            for c, p in zip(constraints, bump_paths):
                xform0 = robot.link(c.link()).getTransform()
                c.matchDestination(*xform0)
            xb = config.getConfig(constraints)
            #TODO: add joint limits into the solver?
            newseg = cartesian_interpolate_bisect(robot,
                                                  xa,
                                                  xb,
                                                  constraints,
                                                  startConfig=q,
                                                  endConfig=qnext,
                                                  delta=delta,
                                                  solver=solver)
            if newseg == None:
                print "cartesian_bump(): Unable to complete bump while subdividing segment at time", ta
                if closest:
                    i += 1
                    continue
                if maximize:
                    res.times = res.times[:i + 1]
                    res.milestones = res.milestones[:i + 1]
                return None
            #splice in the results
            assert newseg.times[0] == 0 and newseg.times[-1] == 1
            newseg.times = [ta + float(t) * (tb - ta) for t in newseg.times]
            res.times = res.times[:i + 1] + newseg.times[1:-1] + res.times[i +
                                                                           1:]
            #print "Adding",len(newseg.milestones)-2,"intermediate milestones"
            assert res.milestones[i] == newseg.milestones[0]
            assert res.milestones[i + 1] == newseg.milestones[-1]
            res.milestones = res.milestones[:i + 1] + newseg.milestones[
                1:-1] + res.milestones[i + 1:]
            #adjust close intervals
            newclose = set()
            for c in closeIntervals:
                if c > i:
                    newclose.add(c + len(newseg.times) - 2)
            closeIntervals = newclose
            i += len(newseg.milestones) - 2
            numResolved += 1
        else:
            #print "Skipping",i
            numResolved += 1
        i += 1
    print "cartesian_bump(): Resolved %d/%d bumped edges" % (numResolved,
                                                             numTotalEdges)
    return res
def cartesian_bump(robot,js_path,constraints,bump_paths,
    delta=1e-2,
    solver=None,
    ee_relative=False,
    maximize=False,
    closest=False,
    maxDeviation=None):
    """Given the robot and a reference joint space trajectory, "bumps" the trajectory
    in cartesian space using a given relative transform (or transform path).  The movement in
    joint space is approximately minimized to follow the bumped cartesian path.

    For example, to translate the motion of an end effector by [dx,dy,dz] in world coordinates, 
    call::

        cartesian_bump(robot,traj,ik.fixed_objective(link),se3.from_translation([dx,dy,dz]))

    Args:
        robot (RobotModel or SubRobotModel): the robot for which the bump is applied.  
        js_path: the reference joint space Trajectory of the robot.  May be a RobotTrajectory.
        constraints: one or more link indices, link names, or IKObjective's giving the manner
            in which the Cartesian space is defined.  Interpreted as follows:

            * int or str: the specified link's entire pose is constrained
            * IKObjective: the links, constraint types, local positions, and local axes are used as constraints.
                The world space elements are considered temporary and will change to match the Cartesian trajectory.
            * list of int, list of str, or list of IKObjective: concatenates the specified constraints together

        bump_paths: one or more transforms or transform paths specifying the world-space relative
            "bump" of each cartesian goal.  One bump per constraint must be given as input.  Each bump can
            either be a static klampt.se3 element or a SE3Trajectory.
        delta (float, optional): the maximum configuration space distance between points on the output path
        method: method used.  Can be 'any', 'pointwise', or 'roadmap'.
        solver (IKSolver, optional): if provided, an IKSolver configured with the desired parameters for IK
            constraint solving.
        ee_relative (bool, optional): if False (default), bumps are given in world coordinates.  If True,
            bumps are given in end-effector local coordinates.
        maximize (bool, optional): if true, goes as far as possible along the path.
        closest (bool, optional): if not resolved and this is True, the function returns the robot trajectory
            whose cartesian targets get as close as possible (locally) to the bumped trajectory
        maxDeviation (list of floats, optional): if not None, this is a vector giving the max joint space
            distance by which each active joint is allowed to move from js_path.

    Returns:
        RobotTrajectory: the bumped trajectory, or None if none can be found
    """
    #make into canonical form
    if not hasattr(constraints,'__iter__'):
        constraints = [constraints]
    if not hasattr(bump_paths,'__iter__'):
        bump_paths = [bump_paths]
    assert len(constraints) == len(bump_paths),"Must specify one bump per constraint"
    if maxDeviation != None:
        assert len(maxDeviation) == robot.numLinks()
    for c in constraints:
        if isinstance(c,(int,str)):
            newconstraints = []
            for d in constraints:
                if isinstance(d,(int,str)):
                    newconstraints.append(ik.objective(robot,d,R=so3.identity(),t=[0,0,0]))
                else:
                    assert isinstance(d,IKObjective)
                    newconstraints.append(d)
    is1xform = any(isinstance(p,(int,float)) for p in bump_paths)
    if is1xform:
        bump_paths = [bump_paths]
    meshpts = []
    for i,p in enumerate(bump_paths):
        #it's a static transform, map it to a path
        if isinstance(p,(list,tuple)):
            bump_paths[i] = SE3Trajectory(times=[js_path.startTime()],milestones=[p])
        else:
            assert hasattr(p,'times'),"bump_paths must contain SE3Trajectory's"
            meshpts += p.times
    if solver is None:
        solver = ik.solver(constraints)
    #now preprocess the joint space so that everything is initially within delta distance
    for i in xrange(len(js_path.milestones)-1):
        d = robot.distance(js_path.milestones[i],js_path.milestones[i+1])
        if d > delta:
            #add in subdividing mesh points
            a,b = js_path.times[i],js_path.times[i+1]
            numdivs = int(math.ceil(d/delta))
            for j in xrange(1,numdivs):
                meshpts.append(a + float(j)/float(numdivs)*(b-a))
    #ensure that all the movements of the SE3 trajectories are captured
    if len(meshpts) > 0:
        js_path = js_path.remesh(meshpts)[0]
    qmin0,qmax0 = solver.getJointLimits()
    #OK, now move all the cartesian points
    numsolved = 0
    res = RobotTrajectory(robot)
    res.times = js_path.times
    closeIntervals = set()
    for i,q in enumerate(js_path.milestones):
        t = js_path.times[i]
        robot.setConfig(q)
        solver.clear()
        for c,p in zip(constraints,bump_paths):
            xform0 = robot.link(c.link()).getTransform()
            xformrel = p.eval_se3(t)
            xform = (se3.mul(xform0,xformrel) if ee_relative else se3.mul(xformrel,xform0))
            c.matchDestination(*xform)
            solver.add(c)
        if maxDeviation != None:
            qmin = [max(v-d,vmin) for (v,d,vmin) in zip(q,maxDeviation,qmin0)]
            qmax = [min(v+d,vmax) for (v,d,vmax) in zip(q,maxDeviation,qmax0)]
            solver.setJointLimits(qmin,qmax)
        if not solver.solve():
            print "cartesian_bump(): Unable to perform Cartesian solve on milestone at time",t
            if not closest:
                if maximize:
                    #going as far as possible, just clip the result
                    res.times = res.times[:len(res.milestones)]
                    break
                else:
                    solver.setJointLimits(qmin0,qmax0)
                    return None
            else:
                closeIntervals.add(i)
                #otherwise soldier on with an imperfect solution
        else:
            numsolved += 1
        res.milestones.append(robot.getConfig())
    print "cartesian_bump(): Solved %d/%d milestone configurations along path, now interpolating paths..."%(numsolved,len(res.milestones))
    numResolved = 0
    numTotalEdges = len(res.milestones)-1
    solver.setJointLimits(qmin0,qmax0)
    i = 0
    while i+1 < len(res.milestones):
        q = res.milestones[i]
        qnext = res.milestones[i+1]
        d = robot.distance(q,qnext)
        if d > delta:
            if i in closeIntervals:
                i += 1
                continue
            #resolve cartesian path
            ta = res.times[i]
            tb = res.times[i+1]
            robot.setConfig(q)
            for c,p in zip(constraints,bump_paths):
                xform0 = robot.link(c.link()).getTransform()
                c.matchDestination(*xform0)
            xa = config.getConfig(constraints)
            robot.setConfig(qnext)
            for c,p in zip(constraints,bump_paths):
                xform0 = robot.link(c.link()).getTransform()
                c.matchDestination(*xform0)
            xb = config.getConfig(constraints)
            #TODO: add joint limits into the solver?
            newseg = cartesian_interpolate_bisect(robot,xa,xb,constraints,
                startConfig=q,endConfig=qnext,
                delta=delta,solver=solver)
            if newseg == None:
                print "cartesian_bump(): Unable to complete bump while subdividing segment at time",ta
                if closest:
                    i += 1
                    continue
                if maximize:
                    res.times = res.times[:i+1]
                    res.milestones = res.milestones[:i+1]
                return None
            #splice in the results
            assert newseg.times[0] == 0 and newseg.times[-1] == 1
            newseg.times = [ta + float(t)*(tb-ta) for t in newseg.times]
            res.times = res.times[:i+1]+newseg.times[1:-1]+res.times[i+1:]
            #print "Adding",len(newseg.milestones)-2,"intermediate milestones"
            assert res.milestones[i] == newseg.milestones[0]
            assert res.milestones[i+1] == newseg.milestones[-1]
            res.milestones = res.milestones[:i+1]+newseg.milestones[1:-1]+res.milestones[i+1:]
            #adjust close intervals
            newclose = set()
            for c in closeIntervals:
                if c > i:
                    newclose.add(c + len(newseg.times)-2)
            closeIntervals = newclose
            i += len(newseg.milestones)-2
            numResolved += 1
        else:
            #print "Skipping",i
            numResolved += 1
        i += 1
    print "cartesian_bump(): Resolved %d/%d bumped edges"%(numResolved,numTotalEdges)
    return res