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 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()
Beispiel #4
0
 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)
Beispiel #5
0
# import Sensor modules and the ev3 ports used for it
from ShivaColor import ShivaColor
from ev3dev2.sensor import INPUT_1, INPUT_2, INPUT_4

from ev3dev2.sensor.lego import GyroSensor, TouchSensor
from ev3dev2.sensor import INPUT_3
from ShivaGyro import ShivaGyro

# Creates sound and button objects
from ev3dev2.sound import Sound
from ev3dev2.button import Button

# Sets the font size for robot lcd
console = Console()
console.set_font('Lat15-VGA16.psf.gz')

# Port assignments
MEDIUM_MOTOR_LEFT = OUTPUT_A
MEDIUM_MOTOR_RIGHT = OUTPUT_D
LARGE_MOTOR_LEFT_PORT = OUTPUT_B
LARGE_MOTOR_RIGHT_PORT = OUTPUT_C

COLORSENSOR_RIGHT = INPUT_1
COLORSENSOR_LEFT = INPUT_3
TOUCHSENSOR_PORT = INPUT_4
GYROSENSOR_PORT = INPUT_2

# Checks every port on the robot to see if its connected properly

healthy = False
Beispiel #6
0
class MindstormsGadget(AlexaGadget):
    def __init__(self):
        super().__init__(gadget_config_path='./auth.ini')

        # order queue
        self.queue = Queue()

        self.button = Button()
        self.leds = Leds()
        self.sound = Sound()
        self.console = Console()
        self.console.set_font("Lat15-TerminusBold16.psf.gz", True)

        self.dispense_motor = LargeMotor(OUTPUT_A)
        self.pump_motor = LargeMotor(OUTPUT_B)
        self.touch_sensor = TouchSensor(INPUT_1)

        # Start threads
        threading.Thread(target=self._handle_queue, daemon=True).start()
        threading.Thread(target=self._test, daemon=True).start()

    def on_connected(self, device_addr):
        self.leds.animate_rainbow(duration=3, block=False)
        self.sound.play_song((('C4', 'e3'), ('C5', 'e3')))

    def on_disconnected(self, device_addr):
        self.leds.animate_police_lights('RED',
                                        'ORANGE',
                                        duration=3,
                                        block=False)
        self.leds.set_color("LEFT", "BLACK")
        self.leds.set_color("RIGHT", "BLACK")
        self.sound.play_song((('C5', 'e3'), ('C4', 'e3')))

    def _test(self):
        while 1:
            self.button.wait_for_pressed('up')
            order = {
                'name': 'Test',
                'tea': 'Jasmine',
                'sugar': 100,
                'ice': 100
            }
            self.queue.put(order)
            sleep(1)

    def _handle_queue(self):
        while 1:
            if self.queue.empty(): continue

            order = self.queue.get()
            self._make(name=order['name'],
                       tea=order['tea'],
                       sugar=order['sugar'],
                       ice=order['ice'])

    def _send_event(self, name, payload):
        self.send_custom_event('Custom.Mindstorms.Gadget', name, payload)

    def _affirm_receive(self):
        self.leds.animate_flash('GREEN',
                                sleeptime=0.25,
                                duration=0.5,
                                block=False)
        self.sound.play_song((('C3', 'e3'), ('C3', 'e3')))

    def on_custom_mindstorms_gadget_control(self, directive):
        try:
            payload = json.loads(directive.payload.decode("utf-8"))
            print("Control payload: {}".format(payload), file=sys.stderr)
            control_type = payload["type"]

            # regular voice commands
            if control_type == "automatic":
                self._affirm_receive()
                order = {
                    "name": payload["name"] or "Anonymous",
                    "tea": payload["tea"] or "Jasmine Milk Tea",
                    "sugar": payload["sugar"] or 100,
                    "ice": payload["ice"] or 100,
                }
                self.queue.put(order)

            # series of voice commands
            elif control_type == "manual":  # Expected params: [command]
                control_command = payload["command"]

                if control_command == "dispense":
                    self._affirm_receive()
                    if payload['num']:
                        self._dispense(payload['num'])
                    else:
                        self._dispense()

                elif control_command == "pour":
                    self._affirm_receive()
                    if payload['num']:
                        self._pour(payload['num'])
                    else:
                        self._pour()

        except KeyError:
            print("Missing expected parameters: {}".format(directive),
                  file=sys.stderr)

    def _make(self, name=None, tea="Jasmine Milk Tea", sugar=100, ice=100):
        if not self.touch_sensor.is_pressed:
            # cup is not in place
            self._send_event('CUP', None)
            self.touch_sensor.wait_for_pressed()
            sleep(3)  # cup enter delay

        # mid_col = console.columns // 2
        # mid_row = console.rows // 2
        # mid_col = 1
        # mid_row = 1
        # alignment = "L"

        process = self.sound.play_file('mega.wav', 100,
                                       Sound.PLAY_NO_WAIT_FOR_COMPLETE)

        # dispense boba
        self._dispense()

        # dispense liquid
        self._pour(tea=tea)

        # self.console.text_at(
        #     s, column=mid_col, row=mid_row, alignment=alignment, reset_console=True
        # )
        # notify alexa that drink is finished
        payload = {
            "name": name,
            "tea": tea,
            "sugar": sugar,
            "ice": ice,
        }
        self._send_event("DONE", payload)

        process.kill()  # kill song
        self.sound.play_song((('C4', 'q'), ('C4', 'q'), ('C4', 'q')),
                             delay=0.1)
        self.touch_sensor.wait_for_released()

    # dispense liquid
    def _pour(self, time_in_s=10, tea="Jasmine Milk Tea"):
        # send event to alexa
        payload = {"time_in_s": time_in_s, "tea": tea}
        self._send_event("POUR", payload)
        self.pump_motor.run_forever(speed_sp=1000)
        sleep(time_in_s)
        self.pump_motor.stop()

    # dispense boba
    def _dispense(self, cycles=10):
        # send event to alexa
        payload = {"cycles": cycles}
        self._send_event("DISPENSE", payload)

        # ensure the dispenser resets to the correct position everytime
        if cycles % 2:
            cycles += 1

        # agitate the boba to make it fall
        for i in range(cycles):
            deg = 45 if i % 2 else -45
            self.dispense_motor.on_for_degrees(SpeedPercent(75), deg)
            sleep(0.5)
Beispiel #7
0
    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)
Beispiel #9
0
#!/usr/bin/env python3

import argparse
import requests
from time import sleep

from ev3dev2.motor import LargeMotor, OUTPUT_A, OUTPUT_B, SpeedPercent
from ev3dev2.sound import Sound
from ev3dev2.console import Console

from agt import AlexaGadget

URL = "http://35.230.20.197:5000" or "http://bobafetch.me:5000"

console = Console()
console.set_font("Lat15-TerminusBold16.psf.gz", True)

# mid_col = console.columns // 2
# mid_row = console.rows // 2
mid_col = 1
mid_row = 1
alignment = "L"


def main():
    console.text_at(
        "Mindstorms is running",
        column=mid_col,
        row=mid_row,
        alignment=alignment,
        reset_console=True,