diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a295864 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +__pycache__ diff --git a/README.md b/README.md index 4e036f9..1435a12 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ # arduino-modulino-lessons -# arduino-modulino-lessons diff --git a/micropython/01-pixels.py b/micropython/01-pixels.py new file mode 100644 index 0000000..bdb4330 --- /dev/null +++ b/micropython/01-pixels.py @@ -0,0 +1,63 @@ +# Animation +# Difficulty: medium +# Material:. Modulino Pixels + +# Exercise: +# Using the Modulino Pixels, create a continuous animation (that never ends) that lights up one LED at a time starting from LED 0 to LED 7 +# and then goes back lighting up one LED from LED 6 to LED 0 (and then repeats the sequence without ever stopping). +# At any given moment, one and only one LED is on. + +# The sequence should be as follows, executed forever: +# - LED 0 on, LED 0 off, LED 1 on, LED 1 off,..., LED 7 on, LED 7 off +# - LED 6 on, LED 6 off, LED 5 on, LED 5 off, … , LED 1 on, LED 1 off + + +from modulino import VirtualModulinoPixels, ModulinoColor + +from time import sleep + +pixels = VirtualModulinoPixels() + +pixels.set_rgb(0, 0, 0, 0, 20) +pixels.show() + +# print(ModulinoColor.GREEN) + +# for index in range(0, 8): +# color_wheel_colors = [ +# (255, 0, 0), +# (255, 85, 0), +# (255, 255, 0), +# (0, 255, 0), +# (0, 255, 255), +# (0, 0, 255), +# (255, 0, 255), +# (255, 0, 0) +# ] +# pixels.set_rgb(index, *color_wheel_colors[index], 40) +# pixels.show() + + +# pixels.set_all_rgb(255, 255, 255) +# pixels.show() + + +# Night Rider animation + +for j in range(0, 3): + for i in range(0, 8): + pixels.clear_all() + pixels.set_rgb(i, 255, 0, 0, 100) + pixels.show() + sleep(0.05) + + for i in range(7, -1, -1): + pixels.clear_all() + pixels.set_rgb(i, 255, 0, 0, 100) + pixels.show() + sleep(0.05) + + +# Turn off all LEDs +pixels.clear_all() +pixels.show() diff --git a/micropython/02-buttons.py b/micropython/02-buttons.py new file mode 100644 index 0000000..eb44667 --- /dev/null +++ b/micropython/02-buttons.py @@ -0,0 +1,13 @@ + +from modulino import ModulinoButtons + + +buttons = ModulinoButtons() + + +buttons.on_button_a_press = lambda : print("Button A pressed") +buttons.on_button_b_press = lambda : print("Button B pressed") +buttons.on_button_c_press = lambda : print("Button C pressed") + +while True: + buttons_state_changed = buttons.update() diff --git a/micropython/03-pixels-buttons.py b/micropython/03-pixels-buttons.py new file mode 100644 index 0000000..865b3f5 --- /dev/null +++ b/micropython/03-pixels-buttons.py @@ -0,0 +1,31 @@ + +from modulino import ModulinoButtons, VirtualModulinoPixels + +buttons = ModulinoButtons() +pixels = VirtualModulinoPixels() + + +buttons.on_button_a_press = lambda : print("Button A pressed") +buttons.on_button_b_press = lambda : print("Button B pressed") +buttons.on_button_c_press = lambda : print("Button C pressed") + +buttons.on_button_a_release = lambda : print("Button A released") +buttons.on_button_b_release = lambda : print("Button B released") +buttons.on_button_c_release = lambda : print("Button C released") + +while True: + buttons_state_changed = buttons.update() + if buttons_state_changed: + if buttons.is_pressed(0): + pixels.set_rgb(0, 255, 255, 255) + if buttons.is_pressed(1): + pixels.set_rgb(1, 255, 255, 255) + if buttons.is_pressed(2): + pixels.set_rgb(2, 255, 255, 255) + if not buttons.is_pressed(0): + pixels.set_rgb(0, 0, 0, 0) + if not buttons.is_pressed(1): + pixels.set_rgb(1, 0, 0, 0) + if not buttons.is_pressed(2): + pixels.set_rgb(2, 0, 0, 0) + pixels.show() diff --git a/micropython/modulino/__init__.py b/micropython/modulino/__init__.py new file mode 100644 index 0000000..6fdbf66 --- /dev/null +++ b/micropython/modulino/__init__.py @@ -0,0 +1,4 @@ + +from .pixels import VirtualModulinoPixels +from .pixels import ModulinoColor +from .buttons import ModulinoButtons diff --git a/micropython/modulino/buttons.py b/micropython/modulino/buttons.py new file mode 100644 index 0000000..73f8545 --- /dev/null +++ b/micropython/modulino/buttons.py @@ -0,0 +1,172 @@ + +class ModulinoButtons(): + + def __init__(self): + self._current_buttons_status = [None, None, None] + + # Button callbacks + self._on_button_a_press = None + self._on_button_b_press = None + self._on_button_c_press = None + + # Button callbacks + self._on_button_a_release = None + self._on_button_b_release = None + self._on_button_c_release = None + + @property + def on_button_a_press(self): + """ + Returns the callback for the press event of button A. + """ + return self._on_button_a_press + + @on_button_a_press.setter + def on_button_a_press(self, value) -> None: + """ + Sets the callback for the press event of button A. + """ + self._on_button_a_press = value + + @property + def on_button_a_release(self): + """ + Returns the callback for the release event of button A. + """ + return self._on_button_a_release + + @on_button_a_release.setter + def on_button_a_release(self, value) -> None: + """ + Sets the callback for the release event of button A. + """ + self._on_button_a_release = value + + @property + def on_button_b_press(self): + """ + Returns the callback for the press event of button B. + """ + return self._on_button_b_press + + @on_button_b_press.setter + def on_button_b_press(self, value) -> None: + """ + Sets the callback for the press event of button B. + """ + self._on_button_b_press = value + + @property + def on_button_b_release(self): + """ + Returns the callback for the release event of button B. + """ + return self._on_button_b_release + + @on_button_b_release.setter + def on_button_b_release(self, value) -> None: + """ + Sets the callback for the release event of button B. + """ + self._on_button_b_release = value + + @property + def on_button_c_press(self): + """ + Returns the callback for the press event of button C. + """ + return self._on_button_c_press + + @on_button_c_press.setter + def on_button_c_press(self, value) -> None: + """ + Sets the callback for the press event of button C. + """ + self._on_button_c_press = value + + @property + def on_button_c_release(self): + """ + Returns the callback for the release event of button C. + """ + return self._on_button_c_release + + @on_button_c_release.setter + def on_button_c_release(self, value) -> None: + """ + Sets the callback for the release event of button C. + """ + self._on_button_c_release = value + + def printButtons(self): + print("#########") + print("# #") + print("# ", end="") + print(self, end="") + print(" #") + print("# #") + print("#########") + + def update(self) -> bool: + # TODO: remove input becuase this code runs on micropython boards. + key = input() + if str.capitalize(key) == "A": + self._current_buttons_status[0] = True + self._on_button_a_press() + elif str.capitalize(key) == "B": + self._current_buttons_status[1] = True + self._on_button_b_press() + elif str.capitalize(key) == "C": + self._current_buttons_status[2] = True + self._on_button_c_press() + elif str.capitalize(key) == "X": + self._current_buttons_status[0] = False + self._on_button_a_release() + elif str.capitalize(key) == "Y": + self._current_buttons_status[1] = False + self._on_button_b_release() + elif str.capitalize(key) == "Z": + self._current_buttons_status[2] = False + self._on_button_c_release() + else: + raise ValueError("Invalid pressed button. Allowed keys are: 'A', 'B', 'C', 'X', 'Y', 'Z") + + return True + + def __str__(self): + a = "a" if self._current_buttons_status[0] else "A" + b = "b" if self._current_buttons_status[1] else "B" + c = "c" if self._current_buttons_status[2] else "C" + return f"{a} {b} {c}" + + return + + def is_pressed(self, index: int) -> bool: + """ + Returns True if the button at the given index is currently pressed. + + Parameters: + index (int): The index of the button. A = 0, B = 1, C = 2. + """ + return self._current_buttons_status[index] + + @property + def button_a_pressed(self) -> bool: + """ + Returns True if button A is currently pressed. + """ + return self.is_pressed(0) + + @property + def button_b_pressed(self) -> bool: + """ + Returns True if button B is currently pressed. + """ + return self.is_pressed(1) + + @property + def button_c_pressed(self) -> bool: + """ + Returns True if button C is currently pressed. + """ + return self.is_pressed(2) diff --git a/micropython/modulino/pixels.py b/micropython/modulino/pixels.py new file mode 100644 index 0000000..4c0224f --- /dev/null +++ b/micropython/modulino/pixels.py @@ -0,0 +1,112 @@ +NUM_LEDS = 8 + + +class VirtualModulinoPixels: + + leds = [] + + def __init__(self): + self.leds = [Led() for _ in range(NUM_LEDS)] + + def set_rgb(self, idx: int, r: int, g: int, b: int, brightness: int = 100) -> None: + self.leds[idx].setColor(r, g, b) + self.leds[idx].setBrightness(brightness) + + def set_all_rgb(self, r: int, g: int, b: int, brightness: int = 100) -> None: + for led in self.leds: + led.setColor(r,g,b) + led.setBrightness(brightness) + + def clear_all(self): + [l.clear() for l in self.leds] + + def show(self): + print("##########") + print("# #") + print("#", end="") + for led in self.leds: + print(led, end="") + print("#") + print("# #") + print("##########") + +class Led: + + def __init__(self, r:int=0, g:int=0, b:int=0, brightness:int=100): + self.color = ModulinoColor(r,g,b) + self.brightness = brightness + + def setBrightness(self, brightness:int): + if brightness < 0 or brightness > 100: + raise ValueError(f"Brightness value {brightness} should be between 0 and 100") + self.brightness = brightness + + def setColor(self, r:int, g:int, b:int): + self.color = ModulinoColor(r,g,b) + + def clear(self): + self.color = ModulinoColor(0,0,0) + self.brightness = 100; + + def __str__(self): + return f"{self.color}" + + + +class ModulinoColor: + """ + Class to represent an RGB color. + It comes with predefined colors: + - RED + - GREEN + - BLUE + - YELLOW + - CYAN + - VIOLET + - WHITE + + They can be accessed e.g. as ModulinoColor.RED + """ + + def __init__(self, r: int, g: int, b: int): + """ + Initializes the color with the given RGB values. + + Parameters: + r (int): The red value of the color. + g (int): The green value of the color. + b (int): The blue value of the color. + """ + + if r < 0 or r > 255: + raise ValueError(f"Red value {r} should be between 0 and 255") + if g < 0 or g > 255: + raise ValueError(f"Green value {g} should be between 0 and 255") + if b < 0 or b > 255: + raise ValueError(f"Blue value {b} should be between 0 and 255") + self.r = r + self.g = g + self.b = b + + def __int__(self) -> int: + """Return the 32-bit integer representation of the color.""" + return (self.b << 8 | self.g << 16 | self.r << 24) + + def __repr__(self): + return f"({self.r},{self.g},{self.b})" + + def __str__(self): + i = int(self) + if i == 0: + return " " + return "X" + + + +ModulinoColor.RED = ModulinoColor(255, 0, 0) +ModulinoColor.GREEN = ModulinoColor(0, 255, 0) +ModulinoColor.BLUE = ModulinoColor(0, 0, 255) +ModulinoColor.YELLOW = ModulinoColor(255, 255, 0) +ModulinoColor.CYAN = ModulinoColor(0, 255, 255) +ModulinoColor.VIOLET = ModulinoColor(255, 0, 255) +ModulinoColor.WHITE = ModulinoColor(255, 255, 255)