diff --git a/Navigation b/Navigation index 576dd4a..290895d 160000 --- a/Navigation +++ b/Navigation @@ -1 +1 @@ -Subproject commit 576dd4a2cc0410a8ef88a017afc9dc3312ce0524 +Subproject commit 290895dbbce5c166e376b58c57806a22411a717c diff --git a/RaspberryPi/GamePad_Controller.py b/RaspberryPi/GamePad_Controller.py new file mode 100644 index 0000000..fb5ba22 --- /dev/null +++ b/RaspberryPi/GamePad_Controller.py @@ -0,0 +1,69 @@ +import RPi.GPIO as GPIO +from time import sleep, time +from pynput import keyboard +from gamepad import run_gamepad +from constants import * +from rpi_helper import turn_wheels, rotate_wheels, generate_pwm, reset_angle, debug_print, setup_rpi +import signal +import sys + + +# global variables +current_angle = 0.0 +movement_arr = [V_Directions.halted, H_Directions.straight] +pwm_controls = [] + + +def process_movement_turning(movement, turning): + global current_angle + debug_print(movement, turning, "angle ", current_angle) + try: + if movement == V_Directions.forward: + debug_print("Moving forward") + rotate_wheels(DIR_FORWARD, pwm_controls=pwm_controls) + elif movement == V_Directions.backward: + debug_print("Moving backward") + rotate_wheels(DIR_BACKWARD, pwm_controls=pwm_controls) + else: + # stop moving + generate_pwm(0, pwm_controls=pwm_controls) + + if turning == H_Directions.left: + if current_angle <= -MAX_ANGLE: + debug_print("Max angle reached") + else: + debug_print("Turning left") + current_angle -= REV_ANGLE + turn_wheels(DIR_LEFT) + elif turning == H_Directions.right: + if current_angle >= MAX_ANGLE: + debug_print("Max angle reached") + else: + debug_print("Turning right") + current_angle += REV_ANGLE + turn_wheels(DIR_RIGHT) + else: + # reset angle + current_angle = reset_angle(current_angle=current_angle) + + except AttributeError: + print("Attribute Error") + + +def handler(signum, frame): + # reset angle + reset_angle(current_angle=current_angle) + # stop moving + generate_pwm(0, pwm_controls=pwm_controls) + sys.exit(0) + + +signal.signal(signal.SIGINT, handler) + + +def main(): + setup_rpi(pwm_controls=pwm_controls) + run_gamepad(process_movement_turning) + + +main() diff --git a/RaspberryPi/Keyboard_Controller.py b/RaspberryPi/Keyboard_Controller.py index 35f16fe..1a5e659 100644 --- a/RaspberryPi/Keyboard_Controller.py +++ b/RaspberryPi/Keyboard_Controller.py @@ -1,93 +1,104 @@ -""" -Listens to keyboard presses and sends a string message to the Arduino -Output Format: "XY" where - X = (H = Halt, F = Forward, B = Backward) - Y = (S = Straight, L = Left, R = Right) -To be used in conjunction with the StringReceiver.ino -""" -import time +import RPi.GPIO as GPIO +from time import sleep, time from pynput import keyboard -import serial +from constants import * +from rpi_helper import turn_wheels, rotate_wheels, generate_pwm, reset_angle, debug_print, setup_rpi +import signal +import sys -rpi_path = '/dev/ttyACM0' -ser = serial.Serial( - port=rpi_path, - baudrate=9600, - parity=serial.PARITY_NONE, - stopbits=serial.STOPBITS_ONE, - bytesize=serial.EIGHTBITS, - timeout=1 -) -counter = 0 -''' -Debug flag for button press outputs and output messages -0 = no debug(only final string printed), 1 = output message array, 2 = key presses -''' -debug_level = 1 +# global variables +current_angle = 0.0 +movement_arr = [V_Directions.halted, H_Directions.straight] +pwm_controls = [] -def debug_print(output, level=0): - """ - Function that handles debug levels - """ - if debug_level >= level: - print(output) +def run(): + global current_angle, movement_arr + movement, turning = movement_arr + debug_print(movement, turning, "angle ", current_angle) + try: + if movement == V_Directions.forward: + debug_print("Moving forward") + rotate_wheels(DIR_FORWARD, pwm_controls=pwm_controls) + elif movement == V_Directions.backward: + debug_print("Moving backward") + rotate_wheels(DIR_BACKWARD, pwm_controls=pwm_controls) + else: + # stop moving + generate_pwm(0, pwm_controls=pwm_controls) + if turning == H_Directions.left: + if current_angle <= -MAX_ANGLE: + debug_print("Max angle reached") + else: + debug_print("Turning left") + current_angle -= REV_ANGLE + turn_wheels(DIR_LEFT) + elif turning == H_Directions.right: + if current_angle >= MAX_ANGLE: + debug_print("Max angle reached") + else: + debug_print("Turning right") + current_angle += REV_ANGLE + turn_wheels(DIR_RIGHT) + else: + # reset angle + current_angle = reset_angle(current_angle=current_angle) -# We will keep track of movement state in this array -send_str_arr = ["H", "S"] + except AttributeError: + print("Attribute Error") -""" -Setup keyboard listener -""" +# testing with keyboard +def setup_keyboard(): + def on_press(key): + try: + if key.char == "w": + movement_arr[0] = V_Directions.forward + elif key.char == "s": + movement_arr[0] = V_Directions.backward + elif key.char == "a": + movement_arr[1] = H_Directions.left + elif key.char == "d": + movement_arr[1] = H_Directions.right + except AttributeError: + print(f'special key {key} pressed') -def on_press(key): - try: - debug_print(f'alphanumeric key {key.char} pressed', 2) - if key.char == "w": - send_str_arr[0] = "F" - elif key.char == "s": - send_str_arr[0] = "B" - elif key.char == "a": - send_str_arr[1] = "L" - elif key.char == "d": - send_str_arr[1] = "R" - except AttributeError: - debug_print(f'special key {key} pressed', 2) + def on_release(key): + try: + if key.char == "w" or key.char == "s": + movement_arr[0] = V_Directions.halted + elif key.char == "a" or key.char == "d": + movement_arr[1] = H_Directions.straight + debug_print(f'{key} released') + except AttributeError: + if key == keyboard.Key.esc: + # Stop listener + return False + # Start the keyboard listener in a non-blocking manner + listener = keyboard.Listener(on_press=on_press, on_release=on_release) -def on_release(key): - try: - if key.char == "w": - send_str_arr[0] = "H" - elif key.char == "s": - send_str_arr[0] = "H" - elif key.char == "a": - send_str_arr[1] = "S" - elif key.char == "d": - send_str_arr[1] = "S" - debug_print(f'{key} released', 2) - except AttributeError: - debug_print(f'special key {key} released', 2) - if key == keyboard.Key.esc: - # Stop listener - return False - - -# Start the keyboard listener in a non-blocking manner -listener = keyboard.Listener(on_press=on_press, on_release=on_release) - -listener.start() - -# Run the program -while True: - message = send_str_arr.copy() - message.append("\n") - debug_print("".join(message), 0) - message = [ord(c) for c in message] - debug_print(message, 1) - ser.write(message) - time.sleep(1) - pass + listener.start() + + +def handler(signum, frame): + # reset angle + reset_angle(current_angle=current_angle) + # stop moving + generate_pwm(0, pwm_controls=pwm_controls) + sys.exit(0) + + +signal.signal(signal.SIGINT, handler) + + +def main(): + setup_rpi(pwm_controls=pwm_controls) + setup_keyboard() + while True: + run() + + +main() diff --git a/RaspberryPi/Wheel_Controller.py b/RaspberryPi/Wheel_Controller.py index 7745340..0ede73f 100644 --- a/RaspberryPi/Wheel_Controller.py +++ b/RaspberryPi/Wheel_Controller.py @@ -1,257 +1,19 @@ import RPi.GPIO as GPIO -from time import sleep -from enum import Enum -from pynput import keyboard +from RaspberryPi.rpi_helper import generate_pwm +from constants import * +from rpi_helper import reset_angle, setup_rpi, debug_print +import signal +import sys import cv2 as cv from ..Navigation.algorithms import SeesawAlgorithm as Seesaw -# LEFT and RIGHT output values for stepper motor -DIR_RIGHT = 1 -DIR_LEFT = 0 - -# FORWARD and BACKWARD output values for gearbox motor -DIR_FORWARD = True -DIR_BACKWARD = False - -# Angular Speed, recommended setting 7, DO NOT DECREASE TO < 3 -ANGULAR_SPEED = 7 / 1000 # python sleep uses seconds - -# Strength of PWM, between 0 and 255, higher is faster -PWM_SPEED = 100 -PWM_MAX_SPEED = 255 -PWM_FREQUENCY = 100 - -# 1 pulse to angle -# 400 revs per 360 degrees -REV_ANGLE = 360.0 / 400.0 - -# max turning angle -MAX_ANGLE = 90.0 - -# enum for vertical directions - - -class V_Directions(Enum): - halted = 0 - forward = 1 - backward = 2 - -# enum for horizontal directions - - -class H_Directions(Enum): - straight = 0 - left = 1 - right = 2 - - -# variable for stepper direction [left, right] -angular_dir = H_Directions.straight - -# variable for gearbox direction [forward, backward] -movement_dir = V_Directions.halted - -# current_angle of stepper motor +# global variables current_angle = 0.0 - -movement_arr = (V_Directions.halted, H_Directions.straight) - -'''HARDWARD PWM''' -# from rpi_hardware_pwm import HardwarePWM -# GearboxLeftPWM = HardwarePWM(pwm_channel=0, hz=60) # pwm channel 0: GPIO_18 -# GearboxRightPWM = HardwarePWM(pwm_channel=1, hz=60) # pwm channel 1: GPIO_19 - -# GearboxLeftPWM.start(0) -# GearboxRightPWM.start(0) - -# GearboxLeftPWM.stop() -# GearboxRightPWM.stop() - -# pwm.change_duty_cycle(50) -# pwm.change_frequency(25_000) - - -'''PINS''' -# RPI 3B+ pinout diagram: https://pinout.xyz/ -# G: Gearbox Connection (Stepper motors) -# D: DC Motor Driver -# Each wheel uses a DC Motor controlled by a DC Motor Driver -# the front two wheels uses a Gearbox connection to control the stepper motor for direction -DFL_DIR = 11 -DFL_PWM = 13 -DFR_DIR = 15 -DFR_PWM = 16 -DBL_DIR = 18 -DBL_PWM = 22 -DBR_DIR = 29 -DBR_PWM = 31 -GL_DIR = 32 -GL_PULSE = 33 -GR_DIR = 36 -GR_PULSE = 37 - -PINS = ( - DFL_DIR, - DFL_PWM, - DFR_DIR, - DFR_PWM, - DBL_DIR, - DBL_PWM, - DBR_DIR, - DBR_PWM, - GL_DIR, - GL_PULSE, - GR_DIR, - GR_PULSE, -) - -PWMS = ( - DFL_PWM, - DFR_PWM, - DBL_PWM, - DBR_PWM, -) - +movement_arr = [V_Directions.halted, H_Directions.straight] pwm_controls = [] -def setup_rpi(): - GPIO.setwarnings(False) # disable warnings - GPIO.setmode(GPIO.BOARD) # set pin numbering system - GPIO.setup(PINS, GPIO.OUT) - - for pwm in PWMS: - pwm_control = GPIO.PWM(pwm, PWM_FREQUENCY) # create PWM instance with frequency - pwm_control.start(0) # set 0 Duty Cycle - pwm_controls.append(pwm_control) - -# turns stepper motor in desired direction - - -def turn_wheels(direction): - GPIO.output(GL_DIR, direction) - GPIO.output(GR_DIR, direction) - generate_pulse() - -# generates pulse for stepper motors - - -def generate_pulse(): - GPIO.output(GL_PULSE, GPIO.HIGH) - GPIO.output(GR_PULSE, GPIO.HIGH) - sleep(ANGULAR_SPEED) - GPIO.output(GL_PULSE, GPIO.LOW) - GPIO.output(GR_PULSE, GPIO.LOW) - sleep(ANGULAR_SPEED) - - -# turns gearbox motor in desired direction -def rotate_wheels(direction): - GPIO.output(DFL_DIR, int(direction)) - GPIO.output(DFR_DIR, int(not direction)) - GPIO.output(DBL_DIR, int(direction)) - GPIO.output(DBR_DIR, int(not direction)) - - generate_pwm(PWM_SPEED) - -# generate pwm for gearbox motors - - -def generate_pwm(speed): - for pwmc in pwm_controls: - pwmc.ChangeDutyCycle(speed / PWM_MAX_SPEED) - -# Resets the stepper motor angle to 0 degrees - - -def reset_angle(): - global current_angle - dir = DIR_RIGHT if current_angle < 0 else DIR_LEFT - inc_value = REV_ANGLE if current_angle < 0 else -REV_ANGLE - print("Reseting angle") - - turn_angle = abs(current_angle) // REV_ANGLE - for _ in range(turn_angle): - turn_wheels(dir) - current_angle += inc_value - print("Reset complete") - - -def run(): - global current_angle, PWM_SPEED, movement_arr - print("speed ", PWM_SPEED) - movement, turning = movement_arr - print(movement, turning) - print("angle ", current_angle) - try: - if movement == V_Directions.forward: - print("Moving forward") - PWM_SPEED = min(PWM_SPEED + 10, PWM_MAX_SPEED) - rotate_wheels(DIR_FORWARD) - elif movement == V_Directions.backward: - print("Moving backward") - PWM_SPEED = max(PWM_SPEED - 10, 0) - rotate_wheels(DIR_BACKWARD) - else: - # stop moving - generate_pwm(0) - - if turning == H_Directions.left: - if current_angle <= -MAX_ANGLE: - print("Max angle reached") - else: - print("Turning left") - current_angle -= REV_ANGLE - turn_wheels(DIR_LEFT) - elif turning == H_Directions.right: - if current_angle >= MAX_ANGLE: - print("Max angle reached") - else: - print("Turning right") - current_angle += REV_ANGLE - turn_wheels(DIR_RIGHT) - else: - # reset angle - reset_angle() - - except AttributeError: - print("Attribute Error") - - -# testing with keyboard -def setup_keyboard(): - def on_press(key): - try: - if key.char == "w": - movement_arr[0] = V_Directions.forward - elif key.char == "s": - movement_arr[0] = V_Directions.backward - elif key.char == "a": - movement_arr[1] = H_Directions.left - elif key.char == "d": - movement_arr[1] = H_Directions.right - except AttributeError: - print(f'special key {key} pressed') - - def on_release(key): - try: - if key.char == "w" or key.char == "s": - movement_arr[0] = V_Directions.halted - elif key.char == "a" or key.char == "d": - movement_arr[1] = H_Directions.straight - print(f'{key} released') - except AttributeError: - if key == keyboard.Key.esc: - # Stop listener - return False - - # Start the keyboard listener in a non-blocking manner - listener = keyboard.Listener(on_press=on_press, on_release=on_release) - - listener.start() - - def run_algorithm(alg, vid_file): vid = cv.VideoCapture(vid_file) @@ -268,7 +30,7 @@ def run_algorithm(alg, vid_file): # frame = pre_process.standardize_frame(frame) processed_image, angle = alg.process_frame(frame, show=args.show) - print(angle) + debug_print(angle) key = cv.waitKey(25) @@ -277,9 +39,19 @@ def run_algorithm(alg, vid_file): break +def handler(signum, frame): + # reset angle + reset_angle(current_angle=current_angle) + # stop moving + generate_pwm(0, pwm_controls=pwm_controls) + sys.exit(0) + + +signal.signal(signal.SIGINT, handler) + + def main(): - setup_rpi() - setup_keyboard() + setup_rpi(pwm_controls=pwm_controls) run_algorithm(Seesaw, "../Navigation/videos/down1.mp4") diff --git a/RaspberryPi/Wheel_Controller.spec b/RaspberryPi/Wheel_Controller.spec new file mode 100644 index 0000000..54a5c32 --- /dev/null +++ b/RaspberryPi/Wheel_Controller.spec @@ -0,0 +1,44 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['Wheel_Controller.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=['pynput.keyboard._xorg'], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='Wheel_Controller', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/RaspberryPi/constants.py b/RaspberryPi/constants.py new file mode 100644 index 0000000..03f76c9 --- /dev/null +++ b/RaspberryPi/constants.py @@ -0,0 +1,102 @@ +from enum import Enum + +# LEFT and RIGHT output values for stepper motor +DIR_RIGHT = 1 +DIR_LEFT = 0 + +# FORWARD and BACKWARD output values for gearbox motor +DIR_FORWARD = 1 +DIR_BACKWARD = 0 + +# Angular Speed, recommended setting 7, DO NOT DECREASE TO < 3 +ANGULAR_SPEED = 7 / 1000 # python sleep uses seconds + +# Strength of PWM, between 0 and 255, higher is faster +PWM_SPEED = 80 # % duty cycle +PWM_MAX_SPEED = 100 +PWM_FREQUENCY = 100 + +# 1 pulse to angle +# 400 revs per 360 degrees +REV_ANGLE = 360.0 / 400.0 + +# max turning angle +MAX_ANGLE = 90.0 + +# enum for vertical directions + + +class V_Directions(Enum): + halted = 0 + forward = 1 + backward = 2 + +# enum for horizontal directions + + +class H_Directions(Enum): + straight = 0 + left = 1 + right = 2 + + +# level 0: once every DEBUG_FREQUENCY seconds +# level 1: no timing restrictions +DEBUG_LEVEL = 1 +DEBUG_FREQUNCY = 1 # seconds + +'''HARDWARD PWM''' +# from rpi_hardware_pwm import HardwarePWM +# GearboxLeftPWM = HardwarePWM(pwm_channel=0, hz=60) # pwm channel 0: GPIO_18 +# GearboxRightPWM = HardwarePWM(pwm_channel=1, hz=60) # pwm channel 1: GPIO_19 + +# GearboxLeftPWM.start(0) +# GearboxRightPWM.start(0) + +# GearboxLeftPWM.stop() +# GearboxRightPWM.stop() + +# pwm.change_duty_cycle(50) +# pwm.change_frequency(25_000) + + +'''PINS''' +# RPI 3B+ pinout diagram: https://pinout.xyz/ +# G: Gearbox Connection (Stepper motors) +# D: DC Motor Driver +# Each wheel uses a DC Motor controlled by a DC Motor Driver +# the front two wheels uses a Gearbox connection to control the stepper motor for direction +DFL_DIR = 11 +DFL_PWM = 13 +DFR_DIR = 15 +DFR_PWM = 16 +DBL_DIR = 18 +DBL_PWM = 22 +DBR_DIR = 29 +DBR_PWM = 31 +GL_DIR = 32 +GL_PULSE = 33 +GR_DIR = 36 +GR_PULSE = 37 + +PINS = ( + DFL_DIR, + DFL_PWM, + DFR_DIR, + DFR_PWM, + DBL_DIR, + DBL_PWM, + DBR_DIR, + DBR_PWM, + GL_DIR, + GL_PULSE, + GR_DIR, + GR_PULSE, +) + +PWMS = ( + DFL_PWM, + DFR_PWM, + DBL_PWM, + DBR_PWM, +) diff --git a/RaspberryPi/gamepad.py b/RaspberryPi/gamepad.py new file mode 100644 index 0000000..edfb0e5 --- /dev/null +++ b/RaspberryPi/gamepad.py @@ -0,0 +1,69 @@ +from constants import H_Directions, V_Directions +from evdev import list_devices, InputDevice, categorize, ecodes + +# https://stackoverflow.com/questions/44934309/how-to-access-the-joysticks-of-a-gamepad-using-python-evdev + +CENTER_TOLERANCE = 150 +STICK_MAX = 65536 + +dev = InputDevice(list_devices()[0]) + +axis = { + ecodes.ABS_X: 'ls_x', # 0 - 65,536 the middle is 32768 + ecodes.ABS_Y: 'ls_y', + ecodes.ABS_RX: 'rs_x', + ecodes.ABS_RY: 'rs_y', + 2: 'lt', # 0 - 1023 + 5: 'rt', + + ecodes.ABS_HAT0X: 'dpad_x', # -1 - 1 + ecodes.ABS_HAT0Y: 'dpad_y' +} + +center = { + 'ls_x': STICK_MAX / 2, + 'ls_y': STICK_MAX / 2, + 'rs_x': STICK_MAX / 2, + 'rs_y': STICK_MAX / 2 +} + +last = { + 'ls_x': STICK_MAX / 2, + 'ls_y': STICK_MAX / 2, + 'rs_x': STICK_MAX / 2, + 'rs_y': STICK_MAX / 2, + 'rt': 0, + 'lt': 0 +} + + +def run_gamepad(process): + move, turn = V_Directions.halted, H_Directions.straight + for event in dev.read_loop(): + # deleted calibration, might need in the future, look at stackoverflow answer above + if event.type == ecodes.EV_ABS and (event.code in list(axis)): + last[axis[event.code]] = event.value + value = event.value + if abs(value) <= CENTER_TOLERANCE: + value = 0 + if event.code == 2: + if value == 0: + move = V_Directions.halted + else: + move = V_Directions.backward + elif event.code == 5: + if value == 0: + move = V_Directions.halted + else: + move = V_Directions.forward + + elif axis[event.code] == 'ls_x': + # print(value) + if value < 0: + turn = H_Directions.left + elif value == 0: + turn = H_Directions.straight + else: + turn = H_Directions.right + # print(move + ", " + turn) + process(move, turn) diff --git a/RaspberryPi/rpi_helper.py b/RaspberryPi/rpi_helper.py new file mode 100644 index 0000000..e8ae5f9 --- /dev/null +++ b/RaspberryPi/rpi_helper.py @@ -0,0 +1,83 @@ +import RPi.GPIO as GPIO +from time import sleep, time +from constants import * + +# turns stepper motor in desired direction + + +def turn_wheels(direction): + GPIO.output(GL_DIR, direction) + GPIO.output(GR_DIR, direction) + generate_pulse() + +# generates pulse for stepper motors + + +def generate_pulse(): + GPIO.output(GL_PULSE, GPIO.HIGH) + GPIO.output(GR_PULSE, GPIO.HIGH) + sleep(ANGULAR_SPEED) + GPIO.output(GL_PULSE, GPIO.LOW) + GPIO.output(GR_PULSE, GPIO.LOW) + sleep(ANGULAR_SPEED) + + +# turns gearbox motor in desired direction +def rotate_wheels(direction, pwm_controls): + GPIO.output(DFL_DIR, int(direction)) + GPIO.output(DFR_DIR, int(not direction)) + GPIO.output(DBL_DIR, int(direction)) + GPIO.output(DBR_DIR, int(not direction)) + + generate_pwm(PWM_SPEED, pwm_controls) + +# generate pwm for gearbox motors + + +def generate_pwm(speed, pwm_controls): + for pwmc in pwm_controls: + pwmc.ChangeDutyCycle(int((speed // 10) * 10)) + +# Resets the stepper motor angle to 0 degrees + + +def reset_angle(current_angle): + dir = DIR_RIGHT if current_angle < 0 else DIR_LEFT + inc_value = REV_ANGLE if current_angle < 0 else -REV_ANGLE + debug_print("Reseting angle") + + turn_angle = int(abs(current_angle) // REV_ANGLE) + # for _ in range(turn_angle): + # turn_wheels(dir) + # current_angle += inc_value + # debug_print("Reset complete") + + turn_wheels(dir) + current_angle += inc_value + debug_print("Resetting...") + + return current_angle + + +def setup_rpi(pwm_controls): + GPIO.setwarnings(False) # disable warnings + GPIO.setmode(GPIO.BOARD) # set pin numbering system + GPIO.setup(PINS, GPIO.OUT) + + for pwm in PWMS: + # create PWM instance with frequency + pwm_control = GPIO.PWM(pwm, PWM_FREQUENCY) + pwm_control.start(0) # set 0 Duty Cycle + pwm_controls.append(pwm_control) + + +last_debug_print_time = 0 + + +def debug_print(*output: object): + if DEBUG_LEVEL == 0: + if time() - last_debug_print_time > DEBUG_FREQUNCY: + print(output) + last_debug_print_time = time() + elif DEBUG_LEVEL == 1: + print(output)