Source code for instruments.StepMotor_MST_DRV

# Step Motor Class
#    - wraps around Motor


from Motor_MST_DRV import Motor_MST_DRV as Motor, hexString, int2hexStr, send_short_dst_src, send_long_dst_src,send_chan_ident,prep_short_src_dst,prep_long_src_dst

#import serial
import logging
import time
from struct import unpack
import threading

STEPS_PER_MM = 51200    # 136533.33
LIMIT_SWITCH = 13
BACKLASH_STEPS = 2560

# STEPS_PER_MM = 2184533.33    # 136533.33
# LIMIT_SWITCH = 13
# BACKLASH_STEPS = 43691

# DEBUG
Constructor_Counter = 0
Home_Counter = 0

[docs]class StepMotor_MST_DRV(Motor): def __init__(self, ser, bay=0,chan=1): ''' Constructor :param ser: (Serial) the Serial object that corresponds to the port the motor is connected to. If the serial was successfully locked ser.write() can be called. If the object waits for an answer from the serial object ser.in_buffer(pattern,trail_bytes) should be used. :type ser: multi_serial Object :param bay: the bay of the motor controller in main frame. For stand alone system bay should be 0. :type ser: integer :param chan: channel of motor controller in corresponding bay :type chan: integer :param lock: if the step motor shares a serial connection with other motors (by being a part of a mainframe) the lock needs to be a threading.Lock() object shared with all objects making calls to the shared serial interface. Before each serial call lock.acquire() and after each call lock.realease() needs to be called :type lock: threading.Lock() object ''' ### global Constructor_Counter Constructor_Counter += 1 ### self.ser = ser self.ser.timeout = 0.1 self.moving = False self.bay = int(bay) self.chan = int(chan) Motor.__init__(self, ser,bay,chan) self.ext['ClassName'] = 'StepMotor' self.home() # home motor #self._set_backlash(0) # set 0 backlash correction self.mm_pos = 0 # position of motor, in millimieters self.mm_zeros = 0 # the origin, in millimeters
[docs] def home(self): ''' Initializes all paremeters specific to the step motor and homes the motor. The homing and backlash position need to be set up in a way that homing the system brings the system into a safe position. The backlash correction needs to be performed in such away that the correction is performed in the direction away from the chip and the other probes. ''' ### global Home_Counter Home_Counter += 1 ### self.moving = True self.logger.debug('Homing...', extra=self.ext) #Acquire Lock over Serial if self.ser.lock: self.ser.lock.acquire() #### SETTING UP MOTOR PARAMETERS #### #MGMSG_MOT_SET_LIMSWITCHPARAMS self.ser.write(hexString('23 04 10 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('03 00')) # CW Hard Limit self.ser.write(hexString('01 00')) # CCW Hard Limit self.ser.write(hexString('00 84 03 00')) # CW SoftLimit self.ser.write(hexString('00 64 00 00')) # CCW SoftLimit self.ser.write(hexString('01 00')) # SoftLimit Mode # CHECKING FOR ERROR MESSAGES #response = self.ser.read(1) #print map(hex,unpack('B'*len(response),response)) #while map(hex,unpack('B'*len(response),response)) != []: # response = self.ser.read(1) # print map(hex,unpack('B'*len(response),response)) # Check whether Parameters were written # < MGMSG_MOT_REQ_LIMSWITCHPARAMS > #self.ser.write(hexString('24 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(22) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_VELPARAMS self.ser.write(hexString('13 04 0E 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('00 00 00 00')) # Min Vel self.ser.write(hexString('00 32 00 00')) # Acceleration self.ser.write(hexString('00 64 00 00')) # Max Velocity # Check whether Parameters were written # < MGMSG_MOT_REQ_VELPARAMS > #self.ser.write(hexString('14 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(22) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_JOGPARAMS self.ser.write(hexString('16 04 16 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('02 00')) # Jog Mode self.ser.write(hexString('00 05 00 00')) # Jog Step Size self.ser.write(hexString('00 00 00 00')) # Jog Min Vel self.ser.write(hexString('00 C8 00 00')) # Jog Acceleration self.ser.write(hexString('00 64 00 00')) # Max Velocity self.ser.write(hexString('02 00')) # Stop Mode # Check whether Parameters were written # < MGMSG_MOT_REQ_JOGPARAMS > #self.ser.write(hexString('17 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(28) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_POWERPARAMS self.ser.write(hexString('26 04 06 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('14 00')) # Rest Factor self.ser.write(hexString('64 00')) # Move Factor # Check whether Parameters were written # < MGMSG_MOT_REQ_POWERPARAMS > #self.ser.write(hexString('27 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(12) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_GENMOVEPARAMS self.ser.write(hexString('3A 04 06 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('00 0A 00 00')) # Backlash Distance # Check whether Parameters were written # < MGMSG_MOT_REQ_GENMOVEPARAMS > #self.ser.write(hexString('3B 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(12) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_MOVERELPARAMS self.ser.write(hexString('45 04 06 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('00 0A 00 00')) # Relative Distance Distance # Check whether Parameters were written # < MGMSG_MOT_REQ_MOVERELPARAMS > #self.ser.write(hexString('46 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(12) #print map(hex,unpack('B'*len(switch_response),switch_response)) #MGMSG_MOT_SET_MOVEABSPARAMS self.ser.write(hexString('50 04 06 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(hexString('00 00 00 00')) # Relative Distance Distance # Check whether Parameters were written # < MGMSG_MOT_REQ_MOVEABSPARAMS > #self.ser.write(hexString('51 04 01 00 21 01')) #self.ser.reset_input_buffer() #switch_response = self.ser.read(12) #print map(hex,unpack('B'*len(switch_response),switch_response)) # < MGMSG_MOT_SET_HOMEPARAMS > #self.ser.write(hexString('40 04 0E 00')) # header #send_long_dst_src(self.ser,self.bay) #send_chan_ident(self.ser, self.chan) #self.ser.write(hexString('02 00')) # Home Dir #self.ser.write(hexString('01 00')) # Limit Switch #self.ser.write('00 64 00 00') # Home Velocity #self.ser.write('00 32 00 00') # Offset Distance # Check whether Parameters were written # < MGMSG_MOT_REQ_HOMEPARAMS > #self.ser.write(hexString('41 04 01 00 21 01')) #self.ser.reset_input_buffer() #home_response = self.ser.read(20) #print map(hex,unpack('B'*len(home_response),home_response)) # ACTUALLY STARTING THE HOMING # MGMSG_MOT_MOVE_HOME self.ser.write(hexString('43 04 {:02d} 00'.format(self.chan))) send_short_dst_src(self.ser,self.bay) # Relase Serial if self.ser.lock: self.ser.lock.release() # Wait for Homing Completion counter = 0 found = False while counter < 60 and found == False: # MGMSG_MOT_MOVE_HOMED time.sleep(1) if self.ser.lock: self.ser.lock.acquire() # self.ser.print_buffer() found = self.ser.in_buffer(hexString('44 04 {:02d} 00 '.format(self.chan)+prep_short_src_dst(self.bay))) if self.ser.lock: self.ser.lock.release() counter = counter + 1 if counter >= 60: self.logger.error('problem homing', extra=self.ext) exit() self.logger.info('homed successfully.', extra=self.ext) self.moving = False
[docs] def get_info(self): ''' Get information back form the controller Used for debugging purposes ''' #Acquire Lock over Serial if self.ser.lock: self.ser.lock.acquire() # MGMSG_HW_REQ_INFO self.ser.write(hexString('05 00 00 00')) send_short_dst_src(self.ser,self.bay) response = self.ser.read(90) self.ser.release() # Relase Serial if self.ser.lock: self.ser.lock.release() print response
def _set_backlash(self, backlash_distance): ''' Set the backlash correction distance for backwards motor movement backlash_distance (int): in encoder steps ''' #Acquire Lock over Serial if self.ser.lock: self.ser.lock.acquire() # change backlash value self.ser.write(hexString('3A 04 06 00')) # header send_long_dst_src(self.ser,self.bay) send_chan_ident(self.ser, self.chan) self.ser.write(int2hexStr(backlash_distance, 4)) # backlash dist self.ser.release() # request backlash data #self.ser.write(hexString('3B 04 01 00')) #send_short_dst_src(self.ser,self.bay) # confirm backlash distance value #res = self.ser.read(12) #back_dist_r = unpack('<l', res[8:12])[0] #if back_dist_r != backlash_distance: # self.logger.error('Problem setting backlash distance [{}]'.format(backlash_distance), extra=self.ext) # Relase Serial if self.ser.lock: self.ser.lock.release()
[docs] def delta_transl(self, dist): #, m_callback = None, params = ()): ''' Relative translation on the motor dist (float): the millimeters of translation (negative -> backwards) m_callback (function): (Optional) a function that will run while the motor will be in motion. (e.g. show camera) This callback's last parameter must be a callback itself, named 'callback' params (tuple): the callback's parameters ''' self.moving = True # check weather we are within limits if self.mm_pos + dist > LIMIT_SWITCH or self.mm_pos + dist < 0: self.logger.error('Out of bounds error (dist:{}, pos:{})'.format(dist, self.mm_pos), extra=self.ext) self.moving = False return False self.mm_pos += dist # convert millimeters to steps steps = int(round(dist * STEPS_PER_MM)) if steps < 0: Motor.delta_move(self, (steps - BACKLASH_STEPS)) # manual backlash correction Motor.delta_move(self, BACKLASH_STEPS) else: Motor.delta_move(self, steps) self.moving = False return True
[docs] def check_abs_transl(self,dist): ''' Check wether a move to position 'dist' is in range ''' if dist > LIMIT_SWITCH or dist < 0: return False else: return True
[docs] def abs_transl(self, dist): ''' Absolute translation on the motor dist (float): the millmeters of rotation (negative -> backwards) ''' self.moving = True # check whether we are within limits if dist > LIMIT_SWITCH or dist < 0: self.logger.error('Out of bounds error (abs_pos:{})'.format(dist), extra=self.ext) self.moving = False return # convert degrees to steps steps = int(round(dist * STEPS_PER_MM)) # manual backlash correction if dist - self.mm_pos < 0: Motor.abs_move(self, (steps - BACKLASH_STEPS)) Motor.delta_move(self, BACKLASH_STEPS) else: Motor.abs_move(self, steps) self.mm_pos = dist self.moving = False
[docs] def get_mm_pos(self): ''' return the motors current position, in millimeters ''' return self.mm_pos
[docs] def set_as_zero(self, zer_mm): ''' change the origin (zero) ''' n_zero = int(round(zer_mm / STEPS_PER_MM)) Motor.set_as_zero(self, n_zero) self.mm_zeros = zer_mm self.mm_pos -= zer_mm
def __str__(self): ''' <For Debugging Purposes> gives information relevant to the motor state ''' return 'StepMotor({})\n'.format(self.ser.port) + ' position(millimeters): ' + str(self.mm_pos) + '\n zeros-position(millimeters): ' + str(self.mm_zeros)
''' Copyright (C) 2017 Robert Polster This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. '''