def sync(self, position_pub, data):

        switch = 0
        with SyncLogger(self.crazyflie, self.log1()) as logger1, \
                SyncLogger(self.crazyflie, self.log2()) as logger2:
            end_time = time.time() + 24
            while time.time() < end_time:
                if switch == 0:
                    logger = logger2
                elif switch == 1:
                    logger = logger1

                for log_entry in logger:
                    row = log_entry[1]
                    row["timestamp"] = log_entry[0]
                    if switch == 1:
                        x = row['stateEstimate.x']
                        y = row['stateEstimate.y']
                        z = row['stateEstimate.z']

                        self.pose.position.x = x
                        self.pose.position.y = y
                        self.pose.position.z = z

                        position_pub.publish(self.pose)
                        print('x:', x, ' y:', y, ' z:', z)
                        print()
                    data.append(row)
                    switch += 1
                    break

                if switch == 2:
                    switch = 0
            return None
Exemple #2
0
    def test_construction_with_sync_crazyflie_instance(self):
        # Fixture
        scf_mock = MagicMock(spec=SyncCrazyflie)
        scf_mock.cf = self.cf_mock

        # Test
        sut = SyncLogger(scf_mock, self.log_config_mock)
        sut.connect()
    def test_construction_with_sync_crazyflie_instance(self):
        # Fixture
        scf_mock = MagicMock(spec=SyncCrazyflie)
        scf_mock.cf = self.cf_mock

        # Test
        sut = SyncLogger(scf_mock, self.log_config_mock)
        sut.connect()
Exemple #4
0
    def setUp(self):
        self.cf_mock = MagicMock(spec=Crazyflie)
        self.cf_mock.disconnected = Caller()

        self.log_mock = MagicMock(spec=Log)
        self.cf_mock.log = self.log_mock

        self.log_config_mock = MagicMock(spec=LogConfig)
        self.log_config_mock.data_received_cb = Caller()

        self.sut = SyncLogger(self.cf_mock, self.log_config_mock)
Exemple #5
0
 def __init__(self, scf, log_vars, period_in_ms=10):
     Thread.__init__(self)
     log_config = LogConfig('GenericLogConfig', period_in_ms)
     log_vars = set(log_vars)
     log_vars |= {
         'kalman.stateX', 'kalman.stateY', 'kalman.stateZ', 'controller.yaw'
     }
     self.data = dict()
     for var in log_vars:
         log_config.add_variable(var)
         self.data[var] = []
     self.data['timestamp'] = []
     self.sync_logger = SyncLogger(scf, log_config)
     self.terminate = False
Exemple #6
0
def sleep_while_checking_stable(scf: SyncCrazyflie, tf_sec, dt_sec=0.1):
    if tf_sec == 0:
        return
    log_config = LogConfig(name='Roll', period_in_ms=int(dt_sec * 1000.0))
    log_config.add_variable('stabilizer.roll', 'float')
    log_config.add_variable('pm.vbat', 'float')
    t_sec = 0
    print('sleeping {:10.4f} seconds'.format(tf_sec))
    with SyncLogger(scf, log_config) as logger:
        for log_entry in logger:
            log_data = log_entry[1]
            roll = log_data['stabilizer.roll']
            batt = log_data['pm.vbat']
            if np.abs(roll) > 60:
                raise UnstableException(
                    "flip detected {:10.4f} deg, for {:s}".format(
                        roll, scf.cf.link_uri))
            # print("battery {:10.4f} V, for {:s}".format(batt, scf.cf.link_uri))
            if batt < 3.0:
                raise LowBatteryException(
                    "low battery {:10.4f} V, for {:s}".format(
                        batt, scf.cf.link_uri))
            t_sec += dt_sec
            if t_sec > tf_sec:
                return
Exemple #7
0
def check_state(scf: SyncCrazyflie):
    print('Checking state.')
    log_config = LogConfig(name='State', period_in_ms=500)
    log_config.add_variable('stabilizer.roll', 'float')
    log_config.add_variable('stabilizer.pitch', 'float')
    log_config.add_variable('stabilizer.yaw', 'float')
    print('Log configured.')

    with SyncLogger(scf, log_config) as logger:
        for log_entry in logger:
            log_data = log_entry[1]
            roll = log_data['stabilizer.roll']
            pitch = log_data['stabilizer.pitch']
            yaw = log_data['stabilizer.yaw']
            print('Checking roll/pitch/yaw.')

            #('yaw', yaw)
            if SEND_FULL_POSE:
                euler_checks = [('roll', roll, 5), ('pitch', pitch, 5)]
            else:
                euler_checks = [('roll', roll, 5), ('pitch', pitch, 5),
                                ('yaw', yaw, 5)]

            for name, val, val_max in euler_checks:
                print(name, val, val_max)
                if np.abs(val) > val_max:
                    print('exceeded')
                    msg = "too much {:s}, {:10.4f} deg, for {:s}".format(
                        name, val, scf.cf.link_uri)
                    print(msg)
                    raise UnstableException(msg)
            return
def producer(queue):
    fileTag = open(filenameTag, 'w')
    lg_stab = LogConfig(name='Stabilizer', period_in_ms=100)
    lg_stab.add_variable('stateEstimate.x', 'float')
    lg_stab.add_variable('stateEstimate.y', 'float')
    lg_stab.add_variable('stateEstimate.z', 'float')
    cnt = 0

    with SyncCrazyflie(uriTag, cf=Crazyflie(rw_cache='./cache')) as scf:
        with SyncLogger(scf, lg_stab) as logger:

            for log_entry in logger:
                timestamp = log_entry[0]
                data = log_entry[1]
                logconf_name = log_entry[2]

                # print('[%d][%s]: %s' % (timestamp, logconf_name, data))
                a = '%s, %s, %s\n' % (data["stateEstimate.x"], data["stateEstimate.y"], data["stateEstimate.z"])
                x = float(data["stateEstimate.x"])
                y = float(data["stateEstimate.y"])
                fileTag.write(a)
                if cnt == 15:
                    consumerPos = (x, y)
                    queue.put(consumerPos)
                    cnt = 0
                else:
                    cnt += 1

                if is_finished == True:
                    endPos = (x, y)
                    queue.put(endPos)
                    break
    fileTag.close()
    print('Productor ended')
    def cf_handler(self):
        uri = "radio://0/30"

        lg_block = LogConfig(name='LH', period_in_ms=50)
        lg_block.add_variable('lighthouse.angle0x', 'float')
        lg_block.add_variable('lighthouse.angle0y', 'float')
        lg_block.add_variable('lighthouse.angle1x', 'float')
        lg_block.add_variable('lighthouse.angle1y', 'float')

        cf = Crazyflie(rw_cache='./cache')
        with SyncCrazyflie(uri, cf=cf) as scf:
            print("Getting LH geometry")
            mems = scf.cf.mem.get_mems(MemoryElement.TYPE_LH)
            mems[0].update(self._update_geometry)

            with SyncLogger(scf, lg_block) as logger:
                for log_entry in logger:
                    data = log_entry[1]

                    self.angles[0][0] = data['lighthouse.angle0x']
                    self.angles[0][1] = data['lighthouse.angle0y']
                    self.angles[1][0] = data['lighthouse.angle1x']
                    self.angles[1][1] = data['lighthouse.angle1y']

                    if self.terminate:
                        break

                    self.update_scene()
        def run(self):
            #cradio = crazyradio.Crazyradio()
            print ("hi")
            #print (cradio)
            #cradio.set_data_rate(cradio.DR_2MPS)
            #cradio.set_channel(70)
            print ("Thread start")

            log_rssi = LogConfig(name='RSSI', period_in_ms=1000)
            log_rssi.add_variable('radio.rssi', 'float')

            while self.running == True:

                with SyncLogger(scf, log_rssi) as logger:
                endTime = time.time() + 10

                for log_entry in logger:
                    timestamp = log_entry[0]
                    data = log_entry[1]
                    logconf_name = log_entry[2]

                    #print('[%d][%s]: %s' % (timestamp, logconf_name, data))
                    print(data["radio.rssi"])

                    if time.time() > endTime:
                        break
                
                time.sleep(0)
        def kill(self):
            self.running = 0
Exemple #11
0
def wait_for_position_estimator(scf):
    print('Waiting for estimator to find position...')

    log_config = LogConfig(name='Variance', period_in_ms=500)
    log_config.add_variable('kalman.varPX', 'float')
    log_config.add_variable('kalman.varPY', 'float')
    log_config.add_variable('kalman.varPZ', 'float')

    var_y_history = [1000] * 10
    var_x_history = [1000] * 10
    var_z_history = [1000] * 10

    threshold = 0.001

    with SyncLogger(scf, log_config) as logger:
        for log_entry in logger:
            data = log_entry[1]

            var_x_history.append(data['kalman.varPX'])
            var_x_history.pop(0)
            var_y_history.append(data['kalman.varPY'])
            var_y_history.pop(0)
            var_z_history.append(data['kalman.varPZ'])
            var_z_history.pop(0)

            min_x = min(var_x_history)
            max_x = max(var_x_history)
            min_y = min(var_y_history)
            max_y = max(var_y_history)
            min_z = min(var_z_history)
            max_z = max(var_z_history)

            if (max_x - min_x) < threshold and (
                    max_y - min_y) < threshold and (max_z - min_z) < threshold:
                break
def log_ranging(link_uri, period_in_ms=100, keep_time_in_s=5):
    cflib.crtp.init_drivers()

    log_data = pd.DataFrame(columns=[
        'timestamp', 'receive_from_1', 'receive_from_2', 'receive_from_3',
        'receive_from_4', 'compute_from_1', 'compute_from_2', 'compute_from_3',
        'compute_from_4', 'total_receive', 'total_send', 'total_compute',
        'receive_error', 'compute_error'
    ])

    with SyncCrazyflie(link_uri=link_uri,
                       cf=Crazyflie(rw_cache="./cache")) as scf:

        log_ranging = LogConfig(name='TSranging', period_in_ms=period_in_ms)
        log_ranging.add_variable('TSranging.receive_from_1', 'uint16_t')
        log_ranging.add_variable('TSranging.receive_from_2', 'uint16_t')
        log_ranging.add_variable('TSranging.receive_from_3', 'uint16_t')
        log_ranging.add_variable('TSranging.receive_from_4', 'uint16_t')

        log_ranging.add_variable('TSranging.compute_from_1', 'uint16_t')
        log_ranging.add_variable('TSranging.compute_from_2', 'uint16_t')
        log_ranging.add_variable('TSranging.compute_from_3', 'uint16_t')
        log_ranging.add_variable('TSranging.compute_from_4', 'uint16_t')

        log_ranging.add_variable('TSranging.total_receive', 'uint16_t')
        log_ranging.add_variable('TSranging.total_send', 'uint16_t')
        log_ranging.add_variable('TSranging.total_compute', 'uint16_t')
        log_ranging.add_variable('TSranging.receive_error', 'uint16_t')
        log_ranging.add_variable('TSranging.compute_error', 'uint16_t')

        with SyncLogger(scf, log_ranging) as logger:
            end_time = time.time() + keep_time_in_s
            for log_entry in logger:
                timestamp = log_entry[0]
                data = log_entry[1]
                logconf_name = log_entry[2]

                temp = {
                    'timestamp': timestamp,
                    'receive_from_1': data['TSranging.receive_from_1'],
                    'receive_from_2': data['TSranging.receive_from_2'],
                    'receive_from_3': data['TSranging.receive_from_3'],
                    'receive_from_4': data['TSranging.receive_from_4'],
                    'compute_from_1': data['TSranging.compute_from_1'],
                    'compute_from_2': data['TSranging.compute_from_2'],
                    'compute_from_3': data['TSranging.compute_from_3'],
                    'compute_from_4': data['TSranging.compute_from_4'],
                    'total_receive': data['TSranging.total_receive'],
                    'total_send': data['TSranging.total_send'],
                    'total_compute': data['TSranging.total_compute'],
                    'receive_error': data['TSranging.receive_error'],
                    'compute_error': data['TSranging.compute_error']
                }
                log_data = log_data.append(temp, ignore_index=True)
                # print(log_data.iloc[log_data.shape[0] - 1, :])
                print(temp)
                if time.time() > end_time:
                    break

                log_data.to_csv('../data/LAB2.csv', index=False)
Exemple #13
0
def check_state(scf: SyncCrazyflie, min_voltage=4.0):
    print('Checking state.')
    log_config = LogConfig(name='State', period_in_ms=500)
    log_config.add_variable('stabilizer.roll', 'float')
    log_config.add_variable('stabilizer.pitch', 'float')
    log_config.add_variable('stabilizer.yaw', 'float')
    print('Log configured.')

    with SyncLogger(scf, log_config) as logger:
        for log_entry in logger:
            log_data = log_entry[1]
            roll = log_data['stabilizer.roll']
            pitch = log_data['stabilizer.pitch']
            yaw = log_data['stabilizer.yaw']
            print('Checking roll/pitch/yaw.')

            for name, val in [('roll', roll), ('pitch', pitch), ('yaw', yaw)]:

                if np.abs(val) > 20:
                    print('exceeded')
                    msg = "too much {:s}, {:10.4f} deg, for {:s}".format(
                        name, val, scf.cf.link_uri)
                    print(msg)
                    raise Exception(msg)
            return
 def run_logger(self):
     with SyncLogger(self.scf, self.lighthouse_log_conf) as logger:
         for log_entry in logger:
             #timestamp = log_entry[0]
             #logconf_name = log_entry[2]
             data = log_entry[1]
             self.lighthouse_pos_history.append(data)
             self.lighthouse_pos_history.pop(0)
def print_state(f):
    with SyncLogger(scf, lg_posEst) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]

            print('[%d]: %s' % (timestamp, data), file=f)
            break
def print_control_target(f):
    with SyncLogger(scf, lg_ctrltarget) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]

            print('[%d]: %s' % (timestamp, data), file=f)
            break
Exemple #17
0
    def test_connect_disconnect_with_context_management(self):
        # Fixture

        # Test
        with (SyncLogger(self.cf_mock, self.log_config_mock)) as sut:
            # Assert
            self.assertTrue(sut.is_connected())

        self.assertFalse(sut.is_connected())
Exemple #18
0
def logParameter(scf, parameter, Type):
    data = LogConfig(name='data', period_in_ms=10)
    data.add_variable(parameter, Type)
    #logs data through drone connnection
    with SyncLogger(scf, data) as logger:
        for log_entry in logger:
            data = log_entry[1]
            return data[parameter]
            break
def print_all(f):
    config =[lg_posEst]
    with SyncLogger(scf, config) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]

            print('[%d]: %s' % (timestamp, data), file=f)
            break
 def __init__(self):
     cflib.crtp.init_drivers(enable_debug_driver=False)
     cf = Crazyflie(rw_cache='./cache')
     self.scf = SyncCrazyflie(URI, cf=cf)
     self.scf.open_link()
     self.client = None
     log_config = LogConfig(name='kalman', period_in_ms=100)
     log_config.add_variable('kalman.stateX', 'float')
     log_config.add_variable('kalman.stateY', 'float')
     self.logger_pos = SyncLogger(self.scf, log_config)
     log_config_2 = LogConfig(name='stabilizer', period_in_ms=100)
     log_config_2.add_variable('stabilizer.yaw', 'float')
     self.logger_orientation = SyncLogger(self.scf, log_config_2)
     self.home_pos = self.get_position()
     print('Home = %s ' % self.home_pos)
     self.orientation = self.get_orientation()
     self.client = MotionCommander(self.scf)
     self.client.take_off(height=0.6)
def print_battery(f):
    with SyncLogger(scf, lg_pm) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]
            
            print('[%d]: %s' % (timestamp, data), file=f)
            print('[%d]: %s' % (timestamp, data))
            break
Exemple #22
0
    def waitForEstimator(self):
        startTime = time.time()
        log_config = LogConfig(name='Kalman Variance', period_in_ms=500)
        log_config.add_variable('kalman.varPX', 'float')
        log_config.add_variable('kalman.varPY', 'float')
        log_config.add_variable('kalman.varPZ', 'float')
        log_config.add_variable('kalman.stateX', 'float')
        log_config.add_variable('kalman.stateY', 'float')
        log_config.add_variable('kalman.stateZ', 'float')

        var_y_history = [1000] * 10
        var_x_history = [1000] * 10
        var_z_history = [1000] * 10
        threshold = 0.001

        with SyncLogger(self.crazyflie, log_config) as logger:
            for log_entry in logger:

                exceptionUtil.checkInterrupt()
                data = log_entry[1]

                var_x_history.append(data['kalman.varPX'])
                var_x_history.pop(0)
                var_y_history.append(data['kalman.varPY'])
                var_y_history.pop(0)
                var_z_history.append(data['kalman.varPZ'])
                var_z_history.pop(0)

                min_x = min(var_x_history)
                max_x = max(var_x_history)
                min_y = min(var_y_history)
                max_y = max(var_y_history)
                min_z = min(var_z_history)
                max_z = max(var_z_history)

                x = data['kalman.stateX']
                y = data['kalman.stateY']
                z = data['kalman.stateZ']

                has_converged = (max_x - min_x) < threshold and (
                    max_y - min_y) < threshold and (max_z - min_z) < threshold
                timed_out = (time.time() -
                             startTime) > Drone.ESTIMATOR_TIMEOUT_SEC

                if has_converged:
                    print("Initial position for drone", self.swarmIndex,
                          "has converged, to position: ",
                          ("({:.2f}, {:.2f}, {:.2f})".format(x, y, z)))
                    self.startPosition = (float(x), float(y), float(z))
                    break
                elif timed_out:
                    Logger.error("Drone position sensor failed to update!",
                                 self.swarmIndex)
                    self.setError()
                    raise DroneException(
                        "Drone did not achieve the target position")
Exemple #23
0
def getData():
    with SyncLogger(scf, lg_stab) as logger:
        for log_entry in logger:
            data = log_entry[1]
            yaw = data.get('stabilizer.yaw')
            pitch = data.get('stabilizer.pitch')
            roll = data.get('stabilizer.roll')
            vbat = data.get('pm.vbat')
            time.sleep(0.02)
            return (yaw, pitch, roll, vbat)
def simple_log(scf, logconf):
    with SyncLogger(scf, logconf) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]
            logconf_name = log_entry[2]
            # the logged data is a dict
            values = data.values()
            keys = data
            print('[%d][%s]: %s' % (timestamp, logconf.name, data))
def getData():
    with SyncLogger(scf, lg_stab) as logger:
        for log_entry in logger:
            data = log_entry[1]
            vbat = data.get('pm.vbat')
            blevel = data.get('pm.batteryLevel')
            pwm = data.get('pwm.m1_pwm')
            temp = data.get('baro.temp')
            time.sleep(0.05)
            return(vbat, blevel, pwm, temp)
def read_sensors(scf):
    logs = {
        'lighthouse.angle0x': [0, 0, 0],
        'lighthouse.angle0y': [0, 0, 1],
        'lighthouse.angle0x_1': [0, 1, 0],
        'lighthouse.angle0y_1': [0, 1, 1],
        'lighthouse.angle0x_2': [0, 2, 0],
        'lighthouse.angle0y_2': [0, 2, 1],
        'lighthouse.angle0x_3': [0, 3, 0],
        'lighthouse.angle0y_3': [0, 3, 1],
        'lighthouse.angle1x': [1, 0, 0],
        'lighthouse.angle1y': [1, 0, 1],
        'lighthouse.angle1x_1': [1, 1, 0],
        'lighthouse.angle1y_1': [1, 1, 1],
        'lighthouse.angle1x_2': [1, 2, 0],
        'lighthouse.angle1y_2': [1, 2, 1],
        'lighthouse.angle1x_3': [1, 3, 0],
        'lighthouse.angle1y_3': [1, 3, 1],
    }

    storage = {}

    confs = [
        LogConfig(name='lh1', period_in_ms=10),
        LogConfig(name='lh2', period_in_ms=10),
        LogConfig(name='lh3', period_in_ms=10),
    ]

    # Set up log blocks
    count = 0
    floats_per_block = 6
    for name in logs.keys():
        confs[int(count / floats_per_block)].add_variable(name, 'float')
        count += 1

    # Read log data
    with SyncLogger(scf, confs) as logger:
        end_time = time.time() + 1.0
        for log_entry in logger:
            data = log_entry[1]
            for log_name in data:
                if not log_name in storage:
                    storage[log_name] = []
                storage[log_name].append(data[log_name])
            if time.time() > end_time:
                break

    # Average sensor data
    sensor_sweeps = np.zeros([2, 4, 2])
    for log_name, data in storage.items():
        sensor_info = logs[log_name]
        sensor_sweeps[sensor_info[0]][sensor_info[1]][
            sensor_info[2]] = np.average(data)

    return sensor_sweeps
def setup_estimator(cf):
    """Set up Crazyflie state estimator."""
    # Activate Kalman estimator
    cf.param.set_value('stabilizer.estimator', '2')

    # Set the std deviation for the quaternion data pushed into the Kalman filter.
    # The default value seems to be a bit too low.
    cf.param.set_value('locSrv.extQuatStdDev', 0.6)

    # Reset estimator
    cf.param.set_value('kalman.resetEstimation', '1')
    time.sleep(0.1)
    cf.param.set_value('kalman.resetEstimation', '0')
    time.sleep(1)

    # Wait for estimator to stabilize

    print('Waiting for estimator to find position...')

    log_config = LogConfig(name='Kalman Variance', period_in_ms=500)
    log_config.add_variable('kalman.varPX', 'float')
    log_config.add_variable('kalman.varPY', 'float')
    log_config.add_variable('kalman.varPZ', 'float')

    var_y_history = [1000] * 10
    var_x_history = [1000] * 10
    var_z_history = [1000] * 10

    threshold = 0.001

    with SyncLogger(scf, log_config) as logger:
        for log_entry in logger:
            data = log_entry[1]

            var_x_history.append(data['kalman.varPX'])
            var_x_history.pop(0)
            var_y_history.append(data['kalman.varPY'])
            var_y_history.pop(0)
            var_z_history.append(data['kalman.varPZ'])
            var_z_history.pop(0)

            min_x = min(var_x_history)
            max_x = max(var_x_history)
            min_y = min(var_y_history)
            max_y = max(var_y_history)
            min_z = min(var_z_history)
            max_z = max(var_z_history)

            print(
                "Kalman variance | X: {:8.4f}  Y: {:8.4f}  Z: {:8.4f}".format(
                    max_x - min_x, max_y - min_y, max_z - min_z))

            if (max_x - min_x) < threshold and (
                    max_y - min_y) < threshold and (max_z - min_z) < threshold:
                break
    def setUp(self):
        self.cf_mock = MagicMock(spec=Crazyflie)
        self.cf_mock.disconnected = Caller()

        self.log_mock = MagicMock(spec=Log)
        self.cf_mock.log = self.log_mock

        self.log_config_mock = MagicMock(spec=LogConfig)
        self.log_config_mock.data_received_cb = Caller()

        self.sut = SyncLogger(self.cf_mock, self.log_config_mock)
def simple_log(scf, logconf):
    with SyncLogger(scf, lg_stab) as logger:
        for log_entry in logger:

            timestamp = log_entry[0]
            data = log_entry[1]
            logconf_name = log_entry[2]

            print('[%d][%s]: %s' % (timestamp, logconf_name, data))

            break
Exemple #30
0
def get_cf_position(scf, log_conf):
    print('getting crazyflie position')
    with SyncLogger(scf, log_conf) as logger:
        for log_entry in logger:
            timestamp = log_entry[0]
            data = log_entry[1]
            logconf_name = log_entry[2]
            #print('timestamp:%d \t logconf_name: %s' % (timestamp, logconf_name))
            #print('lighthouse.x = %s, lighthouse.y = %s, lighthouse.z = %s' % (data['lighthouse.x'], data['lighthouse.y'], data['lighthouse.z']))
            break 
    return {'x':data['lighthouse.x'], 'y':data['lighthouse.y'], 'z':data['lighthouse.z']} 
Exemple #31
0
def getDirection(scf):
    data = LogConfig(name='data', period_in_ms=10)
    data.add_variable('stabilizer.yaw', 'float')

    with SyncLogger(scf, data) as logger:
        for log_entry in logger:
            #timestamp = log_entry[0]
            data = log_entry[1]
            #logconf_name = log_entry[2]

            return data['stabilizer.yaw']
            break
def find_initial_position(scf):
  print('Finding intial position and state')
  log_config = LogConfig(name='Variance', period_in_ms=100)
  log_config.add_variable('stateEstimate.x', 'float')
  log_config.add_variable('stateEstimate.y', 'float')
  log_config.add_variable('stateEstimate.z', 'float')
  log_config.add_variable('stabilizer.yaw', 'float')

  with SyncLogger(scf, log_config) as logger:
    for log_entry in logger:
      data = log_entry[1]
      return data['stateEstimate.x'], data['stateEstimate.y'], data['stateEstimate.z'], data['stabilizer.yaw']
class SyncLoggerTest(unittest.TestCase):

    def setUp(self):
        self.cf_mock = MagicMock(spec=Crazyflie)
        self.cf_mock.disconnected = Caller()

        self.log_mock = MagicMock(spec=Log)
        self.cf_mock.log = self.log_mock

        self.log_config_mock = MagicMock(spec=LogConfig)
        self.log_config_mock.data_received_cb = Caller()

        self.sut = SyncLogger(self.cf_mock, self.log_config_mock)

    def test_that_log_configuration_is_added_on_connect(self):
        # Fixture

        # Test
        self.sut.connect()

        # Assert
        self.log_mock.add_config.assert_called_once_with(self.log_config_mock)

    def test_that_logging_is_started_on_connect(self):
        # Fixture

        # Test
        self.sut.connect()

        # Assert
        self.log_config_mock.start.assert_called_once_with()

    def test_connection_status_after_connect(self):
        # Fixture
        self.sut.connect()

        # Test
        actual = self.sut.is_connected()

        # Assert
        self.assertTrue(actual)

    def test_that_callbacks_are_removed_on_disconnect(self):
        # Fixture

        # Test
        self.sut.connect()
        self.sut.disconnect()

        # Assert
        self.assertEqual(0, len(self.cf_mock.disconnected.callbacks))
        self.assertEqual(0,
                         len(self.log_config_mock.data_received_cb.callbacks))

    def test_that_log_config_is_stopped_on_disconnect(self):
        # Fixture
        self.sut.connect()

        # Test
        self.sut.disconnect()

        # Assert
        self.log_config_mock.stop.assert_called_once_with()
        self.log_config_mock.delete.assert_called_once_with()

    def test_that_data_is_received(self):
        # Fixture
        self.sut.connect()

        expected = ('Some ts', 'Some data', 'Some logblock')
        AsyncCallbackCaller(cb=self.log_config_mock.data_received_cb,
                            args=[expected[0], expected[1], expected[2]]
                            ).trigger()

        # Test
        actual = None
        for log_block in self.sut:
            actual = log_block
            break

        # Assert
        self.assertEqual(expected, actual)

    def test_connection_status_after_disconnect(self):
        # Fixture
        self.sut.connect()
        self.sut.disconnect()

        # Test
        actual = self.sut.is_connected()

        # Assert
        self.assertFalse(actual)

    def test_that_connect_to_connected_instance_raises_exception(self):
        # Fixture
        self.sut.connect()

        # Test
        # Assert
        with self.assertRaises(Exception):
            self.sut.connect()

    def test_connect_to_disconnected_instance(self):
        # Fixture
        self.sut.connect()
        self.sut.disconnect()

        # Test
        self.sut.connect()

        # Assert
        # Nothing here. Just not expecting an exception

    def test_disconnect_from_disconnected_instance(self):
        # Fixture

        # Test
        self.sut.disconnect()

        # Assert
        # Nothing here. Just not expecting an exception

    def test_connect_disconnect_with_context_management(self):
        # Fixture

        # Test
        with(SyncLogger(self.cf_mock, self.log_config_mock)) as sut:
            # Assert
            self.assertTrue(sut.is_connected())

        self.assertFalse(sut.is_connected())

    def test_that_iterator_is_implemented(self):
        # Fixture

        # Test
        actual = self.sut.__iter__()

        # Assert
        self.assertEqual(self.sut, actual)

    def test_construction_with_sync_crazyflie_instance(self):
        # Fixture
        scf_mock = MagicMock(spec=SyncCrazyflie)
        scf_mock.cf = self.cf_mock

        # Test
        sut = SyncLogger(scf_mock, self.log_config_mock)
        sut.connect()

        # Assert
        # Nothing here. Just not expecting an exception

    def test_getting_data_without_conection_raises_exception(self):
        # Fixture

        # Test
        with self.assertRaises(StopIteration):
            self.sut.__next__()

            # Assert

    def test_lost_connection_in_crazyflie_disconnects(self):
        # Fixture
        self.sut.connect()

        # Test
        AsyncCallbackCaller(cb=self.cf_mock.disconnected,
                            args=['Some uri']
                            ).call_and_wait()

        # Assert
        self.assertFalse(self.sut.is_connected())

    def test_lost_connection_in_crazyflie_raises_exception_in_iterator(self):
        # Fixture
        self.sut.connect()

        # Note this is not foolproof, the disconnected callback may be called
        # before we are waiting on data. It will raise the same exception
        # though and will pass
        AsyncCallbackCaller(cb=self.cf_mock.disconnected,
                            delay=0.5,
                            args=['Some uri']
                            ).trigger()

        # Test
        # Assert
        with self.assertRaises(StopIteration):
            self.sut.__next__()