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
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 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 __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
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
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
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)
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
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 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
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")
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 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
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']}
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__()