コード例 #1
0
    def _to_idyntree_transform(position: np.ndarray, quaternion: np.ndarray):
        p = InverseKinematicsNLP._to_idyntree_position(position=position)
        R = InverseKinematicsNLP._to_idyntree_rotation(quaternion=quaternion)

        import iDynTree
        H = iDynTree.Transform()
        H.setPosition(p)
        H.setRotation(R)

        return H
コード例 #2
0
 def randomTransform(self):
     ''' Return a random Transform '''
     res = iDynTree.Transform()
     res.setPosition(
         iDynTree.Position(random.uniform(-10, 10), random.uniform(-10, 10),
                           random.uniform(-10, 10)))
     res.setRotation(
         iDynTree.Rotation.RPY(random.uniform(-10, 10),
                               random.uniform(-10, 10),
                               random.uniform(-10, 10)))
     return res
コード例 #3
0
    def getRandomRegressor(self, n_samples=None):
        """
        Utility function for generating a random regressor for numerical base parameter calculation
        Given n_samples, the Y (n_samples*getNrOfOutputs() X getNrOfParameters() ) regressor is
        obtained by stacking the n_samples generated regressors
        This function returns Y^T Y (getNrOfParameters() X getNrOfParameters() ) (that share the row space with Y)
        (partly ported from iDynTree)
        """

        if self.opt['identifyGravityParamsOnly']:
            regr_filename = self.urdf_file + '.gravity_regressor.npz'
        else:
            regr_filename = self.urdf_file + '.regressor.npz'
        generate_new = False
        fb = self.opt['floatingBase']

        try:
            regr_file = np.load(regr_filename)
            R = regr_file['R']  #regressor matrix
            Q = regr_file['Q']  #QR decomposition
            RQ = regr_file['RQ']
            PQ = regr_file['PQ']
            n = regr_file['n']   #number of samples that were used
            fbase = regr_file['fb']  #floating base flag
            grav = regr_file['grav_only']
            fric = regr_file['fric']
            fric_sym = regr_file['fric_sym']
            if self.opt['verbose']:
                print("loaded random structural regressor from {}".format(regr_filename))
            if n != n_samples or fbase != fb or R.shape[0] != self.num_identified_params or \
                    self.opt['identifyGravityParamsOnly'] != grav or \
                    fric != self.opt['identifyFriction'] or fric_sym != self.opt['identifySymmetricVelFriction']:
                generate_new = True
            #TODO: save and check timestamp of urdf file, if newer regenerate
        except (IOError, KeyError):
            generate_new = True

        if generate_new:
            if not n_samples:
                n_samples = self.num_dofs * 1000

            if self.opt['verbose']:
                print("(re-)generating structural regressor ({} random positions)".format(n_samples))

            R = np.array((self.N_OUT, self.num_model_params))
            regressor = iDynTree.MatrixDynSize(self.N_OUT, self.num_model_params)
            knownTerms = iDynTree.VectorDynSize(self.N_OUT)
            if len(self.limits) > 0:
                jn = self.jointNames
                q_lim_pos = [self.limits[jn[n]]['upper'] for n in range(self.num_dofs)]
                q_lim_neg = [self.limits[jn[n]]['lower'] for n in range(self.num_dofs)]
                dq_lim = [self.limits[jn[n]]['velocity'] for n in range(self.num_dofs)]
                q_range = (np.array(q_lim_pos) - np.array(q_lim_neg)).tolist()
            for i in self.progress(range(0, n_samples)):
                # set random system state
                if len(self.limits) > 0:
                    rnd = np.random.rand(self.num_dofs) #0..1
                    q = iDynTree.VectorDynSize.fromList((q_lim_neg+q_range*rnd))
                    if self.opt['identifyGravityParamsOnly']:
                        #set vel and acc to zero for static case
                        vel = np.zeros(self.num_dofs)
                        acc = np.zeros(self.num_dofs)
                    else:
                        vel = ((np.random.rand(self.num_dofs)-0.5)*2*dq_lim)
                        acc = ((np.random.rand(self.num_dofs)-0.5)*2*np.pi)
                    dq = iDynTree.VectorDynSize.fromList(vel.tolist())
                    ddq = iDynTree.VectorDynSize.fromList(acc.tolist())
                else:
                    q = iDynTree.VectorDynSize.fromList(((np.random.ranf(self.num_dofs)*2-1)*np.pi).tolist())
                    dq = iDynTree.VectorDynSize.fromList(((np.random.ranf(self.num_dofs)*2-1)*np.pi).tolist())
                    ddq = iDynTree.VectorDynSize.fromList(((np.random.ranf(self.num_dofs)*2-1)*np.pi).tolist())

                # TODO: make work with fixed dofs (set vel and acc to zero, look at iDynTree method)

                if self.opt['floatingBase']:
                    base_vel = np.pi*np.random.rand(6)
                    base_acc = np.pi*np.random.rand(6)
                    if self.opt['identifyGravityParamsOnly']:
                        #set vel and acc to zero for static case (reduces resulting amount of base dependencies)
                        base_vel[:] = 0.0
                        base_acc[:] = 0.0
                    rpy = np.random.ranf(3)*0.1
                    rot = iDynTree.Rotation.RPY(rpy[0], rpy[1], rpy[2])
                    pos = iDynTree.Position.Zero()
                    world_T_base = iDynTree.Transform(rot, pos).inverse()

                    '''
                    # rotate base vel and acc to world frame
                    to_world = world_T_base.getRotation().toNumPy()
                    base_vel[0:3] = to_world.dot(base_vel[0:3])
                    base_vel[3:] = to_world.dot(base_vel[3:])
                    base_acc[0:3] = to_world.dot(base_acc[0:3])
                    base_acc[3:] = to_world.dot(base_acc[3:])
                    '''

                    base_velocity = iDynTree.Twist.fromList(base_vel)
                    base_acceleration = iDynTree.Twist.fromList(base_acc)

                    self.generator.setRobotState(q,dq,ddq, world_T_base, base_velocity, base_acceleration, self.gravity_twist)
                else:
                    self.generator.setRobotState(q,dq,ddq, self.gravity_twist)

                # get regressor
                if not self.generator.computeRegressor(regressor, knownTerms):
                    print("Error during numeric computation of regressor")

                A = regressor.toNumPy()

                #the base forces are expressed in the base frame for the regressor, so rotate them
                if self.opt['floatingBase']:
                    to_world = np.fromstring(world_T_base.getRotation().toString(), sep=' ').reshape((3,3))
                    A[0:3, :] = to_world.dot(A[0:3, :])
                    A[3:6, :] = to_world.dot(A[3:6, :])

                if self.opt['identifyGravityParamsOnly']:
                    #delete inertia param columns
                    A = np.delete(A, self.inertia_params, 1)

                if self.opt['identifyFriction']:
                    # append unitary matrix to regressor for offsets/constant friction
                    sign = 1 #np.sign(dq.toNumPy())
                    static_diag = np.identity(self.num_dofs)*sign
                    offset_regressor = np.vstack( (np.zeros((fb*6, self.num_dofs)), static_diag))
                    A = np.concatenate((A, offset_regressor), axis=1)

                    if not self.opt['identifyGravityParamsOnly']:
                        if self.opt['identifySymmetricVelFriction']:
                            # just use velocity directly
                            vel_diag = np.identity(self.num_dofs)*dq.toNumPy()
                            friction_regressor = np.vstack( (np.zeros((fb*6, self.num_dofs)), vel_diag))   # add base dynamics rows
                        else:
                            # append positive/negative velocity matrix for velocity dependent asymmetrical friction
                            dq_p = dq.toNumPy().copy()
                            dq_p[dq_p < 0] = 0 #set to zero where v < 0
                            dq_m = dq.toNumPy().copy()
                            dq_m[dq_m > 0] = 0 #set to zero where v > 0
                            vel_diag = np.hstack((np.identity(self.num_dofs)*dq_p, np.identity(self.num_dofs)*dq_m))
                            friction_regressor = np.vstack( (np.zeros((fb*6, self.num_dofs*2)), vel_diag))   # add base dynamics rows
                        A = np.concatenate((A, friction_regressor), axis=1)

                # add to previous regressors, linear dependencies don't change
                # (if too many, saturation or accuracy problems?)
                if i==0:
                    R = A.T.dot(A)
                else:
                    R += A.T.dot(A)

            # get column space dependencies
            Q,RQ,PQ = sla.qr(R, pivoting=True, mode='economic')

            np.savez(regr_filename, R=R, Q=Q, RQ=RQ, PQ=PQ, n=n_samples, fb=self.opt['floatingBase'], grav_only=self.opt['identifyGravityParamsOnly'], fric=self.opt['identifyFriction'], fric_sym=self.opt['identifySymmetricVelFriction'])

        if 'showRandomRegressor' in self.opt and self.opt['showRandomRegressor']:
            import matplotlib.pyplot as plt
            plt.imshow(R, interpolation='nearest')
            plt.show()

        return R, Q,RQ,PQ
コード例 #4
0
    def computeRegressors(self, data, only_simulate=False):
        # type: (Model, Data, bool) -> (None)
        """ compute regressors from measurements for each time step of the measurement data
            and stack them vertically. also stack measured torques and get simulation data.
            for floating base, get estimated base forces (6D wrench) and add to torque measure stack
        """

        self.data = data

        num_time = 0
        simulate_time = 0

        #extra regressor rows for floating base
        if self.opt['floatingBase']: fb = 6
        else: fb = 0
        self.regressor_stack = np.zeros(shape=((self.num_dofs+fb)*data.num_used_samples, self.num_identified_params))
        self.torques_stack = np.zeros(shape=((self.num_dofs+fb)*data.num_used_samples))
        self.sim_torq_stack = np.zeros(shape=((self.num_dofs+fb)*data.num_used_samples))
        self.torquesAP_stack = np.zeros(shape=((self.num_dofs+fb)*data.num_used_samples))

        num_contacts = len(data.samples['contacts'].item(0).keys()) if 'contacts' in data.samples else 0
        self.contacts_stack = np.zeros(shape=(num_contacts, (self.num_dofs+fb)*data.num_used_samples))
        self.contactForcesSum = np.zeros(shape=((self.num_dofs+fb)*data.num_used_samples))

        """loop over measurement data, optionally skip some values
            - get the regressor for each time step
            - if necessary, calculate inverse dynamics to get simulated torques
            - if necessary, get torques from contact wrenches and add them to the torques
            - stack the torques, regressors and contacts into matrices
        """
        contacts = {}
        for sample_index in self.progress(range(data.num_used_samples)):
            m_idx = sample_index*(self.opt['skipSamples'])+sample_index
            with helpers.Timer() as t:
                # read samples
                pos = data.samples['positions'][m_idx]
                vel = data.samples['velocities'][m_idx]
                acc = data.samples['accelerations'][m_idx]
                torq = data.samples['torques'][m_idx]
                if 'contacts' in data.samples:
                    for frame in data.samples['contacts'].item(0).keys():
                        contacts[frame] = data.samples['contacts'].item(0)[frame][m_idx]

                if self.opt['identifyGravityParamsOnly']:
                    #set vel and acc to zero (should be almost zero already) to remove noise
                    vel[:] = 0.0
                    acc[:] = 0.0

                # system state for iDynTree
                q = iDynTree.VectorDynSize.fromList(pos)
                dq = iDynTree.VectorDynSize.fromList(vel)
                ddq = iDynTree.VectorDynSize.fromList(acc)

                # in case that we simulate the torque measurements, need torque estimation for a priori parameters
                # or that we need to simulate the base reaction forces for floating base
                if self.opt['simulateTorques'] or self.opt['useAPriori'] or self.opt['floatingBase']:
                    if self.opt['useRBDL']:
                        #TODO: make sure joint order of torques is the same as iDynTree!
                        sim_torques = self.simulateDynamicsRBDL(data.samples, m_idx)
                    else:
                        sim_torques = self.simulateDynamicsIDynTree(data.samples, m_idx)

                    if self.opt['useAPriori']:
                        # torques sometimes contain nans, just a very small C number that gets converted to nan?
                        torqAP = np.nan_to_num(sim_torques)

                    if not self.opt['useRegressorForSimulation']:
                        if self.opt['simulateTorques']:
                            torq = np.nan_to_num(sim_torques)
                        else:
                            # write estimated base forces to measured torq vector from file (usually
                            # can't be measured so they are simulated from the measured base motion,
                            # contacts are added further down)
                            if self.opt['floatingBase']:
                                if len(torq) < (self.num_dofs + fb):
                                    torq = np.concatenate((np.nan_to_num(sim_torques[0:6]), torq))
                                else:
                                    torq[0:6] = np.nan_to_num(sim_torques[0:6])

            simulate_time += t.interval

            #...still looping over measurement samples

            row_index = (self.num_dofs+fb)*sample_index   # index for current row in stacked matrices

            if not only_simulate:
                # get numerical regressor (std)
                with helpers.Timer() as t:
                    if self.opt['floatingBase']:
                        base_vel = data.samples['base_velocity'][m_idx]
                        base_acc = data.samples['base_acceleration'][m_idx]

                        # get transform from base to world
                        rpy = data.samples['base_rpy'][m_idx]
                        rot = iDynTree.Rotation.RPY(rpy[0], rpy[1], rpy[2])
                        pos = iDynTree.Position.Zero()
                        world_T_base = iDynTree.Transform(rot, pos).inverse()

                        '''
                        # rotate base vel and acc to world frame
                        to_world = world_T_base.getRotation().toNumPy()
                        base_vel[0:3] = to_world.dot(base_vel[0:3])
                        base_vel[3:] = to_world.dot(base_vel[3:])
                        base_acc[0:3] = to_world.dot(base_acc[0:3])
                        base_acc[3:] = to_world.dot(base_acc[3:])
                        '''

                        base_velocity = iDynTree.Twist.fromList(base_vel)
                        base_acceleration = iDynTree.Twist.fromList(base_acc)

                        self.generator.setRobotState(q,dq,ddq, world_T_base, base_velocity, base_acceleration,
                                                     self.gravity_twist)
                    else:
                        self.generator.setRobotState(q,dq,ddq, self.gravity_twist)

                    # get (standard) regressor
                    regressor = iDynTree.MatrixDynSize(self.N_OUT, self.num_model_params)
                    knownTerms = iDynTree.VectorDynSize(self.N_OUT)   # what are known terms useable for?
                    if not self.generator.computeRegressor(regressor, knownTerms):
                        print("Error during numeric computation of regressor")

                    regressor = regressor.toNumPy()
                    if self.opt['floatingBase']:
                        # the base forces are expressed in the base frame for the regressor, so
                        # rotate them to world frame (inverse dynamics use world frame)
                        to_world = world_T_base.getRotation().toNumPy()
                        regressor[0:3, :] = to_world.dot(regressor[0:3, :])
                        regressor[3:6, :] = to_world.dot(regressor[3:6, :])

                    if self.opt['identifyGravityParamsOnly']:
                        #delete inertia param columns
                        regressor = np.delete(regressor, self.inertia_params, 1)

                    if self.opt['identifyFriction']:
                        # append unitary matrix to regressor for offsets/constant friction
                        sign = 1 #np.sign(dq.toNumPy())   #TODO: dependent on direction or always constant?
                        static_diag = np.identity(self.num_dofs)*sign
                        offset_regressor = np.vstack( (np.zeros((fb, self.num_dofs)), static_diag))
                        regressor = np.concatenate((regressor, offset_regressor), axis=1)

                        if not self.opt['identifyGravityParamsOnly']:
                            if self.opt['identifySymmetricVelFriction']:
                                # just use velocity directly
                                vel_diag = np.identity(self.num_dofs)*dq.toNumPy()
                                friction_regressor = np.vstack( (np.zeros((fb, self.num_dofs)), vel_diag))   # add base dynamics rows
                            else:
                                # append positive/negative velocity matrix for velocity dependent asymmetrical friction
                                dq_p = dq.toNumPy().copy()
                                dq_p[dq_p < 0] = 0 #set to zero where v < 0
                                dq_m = dq.toNumPy().copy()
                                dq_m[dq_m > 0] = 0 #set to zero where v > 0
                                vel_diag = np.hstack((np.identity(self.num_dofs)*dq_p, np.identity(self.num_dofs)*dq_m))
                                friction_regressor = np.vstack( (np.zeros((fb, self.num_dofs*2)), vel_diag))   # add base dynamics rows
                            regressor = np.concatenate((regressor, friction_regressor), axis=1)

                    # simulate with regressor
                    if self.opt['useRegressorForSimulation'] and (self.opt['simulateTorques'] or
                            self.opt['useAPriori'] or self.opt['floatingBase']):
                        torques = regressor.dot(self.xStdModel[self.identified_params])
                        if self.opt['simulateTorques']:
                            torq = torques
                        else:
                            # write estimated base forces to measured torq vector from file (usually
                            # can't be measured so they are simulated from the measured base motion,
                            # contacts are added further down)
                            if self.opt['floatingBase']:
                                if len(torq) < (self.num_dofs + fb):
                                    torq = np.concatenate((np.nan_to_num(torques[0:6]), torq))
                                else:
                                    torq[0:6] = np.nan_to_num(torques[0:6])
                        torques_simulated = np.nan_to_num(torques)

                    # stack on previous regressors
                    np.copyto(self.regressor_stack[row_index:row_index+self.num_dofs+fb], regressor)
                num_time += t.interval

            # stack results onto matrices of previous time steps
            np.copyto(self.torques_stack[row_index:row_index+self.num_dofs+fb], torq)

            if self.opt['useAPriori']:
                np.copyto(self.torquesAP_stack[row_index:row_index+self.num_dofs+fb], torqAP)

            if len(contacts.keys()):
                #convert contact wrenches into torque contribution
                for c in range(num_contacts):
                    frame = list(contacts.keys())[c]

                    dim = self.num_dofs+fb
                    # get jacobian and contact wrench for each contact frame and measurement sample
                    jacobian = iDynTree.MatrixDynSize(6, dim)
                    if not self.dynComp.getFrameJacobian(str(frame), jacobian):
                        continue
                    jacobian = jacobian.toNumPy()

                    # mul each sample of measured contact wrenches with frame jacobian
                    contacts_torq = np.empty(dim)
                    contacts_torq = jacobian.T.dot(contacts[frame])

                    contact_idx = (sample_index*dim)
                    np.copyto(self.contacts_stack[c][contact_idx:contact_idx+dim], contacts_torq[-dim:])

        # finished looping over samples

        # sum over (contact torques) for each contact frame
        self.contactForcesSum = np.sum(self.contacts_stack, axis=0)

        if self.opt['floatingBase']:
            if self.opt['simulateTorques']:
                # add measured contact wrench to torque estimation from iDynTree
                if self.opt['addContacts']:
                    self.torques_stack = self.torques_stack + self.contactForcesSum
            else:
                # if not simulating, measurements of joint torques already contain contact contribution,
                # so only add it to the (always simulated) base force estimation
                torques_stack_2dim = np.reshape(self.torques_stack, (data.num_used_samples, self.num_dofs+fb))
                self.contactForcesSum_2dim = np.reshape(self.contactForcesSum, (data.num_used_samples, self.num_dofs+fb))
                if self.opt['addContacts']:
                    torques_stack_2dim[:, :6] += self.contactForcesSum_2dim[:, :6]
                self.torques_stack = torques_stack_2dim.flatten()

        if self.opt['addContacts']:
            self.sim_torq_stack = self.sim_torq_stack + self.contactForcesSum

        if len(contacts.keys()) or self.opt['simulateTorques']:
            # write back torques to data object when simulating or contacts were added
            self.data.samples['torques'] = np.reshape(self.torques_stack, (data.num_used_samples, self.num_dofs+fb))

        with helpers.Timer() as t:
            if self.opt['useAPriori']:
                # get torque delta to identify with
                self.tau = self.torques_stack - self.torquesAP_stack
            else:
                self.tau = self.torques_stack
        simulate_time+=t.interval

        self.YStd = self.regressor_stack

        # if difference between random regressor (that was used for base projection) and regressor
        # from the data is too big, the base regressor can still have linear dependencies.
        # for these cases, it seems to be better to get the base columns directly from the data regressor matrix
        if not self.opt['useStructuralRegressor'] and not only_simulate:
            if self.opt['verbose']:
                print('Getting independent base columns again from data regressor')
            self.computeRegressorLinDepsQR(self.YStd)

        if self.opt['useBasisProjection']:
            self.YBase = np.dot(self.YStd, self.B)   # project regressor to base regressor
        else:
            self.YBase = np.dot(self.YStd, self.Pb)  # regressor following Sousa, 2014

        if self.opt['filterRegressor']:
            order = 5                            # Filter order
            fs = self.data.samples['frequency']  # Sampling freq
            fc = self.opt['filterRegCutoff']     # Cut-off frequency (Hz)
            b, a = signal.butter(order, fc / (fs / 2), btype='low', analog=False)
            for j in range(0, self.num_base_inertial_params):
                for i in range(0, self.num_dofs):
                    self.YBase[i::self.num_dofs, j] = signal.filtfilt(b, a, self.YBase[i::self.num_dofs, j])

        self.sample_end = data.samples['positions'].shape[0]
        if self.opt['skipSamples'] > 0: self.sample_end -= (self.opt['skipSamples'])

        # keep absolute torques (self.tau can be relative)
        self.tauMeasured = np.reshape(self.torques_stack, (data.num_used_samples, self.num_dofs+fb))

        self.T = data.samples['times'][0:self.sample_end:self.opt['skipSamples']+1]

        if self.opt['showTiming']:
            print('(simulation for regressors took %.03f sec.)' % simulate_time)
            print('(getting regressors took %.03f sec.)' % num_time)

        if self.opt['verbose'] == 2:
            print("YStd: {}".format(self.YStd.shape), end=' ')
            print("YBase: {}, cond: {}".format(self.YBase.shape, la.cond(self.YBase)))
コード例 #5
0
    def simulateDynamicsIDynTree(self, samples, sample_idx, dynComp=None, xStdModel=None):
        # type: (Dict[str, np._ArrayLike], int, iDynTree.DynamicsComputations, np._ArrayLike[float]) -> np._ArrayLike[float]
        """ compute torques for one time step of measurements """

        if not dynComp:
            dynComp = self.dynComp
        if xStdModel is None:
            xStdModel = self.xStdModel
        world_gravity = iDynTree.SpatialAcc.fromList(self.gravity)

        # read sample data
        pos = samples['positions'][sample_idx]
        vel = samples['velocities'][sample_idx]
        acc = samples['accelerations'][sample_idx]

        # system state for iDynTree
        q = iDynTree.VectorDynSize.fromList(pos)
        dq = iDynTree.VectorDynSize.fromList(vel)
        ddq = iDynTree.VectorDynSize.fromList(acc)

        # calc torques and forces with iDynTree dynamicsComputation class
        if self.opt['floatingBase']:
            base_vel = samples['base_velocity'][sample_idx]
            base_acc = samples['base_acceleration'][sample_idx]
            rpy = samples['base_rpy'][sample_idx]

            # get the homogeneous transformation that transforms vectors expressed
            # in the base reference frame to frames expressed in the world
            # reference frame, i.e. pos_world = world_T_base*pos_base
            # for identification purposes, the position does not matter but rotation is taken
            # from IMU estimation. The gravity, base velocity and acceleration all need to be
            # expressed in world frame
            rot = iDynTree.Rotation.RPY(rpy[0], rpy[1], rpy[2])
            pos = iDynTree.Position.Zero()
            world_T_base = iDynTree.Transform(rot, pos).inverse()

            '''
            # rotate base vel and acc to world frame
            to_world = world_T_base.getRotation().toNumPy()
            base_vel[0:3] = to_world.dot(base_vel[0:3])
            base_vel[3:] = to_world.dot(base_vel[3:])
            base_acc[0:3] = to_world.dot(base_acc[0:3])
            base_acc[3:] = to_world.dot(base_acc[3:])
            '''

            # The twist (linear, angular velocity) of the base, expressed in the world
            # orientation frame and with respect to the base origin
            base_velocity = iDynTree.Twist.fromList(base_vel)
            # The 6d classical acceleration (linear, angular acceleration) of the base
            # expressed in the world orientation frame and with respect to the base origin
            base_acceleration = iDynTree.ClassicalAcc.fromList(base_acc)

            dynComp.setRobotState(q, dq, ddq, world_T_base, base_velocity, base_acceleration,
                                  world_gravity)
        else:
            dynComp.setRobotState(q, dq, ddq, world_gravity)

        # compute inverse dynamics
        torques = iDynTree.VectorDynSize(self.num_dofs)
        baseReactionForce = iDynTree.Wrench()
        dynComp.inverseDynamics(torques, baseReactionForce)
        torques = torques.toNumPy()

        if self.opt['identifyFriction']:
            # add friction torques
            # constant
            sign = 1 #np.sign(vel)
            p_constant = range(self.friction_params_start, self.friction_params_start+self.num_dofs)
            torques += sign*xStdModel[p_constant]

            # vel dependents
            if not self.opt['identifyGravityParamsOnly']:
                # (take only first half of params as they are not direction dependent in urdf anyway)
                p_vel = range(self.friction_params_start+self.num_dofs, self.friction_params_start+self.num_dofs*2)
                torques += xStdModel[p_vel]*vel

        if self.opt['floatingBase']:
            return np.concatenate((baseReactionForce.toNumPy(), torques))
        else:
            return torques
コード例 #6
0
def test_regressors():
    #get some random state values and compare inverse dynamics torques with torques
    #obtained with regressor and parameter vector

    idyn_model = iDynTree.Model()
    iDynTree.modelFromURDF(urdf_file, idyn_model)

    # create generator instance and load model
    generator = iDynTree.DynamicsRegressorGenerator()
    generator.loadRobotAndSensorsModelFromFile(urdf_file)
    regrXml = '''
    <regressor>
      <baseLinkDynamics/>
      <jointTorqueDynamics>
        <allJoints/>
      </jointTorqueDynamics>
    </regressor>'''
    generator.loadRegressorStructureFromString(regrXml)
    num_model_params = generator.getNrOfParameters()
    num_out = generator.getNrOfOutputs()
    n_dofs = generator.getNrOfDegreesOfFreedom()
    num_samples = 100

    xStdModel = iDynTree.VectorDynSize(num_model_params)
    generator.getModelParameters(xStdModel)
    xStdModel = xStdModel.toNumPy()

    gravity_twist = iDynTree.Twist.fromList([0, 0, -9.81, 0, 0, 0])
    gravity_acc = iDynTree.SpatialAcc.fromList([0, 0, -9.81, 0, 0, 0])

    dynComp = iDynTree.DynamicsComputations()
    dynComp.loadRobotModelFromFile(urdf_file)

    regressor_stack = np.zeros(shape=((n_dofs + 6) * num_samples,
                                      num_model_params))
    idyn_torques = np.zeros(shape=((n_dofs + 6) * num_samples))
    contactForceSum = np.zeros(shape=((n_dofs + 6) * num_samples))

    for sample_index in range(0, num_samples):
        q = iDynTree.VectorDynSize.fromList(
            ((np.random.ranf(n_dofs) * 2 - 1) * np.pi).tolist())
        dq = iDynTree.VectorDynSize.fromList(
            ((np.random.ranf(n_dofs) * 2 - 1) * np.pi).tolist())
        ddq = iDynTree.VectorDynSize.fromList(
            ((np.random.ranf(n_dofs) * 2 - 1) * np.pi).tolist())
        base_vel = np.pi * np.random.rand(6)
        base_acc = np.pi * np.random.rand(6)

        #rpy = [0,0,0]
        rpy = np.random.ranf(3) * 0.1
        rot = iDynTree.Rotation.RPY(rpy[0], rpy[1], rpy[2])
        pos = iDynTree.Position.Zero()
        world_T_base = iDynTree.Transform(rot, pos).inverse()

        # rotate base vel and acc to world frame
        to_world = world_T_base.getRotation().toNumPy()
        base_vel[0:3] = to_world.dot(base_vel[0:3])
        base_vel[3:] = to_world.dot(base_vel[3:])
        base_acc[0:3] = to_world.dot(base_acc[0:3])
        base_acc[3:] = to_world.dot(base_acc[3:])

        base_velocity = iDynTree.Twist.fromList(base_vel)
        base_acceleration = iDynTree.Twist.fromList(base_acc)
        base_acceleration_acc = iDynTree.ClassicalAcc.fromList(base_acc)

        # regressor
        generator.setRobotState(q, dq, ddq, world_T_base, base_velocity,
                                base_acceleration, gravity_twist)

        regressor = iDynTree.MatrixDynSize(num_out, num_model_params)
        knownTerms = iDynTree.VectorDynSize(num_out)
        if not generator.computeRegressor(regressor, knownTerms):
            print("Error during numeric computation of regressor")

        #the base forces are expressed in the base frame for the regressor, so transform them
        to_world = np.fromstring(world_T_base.getRotation().toString(),
                                 sep=' ').reshape((3, 3))
        regressor = regressor.toNumPy()
        regressor[0:3, :] = to_world.dot(regressor[0:3, :])
        regressor[3:6, :] = to_world.dot(regressor[3:6, :])

        row_index = (
            n_dofs + 6
        ) * sample_index  # index for current row in stacked regressor matrix
        np.copyto(regressor_stack[row_index:row_index + n_dofs + 6], regressor)

        # inverse dynamics
        #dynComp.setFloatingBase('base_link')
        dynComp.setRobotState(q, dq, ddq, world_T_base, base_velocity,
                              base_acceleration_acc, gravity_acc)
        torques = iDynTree.VectorDynSize(n_dofs)
        baseReactionForce = iDynTree.Wrench()
        dynComp.inverseDynamics(torques, baseReactionForce)

        torques = np.concatenate(
            (baseReactionForce.toNumPy(), torques.toNumPy()))
        np.copyto(idyn_torques[row_index:row_index + n_dofs + 6], torques)

        # contacts
        dim = n_dofs + 6
        contact = np.array([0, 0, 10, 0, 0, 0])
        jacobian = iDynTree.MatrixDynSize(6, dim)
        dynComp.getFrameJacobian(contactFrame, jacobian)
        jacobian = jacobian.toNumPy()
        contactForceSum[sample_index * dim:(sample_index + 1) *
                        dim] = jacobian.T.dot(contact)

    regressor_torques = np.dot(regressor_stack, xStdModel) + contactForceSum
    idyn_torques += contactForceSum

    error = np.reshape(regressor_torques - idyn_torques, (num_samples, dim))

    #plots = plt.plot(range(0, num_samples), error)
    #plt.legend(plots, ['f_x', 'f_y', 'f_z', 'm_x', 'm_y', 'm_z', 'j_0'])
    #plt.show()

    error_norm = la.norm(error)
    print(error_norm)
    assert error_norm <= 0.01
コード例 #7
0
Created on Tue Jun 23 11:35:46 2015

@author: adelpret
"""

import iDynTree
from iDynTree import KinDynComputations

URDF_FILE = '/home/letrend/workspace/roboy_control/src/CARDSflow/robots/msj_platform/model.urdf'

kinDyn = KinDynComputations()
kinDyn.loadRobotModelFromFile(URDF_FILE)
print "The loaded model has", kinDyn.getNrOfDegreesOfFreedom(), \
    "internal degrees of freedom and",kinDyn.getNrOfLinks(),"links."

base = iDynTree.Transform()
vel = iDynTree.Twist()
dofs = kinDyn.getNrOfDegreesOfFreedom()
q = iDynTree.VectorDynSize(dofs)
dq = iDynTree.VectorDynSize(dofs)
for dof in range(dofs):
    # For the sake of the example, we fill the joints vector with gibberish data (remember in any case
    # that all quantities are expressed in radians-based units
    q.setVal(dof, 1.0)
    dq.setVal(dof, 0.4)

# The spatial acceleration is a 6d acceleration vector.
# For all 6d quantities, we use the linear-angular serialization
# (the first three value are for the linear quantity, the
#  the last  three values are for the angular quantity)
gravity = iDynTree.Vector3()
コード例 #8
0
    def objectiveFunc(self, x, test=False):
        self.iter_cnt += 1
        print("call #{}/{}".format(self.iter_cnt, self.iter_max))

        wf, q, a, b = self.vecToParams(x)
        
        if self.config['verbose']:
            print('wf {}'.format(wf))
            print('a {}'.format(np.round(a,5).tolist()))
            print('b {}'.format(np.round(b,5).tolist()))
            print('q {}'.format(np.round(q,5).tolist()))

        #input vars out of bounds, skip call
        if not self.testBounds(x):
            # give penalty obj value for out of bounds (because we shouldn't get here)
            # TODO: for some algorithms (with augemented lagrangian added bounds) this should
            # not be very high as it is added again anyway)
            f = 1000.0
            if self.config['minVelocityConstraint']:
                g = [10.0]*self.num_constraints
            else:
                g = [10.0]*self.num_constraints

            fail = 1.0
            return f, g, fail

        self.trajectory.initWithParams(a,b,q, self.nf, wf)

        old_verbose = self.config['verbose']
        self.config['verbose'] = 0
        #old_floatingBase = self.config['floatingBase']
        #self.config['floatingBase'] = 0
        trajectory_data, data = self.sim_func(self.config, self.trajectory, model=self.model)

        self.config['verbose'] = old_verbose
        #self.config['floatingBase'] = old_floatingBase

        self.last_trajectory_data = trajectory_data
        if self.config['showOptimizationTrajs']:
            plotter(self.config, data=trajectory_data)

        f = np.linalg.cond(self.model.YBase)
        #f = np.log(np.linalg.det(self.model.YBase.T.dot(self.model.YBase)))   #fisher information matrix

        #xBaseModel = np.dot(model.Binv | K, model.xStdModel)
        #f = np.linalg.cond(model.YBase.dot(np.diag(xBaseModel)))    #weighted with CAD params

        f1 = 0
        # add constraints  (later tested for all: g(n) <= 0)
        g = [1e10]*self.num_constraints
        jn = self.model.jointNames
        for n in range(self.num_dofs):
            # check for joint limits
            # joint pos lower
            print("minma of trajectory",np.min(trajectory_data['positions'][:, n]))
            print("maxima of trajectory",np.max(trajectory_data['positions'][:, n]))
            
            if len(self.config['ovrPosLimit'])>n and self.config['ovrPosLimit'][n]:
                g[n] = np.deg2rad(self.config['ovrPosLimit'][n][0]) - np.min(trajectory_data['positions'][:, n])
                
            else:
                g[n] = self.limits[jn[n]]['lower'] - np.min(trajectory_data['positions'][:, n])
            # joint pos upper
            if len(self.config['ovrPosLimit'])>n and self.config['ovrPosLimit'][n]:
                g[self.num_dofs+n] = np.max(trajectory_data['positions'][:, n]) - np.deg2rad(self.config['ovrPosLimit'][n][1])
            else:
                g[self.num_dofs+n] = np.max(trajectory_data['positions'][:, n]) - self.limits[jn[n]]['upper']
            # max joint vel
            #g[2*self.num_dofs+n] = np.max(np.abs(trajectory_data['velocities'][:, n])) - self.limits[jn[n]]['velocity']
            
            # max torques
           # g[3*self.num_dofs+n] = np.nanmax(np.abs(data.samples['torques'][:, n])) - self.limits[jn[n]]['torque']

            '''if self.config['minVelocityConstraint']:
                # max joint vel of trajectory should at least be 10% of joint limit
                g[3*self.num_dofs+n] = self.limits[jn[n]]['velocity']*self.config['minVelocityPercentage'] - \
                                    np.max(np.abs(trajectory_data['velocities'][:, n]))'''

            # highest joint torque should at least be 10% of joint limit
            '''g[5*self.num_dofs+n] = self.limits[jn[n]]['torque']*0.1 - np.max(np.abs(data.samples['torques'][:, n]))
            f_tmp = self.limits[jn[n]]['torque']*0.1 - np.max(np.abs(data.samples['torques'][:, n]))
            if f_tmp > 0:
                f1+=f_tmp'''
        print(g)   
        # check collision constraints
        # (for whole trajectory but only get closest distance as constraint value)
        c_s = self.num_constraints - self.num_coll_constraints  # start where collision constraints start
        traversal = iDynTree.Traversal()
        success = self.idyn_model.computeFullTreeTraversal(traversal)
        rotation = iDynTree.Rotation(1.0, 0.0, 0.0,
                                     0.0, 1.0, 0.0,
                                     0.0, 0.0, 1.0)
        position = iDynTree.Position(0.0, 0.0, 0.0)
        worldHbase = iDynTree.Transform(rotation, position)
        jointPosition = iDynTree.VectorDynSize(5)
        
        if self.config['verbose'] > 1:
            print('checking collisions')
        for p in range(0, trajectory_data['positions'].shape[0], 10):
            g_cnt1 = 0
            g_cnt2 = 1
        
            if self.config['verbose'] > 1:
                print("Sample {}".format(p))
            q = trajectory_data['positions'][p]

            for i in range(len(q)):
                jointPosition[i] = q[i]

            linkPositions = iDynTree.LinkPositions(self.idyn_model) 
            iDynTree.ForwardPositionKinematics(self.idyn_model, traversal, worldHbase,jointPosition, linkPositions)
            pose_link5 = linkPositions(5)
            z = pose_link5.getPosition().getVal(2)
            origin = (0, 0 , 0)
            end_eff = (pose_link5.getPosition().getVal(0), pose_link5.getPosition().getVal(1), (pose_link5.getPosition().getVal(2)))
            dist = distance.euclidean(origin, end_eff)
            
            if(z < 0.35 ):
                if (z < g[c_s+g_cnt1]):
                    g[c_s+g_cnt1] = z
               
            if(dist < 0.25):
                if (dist < g[c_s+g_cnt2]):
                    g[c_s+g_cnt2] = dist
                
                
                      
            '''for l0 in range(self.model.num_links + len(self.world_links)):
                for l1 in range(self.model.num_links + len(self.world_links)):
                    l0_name = (self.model.linkNames + self.world_links)[l0]
                    l1_name = (self.model.linkNames + self.world_links)[l1]

                    if (l0 >= l1):  # don't need, distance is the same in both directions; same link never collides
                        continue
                    if l0_name in self.config['ignoreLinksForCollision'] \
                            or l1_name in self.config['ignoreLinksForCollision']:
                        continue
                    if [l0_name, l1_name] in self.config['ignoreLinkPairsForCollision'] or \
                       [l1_name, l0_name] in self.config['ignoreLinkPairsForCollision']:
                        continue

                    # neighbors can't collide with a proper joint range, so ignore--
                    if l0 < self.model.num_links and l1 < self.model.num_links:
                        if l0_name in self.neighbors[l1_name]['links'] or l1_name in self.neighbors[l0_name]['links']:
                            continue

                    if l0 < l1:
                        d = self.getLinkDistance(l0_name, l1_name, q)
                        if d < g[c_s+g_cnt]:
                            print("l0: {} l1: {}".format(l0,l1))
                            g[c_s+g_cnt] = d
                            
                        g_cnt += 1'''

        self.last_g = g
        

        #add min join torques as second objective
        if f1 > 0:
            f+= f1
            print("added cost: {}".format(f1))

        c = self.testConstraints(g)
        if c:
            print(Fore.GREEN, end=' ')
        else:
            print(Fore.YELLOW, end=' ')

        print("objective function value: {} (last best: {} + {})".format(f,
                                                            self.last_best_f-self.last_best_f_f1,
                                                            self.last_best_f_f1), end=' ')
        print(Fore.RESET)

        if self.config['verbose']:
            if self.opt_prob.is_gradient:
                print("(Gradient evaluation)")

        if self.mpi_rank == 0 and not self.opt_prob.is_gradient and self.config['showOptimizationGraph']:
            self.xar.append(self.iter_cnt)
            self.yar.append(f)
            self.x_constr.append(c)
            self.updateGraph()

        self.showVisualizerTrajectory(self.trajectory)

        #keep last best solution (some solvers don't keep it)
        if c and f < self.last_best_f:
            self.last_best_f = f
            self.last_best_f_f1 = f1
            self.last_best_sol = x

        print("\n\n")

        fail = 0.0
        #funcs = {}
        #funcs['opt'] = f
        #funcs['con'] = g
        #return funcs, fail
        return f, g, fail
コード例 #9
0
    #for each joint, sweep through all possible joint angles and get mass matrix
    q = iDynTree.VectorDynSize(n_dofs)
    q.zero()
    dq = iDynTree.VectorDynSize(n_dofs)
    #dq.fromList([1.0]*n_dofs)
    dq.zero()
    ddq = iDynTree.VectorDynSize(n_dofs)
    ddq.zero()
    world_gravity = iDynTree.SpatialAcc.fromList([0, 0, -9.81, 0, 0, 0])
    base_velocity = iDynTree.Twist()
    base_velocity.zero()
    base_acceleration = iDynTree.ClassicalAcc()
    base_acceleration.zero()
    rot = iDynTree.Rotation.RPY(0, 0, 0)
    pos = iDynTree.Position.Zero()
    world_T_base = iDynTree.Transform(rot, pos)
    torques = iDynTree.VectorDynSize(n_dofs)
    baseReactionForce = iDynTree.Wrench()

    m = iDynTree.MatrixDynSize(n_dofs, n_dofs)
    maxima = [0]*n_dofs
    minima = [99999]*n_dofs
    getMaxima = 1

    for i in range(n_dofs):
        for pos in np.arange(limits[jointNames[i]]['lower'], limits[jointNames[i]]['upper'], 0.01):
            q.zero()

            q[i] = pos
            if getMaxima:
                # saggital = pitch, transversal = yaw, lateral = roll