diff --git a/CMakeLists.txt b/CMakeLists.txt index cc144480fb6f115dce7e086e80d078fe16f1edbc..8a4521b7bd2294cd2af16ce6a7966de8cc8857b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,8 @@ SET(PYTHON_FILES python/__init__.py python/utils.py python/robot_wrapper.py + python/rpy.py + python/explog.py ) FOREACH(python ${PYTHON_FILES}) GET_FILENAME_COMPONENT(pythonFile ${python} NAME) diff --git a/src/python/explog.py b/src/python/explog.py new file mode 100644 index 0000000000000000000000000000000000000000..9f98f1bda693cea1d021a8730f5f1c3371d4fd23 --- /dev/null +++ b/src/python/explog.py @@ -0,0 +1,72 @@ +import libpinocchio_pywrap as se3 +import numpy as np +import numpy.linalg as npl +from math import sin,cos +import math +from utils import skew,cross,eye + +def exp3(v): + ''' + Exp: so3 -> SO3. Return the integral of the input angular velocity during time 1. + ''' + nv = npl.norm(v) + return se3.AngleAxis(nv,v/nv).matrix() + +def log3(R): + ''' + Log: SO3 -> so3. Pseudo-inverse of log from SO3 -> { v \in so3, ||v|| < 2pi }. + ''' + return se3.AngleAxis(R).vector() + +def exp6( nu ): + ''' + Exp: se3 -> SE3. Return the integral of the input spatial velocity during time 1. + ''' + if isinstance(nu,se3.Motion): w = nu.angular; v = nu.linear + else: w = nu[3:]; v = nu[:3] + if npl.norm(w)>1e-15: + R = exp3(w) + t = npl.norm(w) + S = skew(w) + V = eye(3) + (1-cos(t))/t**2 * S + (t-sin(t))/t**3 * S*S + p = V*v + return se3.SE3(R,p) + else: + return se3.SE3(eye(3),v) + +def log6( m ): + ''' + Log: SE3 -> se3. Pseudo-inverse of exp from SE3 -> { v,w \in se3, ||w|| < 2pi }. + ''' + if isinstance(m,se3.SE3): R = m.rotation; p = m.translation + else: R = m[:3,:3]; p = m[:3,3] + w = log3(R) + if npl.norm(w)>1e-15: + t = npl.norm(w) + S = skew(w) + V = eye(3) + (1-cos(t))/t**2 * S + (t-sin(t))/t**3 * S*S + v = npl.inv(V)*p + else: + v = p + return se3.Motion(v,w) + +def exp(x): + if isinstance(x,se3.Motion): return exp6(x) + elif np.isscalar(x): return math.exp(x) + elif isinstance(x,np.matrix): + if len(x)==6: return exp6(x) + elif len(x)==3: return exp3(x) + else: print 'Error only 3 and 6 vectors are allowed.' + else: print 'Error exp is only defined for real, vector3, vector6 and se3.Motion objects.' + +def log(x): + if isinstance(x,se3.SE3): return log6(x) + elif np.isscalar(x): return math.log(x) + elif isinstance(x,np.matrix): + if len(x)==6: return log6(x) + elif len(x)==3: return log3(x) + else: print 'Error only 3 and 6 vectors are allowed.' + else: print 'Error log is only defined for real, vector3, vector6 and se3.SE3 objects.' + + +__all__ = [ 'exp3', 'log3', 'exp6', 'log6','exp','log' ] diff --git a/src/python/robot_wrapper.py b/src/python/robot_wrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..aa544b803bfbc6353f1b5abe1e04164b88d420ce --- /dev/null +++ b/src/python/robot_wrapper.py @@ -0,0 +1,115 @@ +import numpy as np +import libpinocchio_pywrap as se3 +import utils +from exp import exp + +class RobotWrapper: + def __init__(self,filename): + self.model = se3.buildModelFromUrdf(filename,True) + self.data = self.model.createData() + self.v0 = utils.zero(self.nv) + self.q0 = np.matrix( [ + 0, 0, 0.840252, 0, 0, 0, 1, # Free flyer + 0, 0, -0.3490658, 0.6981317, -0.3490658, 0, 0, # left leg + 0, 0, -0.3490658, 0.6981317, -0.3490658, 0, 0, # right leg + 0, # chest + 1.5, 0.6, -0.5, -1.05, -0.4, -0.3, -0.2, # left arm + 0, 0, 0, 0, # head + 1.5, -0.6, 0.5, 1.05, -0.4, -0.3, -0.2, # right arm + ] ).T + self.opCorrespondances = { "lh": "LWristPitch", + "rh": "RWristPitch", + "rf": "RAnkleRoll", + "lf": "LAnkleRoll", + } + for op,name in self.opCorrespondances.items(): + self.__dict__[op] = self.index(name) + + def increment(self,q,dq): + M = se3.SE3( se3.Quaternion(q[6,0],q[3,0],q[4,0],q[5,0]).matrix(), q[:3]) + dM = exp(dq[:6]) + M = M*dM + q[:3] = M.translation + q[3:7] = se3.Quaternion(M.rotation).coeffs() + q[7:] += dq[6:] + + def index(self,name): + return [ i for i,n in enumerate(self.model.names) if n == name ][0] + + @property + def nq(self): + return self.model.nq + @property + def nv(self): + return self.model.nv + + def com(self,q): + return se3.centerOfMass(self.model,self.data,q) + def Jcom(self,q): + return se3.centerOfMass(self.model,self.data,q) + + def mass(self,q): + return se3.crba(self.model,self.data,q) + def biais(self,q,v): + return se3.rnea(self.model,self.data,q,v,self.v0) + def gravity(self,q): + return se3.rnea(self.model,self.data,q,self.v0,self.v0) + + def position(self,q,index): + se3.kinematics(self.model,self.data,q,self.v0) + return self.data.oMi[index] + def velocity(self,q,v,index): + se3.kinematics(self.model,self.data,q,v) + return self.data.v[index] + def jacobian(self,q,index): + return se3.jacobian(self.model,self.data,index,q,True) + + + # --- SHORTCUTS --- + def Mrh(self,q): + return self.position(q,self.rh) + def Jrh(self,q): + return self.jacobian(q,self.rh) + def wJrh(self,q): + return se3.jacobian(self.model,self.data,self.rh,q,False) + def vrh(self,q,v): + return self.velocity(q,v,self.rh) + + def Jlh(self,q): + return self.jacobian(q,self.lh) + def Mlh(self,q): + return self.position(q,self.lh) + + def Jlf(self,q): + return self.jacobian(q,self.lf) + def Mlf(self,q): + return self.position(q,self.lf) + def Jrf(self,q): + return self.jacobian(q,self.rf) + def Mrf(self,q): + return self.position(q,self.rf) + + + # --- VIEWER --- + def initDisplay(self): + import robotviewer + try: + self.viewer=robotviewer.client('XML-RPC') + self.viewer.updateElementConfig('TEST',[0,]*6) + except: + if 'viewer' in self.__dict__: del self.viewer + print "Error while starting the viewer client. " + print "Check wheter RobotViewer is properly started (as XML-RPC server)" + + def display(self,q): + if 'viewer' not in self.__dict__: return + # Update the robot geometry. + se3.kinematics(self.model,self.data,q,self.v0) + # Iteratively place the robot bodies. + for i in range(1,self.model.nbody): + xyz = self.data.oMi[i].translation + rpy = utils.matrixToRpy(self.data.oMi[i].rotation) + self.viewer.updateElementConfig('Romeo'+self.model.names[i], + [float(xyz[0,0]), float(xyz[1,0]), float(xyz[2,0]), + float(rpy[0,0]), float(rpy[1,0]), float(rpy[2,0]) ]) +