# Turntable Control by Stepper Motor # ================================== issue = "0.10 02-Jan-17" # Get Required Modules # ==================== from os import system from time import sleep from gpiozero import Button as key from threading import Thread from signal import pause import RPi.GPIO as GPIO GPIO.setwarnings(False) # Use BCM GPIO references # instead of physical pin numbers GPIO.setmode(GPIO.BCM) # Define GPIO signals to use for Stepper Control # ---------------------------------------------- # Physical pins 29,31,33,35 # GPIO 05,06,13,19 stepper_OPs = [5,6,13,19] # Set all Stepper GPIO as output for pin in stepper_OPs: GPIO.setup(pin,GPIO.OUT) GPIO.output(pin, False) # Define advanced sequence # as shown in manufacturers datasheet seq = [[1,0,0,1], [1,0,0,0], [1,1,0,0], [0,1,0,0], [0,1,1,0], [0,0,1,0], [0,0,1,1], [0,0,0,1]] seq_length = len(seq) -1 # Define Control Input Keys # ------------------------- # key(pin,pull_up,bounce_time,hold_time,hold_repeat) # I2C signals controlled from Rowanburn R-Pi-3 # Shutdown this R-Pi-Z or Halt the Program stop_ip = key(18) # Do a full Half Turn, with no Hold Action turn_ip = key(23, True, 0.02) # Manual Push Buttons # Do a Single Sequence Forward, with Repeat on Hold for 1 second. nudge_forward = key(24, True, 0.02, 0.5, False) # Do a Single Sequence Backward, with Repeat on Hold for 1 second. nudge_reverse = key(25, True, 0.02, 0.5, False) # Define Turntable Motion # ----------------------- seq_index = 0 # Initial Stepper Sequence Index half_turn = 2048 # Steps for a Half Turn full_speed_dwell = 20 # msec between individual steps at Full Speed start_speed_dwell = 50 # msec between individual steps when Starting/Stopping accell_steps = 100 # Steps for Acceleration & Decelleration. nudge_dwell = 20 # msec between individual steps when Nudging if accell_steps > 1: dwell_increment = (start_speed_dwell - full_speed_dwell) / float(accell_steps) rotating = False halt = False # Procedures # ========== def all_off(): """Turns all Stepper OPs OFF""" for pin in range(4): op_pin=stepper_OPs[pin] # Get GPIO GPIO.output(op_pin, False) def do_step(dwell): global seq_index if (seq_index > seq_length): seq_index = 0 if (seq_index < 0): seq_index = seq_length for pin in range(4): op_pin=stepper_OPs[pin] # Get GPIO if seq[seq_index][pin] == 0: GPIO.output(op_pin, False) else: GPIO.output(op_pin, True) sleep(dwell) def rotate(steps, direction, speed_dwell): """How many Steps to Rotate, Direction & Speed""" global seq_index, rotating rotating = True step_counter = 0 decell_steps = steps - accell_steps while step_counter < steps: seq_index += direction dwell = speed_dwell/float(1000) do_step(dwell) step_counter += 1 # Accellerate or Decellerate if step_counter <= accell_steps: speed_dwell -= dwell_increment if step_counter >= decell_steps: speed_dwell += dwell_increment # Steps finished all_off() rotating = False def nudge_one(direction, speed_dwell): """Single Step - Direction & Speed""" global seq_index, rotating rotating = True seq_index += direction dwell = speed_dwell/float(1000) do_step(dwell) all_off() rotating = False def nudge_continuously(direction, speed_dwell): """Continuous Step - Direction & Speed""" global seq_index, rotating rotating = True dwell = speed_dwell/float(1000) nudge = True while nudge: seq_index += direction do_step(dwell) if direction == 1: nudge = nudge_forward.is_pressed else: nudge = nudge_reverse.is_pressed if nudge_forward.is_pressed and nudge_reverse.is_pressed: nudge = False all_off() rotating = False # Program Shut Down Procedures # ============================ def stop(): """Manually called from Idle""" global halt halt = True def RunMode(): """Checks 'stop_ip' and the halt flag Returns TRUE if i/p low or if 'stop()' entered manually via Idle""" return ( stop_ip.is_pressed == False ) and ( halt == False ) def shut_down(): """Option to SHUTDOWn or REBOOT. RunMode returns FALSE if 'stop_ip' pressed If RunMode ip NOT reset within 2 seconds do FULL SHUTDOWN Otherwise if Nudge-Forward Pressed do REBOOT or just finish the Program.""" print("Program EXITED - as NOT in RunMode") # Check if RunMode is reset within 2 seconds time_out = 20 # 2 seconds while time_out > 0: if RunMode(): break sleep(0.1) time_out -= 1 # If TimedOut do a Full Shutdown if time_out <= 0: print("SYSTEM SHUTTING DOWN") system("sudo shutdown -h now") # Otherwise Reboot or Finish else: if nudge_forward.is_pressed: # Do a Reset print("SYSTEM REBOOTING") system("sudo shutdown -r now") else: # Do Nothing GPIO.cleanup() # This needed to stop the Key Actions print("Program FINISHED") # Program Actions # =============== def do_half_turn(): rotate(half_turn, 1, start_speed_dwell) def step_forward(): nudge_one(1, nudge_dwell) def step_forward_continuously(): nudge_continuously(1, nudge_dwell) def step_reverse(): nudge_one(-1, nudge_dwell) def step_reverse_continuously(): nudge_continuously(-1, nudge_dwell) # Control Turntable # ================= def control_turntable(): turn_ip.when_pressed = do_half_turn nudge_forward.when_pressed = step_forward nudge_forward.when_held = step_forward_continuously nudge_reverse.when_pressed = step_reverse nudge_reverse.when_held = step_reverse_continuously print("'Turntable' is running.") while RunMode(): sleep(1) # Control Thread Ending, as Not in RunMode print("'Turntable' will Halt when turning finished.") # Wait till Turntable finishes turning while rotating: sleep(1) all_off() ## sleep(1) # Do conditional ShutDown if halt: # Set by call of 'stop()' in Idle GPIO.cleanup() # This needed to stop the Key Actions print("Program Halted by Idle call of 'stop()'") else: # Otherwise do ShutDown with options shut_down() # Script started as a Thread # ========================== Thread(target = control_turntable).start()