def calc_fonts(): """ Iterate through all the Latin "1 & 5" fonts, and use ANSI escape sequences to see how many rows/columns the EV3 LCD console can accommodate for each font """ console = Console() files = [ f for f in listdir("/usr/share/consolefonts/") if f.startswith("Lat15") and f.endswith(".psf.gz") ] files.sort() for font in files: console.set_font(font, True) # position cursor at 50, 50, and ask the console to report its actual cursor position console.text_at("\x1b[6n", 50, 50, False) console.text_at(font, 1, 1, False, True) console.clear_to_eol() # now, read the console response of the actual cursor position, in the form of esc[rr;ccR # requires pressing the center button on the EV3 for each read dims = '' while True: ch = stdin.read(1) if ch == '\x1b' or ch == '[' or ch == '\r' or ch == '\n': continue if ch == 'R': break dims += str(ch) (rows, cols) = dims.split(";") print("({}, {}, \"{}\"),".format(rows, cols, font), file=stderr) sleep(.5)
def write_to_console(self, msg:str, column:int, row:int, reset_console=True, inverse=False, alignment='L', font_size='M'): """Write msg to console at column, and row reset_console clears console first inverse reverses out text alignment: 'L', 'C', or 'R' font_size: 'S', 'M', 'L' Small: 8 rows, 22 columns Medium: 6 rows, 17 columns Large: 4 rows, 12 columns """ console = Console() if font_size == 'S': console.set_font('Lat15-TerminusBoldVGA16.psf.gz', True) elif font_size == 'M': console.set_font('Lat15-Terminus20x10.psf.gz', True) else: console.set_font('Lat15-Terminus32x16.psf.gz', True) console.text_at(msg, column, row, reset_console=reset_console, inverse=inverse, alignment=alignment)
def show_fonts(): """ Iterate over the known Latin "1 & 5" fonts and display each on the EV3 LCD console. Note: `Terminus` fonts are "thinner"; `TerminusBold` and `VGA` offer more contrast on the LCD console and are thus more readable; the `TomThumb` font is waaaaay too small to read! """ # Create a list of tuples with calulated rows, columns, font filename fonts = [ (4, 11, "Lat15-Terminus32x16.psf.gz"), (4, 11, "Lat15-TerminusBold32x16.psf.gz"), (4, 11, "Lat15-VGA28x16.psf.gz"), (4, 11, "Lat15-VGA32x16.psf.gz"), (4, 12, "Lat15-Terminus28x14.psf.gz"), (4, 12, "Lat15-TerminusBold28x14.psf.gz"), (5, 14, "Lat15-Terminus24x12.psf.gz"), (5, 14, "Lat15-TerminusBold24x12.psf.gz"), (5, 16, "Lat15-Terminus22x11.psf.gz"), (5, 16, "Lat15-TerminusBold22x11.psf.gz"), (6, 17, "Lat15-Terminus20x10.psf.gz"), (6, 17, "Lat15-TerminusBold20x10.psf.gz"), (7, 22, "Lat15-Fixed18.psf.gz"), (8, 22, "Lat15-Fixed15.psf.gz"), (8, 22, "Lat15-Fixed16.psf.gz"), (8, 22, "Lat15-Terminus16.psf.gz"), (8, 22, "Lat15-TerminusBold16.psf.gz"), (8, 22, "Lat15-TerminusBoldVGA16.psf.gz"), (8, 22, "Lat15-VGA16.psf.gz"), (9, 22, "Lat15-Fixed13.psf.gz"), (9, 22, "Lat15-Fixed14.psf.gz"), (9, 22, "Lat15-Terminus14.psf.gz"), (9, 22, "Lat15-TerminusBold14.psf.gz"), (9, 22, "Lat15-TerminusBoldVGA14.psf.gz"), (9, 22, "Lat15-VGA14.psf.gz"), (10, 29, "Lat15-Terminus12x6.psf.gz"), (16, 22, "Lat15-VGA8.psf.gz"), (21, 44, "Lat15-TomThumb4x6.psf.gz") ] # Paint the screen full of numbers that represent the column number, reversing the even rows console = Console() for rows, cols, font in fonts: print(rows, cols, font, file=stderr) console.set_font(font, True) for row in range(1, rows + 1): for col in range(1, cols + 1): console.text_at("{}".format(col % 10), col, row, False, (row % 2 == 0)) console.text_at(font.split(".")[0], 1, 1, False, True) console.clear_to_eol() sleep(.5)
def show_fonts(): """ Iterate through all the Latin "1 & 5" fonts, and see how many rows/columns the EV3 LCD console can accommodate for each font. Note: ``Terminus`` fonts are "thinner"; ``TerminusBold`` and ``VGA`` offer more contrast on the LCD console and are thus more readable; the ``TomThumb`` font is waaaaay too small to read! """ console = Console() files = [ f for f in listdir("/usr/share/consolefonts/") if f.startswith("Lat15") and f.endswith(".psf.gz") ] files.sort() fonts = [] for font in files: console.set_font(font, True) console.text_at(font, 1, 1, False, True) console.clear_to_eol() console.text_at("{}, {}".format(console.columns, console.rows), column=2, row=4, reset_console=False, inverse=False) print("{}, {}, \"{}\"".format(console.columns, console.rows, font), file=stderr) fonts.append((console.columns, console.rows, font)) fonts.sort(key=lambda f: (f[0], f[1], f[2])) # Paint the screen full of numbers that represent the column number, reversing the even rows for cols, rows, font in fonts: print(cols, rows, font, file=stderr) console.set_font(font, True) for row in range(1, rows + 1): for col in range(1, cols + 1): console.text_at("{}".format(col % 10), col, row, False, (row % 2 == 0)) console.text_at(font.split(".")[0], 1, 1, False, True) console.clear_to_eol()
def menu(choices, before_run_function=None, after_run_function=None): """ Console Menu that accepts choices and corresponding functions to call. The user must press the same button twice: once to see their choice highlited, a second time to confirm and run the function. The EV3 LEDs show each state change: Green = Ready for button, Amber = Ready for second button, Red = Running Parameters: - `choices` a dictionary of tuples "button-name": ("mission-name", function-to-call) Example: choices = { # "button-name": ("mission-name", function-to-call) # or "button-name": ("mission-name", lambda: call(x, y, z)) "enter": ("CAL", lambda: auto_calibrate(robot, 1.0)), "up": ("MI2", fmission2), "right": ("MI3", fmission3), "down": ("MI4", fmission4), "left": ("MI5", fmission5) } where fmission2, fmission3 are functions; note don't call them with parentheses, unless preceded by lambda: to defer the call - `before_run_function` when not None, call this function before each mission run, passed with mission-name - `after_run_function` when not None, call this function after each mission run, passed with mission-name """ console = Console() leds = Leds() button = Button() leds.all_off() leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") menu_positions = get_positions(console) last = None # the last choice--initialize to None while True: # display the menu of choices, but show the last choice in inverse console.reset_console() for btn, (name, _) in choices.items(): align, col, row = menu_positions[btn] console.text_at(name, col, row, inverse=(btn == last), alignment=align) pressed = wait_for_button_press(button) # get the choice for the button pressed if pressed in choices: if last == pressed: # was same button pressed? console.reset_console() leds.set_color("LEFT", "RED") leds.set_color("RIGHT", "RED") # call the user's subroutine to run the mission, but catch any errors try: name, mission_function = choices[pressed] if before_run_function is not None: before_run_function(name) mission_function() except Exception as ex: print("**** Exception when running") print(ex) finally: if after_run_function is not None: after_run_function(name) last = None leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") else: # different button pressed last = pressed leds.set_color("LEFT", "AMBER") leds.set_color("RIGHT", "AMBER")
def display_menu(self, start_page=0, before_run_function=None, after_run_function=None, skip_to_next_page=True): """ Console Menu that accepts choices and corresponding functions to call. The user must press the same button twice: once to see their choice highlited, a second time to confirm and run the function. The EV3 LEDs show each state change: Green = Ready for button, Amber = Ready for second button, Red = Running Parameters: - `choices` a dictionary of tuples "button-name": ("function-name", function-to-call) NOTE: Don't call functions with parentheses, unless preceded by lambda: to defer the call - `before_run_function` when not None, call this function before each function run, passed with function-name - `after_run_function` when not None, call this function after each function run, passed with function-name """ self.current_page = start_page console = Console() leds = Leds() button = Button() leds.all_off() leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") menu_positions = self.get_menu_positions(console) last = None # the last choice--initialize to None self.menu_tone() self.debug("Starting Menu") while True: # display the menu of choices, but show the last choice in inverse console.reset_console() self.debug("Reset the display screen") console.set_font('Lat15-TerminusBold24x12.psf.gz', True) # store the currently selected menu page menu_page = self.menu_pages[self.current_page] # store the currently selected menu items menu_options_on_page = menu_page.items() for btn, (name, _) in menu_options_on_page: align, col, row = menu_positions[btn] console.text_at(name, col, row, inverse=(btn == last), alignment=align) self.debug("Waiting for button press...") pressed = self.wait_for_button_press(button) self.debug("Registered button press: {}".format(pressed)) # get the choice for the button pressed if pressed in menu_page: if last == pressed: # was same button pressed? console.reset_console() leds.set_color("LEFT", "RED") leds.set_color("RIGHT", "RED") # call the user's subroutine to run the function, but catch any errors try: name, run_function = menu_page[pressed] if before_run_function is not None: self.debug('Running before function') before_run_function(name) self.press_tone() type_of_run_function = type(run_function) self.debug("Type of run_function: {}".format(type_of_run_function)) if isinstance(run_function, str): self.debug("Running {}".format(run_function)) if run_function == 'next': self.debug("About to call next") self.next() elif run_function =='back': self.debug("About to call back") self.back() elif callable(run_function): run_function() except Exception as e: print("**** Exception when running") raise(e) finally: if after_run_function is not None: after_run_function(name) last = None leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") else: # different button pressed last = pressed leds.set_color("LEFT", "AMBER") leds.set_color("RIGHT", "AMBER")
class Robot: def __init__(self): self.sound = Sound() self.direction_motor = MediumMotor(OUTPUT_D) self.swing_motorL = LargeMotor(OUTPUT_A) self.swing_motorC = LargeMotor(OUTPUT_B) self.swing_motorR = LargeMotor(OUTPUT_C) self.swing_motors = [ self.swing_motorL, self.swing_motorC, self.swing_motorR ] self.touch_sensor = TouchSensor(INPUT_1) self.console = Console(DEFAULT_FONT) self.buttons = Button() self.beeps_enabled = True def beep(self, frequency=700, wait_for_comeplete=False): if not self.beeps_enabled: return play_type = Sound.PLAY_WAIT_FOR_COMPLETE if wait_for_comeplete else Sound.PLAY_NO_WAIT_FOR_COMPLETE self.sound.beep("-f %i" % frequency, play_type=play_type) def calibrate_dir(self): ''' Calibrate direction motor ''' # Run motor with 25% power, and wait until it stops running self.direction_motor.on(SpeedPercent(-10), block=False) # while (not self.direction_motor.STATE_OVERLOADED): # print(self.direction_motor.duty_cycle) self.direction_motor.wait_until(self.direction_motor.STATE_OVERLOADED) self.direction_motor.stop_action = Motor.STOP_ACTION_COAST self.direction_motor.stop() time.sleep(.5) # Reset to straight # self.direction_motor.on_for_seconds(SpeedPercent(10), .835, brake=True, block=True) self.direction_motor.on_for_degrees(SpeedPercent(10), 127, brake=True, block=True) self.direction_motor.reset() print("Motor reset, position: " + str(self.direction_motor.position)) time.sleep(.5) def calibrate_swing(self): for m in self.swing_motors: m.stop_action = m.STOP_ACTION_HOLD m.on(SpeedPercent(6)) self.swing_motorC.wait_until(self.swing_motorC.STATE_OVERLOADED, 2000) for m in self.swing_motors: m.stop_action = m.STOP_ACTION_HOLD m.on_for_degrees(SpeedPercent(5), -15, brake=True, block=False) self.swing_motorC.wait_while('running') for m in self.swing_motors: m.reset() m.stop_action = m.STOP_ACTION_HOLD m.stop() print("Ready Angle: %i" % self.swing_motorC.position) def ready_swing(self, angle: int): right_angle = -(angle / 3) # adjust motors to target angle for m in self.swing_motors: m.stop_action = Motor.STOP_ACTION_HOLD m.on_for_degrees(SpeedPercent(2), right_angle, brake=True, block=False) self.swing_motorC.wait_while('running') for m in self.swing_motors: m.stop_action = Motor.STOP_ACTION_HOLD m.stop() print("Swing Angle: %i" % self.swing_motorC.position) def set_direction(self, direction): print("Setting direction to: " + str(direction)) #direction = self.__aim_correction(direction) self.direction_motor.on_for_degrees(SpeedPercent(10), round(direction * 3)) print("Direction set to: " + str(self.direction_motor.position)) # # def __aim_correction(self, direction): # x = direction # y = -0.00000000429085685725*x**6 + 0.00000004144345630728*x**5 + 0.00001219331494759860*x**4 + 0.00020702946527870400*x**3 + 0.00716486965517779000*x**2 + 1.29675836037884000000*x + 0.27064829453014400000 # # return y def shoot(self, power): print("SHOOT, power: %i" % power) for m in self.swing_motors: m.duty_cycle_sp = -power for m in self.swing_motors: m.run_direct() time.sleep(.5) self.swing_motorC.wait_until_not_moving() for m in self.swing_motors: m.reset() def wait_for_button(self): self.touch_sensor.wait_for_bump() def __set_display(self, str): self.console.set_font(font=LARGER_FONT, reset_console=True) self.console.text_at(str, column=1, row=1, reset_console=True) def wait_for_power_select(self, power=0, angle=0, steps=1): self.__set_display("Pow: %i\nAngle: %i" % (power, angle)) def left(): power -= steps if power < 0: power = 0 self.__set_display("Pow: %i\nAngle: %i" % (power, angle)) self.buttons.wait_for_released(buttons=['left'], timeout_ms=150) def right(): power += steps if power > 100: power = 100 self.__set_display("Pow: %i\nAngle: %i" % (power, angle)) self.buttons.wait_for_released(buttons=['right'], timeout_ms=150) def up(): angle += steps if angle > 110: angle = 110 self.__set_display("Pow: %i\nAngle: %i" % (power, angle)) self.buttons.wait_for_released(buttons=['up'], timeout_ms=150) def down(): angle -= steps if angle < 0: angle = 0 self.__set_display("Pow: %i\nAngle: %i" % (power, angle)) self.buttons.wait_for_released(buttons=['down'], timeout_ms=150) while not self.touch_sensor.is_pressed: if self.buttons.left: left() elif self.buttons.right: right() elif self.buttons.up: up() elif self.buttons.down: down() self.console.set_font(font=DEFAULT_FONT, reset_console=True) return (power, angle) def select_connection_mode(self): self.__set_display("Enable Connection\nLeft: True - Right: False") enabled = True while not self.touch_sensor.is_pressed: if self.buttons.left: enabled = True self.buttons.wait_for_released(buttons=['left']) break elif self.buttons.right: enabled = False self.buttons.wait_for_released(buttons=['right']) break self.console.set_font(font=DEFAULT_FONT, reset_console=True) return enabled def print(self, string): print(string)
#!/usr/bin/env micropython from ev3dev2.console import Console from time import sleep # create a Console instance, which uses the default font console = Console() # reset the console to clear it, home the cursor at 1,1, and then turn off the cursor console.reset_console() # display 'Hello World!' at row 5, column 1 in inverse, but reset the EV3 LCD console first console.text_at('Hello World!', column=1, row=5, reset_console=True, inverse=True) sleep(10)
program -= 1 elif type(plus) == type(True): run = currentProgram currentProgram = (program % len(programs)) + 1 button.on_right = lambda x: c(1) button.on_left = lambda x: c(-1) button.on_enter = lambda x: c(True) # Program running handling currentProgram = 1 pastProgram = currentProgram console.reset_console() console.text_at("Selected: " + str(currentProgram)) while True: button.process() if currentProgram != pastProgram: clearColumn(1) console.text_at("Selected: " + str(currentProgram)) if run: clearColumn(1) console.text_at("Running: " + str(currentProgram), 1, 1) console.text_at(" ", 1, 2) console.text_at("", 1, 2) # Running file here reimportModulesAndRun("run%i" % currentProgram) run = False # Running file ending here
def menu(choices, before_run_function=None, after_run_function=None, skip_to_next_page=True): """ Console Menu that accepts choices and corresponding functions to call. The user must press the same button twice: once to see their choice highlited, a second time to confirm and run the function. The EV3 LEDs show each state change: Green = Ready for button, Amber = Ready for second button, Red = Running Parameters: - `choices` a dictionary of tuples "button-name": ("mission-name", function-to-call) NOTE: Don't call functions with parentheses, unless preceded by lambda: to defer the call - `before_run_function` when not None, call this function before each mission run, passed with mission-name - `after_run_function` when not None, call this function after each mission run, passed with mission-name """ global proc console = Console() leds = Leds() button = Button() leds.all_off() leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") menu_positions = get_positions(console) last = None # the last choice--initialize to None while True: # display the menu of choices, but show the last choice in inverse console.reset_console() for btn, (name, _) in choices.items(): align, col, row = menu_positions[btn] console.text_at(name, col, row, inverse=(btn == last), alignment=align) pressed = wait_for_button_press(button) # get the choice for the button pressed if pressed in choices: if last == pressed: # was same button pressed? console.reset_console() leds.set_color("LEFT", "RED") leds.set_color("RIGHT", "RED") # call the user's subroutine to run the mission, but catch any errors try: name, mission_function = choices[pressed] if before_run_function is not None: before_run_function(name) if name in ('NEXT', 'BACK', 'OFF'): mission_function() else: # launch a sub process so it could be canceled with the enter button # store the subprocess in self to reference in the stop function proc = Process(target=mission_function) debug('Starting {}'.format(name)) proc.start() debug('Just started {} in proc {}'.format(name, proc.pid)) sleep(1) proc.terminate() # TODO: Need to figure out when to call self.proc.join except Exception as e: print("**** Exception when running") debug('Exception when running {}'.format(e)) finally: if after_run_function is not None: after_run_function(name) last = None leds.set_color("LEFT", "GREEN") leds.set_color("RIGHT", "GREEN") else: # different button pressed last = pressed leds.set_color("LEFT", "AMBER") leds.set_color("RIGHT", "AMBER")