示例#1
0
 def calcQwt(self, qest, wt, delta_t):
     print self.calcqqwt(qest, wt)
     q1 = qest
     cq1 = quat.conjugate(q1)
     q2 = self.calcqqwt(qest, wt) * delta_t
     cq2 = quat.conjugate(q2)
     print q1 + q2
     return 2
def test_conjugate():

    # pmath.multiply(q0.numpy(), q1.numpy())

    normalized = tq.normalize(torch.Tensor(rand_q(8)))
    con = tq.conjugate(normalized)

    for d in range(normalized.shape[0]):
        con0 = tq.conjugate(normalized[d])
        assert torch.all(con[d] == con0)

    for d in range(normalized.shape[0]):
        con0 = pmath.quaternion_conjugate(normalized[d].numpy())
        assert np.all(con[d].numpy() == con0)
示例#3
0
def CalibrationProcess(cal_pipe, client):
    accel_points = SigmaPoints(.05**2, 12, 10)
    compass_points = SigmaPoints(1.1**2, 28, 3)

    norm = [0, 0, 1]

    accel_calibration = RegisterCalibration(client, 'imu.accel', [[0, 0, 0, 1], 1])
    compass_calibration = RegisterCalibration(client, 'imu.compass', [[0, 0, 0, 30, 0], [1, 1], 0])
    
    client.watch('imu.alignmentQ')
    if not cal_pipe: # get these through client rather than direct pipe
        client.watch('imu.accel')
        client.watch('imu.compass')
        client.watch('imu.fusionQPose')

    def debug(name):
        def debug_by_name(*args):
            s = ''
            for a in args:
                s += str(a) + ' '
            client.set('imu.'+name+'.calibration.log', s)
        return debug_by_name

    last_compass_coverage = 0
    while True:
        t = time.monotonic()
        addedpoint = False
        down = False
        while time.monotonic() - t < calibration_fit_period:
            # receive pypilot messages
            msg = client.receive(1)
            for name in msg:
                value = msg[name]
                if name == 'imu.alignmentQ' and value:
                    norm = quaternion.rotvecquat([0, 0, 1], value)
                    compass_points.Reset()
                elif name == 'imu.accel':
                    if value:
                        accel_points.AddPoint(value)
                    addedpoint = True
                elif name == 'imu.compass' and down:
                    if value and down:
                        compass_points.AddPoint(value, down)
                    addedpoint = True
                elif name == 'imu.fusionQPose':
                    if value:
                        down = quaternion.rotvecquat([0, 0, 1], quaternion.conjugate(value))

            # receive calibration data
            if cal_pipe:
                p = cal_pipe.recv()
                while p:
                    if 'accel' in p:
                        accel_points.AddPoint(p['accel'])
                        addedpoint = True
                    if 'compass' in p:
                        down = quaternion.rotvecquat([0, 0, 1], quaternion.conjugate(p['fusionQPose']))
                        compass_points.AddPoint(p['compass'], down)
                        addedpoint = True
                    p = cal_pipe.recv()

            cals = [(accel_calibration, accel_points), (compass_calibration, compass_points)]
            for calibration, points in cals:
                calibration.age.update()
                if points.Updated():
                    calibration.sigmapoints.set(points.Points())

        if not addedpoint: # don't bother to run fit if no new data
            continue

        accel_points.RemoveOlder(10*60) # 10 minutes
        fit = FitAccel(debug('accel'), accel_points)
        if fit: # reset compass sigmapoints on accel cal
            dist = vector.dist(fit[0][:3], accel_calibration.value[0][:3])
            if dist > .01: # only update when bias changes more than this
                if dist > .08: # reset compass cal from large change in accel bias
                    compass_points.Reset()
                    debug('accel')('reset compass from large accel bias')
                accel_calibration.set(fit)
                accel_calibration.points.set(accel_points.Points())
            else:
                debug('accel')('calibration distance too small ', dist)

        compass_points.RemoveOlder(20*60) # 20 minutes
        fit = FitCompass(debug('compass'), compass_points, compass_calibration.value[0], norm)
        if fit:
            # ignore decreasing compass coverage
            new_coverage = fit[1][2]
            if new_coverage < last_compass_coverage:
                debug('compass')('ignoring decreasing coverage')
            else:
                compass_calibration.set(fit)
                compass_calibration.points.set(compass_points.Points())
        else:
            last_compass_coverage = 0 # reset
示例#4
0
    def IMURead(self):
        data = False

        while self.poller.poll(0):  # read all the data from the pipe
            data = self.imu_pipe.recv()

        if not data:
            if time.time() - self.last_imuread > 1 and self.loopfreq.value:
                print 'IMURead failed!'
                self.loopfreq.set(0)
                for name in self.SensorValues:
                    self.SensorValues[name].set(False)
                self.uptime.reset()
            return False

        if vector.norm(data['accel']) == 0:
            print 'vector n', data['accel']
            return False

        self.last_imuread = time.time()
        self.loopfreq.strobe()

        if not self.FirstTimeStamp:
            self.FirstTimeStamp = data['timestamp']

        data['timestamp'] -= self.FirstTimeStamp

        #data['accel_comp'] = quaternion.rotvecquat(vector.sub(data['accel'], down), self.alignmentQ.value)

        # apply alignment calibration
        gyro_q = quaternion.rotvecquat(data['gyro'], data['fusionQPose'])

        data['pitchrate'], data['rollrate'], data['headingrate'] = map(
            math.degrees, gyro_q)

        origfusionQPose = data['fusionQPose']
        aligned = quaternion.multiply(data['fusionQPose'],
                                      self.alignmentQ.value)
        data['fusionQPose'] = quaternion.normalize(
            aligned)  # floating point precision errors

        data['roll'], data['pitch'], data['heading'] = map(
            math.degrees, quaternion.toeuler(data['fusionQPose']))

        if data['heading'] < 0:
            data['heading'] += 360

        dt = data['timestamp'] - self.lasttimestamp
        self.lasttimestamp = data['timestamp']
        if dt > .02 and dt < .5:
            data['headingraterate'] = (data['headingrate'] -
                                       self.headingrate) / dt
        else:
            data['headingraterate'] = 0

        self.headingrate = data['headingrate']

        data['heel'] = self.heel = data['roll'] * .03 + self.heel * .97
        #data['roll'] -= data['heel']

        data['gyro'] = list(map(math.degrees, data['gyro']))
        data['gyrobias'] = list(map(math.degrees, data['gyrobias']))

        # lowpass heading and rate
        llp = self.heading_lowpass_constant.value
        data['heading_lowpass'] = heading_filter(
            llp, data['heading'], self.SensorValues['heading_lowpass'].value)

        llp = self.headingrate_lowpass_constant.value
        data['headingrate_lowpass'] = llp * data['headingrate'] + (
            1 - llp) * self.SensorValues['headingrate_lowpass'].value

        llp = self.headingraterate_lowpass_constant.value
        data['headingraterate_lowpass'] = llp * data['headingraterate'] + (
            1 - llp) * self.SensorValues['headingraterate_lowpass'].value

        # set sensors
        self.server.TimeStamp('imu', data['timestamp'])
        for name in self.SensorValues:
            self.SensorValues[name].set(data[name])

        compass, accel, down = False, False, False
        if not self.accel_calibration.locked.value:
            accel = list(data['accel'])
        if not self.compass_calibration.locked.value:
            down = quaternion.rotvecquat([0, 0, 1],
                                         quaternion.conjugate(origfusionQPose))
            compass = list(data['compass']) + down
        if accel or compass:
            self.auto_cal.AddPoint((accel, compass, down))

        self.uptime.update()

        # count down to alignment
        if self.alignmentCounter.value != self.last_alignmentCounter:
            self.alignmentPose = [0, 0, 0, 0]

        if self.alignmentCounter.value > 0:
            self.alignmentPose = list(
                map(lambda x, y: x + y, self.alignmentPose,
                    data['fusionQPose']))
            self.alignmentCounter.set(self.alignmentCounter.value - 1)

            if self.alignmentCounter.value == 0:
                self.alignmentPose = quaternion.normalize(self.alignmentPose)
                adown = quaternion.rotvecquat([0, 0, 1],
                                              quaternion.conjugate(
                                                  self.alignmentPose))
                alignment = []

                alignment = quaternion.vec2vec2quat([0, 0, 1], adown)
                alignment = quaternion.multiply(self.alignmentQ.value,
                                                alignment)

                if len(alignment):
                    self.update_alignment(alignment)

            self.last_alignmentCounter = self.alignmentCounter.value
        if self.heading_off.value != self.last_heading_off:
            self.update_alignment(self.alignmentQ.value)
            self.last_heading_off = self.heading_off.value

        result = self.auto_cal.UpdatedCalibration()

        if result:
            if result[0] == 'accel' and not self.accel_calibration.locked.value:
                #print '[boatimu] cal result', result[0]
                self.accel_calibration.sigmapoints.set(result[2])
                if result[1]:
                    self.accel_calibration.age.reset()
                    self.accel_calibration.set(result[1])
            elif result[
                    0] == 'compass' and not self.compass_calibration.locked.value:
                #print '[boatimu] cal result', result[0]
                self.compass_calibration.sigmapoints.set(result[2])
                if result[1]:
                    self.compass_calibration.age.reset()
                    self.compass_calibration.set(result[1])

        self.accel_calibration.age.update()
        self.compass_calibration.age.update()
        return data
示例#5
0
    def integrate_all(self, use_acc=False):
        """go through each gyro sample and integrate to find orientation

        Returns:
            (np.ndarray, np.ndarray): tuple (time_list, quaternion orientation array)
        """

        if self.already_integrated and (use_acc == self.last_used_acc
                                        or not self.acc_available):
            return (self.time_list, self.orientation_list)

        apply_complementary = self.acc_available and use_acc

        self.last_used_acc = use_acc

        if apply_complementary:
            # find valid accelation data points
            #print(self.acc)
            #print(self.acc.shape)
            asquared = np.sum(self.acc[:, 1:]**2, 1)
            # between 0.9 and 1.1 g
            complementary_mask = np.logical_and(0.81 < asquared,
                                                asquared < 1.21)

        self.orientation = np.copy(self.initial_orientation)

        # temp lists to save data
        temp_orientation_list = []
        temp_time_list = []

        start_time = self.gyro[0][0]  # seconds

        for i in range(self.num_data_points):

            # angular velocity vector
            omega = self.gyro[i][1:]

            # get current and adjecent times
            last_time = self.gyro[i - 1][0] if i > 0 else self.gyro[i][0]
            this_time = self.gyro[i][0]
            next_time = self.gyro[
                i + 1][0] if i < self.num_data_points - 1 else self.gyro[i][0]

            # symmetrical dt calculation. Should give slightly better results when missing data
            delta_time = (next_time - last_time) / 2

            # Only calculate if angular velocity is present
            if np.any(omega) or apply_complementary:
                # complementary filter
                if apply_complementary:
                    if complementary_mask[i]:
                        avec = self.acc[i][1:]
                        avec /= np.linalg.norm(avec)

                        accWorldVec = quat.rotate_vector_fast(
                            self.orientation, avec)
                        correctionWorld = np.cross(accWorldVec, self.grav_vec)

                        # high weight for first two seconds to "lock" it, then
                        weight = 10 if this_time - start_time < 1.5 else 0.6
                        correctionBody = weight * quat.rotate_vector_fast(
                            quat.conjugate(self.orientation), correctionWorld)
                        omega = omega + correctionBody

                # calculate rotation quaternion
                delta_q = self.rate_to_quat(omega, delta_time)

                # rotate orientation by this quaternion
                self.orientation = quat.quaternion_multiply(
                    self.orientation, delta_q)  # Maybe change order

                self.orientation = quat.normalize(self.orientation)

            temp_orientation_list.append(np.copy(self.orientation))
            temp_time_list.append(this_time)

        self.orientation_list = np.array(temp_orientation_list)
        self.time_list = np.array(temp_time_list)

        self.already_integrated = True

        return (self.time_list, self.orientation_list)
示例#6
0
    def read(self):
        data = self.IMUread()
        if not data:
            if time.monotonic(
            ) - self.last_imuread > 1 and self.frequency.value:
                print('IMURead failed!')
                self.frequency.set(False)
                for name in self.SensorValues:
                    self.SensorValues[name].set(False)
                self.uptime.reset()
            return False

        if vector.norm(data['accel']) == 0:
            print('accel values invalid', data['accel'])
            return False

        self.last_imuread = time.monotonic()
        self.frequency.strobe()

        # apply alignment calibration
        gyro_q = quaternion.rotvecquat(data['gyro'], data['fusionQPose'])

        data['pitchrate'], data['rollrate'], data['headingrate'] = map(
            math.degrees, gyro_q)

        aligned = quaternion.multiply(data['fusionQPose'],
                                      self.alignmentQ.value)
        aligned = quaternion.normalize(
            aligned)  # floating point precision errors

        data['roll'], data['pitch'], data['heading'] = map(
            math.degrees, quaternion.toeuler(aligned))

        if data['heading'] < 0:
            data['heading'] += 360

        dt = data['timestamp'] - self.lasttimestamp
        self.lasttimestamp = data['timestamp']
        if dt > .01 and dt < .2:
            data['headingraterate'] = (data['headingrate'] -
                                       self.headingrate) / dt
        else:
            data['headingraterate'] = 0

        self.headingrate = data['headingrate']

        data['heel'] = self.heel = data['roll'] * .03 + self.heel * .97
        #data['roll'] -= data['heel']

        data['gyro'] = list(map(math.degrees, data['gyro']))

        # lowpass heading and rate
        llp = self.heading_lowpass_constant.value
        data['heading_lowpass'] = heading_filter(
            llp, data['heading'], self.SensorValues['heading_lowpass'].value)

        llp = self.headingrate_lowpass_constant.value
        data['headingrate_lowpass'] = llp * data['headingrate'] + (
            1 - llp) * self.SensorValues['headingrate_lowpass'].value

        llp = self.headingraterate_lowpass_constant.value
        data['headingraterate_lowpass'] = llp * data['headingraterate'] + (
            1 - llp) * self.SensorValues['headingraterate_lowpass'].value

        # set sensors
        for name in self.SensorValues:
            self.SensorValues[name].set(data[name])

        self.uptime.update()

        # count down to alignment
        if self.alignmentCounter.value != self.last_alignmentCounter:
            self.alignmentPose = [0, 0, 0, 0]

        if self.alignmentCounter.value > 0:
            self.alignmentPose = list(
                map(lambda x, y: x + y, self.alignmentPose, aligned))
            self.alignmentCounter.set(self.alignmentCounter.value - 1)

            if self.alignmentCounter.value == 0:
                self.alignmentPose = quaternion.normalize(self.alignmentPose)
                adown = quaternion.rotvecquat([0, 0, 1],
                                              quaternion.conjugate(
                                                  self.alignmentPose))

                alignment = []
                alignment = quaternion.vec2vec2quat([0, 0, 1], adown)
                alignment = quaternion.multiply(self.alignmentQ.value,
                                                alignment)

                if len(alignment):
                    self.update_alignment(alignment)

            self.last_alignmentCounter = self.alignmentCounter.value

        # if alignment or heading offset changed:
        if self.heading_off.value != self.heading_off.last or \
           self.alignmentQ.value != self.alignmentQ.last:
            self.update_alignment(self.alignmentQ.value)
            self.heading_off.last = self.heading_off.value
            self.alignmentQ.last = self.alignmentQ.value

        if self.auto_cal.cal_pipe:
            #print('warning, cal pipe always sending despite locks')
            cal_data = {}
            #how to check this here??  if not 'imu.accel.calibration.locked'
            cal_data['accel'] = list(data['accel'])

            #how to check this here??  if not 'imu.compass.calibration.locked'
            cal_data['compass'] = list(data['compass'])
            cal_data['fusionQPose'] = list(data['fusionQPose'])

            if cal_data:
                #print('send', cal_data)
                self.auto_cal.cal_pipe.send(cal_data)

        return data
示例#7
0
    def IMURead(self):
        data = False

        while self.poller.poll(0):  # read all the data from the pipe
            data = self.imu_pipe.recv()

        if not data:
            if time.time() - self.last_imuread > 1 and self.loopfreq.value:
                print('IMURead failed!')
                self.loopfreq.set(0)
                for name in self.SensorValues:
                    self.SensorValues[name].set(False)
                self.uptime.reset()
            return False

        if vector.norm(data['accel']) == 0:
            print('accel values invalid', data['accel'])
            return False

        t = time.time()
        self.timestamp.set(t - self.starttime)

        self.last_imuread = t
        self.loopfreq.strobe()

        # apply alignment calibration
        gyro_q = quaternion.rotvecquat(data['gyro'], data['fusionQPose'])

        data['pitchrate'], data['rollrate'], data['headingrate'] = map(
            math.degrees, gyro_q)
        origfusionQPose = data['fusionQPose']

        aligned = quaternion.multiply(data['fusionQPose'],
                                      self.alignmentQ.value)
        data['fusionQPose'] = quaternion.normalize(
            aligned)  # floating point precision errors

        data['roll'], data['pitch'], data['heading'] = map(
            math.degrees, quaternion.toeuler(data['fusionQPose']))

        if data['heading'] < 0:
            data['heading'] += 360

        dt = data['timestamp'] - self.lasttimestamp
        self.lasttimestamp = data['timestamp']
        if dt > .02 and dt < .5:
            data['headingraterate'] = (data['headingrate'] -
                                       self.headingrate) / dt
        else:
            data['headingraterate'] = 0

        self.headingrate = data['headingrate']

        data['heel'] = self.heel = data['roll'] * .03 + self.heel * .97
        #data['roll'] -= data['heel']

        data['gyro'] = list(map(math.degrees, data['gyro']))
        data['gyrobias'] = list(map(math.degrees, data['gyrobias']))

        # lowpass heading and rate
        llp = self.heading_lowpass_constant.value
        data['heading_lowpass'] = heading_filter(
            llp, data['heading'], self.SensorValues['heading_lowpass'].value)

        llp = self.headingrate_lowpass_constant.value
        data['headingrate_lowpass'] = llp * data['headingrate'] + (
            1 - llp) * self.SensorValues['headingrate_lowpass'].value

        llp = self.headingraterate_lowpass_constant.value
        data['headingraterate_lowpass'] = llp * data['headingraterate'] + (
            1 - llp) * self.SensorValues['headingraterate_lowpass'].value

        # set sensors
        for name in self.SensorValues:
            self.SensorValues[name].set(data[name])

        self.uptime.update()

        # count down to alignment
        if self.alignmentCounter.value != self.last_alignmentCounter:
            self.alignmentPose = [0, 0, 0, 0]

        if self.alignmentCounter.value > 0:
            self.alignmentPose = list(
                map(lambda x, y: x + y, self.alignmentPose,
                    data['fusionQPose']))
            self.alignmentCounter.set(self.alignmentCounter.value - 1)

            if self.alignmentCounter.value == 0:
                self.alignmentPose = quaternion.normalize(self.alignmentPose)
                adown = quaternion.rotvecquat([0, 0, 1],
                                              quaternion.conjugate(
                                                  self.alignmentPose))
                alignment = []
                alignment = quaternion.vec2vec2quat([0, 0, 1], adown)
                alignment = quaternion.multiply(self.alignmentQ.value,
                                                alignment)

                if len(alignment):
                    self.update_alignment(alignment)

            self.last_alignmentCounter = self.alignmentCounter.value

        # if alignment or heading offset changed:
        if self.heading_off.value != self.heading_off.last or self.alignmentQ.value != self.alignmentQ.last:
            self.update_alignment(self.alignmentQ.value)
            self.heading_off.last = self.heading_off.value
            self.alignmentQ.last = self.alignmentQ.value

        cal_data = {}
        if not self.accel_calibration.locked.value:
            cal_data['accel'] = list(data['accel'])
        if not self.compass_calibration.locked.value:
            cal_data['compass'] = list(data['compass'])
            cal_data['down'] = quaternion.rotvecquat(
                [0, 0, 1], quaternion.conjugate(origfusionQPose))

        if cal_data:
            self.auto_cal.cal_pipe.send(cal_data)

        self.accel_calibration.age.update()
        self.compass_calibration.age.update()
        return data