# Turntable Control by Stepper Motor - StepStick A4988 # ==================================================== issue = "0.20 05-Mar-18" # Get Required Modules # ==================== from os import system from time import sleep from gpiozero import LED as output, Button as key from threading import Thread from signal import pause import RPi.GPIO as GPIO # DISPLAY Motion Parameters # & Information in Python Shell # ----------------------------- #show = False show = True # 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(12) # Do a full Half Turn, with no Hold Action turn_ip = key(16, True, 0.02) # Manual Push Buttons # Do a Single Sequence Forward, with Repeat on Hold for 1 second. nudge_forward = key(20, True, 0.02, 0.5, False) # Do a Single Sequence Backward, with Repeat on Hold for 1 second. nudge_reverse = key(21, True, 0.02, 0.5, False) # Define Turntable Motion # ----------------------- full_speed = 95 # In range 1-100 ; 100 is defined by the Minimum Pulse for the Motor nudge_speed = 40 half_turn = 180 # Degrees accell_degrees = 10 # Angle for Acceleration & Decelleration. nudge_degrees = 0.5 # Angle for a Nudge. mode = 8 # Stepper Micro-Stepping Mode: 1,2,4,8 16 rotating = False halt = False # Define GPIO signals to use for Stepper Control # ---------------------------------------------- direction = output(25) direction.off() step = output(5) step.off() status_led = output(24) status_led.blink(0.01,2) # Disable Stepper Outputs disable = output(26) disable.on() # Micro Stepping Control # MS1 MS2 MS3 # L L L Full Step # H L L Half Step # L H L Quarter Step # H H L Eight Step # H H H Sixteenth Step ms1 = output(19) ms2 = output(13) ms3 = output(6) # Minimum Pulse for this motor is # 2 msec for Full Step # 3 msec for Half Step # 4 msec for Quarter Step and above # Minimum Pulse for this motor at 7.5v is 0.35 msec pulse = 0.4 * 0.001 # in seconds if show: print ("Stepper Pulse", pulse * 1000,"ms\n") print print ("rotate ( Degrees, Speed, Accell', Step Mode )") print (" + or - 1-100 degrees 1 2 4 8 16") print ("rotate(180,95,5,8) 33sec") print ("rotate(180,90,5,8) 45sec") print ("rotate(180,90,20,8) 1m") print ("rotate(180,80,5,8) 1m 10sec") print ("rotate(180,80,10,8) 1m 18sec") print ("rotate(180,70,10,8) 1m 45sec") print ("rotate(180,60,10,8) 2m 13sec") print ("rotate(180,50,10,8) 2m 41sec") print ("rotate(180,50,5,8) 1m 55sec") print print ("rotate(180,98,20,16) 58sec") print ("rotate(180,97,20,16) 1m 5sec") print ("rotate(180,95,5,16) 1m 4sec") print ("rotate(180,90,20,16) 1m 58sec") print ("rotate(180,90,10,16) 1m 38sec") print ("rotate(180,85,10,16) 2m 6sec") print ("rotate(180,85,5,16) 1m 53sec") print ("rotate(180,80,5,16) 2m 15sec") print # 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 5 seconds time_out = 50 # 5 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 print("Program FINISHED") # Stepper Motor Procedures # ======================== def set_mode(mode): # Full Step ms1.off() ms2.off() ms3.off() # Half Step if mode == 2: ms1.on() # Quarter Step if mode == 4: ms2.on() # Eighth Step if mode == 8: ms1.on() ms2.on() # Sixteenth Step if mode == 16: ms1.on() ms2.on() ms3.on() def rotate(degrees, speed, accell_degrees, mode): """ Rotation Degrees +-, Speed 1 to 100, Accell/Decell Degrees Step Mode 1 2 4 8 16""" # 4656 steps per revolution - 18 deg step with 232 gearbox global rotating rotating = True status_led.on() steps = int(abs( degrees * 4656 * mode / 360 )) accell_steps = int(accell_degrees * 4656 * mode / 360) decell_steps = steps - accell_steps # set the direction output to true for left and false for right if degrees >= 0: direction.on() stps = steps else: direction.off() stps = - steps # Set MicroStepping Mode set_mode(mode) disable.off() sleep(0.01) # Dwell controls speed full_speed_dwell = 0.0001 * abs(100 - speed) # seconds if accell_steps > 0: start_speed_dwell = ( 10 * full_speed_dwell ) + 0.001 dwell_increment = (start_speed_dwell - full_speed_dwell) / float(accell_steps) speed_dwell = start_speed_dwell else: speed_dwell = full_speed_dwell dwell_increment = 0 if show: print ("Steps",stps, "<",accell_steps,"> Speed Dwell", full_speed_dwell * 1000 ,"ms Dwell Incr'", int(dwell_increment * 1000000), "us") # Track the number of steps taken step_counter = 0 # Do the Move while step_counter < steps: # Turning the GPIO on and off tells the driver to take one step step.on() sleep(pulse) step.off() sleep(pulse) step_counter += 1 # Wait before taking the next step...this controls rotation speed sleep(speed_dwell) # Accellerate or Decellerate if step_counter < accell_steps: speed_dwell -= dwell_increment if step_counter > decell_steps: speed_dwell += dwell_increment disable.on() rotating = False status_led.blink(0.01,1) # Program Actions # =============== #rotate(degrees, speed, accell_degrees, mode) def do_half_turn(): rotate(half_turn, full_speed, accell_degrees, mode) def do_nudge_forward(): rotate(nudge_degrees, nudge_speed, 0, mode) def nudge_forward_continuously(): while nudge_forward.is_pressed: rotate(nudge_degrees, nudge_speed, 0, mode) def do_nudge_reverse(): rotate(-nudge_degrees, nudge_speed, 0, mode) def nudge_reverse_continuously(): while nudge_reverse.is_pressed: rotate(-nudge_degrees, nudge_speed, 0, mode) # Control Turntable # ================= def control_turntable(): turn_ip.when_pressed = do_half_turn nudge_forward.when_pressed = do_nudge_forward nudge_forward.when_held = nudge_forward_continuously nudge_reverse.when_pressed = do_nudge_reverse nudge_reverse.when_held = nudge_reverse_continuously print("'Turntable Application' is running.") status_led.blink(0.01,1) while RunMode(): sleep(1) # Control Thread Ending, as Not in RunMode print("'Turntable Application' will Halt when turning finished.") # Wait till Turntable finishes turning while rotating: sleep(1) # Do conditional ShutDown if halt: # Set by call of 'stop()' in Idle disable.on() direction.off() step.off() status_led.blink(0.01,1) 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()