def __init__(self, virtualMachine=None, virtualNode=None, axes=None, kinematics=None, machinePosition=None, defaultAcceleration=coordinates.uFloat(2000, "steps/s^2"), pullInSpeed=4000, planner=None): '''Configures the move object.''' #convert inputs to lists where appropriate if type(axes) != list: axes = [axes] self.virtualMachine = virtualMachine #a reference to the virtual machine which owns this function. self.virtualNode = virtualNode #a list of nodes which will be used by the function. self.axes = axes #a list of axes which connect physical actuators to the machine kinematics. Some nodes support multiple axes. self.kinematics = kinematics #a kinematics object which will transform between axis coordinates and machine coordinates self.machinePosition = machinePosition #the positional state of the machine. self.defaultAcceleration = defaultAcceleration #if no units are provided, it will be assumed in mm/s^2. #However, the default is in steps/s^2, corresponding to motor inertia dominance. self.pullInSpeed = pullInSpeed #this is the maximum step rate at which the motors can change direction instantaneously. #Eventually, this should support different rates for each motor. #The default was chosen because a 400 step/rev stepper motor with 51oz-in driven at 24V and driving a small mechanical #load thru an 18T MXL pulley could pull in at 200mm/s or 2200 steps/sec. Assuming microstepping of 4, the pull-in speed #derated by 50% is 4000 uSteps/sec. #configure and start motion planner if planner == 'null': self.planner = self.nullMotionPlanner(self) else: #use default planner self.planner = self.motionPlanner( self) #multi-block lookahead motion planner instance self.planner.daemon = True self.planner.start()
def __init__(self, virtualMachine = None, virtualNode = None, axes = None, kinematics = None, machinePosition = None, defaultAcceleration = coordinates.uFloat(2000, "steps/s^2"), pullInSpeed = 4000, planner = None): '''Configures the move object.''' #convert inputs to lists where appropriate if type(axes) != list: axes = [axes] self.virtualMachine = virtualMachine #a reference to the virtual machine which owns this function. self.virtualNode = virtualNode #a list of nodes which will be used by the function. self.axes = axes #a list of axes which connect physical actuators to the machine kinematics. Some nodes support multiple axes. self.kinematics = kinematics #a kinematics object which will transform between axis coordinates and machine coordinates self.machinePosition = machinePosition #the positional state of the machine. self.defaultAcceleration = defaultAcceleration #if no units are provided, it will be assumed in mm/s^2. #However, the default is in steps/s^2, corresponding to motor inertia dominance. self.pullInSpeed = pullInSpeed #this is the maximum step rate at which the motors can change direction instantaneously. #Eventually, this should support different rates for each motor. #The default was chosen because a 400 step/rev stepper motor with 51oz-in driven at 24V and driving a small mechanical #load thru an 18T MXL pulley could pull in at 200mm/s or 2200 steps/sec. Assuming microstepping of 4, the pull-in speed #derated by 50% is 4000 uSteps/sec. #configure and start motion planner if planner == 'null': self.planner = self.nullMotionPlanner(self) else: #use default planner self.planner = self.motionPlanner(self) #multi-block lookahead motion planner instance self.planner.daemon = True self.planner.start()
def __init__(self, move, position = None, velocity = None, acceleration = None): #store parameters self.move = move #the calling move class self.positionCommand = position self.velocityCommand = float(velocity) if acceleration: self.accelerationCommand = acceleration else: self.accelerationCommand = self.move.defaultAcceleration if type(self.accelerationCommand) != coordinates.uFloat: self.accelerationCommand = coordinates.uFloat(self.accelerationCommand, "mm/s^2") #note: need to decide here whether rotor inertia or stage inertia is dominant. # If rotor inertia, the accel rate should be specified in steps/sec^2 rather than mm/sec^2 # Default accel can be set in steps/sec^2 # The typical stepper motor (I = 0.3 oz-in^2) has an equivalent inertia of 134kg thru a 10TPI leadscrew, or 0.6kg thru an 18T MXL pulley #calculate deltas currentMachinePosition = self.move.machinePosition.future() #get the current machine position requestedMachinePosition = [] #build up the requested machine position based on what is provided and what is left as 'None'. for axisIndex, axisPosition in enumerate(self.positionCommand): requestedMachinePosition += [coordinates.uFloat(axisPosition if axisPosition != None else currentMachinePosition[axisIndex], currentMachinePosition[axisIndex].units)] #anything left as none is unchanged #transform between machine and axis coordinates transformedCurrentAxisPositions = self.move.kinematics.reverse(currentMachinePosition) #calculates the current axis positions based on the kinematics transformation matrix transformedRequestedAxisPositions = self.move.kinematics.reverse(requestedMachinePosition) #calculates the requested axis positions based on the kinematics transformation matrix currentMotorPositions = [] for axisIndex, axisPosition in enumerate(transformedCurrentAxisPositions): currentMotorPositions += [self.move.axes[axisIndex].reverse(axisPosition)] requestedMotorPositions = [] for axisIndex, axisPosition in enumerate(transformedRequestedAxisPositions): requestedMotorPositions += [self.move.axes[axisIndex].reverse(axisPosition)] machineDeltas = [end - start for end, start in zip(requestedMachinePosition, currentMachinePosition)] machineLength = math.sqrt(sum([math.pow(position, 2) for position in machineDeltas])) #gets cartesian length of move motorDeltas = [coordinates.uFloat(x - y, x.units) for (x,y) in zip(requestedMotorPositions, currentMotorPositions)] self.actualMotorDeltas = [coordinates.uFloat(int(round(delta,0)), delta.units) for delta in motorDeltas] #rounds steps down. self.majorSteps = max([abs(delta) for delta in self.actualMotorDeltas]) #note: this gets used by the path planner if machineLength != 0: parameterRatio = float(self.majorSteps) / float(machineLength) #this ratio relates velocities and accelerations between the coordinate systems else: parameterRatio = 0.0 #calculate maximum step rates self.segmentMaxStepRate = self.velocityCommand * parameterRatio #units of steps/sec #motion planner parameters. These will be modified by the motion planner self.entryJunctionMaxStepRate = 0 #default to zero in case this move is the first one self.exitJunctionMaxStepRate = 200 #need to fix this eventually, but a minimum rate is necessary to not stall the planner. This is the min exit rate. self.forwardPassEntryStepRate = 0 #used by the forward pass of the path planner self.forwardPassExitStepRate = 0 self.reversePassEntryStepRate = 0 #used by the reverse pass of the path planner self.reversePassExitStepRate = 0 self.accelSteps = 0 self.decelSteps = 0 if self.accelerationCommand.units == "mm/s^2": self.segmentAccelRate = self.accelerationCommand * parameterRatio #transform along major axis, now in steps^s^2 elif self.accelerationCommand.units == "steps/s^2": self.segmentAccelRate = self.accelerationCommand #motor inertia dominant, don't change. #create actionObjects and commit to the channel priority queue self.actionObjects = self.move.virtualNode.spinRequest(axesSteps = tuple(self.actualMotorDeltas), accelSteps = 0, decelSteps = 0, accelRate = 0, external = True, majorSteps = self.majorSteps) #note conversion to tuple. self.actionObjects.commit() #this will lock in their place in the transmit queue, however will not release until this move object is run thru the motion planner #commit self to the path planner. self.commit() #recalculate future machine position newMotorPositions = [coordinates.uFloat(x+y, x.units) for (x,y) in zip(self.actualMotorDeltas, currentMotorPositions)] transformedNewAxisPositions = [] for motorIndex, motorPosition in enumerate(newMotorPositions): transformedNewAxisPositions += [self.move.axes[motorIndex].forward(motorPosition)] newMachinePosition = self.move.kinematics.forward(transformedNewAxisPositions) self.move.machinePosition.future.set(newMachinePosition)
def __init__(self, move, position=None, velocity=None, acceleration=None): #store parameters self.move = move #the calling move class self.positionCommand = position self.velocityCommand = float(velocity) if acceleration: self.accelerationCommand = acceleration else: self.accelerationCommand = self.move.defaultAcceleration if type(self.accelerationCommand) != coordinates.uFloat: self.accelerationCommand = coordinates.uFloat( self.accelerationCommand, "mm/s^2") #note: need to decide here whether rotor inertia or stage inertia is dominant. # If rotor inertia, the accel rate should be specified in steps/sec^2 rather than mm/sec^2 # Default accel can be set in steps/sec^2 # The typical stepper motor (I = 0.3 oz-in^2) has an equivalent inertia of 134kg thru a 10TPI leadscrew, or 0.6kg thru an 18T MXL pulley #calculate deltas currentMachinePosition = self.move.machinePosition.future( ) #get the current machine position requestedMachinePosition = [ ] #build up the requested machine position based on what is provided and what is left as 'None'. for axisIndex, axisPosition in enumerate(self.positionCommand): requestedMachinePosition += [ coordinates.uFloat( axisPosition if axisPosition != None else currentMachinePosition[axisIndex], currentMachinePosition[axisIndex].units) ] #anything left as none is unchanged #transform between machine and axis coordinates transformedCurrentAxisPositions = self.move.kinematics.reverse( currentMachinePosition ) #calculates the current axis positions based on the kinematics transformation matrix transformedRequestedAxisPositions = self.move.kinematics.reverse( requestedMachinePosition ) #calculates the requested axis positions based on the kinematics transformation matrix currentMotorPositions = [] for axisIndex, axisPosition in enumerate( transformedCurrentAxisPositions): currentMotorPositions += [ self.move.axes[axisIndex].reverse(axisPosition) ] requestedMotorPositions = [] for axisIndex, axisPosition in enumerate( transformedRequestedAxisPositions): requestedMotorPositions += [ self.move.axes[axisIndex].reverse(axisPosition) ] machineDeltas = [ end - start for end, start in zip(requestedMachinePosition, currentMachinePosition) ] machineLength = math.sqrt( sum([math.pow(position, 2) for position in machineDeltas ])) #gets cartesian length of move motorDeltas = [ coordinates.uFloat(x - y, x.units) for (x, y) in zip(requestedMotorPositions, currentMotorPositions) ] self.actualMotorDeltas = [ coordinates.uFloat(int(round(delta, 0)), delta.units) for delta in motorDeltas ] #rounds steps down. self.majorSteps = max([abs(delta) for delta in self.actualMotorDeltas ]) #note: this gets used by the path planner if machineLength != 0: parameterRatio = float(self.majorSteps) / float( machineLength ) #this ratio relates velocities and accelerations between the coordinate systems else: parameterRatio = 0.0 #calculate maximum step rates self.segmentMaxStepRate = self.velocityCommand * parameterRatio #units of steps/sec #motion planner parameters. These will be modified by the motion planner self.entryJunctionMaxStepRate = 0 #default to zero in case this move is the first one self.exitJunctionMaxStepRate = 200 #need to fix this eventually, but a minimum rate is necessary to not stall the planner. This is the min exit rate. self.forwardPassEntryStepRate = 0 #used by the forward pass of the path planner self.forwardPassExitStepRate = 0 self.reversePassEntryStepRate = 0 #used by the reverse pass of the path planner self.reversePassExitStepRate = 0 self.accelSteps = 0 self.decelSteps = 0 if self.accelerationCommand.units == "mm/s^2": self.segmentAccelRate = self.accelerationCommand * parameterRatio #transform along major axis, now in steps^s^2 elif self.accelerationCommand.units == "steps/s^2": self.segmentAccelRate = self.accelerationCommand #motor inertia dominant, don't change. #create actionObjects and commit to the channel priority queue self.actionObjects = self.move.virtualNode.spinRequest( axesSteps=tuple(self.actualMotorDeltas), accelSteps=0, decelSteps=0, accelRate=0, external=True, majorSteps=self.majorSteps) #note conversion to tuple. self.actionObjects.commit( ) #this will lock in their place in the transmit queue, however will not release until this move object is run thru the motion planner #commit self to the path planner. self.commit() #recalculate future machine position newMotorPositions = [ coordinates.uFloat(x + y, x.units) for (x, y) in zip(self.actualMotorDeltas, currentMotorPositions) ] transformedNewAxisPositions = [] for motorIndex, motorPosition in enumerate(newMotorPositions): transformedNewAxisPositions += [ self.move.axes[motorIndex].forward(motorPosition) ] newMachinePosition = self.move.kinematics.forward( transformedNewAxisPositions) self.move.machinePosition.future.set(newMachinePosition)