Created
May 14, 2025 19:18
-
-
Save villares/8496a2270acbaa60b92d209ecc31a721 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Alexandre B A Villares | |
árvore recursiva - Circuito SESC de arte 2018 - v2022_08_06 | |
http://abav.lugaralgum.com/lousa-magica | |
Para executar é necessário: | |
py5 (Usando Thonny IDE com o thonny-py5mode ative o *imported mode*) | |
PyFirmata | |
""" | |
def setup(): | |
global arduino | |
size(700, 700) | |
color_mode(HSB) | |
arduino = get_arduino() | |
if arduino is None: | |
print('Could not connect to an Arduino compatible board') | |
exit_sketch() | |
# Or try port name like get_arduino('COM3') or '/dev/ttyUSB0' | |
def draw(): | |
global a, b, c, d | |
background(0) | |
frame_rate(30) | |
stroke_weight(2) | |
a = remap(arduino.analog_read(1), 0, 1023, 0, HALF_PI) # ângulo | |
# randomização do tamanho do galho | |
b = remap(arduino.analog_read(2), 0, 1023, 0, 10) | |
c = 0 # remap(arduino.analog_read(3), 0, 1023, -2, 2) # randomização do ângulo | |
d = 10 #remap(arduino.analog_read(4), 0, 1023, 0, 10) # profundidade da recursão | |
random_seed(int(d * 10)) | |
with push_matrix(): | |
translate(width / 2, height / 2) | |
branch(d, a, width / 25 + (width / 75) * b) | |
def branch(gen, theta, branch_size): | |
stroke_weight(gen) | |
try: | |
cor = (remap(gen, 0, d + 1, 255, 0) + frame_count) % 256 | |
except ZeroDivisionError: | |
cor = 0 | |
stroke(cor, 255, 255) | |
# All recursive functions must have an exit condition!!!! | |
if gen > 1: # and branch_size > 1: | |
with push_matrix(): | |
h = branch_size * (1 - random(b / 3, b) / 15) | |
rotate(theta + c * random(1)) # Rotate by theta | |
line(0, 0, 0, -h) # Draw the branch | |
translate(0, -h) # Move to the end of the branch | |
# Ok, now call myself to draw two branches!! | |
with push_style(): | |
branch(gen - 1, theta, h) | |
with push_matrix(): | |
h = branch_size * (1 - random(b / 3, b) / 15) | |
rotate(-theta + c * random(1)) | |
line(0, 0, 0, -h) | |
translate(0, -h) | |
with push_style(): | |
branch(gen - 1, theta, h) | |
def key_pressed(): | |
if key == 'p': | |
save_frame("lousa-02-####.png") | |
def get_arduino(port=None): | |
""" | |
This is a PyFirmata 'helper' that tries to connect to an Arduino | |
compatible board. | |
If no port is informed, using pyserial's serial.tools.list_ports.comports(), | |
if one port is found, tries that one. If more than one port is found, | |
shows for the user to choose one. Returns None if no port is found or if the | |
user cancels the dialog. | |
If it successfully connects, it will return a pyfirmata Arduino object, | |
but before that, it starts a pyfirmata.util.Iterator, and adds to the object | |
both analog_read() and digital_read() functions that mimic Processing's | |
Firmata library interface: | |
Readings are never None, and analog pins return a value between 0 and 1023. | |
""" | |
from pyfirmata import Arduino, util | |
from serial.tools import list_ports | |
comports = [comport.device for comport in list_ports.comports()] | |
if not comports: | |
print('No ports found.') | |
return None | |
elif isinstance(port, str) and port not in comports: | |
print(f'Port "{port}" not found.') | |
return None | |
elif isinstance(port, int): | |
if port >= len(comports): | |
print(f'Port [{port}] not found.') | |
return None | |
else: | |
port = comports[port] | |
elif len(comports) == 1: | |
port = comports[0] | |
elif port is None: | |
port = option_pane( | |
'Where is your board?', | |
'Please select the USB port where your ' | |
'Arduino compatible board is connected:', | |
comports, | |
-1) # index for default option | |
if port is None: | |
print('No port selected.') | |
return None | |
try: | |
print(f'Connecting to port {port}...') | |
arduino = Arduino(port) | |
util.Iterator(arduino).start() | |
except Exception as e: | |
print(repr(e)) | |
return None | |
# Prepare analog_read() for A0 A1 A2 A3 A4 A5 | |
for a in range(6): | |
arduino.analog[a].enable_reporting() | |
arduino.analog_read = (lambda a: round(arduino.analog[a].read() * 1023) | |
if arduino.analog[a].read() is not None | |
else 0) | |
# Prepare digital_read() for D2 to D13 | |
digital_pin_dict = {d: arduino.get_pin(f'd:{d}:i') | |
for d in range(2, 14)} | |
for d in digital_pin_dict.keys(): | |
digital_pin_dict[d].enable_reporting() | |
arduino.digital_read = (lambda d: digital_pin_dict[d].read() | |
if digital_pin_dict[d].read() is not None | |
else False) | |
return arduino | |
def option_pane(title, message, options, default=None, index_only=False): | |
""" | |
A helper for Java swing JOptionPane input dialog with drop down options. | |
title : str - Dialog window's title (make it shorter than message). | |
message : str - Text shown before the drop down. | |
options : list - List of strings to show in the drop down. | |
default : int - None or index to the pre-selected option in the list. | |
index_only: False - Function returns an option string from the options list | |
provided, or None, if the dialog was cancelled; | |
True - Function returns the position index to the options list. | |
""" | |
from javax.swing import JOptionPane | |
if default is None: | |
default = options[0] | |
elif index_only: | |
default = options[default] | |
selection = JOptionPane.showInputDialog( | |
None, # frame | |
message, | |
title, | |
JOptionPane.INFORMATION_MESSAGE, | |
None, # for Java null | |
options, | |
default) # must be in options, otherwise first is shown | |
if selection: | |
if index_only: | |
return options.index(selection) | |
else: | |
# Trouble: selection can be java.lang.String | |
return str(selection) if selection else None | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment