added hardware board software and PC control guide
This commit is contained in:
233
Software/TMC2130.py
Normal file
233
Software/TMC2130.py
Normal file
@@ -0,0 +1,233 @@
|
||||
from machine import Pin, PWM, SPI
|
||||
import time
|
||||
import utime
|
||||
from config import *
|
||||
from led import *
|
||||
from sTimer import sTimer_Start, sTimer_Stop
|
||||
import sys
|
||||
import _thread
|
||||
|
||||
sLock = _thread.allocate_lock()
|
||||
|
||||
EN = Pin(13, Pin.OUT)
|
||||
DIR = Pin(14, Pin.OUT)
|
||||
STEP = Pin(15, Pin.OUT)
|
||||
ENDSTOP = Pin(8, Pin.IN, Pin.PULL_UP)
|
||||
DC_EN = Pin(11, Pin.OUT)
|
||||
DC_IN = Pin(10, Pin.OUT)
|
||||
DC_OUT = Pin(12, Pin.IN)
|
||||
SPI_MODE = Pin(20, Pin.OUT)
|
||||
spi_cs = Pin(17, Pin.OUT)
|
||||
|
||||
spi = SPI(0, baudrate=100000, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, sck=Pin(18, Pin.OUT), mosi=Pin(19, Pin.OUT), miso=Pin(16, Pin.IN))
|
||||
|
||||
DC_EN(0)
|
||||
DC_IN(0)
|
||||
spi_cs(1)
|
||||
EN(1) #0 = enabled
|
||||
DIR(0)
|
||||
STEP(0)
|
||||
|
||||
MM_PER_STEP = SCREW_PITCH / (MOTOR_STEPS * MICROSTEPPING)
|
||||
FREQ_PER_STEP_INCREASE = (((MOTOR_STEPS * MICROSTEPPING) / SCREW_PITCH) * ACCELERATION) / 60
|
||||
|
||||
REG_GCONF = 0x00
|
||||
REG_GSTAT = 0x01
|
||||
REG_IHOLD_IRUN = 0x10
|
||||
REG_CHOPCONF = 0x6C
|
||||
REG_COOLCONF = 0x6D
|
||||
REG_DCCTRL = 0x6E
|
||||
REG_DRVSTATUS = 0x6F
|
||||
|
||||
step_cntr = 0
|
||||
target_steps = 0
|
||||
target_frequency = 0
|
||||
current_frequency = 0
|
||||
|
||||
def step():
|
||||
global STEP, step_cntr, current_frequency, target_frequency, target_steps, FREQ_PER_STEP_INCREASE
|
||||
STEP.value(not STEP.value())
|
||||
STEP.value(not STEP.value())
|
||||
LED_ERR.value(not LED_ERR.value())
|
||||
|
||||
step_cntr += 1
|
||||
if(current_frequency < target_frequency):
|
||||
current_frequency += FREQ_PER_STEP_INCREASE
|
||||
if(target_steps >= step_cntr):
|
||||
pass
|
||||
|
||||
def rotate_motor(steps, feedrate):
|
||||
global current_frequency, step_cntr, target_steps, target_frequency
|
||||
step_cntr = 0
|
||||
target_steps = steps
|
||||
target_frequency = ((feedrate / SCREW_PITCH) * MOTOR_STEPS * MICROSTEPPING) / 60 #steps/s = rpm * steps_per_rotation / 60
|
||||
print(target_frequency)
|
||||
print(FREQ_PER_STEP_INCREASE)
|
||||
current_frequency = FREQ_PER_STEP_INCREASE
|
||||
|
||||
def timer_callback(counter):
|
||||
if (counter % 1) == 0:
|
||||
step()
|
||||
|
||||
def get_stats():
|
||||
global STEP, step_cntr, current_frequency, target_frequency, target_steps, FREQ_PER_STEP_INCREASE
|
||||
print(step_cntr, current_frequency, target_frequency, FREQ_PER_STEP_INCREASE)
|
||||
|
||||
def rotate_motor_test():
|
||||
rotate_motor(32*200, 5)
|
||||
sTimer_Start()
|
||||
time.sleep(2)
|
||||
sTimer_Stop()
|
||||
|
||||
def prepare_spi_msg(addr, d0, d1, d2, d3, rw):
|
||||
msg = bytearray()
|
||||
if rw == 'r':
|
||||
msg.append(addr)
|
||||
else:
|
||||
msg.append(0x80 + addr)
|
||||
msg.append(d0)
|
||||
msg.append(d1)
|
||||
msg.append(d2)
|
||||
msg.append(d3)
|
||||
|
||||
return msg
|
||||
|
||||
def send_spi_msg(msg):
|
||||
spi_cs(0)
|
||||
rxdata = bytearray(5)
|
||||
spi.write_readinto(msg, rxdata)
|
||||
#print(rxdata.hex())
|
||||
spi_cs(1)
|
||||
time.sleep(0.01)
|
||||
|
||||
def TMC2130_Rotate(dir, steps, speed): #speed in rpm
|
||||
#1rmp = 200steps/min=3.333steps/s~150ms@50%duty
|
||||
sLock.acquire()
|
||||
wait = (((1 / ((MOTOR_STEPS * MICROSTEPPING) / 60)) / 2) / speed) * 1000 * 1000
|
||||
freq = 1 / ((wait / 1000000) * 2)
|
||||
|
||||
if AXIS_REVERSE:
|
||||
if dir == 0:
|
||||
dir = 1
|
||||
else:
|
||||
dir = 0
|
||||
|
||||
DIR(dir)
|
||||
LED_DIR(1)
|
||||
|
||||
STEP = PWM(Pin(15), freq=int(freq), duty_u16=32768)
|
||||
time.sleep((1 / freq) * steps)
|
||||
STEP.deinit()
|
||||
LED_DIR(0)
|
||||
sLock.release()
|
||||
|
||||
homing = False
|
||||
def TMC2130_Home():
|
||||
global homing
|
||||
|
||||
dir = HOME_DIR
|
||||
STEP = Pin(15, Pin.OUT)
|
||||
|
||||
steps_mm = (MOTOR_STEPS * MICROSTEPPING) / SCREW_PITCH
|
||||
rpm = HOME_SPEED / SCREW_PITCH
|
||||
wait = (((1 / ((MOTOR_STEPS * MICROSTEPPING) / 60)) / 2) / rpm) * 1000 * 1000
|
||||
freq = 1 / ((wait / 1000000) * 2)
|
||||
|
||||
if AXIS_REVERSE:
|
||||
if dir == 0:
|
||||
dir = 1
|
||||
else:
|
||||
dir = 0
|
||||
|
||||
DIR(dir)
|
||||
LED_DIR(dir)
|
||||
|
||||
sys.stdout.write('homing\r\n')
|
||||
homing = True
|
||||
STEP = PWM(Pin(15), freq=int(freq), duty_u16=32768)
|
||||
while homing:
|
||||
pass
|
||||
STEP.deinit()
|
||||
|
||||
if HOME_DEBOUNCE == True:
|
||||
sys.stdout.write('debouncing\r\n')
|
||||
if dir == 0:
|
||||
dir = 1
|
||||
else:
|
||||
dir = 0
|
||||
|
||||
DIR(dir)
|
||||
LED_DIR(dir)
|
||||
|
||||
steps = steps_mm * abs(HOME_DEBOUNCE_DISTANCE)
|
||||
|
||||
TMC2130_Rotate(dir, steps, HOME_DEBOUNCE_SPEED)
|
||||
|
||||
rpm = HOME_DEBOUNCE_SPEED / SCREW_PITCH
|
||||
wait = (((1 / ((MOTOR_STEPS * MICROSTEPPING) / 60)) / 2) / rpm) * 1000 * 1000
|
||||
freq = 1 / ((wait / 1000000) * 2)
|
||||
|
||||
if dir == 0:
|
||||
dir = 1
|
||||
else:
|
||||
dir = 0
|
||||
|
||||
DIR(dir)
|
||||
LED_DIR(dir)
|
||||
|
||||
homing = True
|
||||
STEP = PWM(Pin(15), freq=int(freq), duty_u16=32768)
|
||||
while homing:
|
||||
pass
|
||||
STEP.deinit()
|
||||
|
||||
def TMC2130_Disable():
|
||||
EN.value(1)
|
||||
|
||||
def TMC2130_Enable():
|
||||
EN.value(0)
|
||||
|
||||
def endstop_callback(endstop):
|
||||
global homing
|
||||
|
||||
homing = False
|
||||
|
||||
def TMC2130_Init():
|
||||
SPI_MODE(1)
|
||||
# setup coolstep
|
||||
microstep = 0
|
||||
if MICROSTEPPING == 128:
|
||||
microstep = 1
|
||||
elif MICROSTEPPING == 64:
|
||||
microstep = 2
|
||||
elif MICROSTEPPING == 32:
|
||||
microstep = 3
|
||||
elif MICROSTEPPING == 16:
|
||||
microstep = 4
|
||||
elif MICROSTEPPING == 8:
|
||||
microstep = 5
|
||||
elif MICROSTEPPING == 4:
|
||||
microstep = 6
|
||||
elif MICROSTEPPING == 2:
|
||||
microstep = 7
|
||||
elif MICROSTEPPING == 1:
|
||||
microstep = 8
|
||||
else:
|
||||
microstep = 0
|
||||
|
||||
msg = prepare_spi_msg(REG_CHOPCONF, 0x00+microstep, 0x01, 0x00, 0xC3, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(REG_IHOLD_IRUN, 0x00, 0x06, I_RUN, I_HOLD, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(0x11, 0x00, 0x00, 0x00, 0x0A, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(REG_GCONF, 0x00, 0x00, 0x00, 0x04, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(0x13, 0x00, 0x00, 0x01, 0xF4, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(0x70, 0x00, 0x04, 0x01, 0xC8, 'w')
|
||||
send_spi_msg(msg)
|
||||
msg = prepare_spi_msg(REG_COOLCONF, 0x00, 0x00, 0x03, 0x01, 'w')
|
||||
send_spi_msg(msg)
|
||||
|
||||
TMC2130_Enable()
|
||||
27
Software/config.py
Normal file
27
Software/config.py
Normal file
@@ -0,0 +1,27 @@
|
||||
MOTOR_STEPS = 200
|
||||
MICROSTEPPING = 16
|
||||
I_HOLD = 10 #hold current (1-31)
|
||||
I_RUN = 10 #run current (1-31)
|
||||
|
||||
SCREW_PITCH = 5 #in mm/rotation
|
||||
AXIS_LENGTH = 1000 #mm
|
||||
AXIS_ID = 'X' #id of axis (X,Y,U,V)
|
||||
AXIS_REVERSE = False
|
||||
|
||||
HOME_DIR = 0
|
||||
HOME_SPEED = 600 #in mm/s
|
||||
HOME_DEBOUNCE = True
|
||||
HOME_DEBOUNCE_DISTANCE = 5 #in mm
|
||||
HOME_DEBOUNCE_SPEED = 200
|
||||
|
||||
ACCELERATION = 1
|
||||
|
||||
|
||||
FOCUS_MIN = 12000
|
||||
FOCUS_MAX = 23000
|
||||
AP_MIN = 4884
|
||||
AP_MAX = 6132
|
||||
FOCAL_LEN_MIN = 28
|
||||
FOCAL_LEN_MAX = 200
|
||||
|
||||
ZOOM_SPEED = 30
|
||||
6
Software/led.py
Normal file
6
Software/led.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from machine import Pin
|
||||
|
||||
LED_ERR = Pin(25, Pin.OUT)
|
||||
LED_DIR = Pin(3, Pin.OUT)
|
||||
LED_MSG = Pin(6, Pin.OUT)
|
||||
LED_OK = Pin(7, Pin.OUT)
|
||||
@@ -4,11 +4,20 @@ import time
|
||||
import math
|
||||
import sys
|
||||
import select
|
||||
from led import *
|
||||
from config import *
|
||||
import _thread
|
||||
from TMC2130 import TMC2130_Rotate, TMC2130_Init, rotate_motor_test
|
||||
|
||||
lens_cs = machine.Pin(7, machine.Pin.IN)
|
||||
body_cs = machine.Pin(8, machine.Pin.OUT)
|
||||
vd_lens = machine.Pin(9, machine.Pin.OUT)
|
||||
tx_pin = machine.Pin(16, machine.Pin.OUT)
|
||||
|
||||
lens_cs = machine.Pin(4, machine.Pin.IN)
|
||||
body_cs = machine.Pin(5, machine.Pin.OUT)
|
||||
vd_lens = machine.Pin(2, machine.Pin.OUT)
|
||||
tx_pin = machine.Pin(0, machine.Pin.OUT)
|
||||
|
||||
|
||||
|
||||
LED_OK.value(1)
|
||||
|
||||
poll_obj = ''
|
||||
|
||||
@@ -27,13 +36,9 @@ focus_pos = 0 #focus position to be set manually
|
||||
af_in_progress = False
|
||||
focus_mode = "MF" #AF/MF
|
||||
|
||||
focus_min = 12000
|
||||
focus_max = 23000
|
||||
ap_min = 4884
|
||||
ap_max = 6132
|
||||
|
||||
focus_pos = 0
|
||||
change_focus = False
|
||||
relative_focus = False
|
||||
|
||||
utime.sleep(1)
|
||||
vd_lens.value(1)
|
||||
@@ -56,6 +61,18 @@ time.sleep_ms(20)
|
||||
|
||||
rx_ack = False
|
||||
|
||||
def Zoom(focal_distance, steps_per_iter):
|
||||
dir = 0
|
||||
reverse = False
|
||||
|
||||
if focal_distance > focal_length:
|
||||
dir = 1
|
||||
while focal_distance > focal_length:
|
||||
TMC2130_Rotate(dir, steps_per_iter, ZOOM_SPEED)
|
||||
else:
|
||||
while focal_distance < focal_length:
|
||||
TMC2130_Rotate(dir, steps_per_iter, ZOOM_SPEED)
|
||||
|
||||
def Comms_Init():
|
||||
global poll_obj
|
||||
|
||||
@@ -63,24 +80,49 @@ def Comms_Init():
|
||||
poll_obj.register(sys.stdin, select.POLLIN)
|
||||
|
||||
def Comms_Read():
|
||||
global poll_obj, ap, focus_mode, change_focus, focus_pos
|
||||
global poll_obj, ap, focus_mode, change_focus, focus_pos, relative_focus
|
||||
|
||||
poll_results = poll_obj.poll(1)
|
||||
if poll_results:
|
||||
rw = sys.stdin.readline().strip()
|
||||
rw = rw.upper()
|
||||
if "APERTURE" in rw:
|
||||
data = rw.split(' ')
|
||||
ap = int(data[1])
|
||||
try:
|
||||
data = rw.split(' ')
|
||||
if "REL" in rw:
|
||||
ap = aperture_raw + int(data[1])
|
||||
else:
|
||||
ap = int(data[1])
|
||||
except:
|
||||
print("APERTURE SET ERROR")
|
||||
if "FOCUS" in rw:
|
||||
data = rw.split(' ')
|
||||
focus_pos = int(data[1])
|
||||
change_focus = True
|
||||
try:
|
||||
data = rw.split(' ')
|
||||
focus_pos = int(data[1])
|
||||
change_focus = True
|
||||
if "REL" in rw:
|
||||
relative_focus = True
|
||||
except:
|
||||
print("FOCUS SET ERROR")
|
||||
if "AF" in rw:
|
||||
focus_mode = "AF"
|
||||
if "MF" in rw:
|
||||
focus_mode = "MF"
|
||||
|
||||
if "ZOOM" in rw:
|
||||
try:
|
||||
data = rw.split(' ')
|
||||
if "STEPS" in rw:
|
||||
if int(data[1]) < 2:
|
||||
if int(data[1]) >= 0:
|
||||
if int(data[2]) > 0:
|
||||
_thread.start_new_thread(TMC2130_Rotate, (int(data[1]), int(data[2]), ZOOM_SPEED))
|
||||
else:
|
||||
if int(data[1]) > FOCAL_LEN_MIN:
|
||||
if int(data[1]) < FOCAL_LEN_MAX:
|
||||
if int(data[2]) > 0:
|
||||
_thread.start_new_thread(Zoom, (int(data[1]), int(data[2])))
|
||||
except:
|
||||
print("ZOOM SET ERROR")
|
||||
|
||||
def focal_length_conv(raw):
|
||||
return (math.exp((raw+92063.3)/8082.9)+406.979)/3256.82
|
||||
@@ -93,10 +135,10 @@ def aperture_count(value, leftMin=2.8, leftMax=16, rightMin=4884, rightMax=6132)
|
||||
return rightMin + (valueScaled * rightSpan)
|
||||
|
||||
def aperture(value):
|
||||
if value < ap_min:
|
||||
value = ap_min
|
||||
if value > ap_max:
|
||||
value = ap_max
|
||||
if value < AP_MIN:
|
||||
value = AP_MIN
|
||||
if value > AP_MAX:
|
||||
value = AP_MAX
|
||||
return value
|
||||
|
||||
def rx_end(pin):
|
||||
@@ -144,7 +186,8 @@ def print_rx():
|
||||
focus_limit = "UNKNOWN"
|
||||
if msg[5] == 5:
|
||||
aperture_raw = msg[6] + (msg[7] << 8)
|
||||
print("Focus limit:", focus_limit, "Focus:", focus, "Focal length:", focal_length, "Aperture:", aperture_raw)
|
||||
print("Focus mode:", focus_mode, "Focus limit:", focus_limit, "Focus:", focus, "Focal length:", focal_length, "Aperture:", aperture_raw)
|
||||
LED_MSG.toggle()
|
||||
|
||||
else:
|
||||
if b == 0xf0:
|
||||
@@ -215,12 +258,12 @@ def send_af():
|
||||
time.sleep_ms(6)
|
||||
|
||||
def move_focus(position):
|
||||
global ap, ap_closing, af_in_progress, focus_mode, focus_pos, focus_min, focus_max
|
||||
global ap, ap_closing, af_in_progress, focus_mode, focus_pos, FOCUS_MIN, FOCUS_MAX
|
||||
|
||||
if position < focus_min:
|
||||
position = focus_min
|
||||
if position > focus_max:
|
||||
position = focus_max
|
||||
if position < FOCUS_MIN:
|
||||
position = FOCUS_MIN
|
||||
if position > FOCUS_MAX:
|
||||
position = FOCUS_MAX
|
||||
|
||||
vd_pulse()
|
||||
time.sleep_ms(10)
|
||||
@@ -256,10 +299,14 @@ def shutdown():
|
||||
time.sleep_ms(6)
|
||||
|
||||
def normal_loop():
|
||||
global ap, ap_closing, af_in_progress, focus_mode, focus_pos, change_focus
|
||||
global ap, ap_closing, af_in_progress, focus_mode, focus_pos, change_focus, relative_focus
|
||||
|
||||
if change_focus:
|
||||
move_focus(focus_pos)
|
||||
if relative_focus:
|
||||
move_focus(focus+focus_pos)
|
||||
relative_focus = False
|
||||
else:
|
||||
move_focus(focus_pos)
|
||||
change_focus = False
|
||||
else:
|
||||
vd_pulse()
|
||||
@@ -274,14 +321,16 @@ def normal_loop():
|
||||
send_focus(focus_mode, af_in_progress)
|
||||
time.sleep_ms(6)
|
||||
print_rx()
|
||||
|
||||
|
||||
TMC2130_Init()
|
||||
Comms_Init()
|
||||
lens_cs.irq(handler=rx_end, trigger=machine.Pin.IRQ_FALLING)
|
||||
|
||||
vd_pulse()
|
||||
body_cs.value(1)
|
||||
time.sleep_ms(4)
|
||||
uart_bodytx = machine.UART(0, baudrate=750000, tx=machine.Pin(16), rx=machine.Pin(17)) # UART1, GP0 (TX) and GP1 (RX)
|
||||
uart_bodytx = machine.UART(0, baudrate=750000) # UART1, GP0 (TX) and GP1 (RX) #, tx=machine.Pin(16), rx=machine.Pin(17)
|
||||
body_cs.value(0)
|
||||
time.sleep_ms(15)
|
||||
vd_pulse()
|
||||
@@ -313,3 +362,6 @@ while True:
|
||||
normal_loop()
|
||||
Comms_Read()
|
||||
|
||||
|
||||
|
||||
|
||||
18
Software/sTimer.py
Normal file
18
Software/sTimer.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from machine import Timer
|
||||
import TMC2130
|
||||
|
||||
FREQUENCY = 100 #kHz
|
||||
|
||||
counter = 0
|
||||
sTim = Timer()
|
||||
|
||||
def sTim_callback(t):
|
||||
global counter
|
||||
counter += 1
|
||||
TMC2130.timer_callback(counter)
|
||||
|
||||
def sTimer_Start():
|
||||
sTim.init(freq=FREQUENCY*1000, mode=Timer.PERIODIC, callback=sTim_callback)
|
||||
|
||||
def sTimer_Stop():
|
||||
sTim.deinit()
|
||||
Reference in New Issue
Block a user