class Plan(): border_distance = 200 def __init__(self) -> None: self.logging = Logging("events") self.display = DisplayBlock() self.rgb = RgbLedBlock() self.rgb.set_on() self.distance_block = DistanceBlock(measurement_period=0.05) self.smooth_distance = SmoothedVariable(3, SmoothingType.progressive, self.distance_block.value) self.short_distance_event = self.smooth_distance.less_than( self.border_distance, True, self.short_distance) self.smooth_distance.more_than(self.border_distance, True, self.long_distance) self.power_save_state = 0 Planner.repeat(0.5, self.get_distance) def short_distance(self): self.logging.info("short_distance") self.rgb.set_color(RgbLedBlockColor.red) def long_distance(self): self.logging.info("long_distance") self.rgb.set_color(RgbLedBlockColor.green) def get_distance(self): raw_distance = self.distance_block.value.get(False) self.display.clean() self.display.print_text(0, 0, str(raw_distance)) self.display.print_text(0, 9, str(int(self.smooth_distance.get()))) self.display.showtime()
class Plan(): def __init__(self) -> None: self.logging = Logging("events") self.rgb = RgbLedBlock() self.ir_block = IrBlock() self.ir_block.add_remote(IrNumericRemote()) #to demonstrate equal to self.ir_block.value.equal_to(RemoteKey("0"), True, self.light_off) Ble.value_remote.equal_to(RemoteKey("0"), True, self.light_off) #to demonstrate changed self.ir_block.value.updated(True, self.changed, self.ir_block.value) Ble.value_remote.updated(True, self.changed, Ble.value_remote) def changed(self, active_value): value = active_value.get() if value and value.name.isdigit(): key_number = int(value.name) if key_number > 0 and key_number < 10: self.rgb.set_color_by_id(key_number) self.logging.info("set color with id:%d", key_number) def light_off(self): self.rgb.set_off() self.logging.info("light turned off")
def __init__(self, dim_x, dim_y) -> None: self.logging = Logging("map") self.map_layers = [] self.current_x = 0 self.dim_x = dim_x self.dim_y = dim_y self.removed_count = 0 self.init()
def init(cls) -> None: PowerMgmt.register_management_change_callback( cls._set_power_save_timeouts) cls._set_power_save_timeouts( PowerMgmt.get_plan()) # to be set defaults Planner.plan(cls._check_time_to_power_save, True) Logging.add_logger(BleLogger) cls._start_ble( ) #to be allocated big blocks in the beginning it should prevent memory fragmentation cls.just_initialized = True
def __init__(self) -> None: self.logging = Logging("events") self.chassis = Chassis(0x20, 0x21) Ble.value_remote.equal_to(RemoteKey("a"), True, self.turn_left) Ble.value_remote.equal_to(RemoteKey("d"), True, self.turn_right) Ble.value_remote.equal_to(RemoteKey("w"), True, self.speed_up) Ble.value_remote.equal_to(RemoteKey("s"), True, self.slow_down) Ble.value_remote.equal_to(RemoteKey("z"), True, self.stop) Ble.value_remote.equal_to(RemoteKey("x"), True, self.reverse) Planner.repeat(1, self.print_power_info)
def __init__(self) -> None: self.logging = Logging("events") self.rgb = RgbLedBlock() self.ir_block = IrBlock() self.ir_block.add_remote(IrNumericRemote()) #to demonstrate equal to self.ir_block.value.equal_to(RemoteKey("0"), True, self.light_off) Ble.value_remote.equal_to(RemoteKey("0"), True, self.light_off) #to demonstrate changed self.ir_block.value.updated(True, self.changed, self.ir_block.value) Ble.value_remote.updated(True, self.changed, Ble.value_remote)
class Plan: def __init__(self) -> None: self.button = ButtonBlock(measurement_period=0.1) self.led = RgbLedBlock() self.logging = Logging() self.button.value.changed(True, self._button_state_changed) def _button_state_changed(self): if self.button.value.get(): self.led.set_on() self.logging.info("button pressed") else: self.led.set_off() self.logging.info("button released")
def __init__(self) -> None: self.logging = Logging("events") self.chassis = Chassis(power_measurement_period=0.3) self.rgb = RgbLedBlock() self.display = DisplayBlock() self.distance = DistanceBlock(measurement_period=0.1) self.button = ButtonBlock(measurement_period=0.1) self.ir_block = IrBlock() self.ir_block.add_remote(IrNumericRemote()) self.button.value.equal_to(True, True, self.change_patrol) self.near_barrier_event = None self.far_bariier_event = None self.enough_space_event = None self.open_space_event = None self.patrol = False self.display.contrast(0) Ble.value_remote.equal_to(RemoteKey("a"), True, self.turn_left) Ble.value_remote.equal_to(RemoteKey("d"), True, self.turn_right) Ble.value_remote.equal_to(RemoteKey("w"), True, self.speed_up) Ble.value_remote.equal_to(RemoteKey("s"), True, self.slow_down) Ble.value_remote.equal_to(RemoteKey("z"), True, self.stop) Ble.value_remote.equal_to(RemoteKey("x"), True, self.reverse) Ble.value_remote.equal_to(RemoteKey("p"), True, self.change_patrol) self.ir_block.value.equal_to(IrNumericRemote.key_left, True, self.turn_left) self.ir_block.value.equal_to(IrNumericRemote.key_right, True, self.turn_right) self.ir_block.value.equal_to(IrNumericRemote.key_top, True, self.speed_up) self.ir_block.value.equal_to(IrNumericRemote.key_bottom, True, self.slow_down) self.ir_block.value.equal_to(IrNumericRemote.key_ok, True, self.stop) self.ir_block.value.equal_to(IrNumericRemote.key_hash, True, self.reverse) self.ir_block.value.equal_to(IrNumericRemote.key_star, True, self.change_patrol) self.counter = 0 Planner.repeat(0.5, self.print_power_info) PowerMgmt.set_plan(PowerPlan.get_max_performance_plan()) self.current_smoother = SmoothedVariable( 3, SmoothingType.average, self.chassis.power.battery_current_mA) self.current_smoother.more_than(600, True, self.stop_for_a_while, 1) self.heart_beat = False
def __init__(self): self.started = False self.display = DisplayBlock() self.logging = Logging("plan") self.button = ButtonBlock() self.rgb = RgbLedBlock() self.led_default() self.dim_x, self.dim_y = self.display.get_dimensions() self.center_x = int(self.dim_x / 2) self.center_y = int(self.dim_y / 2) self.point = None self.map = None self.score = 0 self.wait_for_start() self.redraw()
def __init__(self) -> None: self.logging = Logging("events") self.display = DisplayBlock() self.rgb = RgbLedBlock() self.rgb.set_on() self.distance_block = DistanceBlock(measurement_period=0.05) self.smooth_distance = SmoothedVariable(3, SmoothingType.progressive, self.distance_block.value) self.short_distance_event = self.smooth_distance.less_than( self.border_distance, True, self.short_distance) self.smooth_distance.more_than(self.border_distance, True, self.long_distance) self.power_save_state = 0 Planner.repeat(0.5, self.get_distance)
class Plan(): def __init__(self) -> None: self.logging = Logging("events") self.chassis = Chassis(0x20, 0x21) Ble.value_remote.equal_to(RemoteKey("a"), True, self.turn_left) Ble.value_remote.equal_to(RemoteKey("d"), True, self.turn_right) Ble.value_remote.equal_to(RemoteKey("w"), True, self.speed_up) Ble.value_remote.equal_to(RemoteKey("s"), True, self.slow_down) Ble.value_remote.equal_to(RemoteKey("z"), True, self.stop) Ble.value_remote.equal_to(RemoteKey("x"), True, self.reverse) Planner.repeat(1, self.print_power_info) def print_power_info(self): voltage = self.chassis.power.battery_voltage_V.get() current = self.chassis.power.battery_current_mA.get() self.logging.info("battery voltage: {0}, current: {1}".format(voltage, current)) def slow_down(self): self.chassis.set_speed(self.chassis.speed - 1) def speed_up(self): self.chassis.set_speed(self.chassis.speed + 1) def turn_left(self): self.chassis.set_manoeuver(self.chassis.manoeuver - 1) def turn_right(self): self.chassis.set_manoeuver(self.chassis.manoeuver + 1) def pressed_l(self): self.chassis.set_direction(self.chassis.direction - 1) def reverse(self): self.logging.info(self.chassis.direction == Direction.forward) self.chassis.set_direction(Direction.backward if self.chassis.direction == Direction.forward else Direction.forward) def stop(self): self.chassis.set_speed(Speed.stop) self.chassis.set_manoeuver(Manoeuver.straight)
def __init__(self, address_driver_front=0x20, address_driver_rear=0x21, addr_power=None, power_measurement_period=1): self.speed = Speed.stop self.manoeuver = Manoeuver.straight self.direction = Direction.forward self.logging = Logging("chassis") self.power = PowerBlock(addr_power, power_measurement_period) self.front_driver = MotorDriverBlock(address_driver_front) self.rear_driver = MotorDriverBlock(address_driver_rear)
def __init__(self, block_type: BlockType, address: int): self.type_id = block_type.id self.address = address if address else block_type.id #default block i2c address is equal to its block type self.block_type_valid = False self.logging = Logging(block_type.name.decode("utf-8")) self.block_version = self._get_block_version() self.power_save_level = PowerSaveLevel.NoPowerSave self._tiny_write_base_id(_power_save_command, self.power_save_level.to_bytes(1, 'big'), True) #wake up block functionality if not self.block_version: self.logging.warning("module with address 0x%x is not available", self.address) elif self.block_version[0] != self.type_id: self.logging.error( "unexpected block type. expected: %d, returned: %d", self.type_id, self.block_version[0]) else: self.block_type_valid = True
def plan(): logging = Logging() display = DisplayBlock() dim_x, dim_y = display.get_dimensions() logging.info("resolution x: %d, y: %d" % (dim_x, dim_y)) display.draw_ellipse(int(dim_x / 2), int(dim_y / 2), int(dim_x / 2) - 5, int(dim_y / 2) - 5) text = "Hallo" letter_width = 8 letter_height = 8 text_x = int(dim_x / 2) - int(len(text) * letter_width / 2) + 1 text_y = int(dim_y / 2) - int(letter_height / 2) - 1 display.print_text(text_x, text_y, text) line_y = text_y + letter_height + 2 display.draw_line(text_x, line_y, text_x + len(text) * letter_width - 2, line_y) display.showtime()
class ActiveVariable(): logging = Logging("act_var") def __init__(self, initial_value=None, renew_period:float=0, renew_func=None): """ @param initial_value: if is set Active variable will be preset to this value @param renew_period: renew_func will be called with this period if this value > 0 @param renew_func: this method will be called periodically if renew_period is > 0 or if get is called with the parameter "force" """ self._old_value = initial_value self._value = initial_value self._renew_period = renew_period self._renew_func = renew_func self._renew_handle = None self._listeners = list() self._handle_count = 0 def change_period(self, new_period): self._renew_period = new_period if self._renew_handle: Planner.kill_task(self._renew_handle) self._renew_handle = None if self._renew_period > 0: self._renew_handle = Planner.repeat(self._renew_period, self._update_value) def set(self, value): if value is None: return #nothing to compare self._old_value = self._value self._value = value for listener in self._listeners: _type = listener[1] repeat = listener[2] if _type == Conditions.equal_to: if isinstance(value, float) or isinstance(listener[3], float): if (self._old_value is None or not math.isclose(self._old_value, listener[3])) and math.isclose(value, listener[3]): if not repeat: self._remove_listener(listener) #TODO: maybe it can be returned to the end of this method it should not be important for the called methd that it will be removed later - events are synchronous listener[4](*listener[5], **listener[6]) else: if (self._old_value is None or self._old_value != listener[3]) and value == listener[3]: if not repeat: self._remove_listener(listener) listener[4](*listener[5], **listener[6]) elif _type == Conditions.not_equal_to: if isinstance(value, float) or isinstance(listener[3], float): if (self._old_value is None or math.isclose(self._old_value, listener[3])) and not math.isclose(value, listener[3]): if not repeat: self._remove_listener(listener) listener[4](*listener[5], **listener[6]) else: if (self._old_value is None or self._old_value == listener[3]) and value != listener[3]: if not repeat: self._remove_listener(listener) listener[4](*listener[5], **listener[6]) elif _type == Conditions.less_than: if (self._old_value is None or self._old_value >= listener[3]) and value < listener[3]: if not repeat: self._remove_listener(listener) listener[4](*listener[5], **listener[6]) elif _type == Conditions.more_than: if (self._old_value is None or self._old_value <= listener[3]) and value > listener[3]: if not repeat: self._remove_listener(listener) listener[4](*listener[5], **listener[6]) elif _type == Conditions.in_range: if (self._old_value is None or self._old_value < listener[3] or self._old_value >= listener[4]) and value >= listener[3] and value < listener[4]: if not repeat: self._remove_listener(listener) listener[5](*listener[6], **listener[7]) elif _type == Conditions.out_of_range: if (self._old_value is None or self._old_value >= listener[3] and self._old_value < listener[4]) and (value < listener[3] or value >= listener[4]): if not repeat: self._remove_listener(listener) listener[5](*listener[6], **listener[7]) elif _type == Conditions.value_changed: if value != self._old_value: if not repeat: self._remove_listener(listener) listener[3](*listener[4], **listener[5]) elif _type == Conditions.value_updated: if not repeat: self._remove_listener(listener) listener[3](*listener[4], **listener[5]) else: self.logging.error("unknown listener type %s" % str(listener[1])) def get(self, force=False): if force: self._update_value() return self._value def get_previous_value(self): return self._old_value def _update_value(self): if self._renew_func: self.set(self._renew_func()) def _add_listener(self, listener): if not self._listeners and self._renew_period > 0: self._renew_handle = Planner.repeat(self._renew_period, self._update_value) self._listeners.append(listener) self._handle_count += 1 return listener[0] #returns provided handle def remove_trigger(self, handle): for listener in self._listeners: if listener[0] == handle: self._listeners.remove(listener) if not self._listeners: Planner.kill_task(self._renew_handle) self._renew_handle = None return True return False def _remove_listener(self, listener): return self.remove_trigger(listener[0]) def equal_to(self, expected, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly equal to expected value """ return self._add_listener((self._handle_count, Conditions.equal_to, repetitive, expected, function, args, kwargs)) def not_equal_to(self, expected, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly not equal to expected value """ return self._add_listener((self._handle_count, Conditions.not_equal_to, repetitive, expected, function, args, kwargs)) def less_than(self, expected, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly smaller than expected value """ return self._add_listener((self._handle_count, Conditions.less_than, repetitive, expected, function, args, kwargs)) def more_than(self, expected, repetitive:bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly bigger than expected value """ return self._add_listener((self._handle_count, Conditions.more_than, repetitive, expected, function, args, kwargs)) def in_range(self, expected_min, expected_max, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly bigger or equal to expected_min value and smaller that expected_max value """ return self._add_listener((self._handle_count, Conditions.in_range, repetitive, expected_min, expected_max, function, args, kwargs)) def out_of_range(self, expected_min, expected_max, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is newly smaller than expected_min value or bigger or equal to expected_max value """ return self._add_listener((self._handle_count, Conditions.out_of_range, repetitive, expected_min, expected_max, function, args, kwargs)) def changed(self, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called when measured value is different that last time measured value """ return self._add_listener((self._handle_count, Conditions.value_changed, repetitive, function, args, kwargs)) def updated(self, repetitive: bool, function: callable, *args, **kwargs): """ provided function with arguments will be called always when a value is measured """ return self._add_listener((self._handle_count, Conditions.value_updated, repetitive, function, args, kwargs)) def __str__(self): return str(self.get())
class Plan(): near_barrier = 300 far_barrier = 600 open_space = 900 def __init__(self) -> None: self.logging = Logging("events") self.chassis = Chassis(power_measurement_period=0.3) self.rgb = RgbLedBlock() self.display = DisplayBlock() self.distance = DistanceBlock(measurement_period=0.1) self.button = ButtonBlock(measurement_period=0.1) self.ir_block = IrBlock() self.ir_block.add_remote(IrNumericRemote()) self.button.value.equal_to(True, True, self.change_patrol) self.near_barrier_event = None self.far_bariier_event = None self.enough_space_event = None self.open_space_event = None self.patrol = False self.display.contrast(0) Ble.value_remote.equal_to(RemoteKey("a"), True, self.turn_left) Ble.value_remote.equal_to(RemoteKey("d"), True, self.turn_right) Ble.value_remote.equal_to(RemoteKey("w"), True, self.speed_up) Ble.value_remote.equal_to(RemoteKey("s"), True, self.slow_down) Ble.value_remote.equal_to(RemoteKey("z"), True, self.stop) Ble.value_remote.equal_to(RemoteKey("x"), True, self.reverse) Ble.value_remote.equal_to(RemoteKey("p"), True, self.change_patrol) self.ir_block.value.equal_to(IrNumericRemote.key_left, True, self.turn_left) self.ir_block.value.equal_to(IrNumericRemote.key_right, True, self.turn_right) self.ir_block.value.equal_to(IrNumericRemote.key_top, True, self.speed_up) self.ir_block.value.equal_to(IrNumericRemote.key_bottom, True, self.slow_down) self.ir_block.value.equal_to(IrNumericRemote.key_ok, True, self.stop) self.ir_block.value.equal_to(IrNumericRemote.key_hash, True, self.reverse) self.ir_block.value.equal_to(IrNumericRemote.key_star, True, self.change_patrol) self.counter = 0 Planner.repeat(0.5, self.print_power_info) PowerMgmt.set_plan(PowerPlan.get_max_performance_plan()) self.current_smoother = SmoothedVariable( 3, SmoothingType.average, self.chassis.power.battery_current_mA) self.current_smoother.more_than(600, True, self.stop_for_a_while, 1) self.heart_beat = False def define_patrol_events(self): self.near_barrier_event = self.distance.value.less_than( self.near_barrier, True, self.near_barrier_detected) self.far_bariier_event = self.distance.value.in_range( self.near_barrier, self.far_barrier, True, self.far_barrier_detected) self.enough_space_event = self.distance.value.in_range( self.far_barrier, self.open_space, True, self.enough_space_detected) self.open_space_event = self.distance.value.more_than( self.open_space - 1, True, self.open_space_detected) def cancel_patrol_events(self): self.distance.value.remove_trigger(self.near_barrier_event) self.distance.value.remove_trigger(self.far_bariier_event) self.distance.value.remove_trigger(self.enough_space_event) self.distance.value.remove_trigger(self.open_space_event) def near_barrier_detected(self): self.logging.info("near_barrier_detected") self.rgb.set_color(RgbLedBlockColor.red) self.chassis.set_speed(Speed.slow) self.chassis.set_direction(Direction.backward) self.chassis.set_manoeuver( Manoeuver.sharply_right) #with reverse will turn left def far_barrier_detected(self): self.logging.info("far_barrier_detected") self.rgb.set_color(RgbLedBlockColor.orange) self.chassis.set_speed(Speed.slow) self.chassis.set_direction(Direction.forward) self.chassis.set_manoeuver(Manoeuver.straight) def enough_space_detected(self): self.logging.info("enough_space") self.rgb.set_color(RgbLedBlockColor.blue) self.chassis.set_speed(Speed.normal) self.chassis.set_direction(Direction.forward) self.chassis.set_manoeuver(Manoeuver.straight) def open_space_detected(self): self.logging.info("open_space") self.rgb.set_color(RgbLedBlockColor.green) self.chassis.set_speed(Speed.normal) self.chassis.set_direction(Direction.forward) self.chassis.set_manoeuver( Manoeuver.slightly_right) #can rotate another wat def change_patrol(self): if self.patrol: self.logging.info("patrol mode canceled") self.cancel_patrol_events() self.chassis.set_speed(Speed.stop) else: self.logging.info("patrol mode activated") self.define_patrol_events() self.chassis.set_speed(Speed.slow) self.patrol = not self.patrol def print_power_info(self): voltage = self.chassis.power.battery_voltage_V.get() self.display.clean() self.heart_beat = not self.heart_beat if self.heart_beat: self.display.print_text(55, 0, "*") self.display.print_text(0, 9, "%2.3f V" % voltage) self.display.print_text(0, 18, "%3.2f mA" % self.current_smoother.get()) self.display.print_text(0, 36, str(self.distance.value.get())) self.counter += 1 self.display.showtime() def slow_down(self): self.chassis.set_speed(self.chassis.speed - 1) def speed_up(self): self.chassis.set_speed(self.chassis.speed + 1) def turn_left(self): self.chassis.set_manoeuver(self.chassis.manoeuver - 1) def turn_right(self): self.chassis.set_manoeuver(self.chassis.manoeuver + 1) def reverse(self): self.logging.info(self.chassis.direction == Direction.forward) self.chassis.set_direction(Direction.backward if self.chassis.direction == Direction.forward else Direction.forward) def stop_for_a_while(self, delay): self.stop() #take a rest Planner.postpone(delay, self.chassis.set_speed, Speed.slow) #... and slowly continue def stop(self): self.chassis.set_speed(Speed.stop) self.chassis.set_manoeuver(Manoeuver.straight)
class Plan(): fullspeed = 100 logging = Logging("events") def __init__(self) -> None: self.speed = 0 self.pwm = 50 Ble.value_remote.equal_to(RemoteKey("a"), True, self.pwm_down) Ble.value_remote.equal_to(RemoteKey("d"), True, self.pwm_up) Ble.value_remote.equal_to(RemoteKey("w"), True, self.speed_up) Ble.value_remote.equal_to(RemoteKey("s"), True, self.slow_down) Ble.value_remote.equal_to(RemoteKey("z"), True, self.stop) Ble.value_remote.equal_to(RemoteKey("o"), True, self.full_speed_up) Ble.value_remote.equal_to(RemoteKey("l"), True, self.full_speed_down) self.motor_driver_front = MotorDriverBlock(0x20) #self.motor_driver_front.change_block_address(0x20) self.motor_driver_front.turn_clockwise(MotorDriverBlock.motor1_id) self.motor_driver_front.turn_opposite(MotorDriverBlock.motor2_id) self.motor_driver_rear = MotorDriverBlock(0x21) #self.motor_driver_rear.change_block_address(0x21) self.motor_driver_rear.turn_clockwise(MotorDriverBlock.motor1_id) self.motor_driver_rear.turn_opposite(MotorDriverBlock.motor2_id) self.motor_driver_front.sensor_power_on() self.motor_driver_rear.sensor_power_on() self.motor_driver_front.reset_sensor_counter( MotorDriverBlock.motor1_id) self.motor_driver_front.reset_sensor_counter( MotorDriverBlock.motor2_id) self.motor_driver_rear.reset_sensor_counter(MotorDriverBlock.motor1_id) self.motor_driver_rear.reset_sensor_counter(MotorDriverBlock.motor2_id) Planner.repeat(1, self.print_counters) def print_counters(self): counter11 = self.motor_driver_front.get_sensor_counter( MotorDriverBlock.motor1_id) counter12 = self.motor_driver_front.get_sensor_counter( MotorDriverBlock.motor2_id) counter21 = self.motor_driver_rear.get_sensor_counter( MotorDriverBlock.motor1_id) counter22 = self.motor_driver_rear.get_sensor_counter( MotorDriverBlock.motor2_id) self.logging.info( "counter11: {0}, counter12: {1}, counter21: {2}, counter22: {3}". format(counter11, counter12, counter21, counter22)) def _adjust_motors(self): self.logging.info("fullspeed: %d, speed: %d, pwm: %d" % (self.fullspeed, self.speed, self.pwm)) fullspeed = 0 if self.fullspeed > 0: self.motor_driver_front.turn_clockwise(MotorDriverBlock.motor1_id) self.motor_driver_rear.turn_clockwise(MotorDriverBlock.motor1_id) fullspeed = self.fullspeed else: self.motor_driver_front.turn_opposite(MotorDriverBlock.motor1_id) self.motor_driver_rear.turn_opposite(MotorDriverBlock.motor1_id) fullspeed = self.fullspeed * -1 self.motor_driver_front.set_speed(MotorDriverBlock.motor1_id, fullspeed) self.motor_driver_front.set_speed(MotorDriverBlock.motor2_id, self.speed) self.motor_driver_rear.set_speed(MotorDriverBlock.motor1_id, fullspeed) self.motor_driver_rear.set_speed(MotorDriverBlock.motor2_id, self.speed) self.motor_driver_front.set_pwm_period(self.pwm) self.motor_driver_rear.set_pwm_period(self.pwm) def full_speed_up(self): self.fullspeed += 10 self._adjust_motors() def full_speed_down(self): self.fullspeed -= 10 self._adjust_motors() def pwm_up(self): self.pwm += 10 self._adjust_motors() def pwm_down(self): self.pwm -= 10 self._adjust_motors() def speed_up(self): self.speed += 5 self._adjust_motors() def slow_down(self): self.speed -= 5 self._adjust_motors() def stop(self): self.motor_driver_front.stop(MotorDriverBlock.motor1_id) self.motor_driver_front.stop(MotorDriverBlock.motor2_id) self.motor_driver_rear.stop(MotorDriverBlock.motor1_id) self.motor_driver_rear.stop(MotorDriverBlock.motor2_id)
class Map: def __init__(self, dim_x, dim_y) -> None: self.logging = Logging("map") self.map_layers = [] self.current_x = 0 self.dim_x = dim_x self.dim_y = dim_y self.removed_count = 0 self.init() def add_map_layer(self, top_y, bottom_y, diamond): self.map_layers.append(MapLayer(top_y, bottom_y, diamond)) def get_borders(self, x): pos = self.current_x + x - self.removed_count try: layer = self.map_layers[pos] return layer.top, self.dim_y - layer.bottom except Exception: self.logging.error(pos) def remove_diamond(self, diamond): for layer in self.map_layers: if layer.diamond == diamond: layer.diamond = None def get_diamonds(self, x): diamonds = list() for current_x in range(x - int(Diamond.max_dim), x + int(Diamond.max_dim) + 1): pos = self.current_x + current_x - self.removed_count layer = self.map_layers[pos] if layer.diamond: diamonds.append(layer.diamond) return diamonds def add_random_layers(self, count): for _index in range(count): top_min = 8 bottom_min = 0 last_top = self.map_layers[-1].top last_bottom = self.map_layers[-1].bottom change_top = int(random.random() * 3) - 1 change_bottom = int(random.random() * 3) - 1 top_pos = last_top - change_top if last_top - change_top > top_min else top_min bottom_pos = last_bottom - change_bottom if last_bottom - change_bottom > bottom_min else bottom_min if top_pos + bottom_pos > self.dim_y - 20: if top_pos - top_min > bottom_pos: top_pos -= top_pos + bottom_pos - (self.dim_y - 20) else: bottom_pos -= top_pos + bottom_pos - (self.dim_y - 20) diamond = None if self.current_x + _index > 10 and (self.current_x + _index) % ( Diamond.max_dim * 2) == 0 and int( random.random() * 10) > 5: is_top = True if int(random.random() * 2) else False dimension = int(random.random() * (Diamond.dim_diff * 2 + 1)) - Diamond.dim_diff + Diamond.base_dim embedding = 1 if dimension < Diamond.base_dim else 2 if is_top: diamond = Diamond(top_pos + dimension - embedding, True, dimension) else: diamond = Diamond( self.dim_y - bottom_pos - dimension + embedding, False, dimension) self.add_map_layer(top_pos, bottom_pos, diamond) def remove_first_layers(self, count): self.map_layers = self.map_layers[count:] self.removed_count += count def init(self): self.map_layers = [] self.add_map_layer(11, 2, None) self.add_random_layers(100) self.current_x = 0 def is_enough_data(self): return self.current_x - self.removed_count + self.dim_x < len( self.map_layers) def draw(self, display: DisplayBlock): for x in range(self.dim_x): pos = self.current_x + x - self.removed_count if x >= 0: layer = self.map_layers[pos] display.draw_line(x, layer.top, x, 0) display.draw_line(x, self.dim_y - layer.bottom - 1, x, self.dim_y - 1) if layer.diamond: layer.diamond.draw(x, display)
class Plan: def __init__(self): self.started = False self.display = DisplayBlock() self.logging = Logging("plan") self.button = ButtonBlock() self.rgb = RgbLedBlock() self.led_default() self.dim_x, self.dim_y = self.display.get_dimensions() self.center_x = int(self.dim_x / 2) self.center_y = int(self.dim_y / 2) self.point = None self.map = None self.score = 0 self.wait_for_start() self.redraw() def wait_for_start(self): self.started = False self.score = 0 self.point = Point(self.center_y) self.map = Map(self.dim_x, self.dim_y) self.display.invert(True) self.button.value.changed(False, self.start_button) gc.collect() #force garbage collection before game starts def start_button(self): self.started = True self.logging.info("started") self.redraw() self.led_default() def redraw(self): speed = int(self.map.current_x / 400) + 1 if speed > 10: speed = 10 if not self.map.is_enough_data(): remove_step_count = speed self.map.remove_first_layers(remove_step_count) self.map.add_random_layers(remove_step_count) self.display.clean() self.point.draw(self.display) if self.started: if self.button.value.get(): self.point.y -= 2 else: self.point.y += 2 border_top, border_bottom = self.map.get_borders(self.point.x) touch = False if self.point.y < border_top + self.point.r - 1: self.point.y = border_top + self.point.r touch = True if self.point.y > border_bottom - self.point.r: self.point.y = border_bottom - self.point.r touch = True if not touch: diamonds = self.map.get_diamonds(self.point.x) for diamond in diamonds: if diamond.is_in_area(self.point.y - self.point.r, self.point.y + self.point.r): self.map.remove_diamond(diamond) self.score += 1 self.rgb.set_color(RgbLedBlockColor.green) Planner.postpone(0.05, self.led_default) self.map.draw(self.display) if self.started: self.display.invert(False if touch else True) self.map.current_x += speed #score = int(self.map.current_x / 10) self.display.print_text(0, 0, str(self.score), color=0) self.display.showtime() if not touch: Planner.postpone(0.05, self.redraw) else: self.started = False self.rgb.set_color(RgbLedBlockColor.red) Planner.postpone( 1, self.wait_for_reset_pressed ) #wait a while to prevent random press and wait for starting new game def led_default(self): self.rgb.set_color(RgbLedBlockColor.aquamarine) def wait_for_reset_pressed(self): self.button.value.equal_to(True, False, self.wait_for_reset_released) def wait_for_reset_released(self): self.button.value.equal_to(False, False, self.wait_for_start)
def __init__(self) -> None: self.button = ButtonBlock(measurement_period=0.1) self.led = RgbLedBlock() self.logging = Logging() self.button.value.changed(True, self._button_state_changed)
class Shell(): events_file_name = "events.mpy" do_not_import_file_name = ".do_not_import_import" file_path = None new_file = False path = [""] dir_contents = list() dir_positions = list() logging = Logging("Shell") events_imported = False @classmethod def file_exists(cls, path): try: file = open(path, "r") file.close() return True except OSError: # open failed return False @classmethod def create_file(cls, file_path): with open(file_path, "w"): pass @classmethod def remove_file(cls, file_path): os.remove(file_path) @classmethod def rename_file(cls, orig_file_path, dest_file_path): os.rename(orig_file_path, dest_file_path) @classmethod def _reboot(cls): MainBlock.reboot() @classmethod def _import_events(cls): if not cls.file_exists(cls.events_file_name): print("events file not found") return False try: print("events will be imported") import events #events will planned cls.logging.info("events loaded successfully") cls.events_imported = True return True except Exception as error: cls.logging.exception(error, extra_message="events.py was not imported properly") import sys sys.print_exception(error, sys.stdout) return False @classmethod def load_events(cls): if cls.file_exists(cls.do_not_import_file_name): print("do_not_import_file_name removed") cls.remove_file(cls.do_not_import_file_name) else: cls._import_events() @classmethod def read_chunks(file, chunk_size): while True: data = file.read(chunk_size) if not data: break yield data @classmethod def _get_file_checksum(cls, file_path): sha1 = hashlib.sha1(b"") with open(file_path, "rb") as file: while True: chunk = file.read(1000) if not chunk: break sha1.update(chunk) return sha1.digest() @classmethod def _get_path(cls): path = "" for item in cls.path: path += item + "/" return path @classmethod def _is_file(cls, path): try: f = open(path, "r") f.close() return True except OSError: return False @classmethod def _get_next_file_info(cls): path = cls._get_path() if len(cls.dir_contents) < len(cls.path): cls.dir_contents.append(os.listdir(path)) cls.dir_positions.append(0) if cls.dir_positions[-1] >= len(cls.dir_contents[-1]): if len(cls.dir_positions) > 1: cls.dir_contents = cls.dir_contents[:-1] cls.dir_positions = cls.dir_positions[:-1] cls.path = cls.path[:-1] return cls._get_next_file_info() else: return ble_ids.b_false #proceses last file of root directory name = cls.dir_contents[-1][cls.dir_positions[-1]] file_path = path + name cls.dir_positions[-1] += 1 if cls._is_file(file_path): return cls._get_file_checksum(file_path) + file_path.encode("utf-8") else: cls.path.append(name) return cls._get_next_file_info() @classmethod def command_request(cls, command, data): if command == ble_ids.cmd_common_version: return ble_ids.b_true elif command == ble_ids.cmd_shell_program_started: return (ble_ids.b_true if cls.events_imported else ble_ids.b_false) elif command == ble_ids.cmd_shell_stop_program: print("cmd_stop_program") if data[0] == ble_ids.b_true and cls.file_exists(cls.events_file_name): print("do not import file will be created") cls.create_file(cls.do_not_import_file_name) print("reboot planned") Planner.postpone(0.1, cls._reboot) return ble_ids.b_true elif command == ble_ids.cmd_shell_start_program: return (ble_ids.b_true if cls._import_events() else ble_ids.b_false) elif command == ble_ids.cmd_shell_get_next_file_info: return cls._get_next_file_info() elif command == ble_ids.cmd_shell_remove_file: cls.remove_file(data) return ble_ids.b_true elif command == ble_ids.cmd_shell_handle_file: cls.handeled_file_path = data cls.new_file = True return ble_ids.b_true elif command == ble_ids.cmd_shell_get_file_checksum: return cls._get_file_checksum(cls.handeled_file_path) elif command == ble_ids.cmd_shell_append: if cls.new_file: file = open(cls.handeled_file_path, "wb") cls.new_file = False else: file = open(cls.handeled_file_path, "ab") file.write(data) file.close() return ble_ids.b_true elif command == ble_ids.cmd_shell_mk_dir: try: os.mkdir(data) except Exception: return ble_ids.b_false return ble_ids.b_true else: return None
def _info(cls, message_id:str, activeVariable:ActiveVariable): Logging(message_id).value(str(activeVariable))
# Copyright (c) 2022 Jakub Vesely # This software is published under MIT license. Full text of the license is available at https://opensource.org/licenses/MIT from basal.logging import Logging from basal.power_mgmt import PowerMgmt import sys import time import uasyncio import gc logging = Logging("planner") unhandled_exception_prefix = "Unhandled exception" class TaskProperties: kill = False waiting_start_ms = 0 waiting_time_ms = 0 class Planner: _performed_tasks = { } #expected dict with task handle as key and tasks properties as value _handle_count = 0 _loop = uasyncio.get_event_loop() _power_mgmt = PowerMgmt() @classmethod def _get_next_handle(cls): handle = cls._handle_count cls._handle_count += 1
class BlockBase: i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21), freq=100000) def __init__(self, block_type: BlockType, address: int): self.type_id = block_type.id self.address = address if address else block_type.id #default block i2c address is equal to its block type self.block_type_valid = False self.logging = Logging(block_type.name.decode("utf-8")) self.block_version = self._get_block_version() self.power_save_level = PowerSaveLevel.NoPowerSave self._tiny_write_base_id(_power_save_command, self.power_save_level.to_bytes(1, 'big'), True) #wake up block functionality if not self.block_version: self.logging.warning("module with address 0x%x is not available", self.address) elif self.block_version[0] != self.type_id: self.logging.error( "unexpected block type. expected: %d, returned: %d", self.type_id, self.block_version[0]) else: self.block_type_valid = True def _raw_tiny_write(self, type_id: int, command: int, data=None, silent=False): try: payload = type_id.to_bytes(1, 'big') + command.to_bytes(1, 'big') if data: payload += data #self.logging.info(("write", payload)) self.i2c.writeto(self.address, payload) except OSError: if not silent: self.logging.error( "tiny-block with address 0x%02X is unavailable for writing", self.address) def _check_type(self, type_id): return type_id in (_i2c_block_type_id_base, self.type_id) and (_i2c_block_type_id_base or self.block_type_valid) def __tiny_write_common(self, type_id: int, command: int, data=None, silent=False): """ writes data to tiny_block via I2C @param type_id: block type id @param command: one byte command @param data: specify input data for entered command """ if self._check_type(type_id): self._raw_tiny_write(type_id, command, data, silent) else: self.logging.error("invalid block type - writing interupted") def _tiny_write_base_id(self, command: int, data=None, silent=False): self.__tiny_write_common(_i2c_block_type_id_base, command, data, silent) def _tiny_write(self, command: int, data=None, silent=False): if not self.is_available(): return self.__tiny_write_common(self.type_id, command, data, silent) def __tiny_read_common(self, type_id: int, command: int, in_data: typing.Union[bytes, None] = None, expected_length: int = 0, silent=False): """ reads data form tiny_block via I2C @param type_id: block type id @param command: one byte command @param in_data: specify input data for entered command @param expected_length: if defined will be read entered number of bytes. If None is expected length as a first byte @return provided bytes. If size is first byte is not included to output data """ if self._check_type(type_id): self._raw_tiny_write(type_id, command, in_data, silent) try: data = self.i2c.readfrom(self.address, expected_length, True) return data except OSError: if not silent: self.logging.error( "tiny-block with address 0x%02X is unavailable for reading", self.address) return None else: self.logging.error("invalid block type - reading interupted") return None def _tiny_read_base_id(self, command: int, in_data: typing.Union[bytes, None] = None, expected_length: int = 0, silent=False): return self.__tiny_read_common(_i2c_block_type_id_base, command, in_data, expected_length, silent) def _tiny_read(self, command: int, in_data: typing.Union[bytes, None] = None, expected_length: int = 0): if not self.is_available(): return None return self.__tiny_read_common(self.type_id, command, in_data, expected_length) def change_block_address(self, new_address): self._tiny_write_base_id(_change_i2c_address_command, new_address.to_bytes(1, 'big')) self.address = new_address time.sleep(0.1) #wait to the change is performed and stopped def _get_block_version(self): """ returns block_type, pcb version, adjustment_version """ data = self._tiny_read_base_id(_get_module_version_command, None, 3, silent=True) if not data: return b"" return (data[0], data[1], data[2]) def is_available(self): return self.block_type_valid #available and valid block version def power_save(self, level: int) -> None: """ level is aPowerSaveLevel value """ self.power_save_level = level self._tiny_write_base_id(_power_save_command, level.to_bytes(1, 'big'))