def getSearchTerms(self, interfaceType): '''returns the likely prefix for a serial port based on the operating system and device type''' #define search strings in format {'OperatingSystem':'SearchString'} ftdi = {'Darwin': 'tty.usbserial-'} lufa = {'Darwin': 'tty.usbmodem'} genericSerial = {'Darwin': 'tty.'} searchStrings = { 'ftdi': ftdi, 'lufa': lufa, 'genericSerial': genericSerial } opSys = platform.system() #nominally detects the system if interfaceType in searchStrings: if opSys in searchStrings[interfaceType]: return searchStrings[interfaceType][opSys] else: notice( 'getSearchTerm', 'operating system support not found for interface type ' + interfaceType) return False else: notice( 'getSearchTerm', 'interface support not found for interface type ' + interfaceType) return False
def transmit(self, data): '''Sends request for data to be transmitted over the serial port. Format is as a list.''' if self.isConnected: self.transmitQueue.put( data) #converts to list in case data comes in as a string. else: notice(self, 'serialInterface is not connected.')
def init(self, axesSteps, accelSteps = 0, decelSteps = 0, accelRate = 0, external = False, sync = False, majorSteps = None): # axesSteps: a list containing the number of steps which each axis of the node should take in synchrony. # accelSteps: number of virtual major axis steps during which acceleration should occur. # deccelSteps: number of virtual major axis steps during which deceleration should occur. # accelRate: accel/decel rate in steps/sec^2 # external: indicates whether the actionObject will be commited to its interface externally. # When False, the actionObject will self commit and release. # When True, the actionObject will prepare a packet but will need to be commited and release externally. # sync: indicates that this actionObject will be synchronized externally and that parameters might change. This will prevent it from spawning. # majorSteps: this parameter is only called internally when a request calls for too many steps for one actionObject and the actionObject needs to spawn. if type(axesSteps) != list and type(axesSteps) != tuple: axesSteps = [axesSteps] self.axesSteps = [int(axis) for axis in axesSteps] #list of steps to take in each axis e.g. [x, y, z]. May be provided as a tuple. self.accelSteps = accelSteps self.decelSteps = decelSteps self.accelRate = accelRate self.external = external self.sync = sync self.actionSequence = False #start out with no action sequence self.sequenceMajorSteps = None #if this actionObject becomes an actionSequence parent, this will store the list of major axes #calculate virtual major axis if majorSteps: #if provided externally, use that. self.majorSteps = majorSteps else: #generate majorSteps from provided axes. self.majorSteps = max([abs(axis) for axis in self.axesSteps]) if self.majorSteps > self.virtualNode.maxSteps: #check if step request exceeds maximum length if not sync: #no other anticipated recalculations, so go ahead and generate actionSequence #need to generate an actionSequence with multiple new actionObjects self.actionSequence = self.actionSequenceGen() return self.actionSequence else: #the majorSteps has not yet been synchronized, so cannot generate an action sequence yet. return self else: #step request is executable by this action object. Either initial request met this criteria, or this actionObject was initialized by actionSequence(). #calculate directions directions = [1 if axis>0 else 0 for axis in self.axesSteps] directionMultiplexer = [2**b for b in range(self.virtualNode.numberOfAxes-1, -1, -1)] #generates [2^n, 2^n-1,...,2^0] self.directionByte = sum(map(lambda x,y: x*y, directionMultiplexer, directions)) #directionByte is each term of directionMultiplexer multiplied by the directions and then summed. if external or sync: #actionObject is being managed by an external function and shouldn't auto-commit return self else: #set packet accelRate = self.tbAccelRate(self.accelRate) #convert accel rate into timebase self.setPacket({'majorSteps':self.majorSteps, 'directions':self.directionByte, 'steps':abs(self.axesSteps[0]), 'accel':accelRate, 'accelSteps':accelSteps, 'decelSteps':decelSteps}) self.commitAndRelease() self.waitForChannelAccess() moveQueued = False while not moveQueued: if self.transmitPersistent(): responsePacket = self.getPacket() moveQueued = bool(responsePacket['statusCode']) #False if move was not queued time.sleep(0.02) else: notice(self.virtualNode, "got no response to spin request") return False return responsePacket
def __init__(self, elements): if type(elements) == list: self.init(transformation=elements) else: notice( self, 'expected input of type list but instead got ' + str(type(elements))) return None
def __init__(self, inputMatrices): if type(inputMatrices) != list: #make sure that input is a list notice(self, 'expected input of type list but instead got type ' + str(list)) return False self.arrays = inputMatrices self.lengths = [array.length for array in inputMatrices] #stores lengths of each array self.length = sum(self.lengths)
def transmitPersistent(self, tries = 10, timeout = 0.2): '''Transmit a packet until a response is received.''' for i in range(tries): self.transmit() if self.waitForResponse(timeout): return True notice(self.virtualNode, 'Could not reach virtual node. Retrying (#' + str(i+2) + ')') #i starts at 0, and when this gets called already tried once. return False
def __init__(self, *args, **kwargs): if 'name' in kwargs: #set name as provided self.name = kwargs['name'] else: #set name to filename for generating proper notice commands self.name = inspect.getfile(self.__class__) if 'persistenceFile' in kwargs: #set persistence file as provided self.persistenceFilename = kwargs['persistenceFile'] if 'name' not in kwargs: #If no name is provided, and multiple machines share the persistence file, this can result in a namespace conflict. notice(self, 'Warning: setting persistence without providing a name to the virtual machine can result in a conflict in multi-machine persistence files.') else: self.persistenceFilename = None self.persistence = utilities.persistenceManager(filename = self.persistenceFilename, namespace = self.name) if 'interface' in kwargs: self.providedInterface = kwargs['interface'] #interface provided on instantiation of virtual machine. else: self.providedInterface = None self.publishEnabled = True #this should get set explicitly to false in user init by calling disablePublishing #run user initialization self.init(*args, **kwargs) #calls child class init function self.initInterfaces() self.initControllers() self.initCoordinates() self.initKinematics() self.initFunctions() self.initPublish() self.initLast() self.publish()
def __new__(cls, *args, **kwargs): """Intantiation routine for actionObject base class. When a call is made to the action object class, this "magic" function creates the instance. Any arguments are passed along to the subclass's init() function, which may either return a value or None. If nothing is returned, as is the case in typical __init__ methods, then we return the actionObject. But if a return value is provided by the user (i.e. the interpreted reply of a real node), this is passed along. Note that if a call is made to the actionObject before it is bound to a port, a notice will be issued and a None object will be returned. """ if cls.virtualNode == None: #check to make sure the actionObject is bound notice(cls.__name__, "Can not instantiate actionObject because it isn't bound to a port on a virtual node!") #not bound! give notice return None #not bound, return None newActionObject = object.__new__(cls) #creates the new actionObject newActionObject._init_() #runs the actionObject base class's initialization. Note that #__init__ is intentionally not used, because otherwise it would get called twice. returnValue = newActionObject.init(*args, **kwargs) # calls the user-defined initialization routine, this time # with any provided arguments. if returnValue == None: #if the user initialization doesn't return anything, then return the actionObject return newActionObject else: #otherwise pass along whatever the user has provided return returnValue
def transmit(self): '''Sends a packet over the interface to the matching physical node. Note that this method will only be called within the interface channelAccess thread, which guarantees that the channel is avaliable.''' if self.channelAccessGranted.is_set(): self.interface.transmit(virtualNode = self.virtualNode, port = self.port, packetSet = self.packetSet, mode = self.mode) else: notice(self.virtualNode, 'tried to transmit without channel access!')
def __getattr__(self, attribute): ''' Forwards all unsupported calls to the parent actionObject.''' if hasattr(self.parent, attribute): #parent actionObject contains requested attribute return getattr(self.parent, attribute) else: notice(self, "ActionObject DOESN'T HAVE REQUESTED ATTRIBUTE") raise AttributeError(attribute)
def channelAccess(self): '''This gets called when channel access is granted. To prevent double-transmission, only transmit if external is True.''' if self.external: #set packet accelRate = self.tbAccelRate( self.accelRate) #convert accel rate into timebase self.setPacket({ 'majorSteps': self.majorSteps, 'directions': self.directionByte, 'steps': abs(self.axesSteps[0]), 'accel': accelRate, 'accelSteps': self.accelSteps, 'decelSteps': self.decelSteps, 'sync': int(bool(self.sync)) }) #since this node was instantiated under external control, it did not auto-transmit. moveQueued = False while not moveQueued: if self.transmitPersistent(): responsePacket = self.getPacket() print responsePacket moveQueued = bool( responsePacket['statusCode'] ) #False if move was not queued, meaning buffer is full if not moveQueued: time.sleep(0.02) #wait before retransmitting else: notice(self.virtualNode, "got no response to spin request")
def transmit(self, mode = 'unicast', releaseChannelOnTransmit = True): """Transmits packet on the virtualNode's interface. mode -- the transmission mode, either 'unicast to direct at a single node, or 'multicast' to direct at all nodes. releaseChannelOnTransmit -- If True (default), will automatically release the actionObject's channel lock after transmission """ if self.channelAccessIsGranted(): #very likely that transmit has been called from within an onChannelAccess function, since access is avaliable immediately self._putActionObjectIntoInboundPacketFlagQueue_(self) #put a reference to self in the inbound packet flag queue self.virtualNode._interface_.transmit(actionObject = self, mode = mode) #pass actionObject to interface for transmission if releaseChannelOnTransmit: #check if should release the channel lock after transmission self._releaseChannelAccessLock_() #release the channel access lock return True else: #transmit was called before actionObject was granted channel access, take node thru to channel access if not self._isCommitted_(): #check if actionObject is already committed self.commit() #commit actionObject to channel priority queue if not self._isClearForRelease_(): #check if actionObject is cleared for release from the channel priority queue self.clearForRelease() #clear actionObject for release from the channel priority queue if self.waitForChannelAccess(): #wait for channel access self._putActionObjectIntoInboundPacketFlagQueue_(self) #put a reference to self in the inbound packet flag queue self.virtualNode._interface_.transmit(actionObject = self, mode = mode) #transmit on interface if releaseChannelOnTransmit: #check if should release the channel access lock self._releaseChannelAccessLock_() #release the channel access lock else: notice(self, "timed out waiting for channel access") #timed out! return False return True
def setTimeout(self, timeout): '''Sets timeout for receiving on port.''' if self.port: try: self.port.timeout = timeout except: notice(self, "could not set timeout: " + sys.exc_info()[0])
def acquirePort(self, interfaceType=None): '''Discovers and connects to a port by waiting for a new device to be plugged in.''' #get search terms if interfaceType: searchTerm = self.getSearchTerms(interfaceType) else: searchTerm = self.getSearchTerms('genericSerial') #try to find a single port that's open. This is good for when only a single device is attached. availablePorts = self.getAvailablePorts(self.deviceScan(searchTerm)) if len(availablePorts) == 1: self.portName = availablePorts[0] return self.connect() else: notice(self.owner, "trying to acquire. Please plug me in.") newPorts = self.waitForNewPort(searchTerm, 10) #wait for new port if newPorts: if len(newPorts) > 1: notice( self.owner, 'Could not acquire. Multiple ports plugged in simultaneously.' ) return False else: self.portName = newPorts[0] return self.connect() else: return False
def nodeFunctionCall(self, node, attribute, args, kwargs): if hasattr(node, attribute): return getattr(node, attribute)(*list(args), **kwargs) else: notice(self.compoundNode, "NODE DOESN'T HAVE REQUESTED ATTRIBUTE") raise AttributeError(attribute)
def init(self): self.setPacket({}) self.commitAndRelease() self.waitForChannelAccess() if self.transmitPersistent(): return self.getPacket() else: notice(self.virtualNode, 'unable to get status from node.')
def functionCall(callObject, attribute, args, kwargs): '''Calls callObject.attribute(*args, **kwargs)''' if hasattr(callObject, attribute): return getattr(callObject, attribute)(*list(args), **kwargs) else: notice(callObject, "actionObject DOESN'T HAVE REQUESTED ATTRIBUTE") raise AttributeError(attribute)
def init(self): self.commitAndRelease() #commit self immediately self.waitForChannelAccess() if self.transmitPersistent(): return self.getPacket()['URL'] else: notice(self.virtualNode, 'NO URL RECEIVED') return False
def run(self): '''Code run by the transmit thread.''' while True: transmitState, transmitPacket = self.getTransmitPacket() if transmitState: if self.port: self.port.write(serialize(transmitPacket)) else: notice(self, 'Cannot Transmit - No Serial Port Initialized') time.sleep(0.0005)
def set(self, valueArray): if len(valueArray) != len(self.baseList): notice(self, 'input array length must match coordinate length.') return False else: for index, item in enumerate(valueArray): #any None input will not modify value self.baseList[index] = coordinates.uFloat(item, self.baseList[index].units) if item != None else self.baseList[index] return True
def init(self, IP): self.setPacket({'setAddress':IP}, mode = 'multicast') self.commitAndRelease() #commit self immediately self.waitForChannelAccess(5) if self.transmitPersistent(timeout = 15): time.sleep(1) #debounce for button press return self.getPacket()['URL'] else: notice(self.virtualNode, 'TIMEOUT WAITING FOR BUTTON PRESS')
def initAfterSet(self): #gets called once interface is set into shell. self.receiveSocket = socket.socket( socket.AF_INET, socket.SOCK_DGRAM) #UDP, would be socket.SOCK_STREAM for TCP self.receiveSocket.bind( (self.receiveIPAddress, self.receiveIPPort)) #bind to socket notice( self, "opened socket on " + str(self.receiveIPAddress) + " port " + str(self.receiveIPPort)) self.transmitSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def init(self, IP): self.setPacket({'setAddress': IP}, mode='multicast') self.commitAndRelease() #commit self immediately self.waitForChannelAccess(5) if self.transmitPersistent(timeout=15): time.sleep(1) #debounce for button press return self.getPacket()['URL'] else: notice(self.virtualNode, 'TIMEOUT WAITING FOR BUTTON PRESS')
def __init__(self, *nodes): self.nodes = nodes self.nodeCount = len(self.nodes) self.name = "[" + ''.join([str(node.name) + "," for node in nodes])[:-1] + "]" interfaces = [node.interface.Interface for node in nodes] #nodes have an interface shell if all(interface == interfaces[0] for interface in interfaces): self.commonInterface = True else: self.commonInterface = False notice(self, "warning: not all members of compound node share a common interface!")
def init(self): self.setPacket({}) self.commitAndRelease() self.waitForChannelAccess() if self.transmitPersistent(): notice(self.virtualNode, "Stepper motor disabled.") return True else: notice(self.virtualNode, "Stepper motor could not be disabled.") return False
def __init__(self, inputMatrices): if type(inputMatrices) != list: #make sure that input is a list notice( self, 'expected input of type list but instead got type ' + str(list)) return False self.arrays = inputMatrices self.lengths = [array.length for array in inputMatrices ] #stores lengths of each array self.length = sum(self.lengths)
def __getattr__(self, attribute): ''' Forwards any unsupported calls to the shell onto the node.''' if self.hasNode(): #Shell contains a node. if hasattr(self.node, attribute): #node contains requested attribute return getattr(self.node, attribute) else: notice(self, "NODE DOESN'T HAVE REQUESTED ATTRIBUTE") raise AttributeError(attribute) else: notice(self, "NODE IS NOT INITIALIZED") raise AttributeError(attribute)
def loadNodeFromFile(self, filename, **kwargs): ''' Loads a node into the node shell from a provided filename. Assumes that this is called from a node shell that has defined self.name''' try: self.setNode(imp.load_source('', filename).virtualNode(**kwargs)) notice(self, "loaded node from: " + filename) return True except IOError, error: notice(self, "error loading file.") print error return False
def set(self, valueArray): if len(valueArray) != len(self.baseList): notice(self, 'input array length must match coordinate length.') return False else: for index, item in enumerate(valueArray): #any None input will not modify value self.baseList[index] = coordinates.uFloat( item, self.baseList[index].units ) if item != None else self.baseList[index] return True
def init(self, velocity): #velocity is in steps/sec velocity = int(round((velocity * self.virtualNode.uStepsPerStep * self.virtualNode.timeBasePeriod)/16.0,0)) #convert into 16*uSteps/timebase print velocity self.setPacket({'velocity': velocity}) self.commitAndRelease() self.waitForChannelAccess() if self.transmitPersistent(): return True else: notice(self.virtualNode, 'unable to set velocity.') return False
def loadNodeFromModule(self, module, **kwargs): '''Loads a node into the node shell from the provided class. Note that class itself should be provided, NOT a class instance.''' try: if hasattr(module, 'virtualNode'): self.setNode(module.virtualNode(**kwargs)) else: self.setNode(module(**kwargs)) notice(self, "loaded module " + str(module.__name__)) return True except AttributeError, err: notice(self, "unable to load module: " + str(err)) return False
def connectToPort(self, portName): '''Actually connects the interface to the port''' try: self.port = serial.Serial(portName, self.baudRate, timeout = self.timeOut) self.port.flushInput() self.port.flushOutput() notice(self, "port " + str(portName) + " connected succesfully.") time.sleep(2) #some serial ports require a brief amount of time between opening and transmission self.isConnected = True self.startTransmitter() return True except: notice(self, "error opening serial port "+ str(portName)) return False
def reverse(self, reverseState): """Tranforms in the reverse direction from an output state of the tranformer to the corresponding input state. inputState -- the input state of the transformer. MUST be provided as a units.dFloat type. Note that this function over-rides its base class transformer.forward() function. """ if type(reverseState) == units.dFloat: convertedReverseState = units.convertToUnits(reverseState, self.outputUnits, strict = True) #convert to input units, don't allow reciprocals return self.reverseTransform*convertedReverseState else: utilities.notice(self, "Input to singleAxisElement transformer must be of type units.dFloat!") raise errors.MechanismError("Incorrect input type to singleAxisElement.reverse()")
def init(self, velocity): #velocity is in steps/sec velocity = int( round((velocity * self.virtualNode.uStepsPerStep * self.virtualNode.timeBasePeriod) / 16.0, 0)) #convert into 16*uSteps/timebase print velocity self.setPacket({'velocity': velocity}) self.commitAndRelease() self.waitForChannelAccess() if self.transmitPersistent(): return True else: notice(self.virtualNode, 'unable to set velocity.') return False
def __init__(self, *nodes): self.nodes = nodes self.nodeCount = len(self.nodes) self.name = "[" + ''.join([str(node.name) + "," for node in nodes])[:-1] + "]" interfaces = [node.interface.Interface for node in nodes] #nodes have an interface shell if all(interface == interfaces[0] for interface in interfaces): self.commonInterface = True else: self.commonInterface = False notice( self, "warning: not all members of compound node share a common interface!" )
def connect(self, portName = None): '''Locates port for interface on host machine.''' #check if port has been provided explicitly to connect function if portName: self.connectToPort(portName) return True #port hasn't been provided to connect function, check if assigned on instantiation elif self.portName: self.connectToPort(self.portName) return True #no port name provided else: notice(self, 'no port name provided.') return False
def connect(self, portName=None): '''Locates port for interface on host machine.''' #check if port has been provided explicitly to connect function if portName: self.connectToPort(portName) return True #port hasn't been provided to connect function, check if assigned on instantiation elif self.portName: self.connectToPort(self.portName) return True #no port name provided else: notice(self, 'no port name provided.') return False
def channelAccess(self): '''This gets called when channel access is granted. To prevent double-transmission, only transmit if external is True.''' if self.external: #set packet accelRate = self.tbAccelRate(self.accelRate) #convert accel rate into timebase self.setPacket({'majorSteps':self.majorSteps, 'directions':self.directionByte, 'steps':abs(self.axesSteps[0]), 'accel':accelRate, 'accelSteps':self.accelSteps, 'decelSteps':self.decelSteps, 'sync':int(bool(self.sync))}) #since this node was instantiated under external control, it did not auto-transmit. moveQueued = False while not moveQueued: if self.transmitPersistent(): responsePacket = self.getPacket() print responsePacket moveQueued = bool(responsePacket['statusCode']) #False if move was not queued, meaning buffer is full if not moveQueued: time.sleep(0.02) #wait before retransmitting else: notice(self.virtualNode, "got no response to spin request")
def connectToPort(self, portName): '''Actually connects the interface to the port''' try: self.port = serial.Serial(portName, self.baudRate, timeout=self.timeOut) self.port.flushInput() self.port.flushOutput() notice(self, "port " + str(portName) + " connected succesfully.") time.sleep( 2 ) #some serial ports require a brief amount of time between opening and transmission self.isConnected = True self.startTransmitter() return True except: notice(self, "error opening serial port " + str(portName)) return False
def __init__(self, name=None, interface=None, filename=None, URL=None, module=None, **kwargs): ''' Initialization procedure for Solo/Independent Node Shell. name: a unique name assigned by the user. This is used by the persistence algorithm to re-acquire the node. interface: the object thru which the virtual node communicates with its physical counterpart. **kwargs: any additional arguments to be passed to the node during initialization Methods of Loading Virtual Node: filename: an import-able module containing the virtual node. URL: a URL pointing to a module as a resource containing the virtual node. module: a python module name containing the virtual node. ''' #call base class __init__ method super(soloIndependentNode, self).__init__() #assign parameters to variables self.name = name self.filename = filename self.URL = URL self.module = module self.interface.set( interface, self) #interface isn't shared with other nodes, so owner is self. #acquire node. For an SI node, some method of acquisition MUST be provided, as it has no protocol for auto-loading. #load via filename if filename: self.loadNodeFromFile(filename, **kwargs) #load via URL elif URL: self.loadNodeFromURL(URL, **kwargs) #load via module elif module: self.loadNodeFromModule(module, **kwargs) else: notice(self, "no node source was provided.") notice(self, "please provide a filename, URL, or class")
def transformReverse( self, value ): #NOTE: THIS GETS REASSIGNED TO THE NAME "reverse" ON INSTANTIATION BY CLASSMETHOD "reverse" if type(self.transformation ) == list: #transformation is a list of elements reverseTransformation = copy.copy(self.transformation) reverseTransformation.reverse() for element in reverseTransformation: #transform value thru elements in forwards direction value = element.reverse(value) return value elif type( value ) == coordinates.uFloat: #input value is a uFloat, transform directly if value.units == self.outputUnits: #output units match (going in reverse!) return coordinates.uFloat( value / float(self.transformation), self.inputUnits ) #return a transformed uFloat in input units elif self.inputUnits: #input units are specified for this element, enforce match newValue = value.convertUnits( self.outputUnits ) #try to convert to input units. i.e. mm to inch if newValue: return coordinates.uFloat( newValue / float(self.transformation), self.inputUnits ) #conversion successful, return a transformed uFloat in output units else: notice( self, 'provided units ' + str(value.units) + ' but this element works in units of ' + str(self.outputUnits) + ' in the reverse direction.') return False else: #no input units specified, transform anyways return coordinates.uFloat( value / float(self.transformation), value.units ) #return a transformed uFloat in same units as input value else: notice( self, 'expected an input of type uFloat but instead got ' + str(type(value))) return False
def getSearchTerms(self, interfaceType): '''returns the likely prefix for a serial port based on the operating system and device type''' #define search strings in format {'OperatingSystem':'SearchString'} ftdi = {'Darwin':'tty.usbserial-'} lufa = {'Darwin':'tty.usbmodem'} genericSerial = {'Darwin': 'tty.'} searchStrings = {'ftdi':ftdi, 'lufa':lufa, 'genericSerial':genericSerial} opSys = platform.system() #nominally detects the system if interfaceType in searchStrings: if opSys in searchStrings[interfaceType]: return searchStrings[interfaceType][opSys] else: notice('getSearchTerm', 'operating system support not found for interface type '+ interfaceType) return False else: notice('getSearchTerm', 'interface support not found for interface type ' + interfaceType) return False
def transformForward(self, value): #NOTE: THIS GETS REASSIGNED TO THE NAME "forward" ON INSTANTIATION BY CLASSMETHOD "forward" if type(self.transformation) == list: #transformation is a list of elements for element in self.transformation: #transform value thru elements in forwards direction value = element.forward(value) return value elif type(value) == coordinates.uFloat: #input value is a uFloat, transform directly if value.units == self.inputUnits: #input units match return coordinates.uFloat(value*self.transformation, self.outputUnits) #return a transformed uFloat in output units elif self.inputUnits: #input units are specified for this element, enforce match newValue = value.convertUnits(self.inputUnits) #try to convert to input units. i.e. mm to inch if newValue: return coordinates.uFloat(newValue*self.transformation, self.outputUnits) #conversion successful, return a transformed uFloat in output units else: notice(self, 'provided units ' + str(value.units) + ' but this element works in units of ' + str(self.inputUnits) + ' in the forward direction.') return False else: #no input units specified, transform anyways return coordinates.uFloat(value*self.transformation, value.units) #return a transformed uFloat in same units as input value else: notice(self, 'expected an input of type uFloat but instead got ' + str(type(value))) return False
def waitForNewPort(self, searchTerms = '', timeout = 10): '''Scans for a new port to appear in /dev/ and returns the name of the port. Search terms is a list that can contain several terms. For now only implemented for one term.''' timerCount = 0 devPorts = self.deviceScan(searchTerms) numDevPorts = len(devPorts) while True: time.sleep(0.25) timerCount += 0.25 if timerCount > timeout: notice(self.owner, 'TIMOUT in acquiring a port.') return False currentDevPorts = self.deviceScan(searchTerms) numCurrentDevPorts = len(currentDevPorts) #port has been unplugged... update number of ports if numCurrentDevPorts < numDevPorts: devPorts = list(currentDevPorts) numDevPorts = numCurrentDevPorts elif numCurrentDevPorts > numDevPorts: return list(set(currentDevPorts) - set(devPorts)) #returns all ports that just appeared
def setMotorCurrent(self, setCurrent): if setCurrent < 0 or setCurrent > 2.0: notice(self, "Motor current must be between 0 and 2.0 amps. " + str(setCurrent) + " was requested.") setCurrent = round(float(setCurrent), 1) while True: motorVoltage = self.getReferenceVoltage() motorCurrent = round(motorVoltage /(8.0*self.motorSenseResistor),2) #amps if round(motorCurrent,1) > setCurrent: notice(self, "Motor current: " + str(motorCurrent) + "A / " + "Desired: " + str(setCurrent) + "A. Turn trimmer CW.") elif round(motorCurrent,1) < setCurrent: notice(self, "Motor current: " + str(motorCurrent) + "A / " + "Desired: " + str(setCurrent) + "A. Turn trimmer CCW.") else: notice(self, "Motor current set to: " + str(motorCurrent) + "A") break; time.sleep(0.5)
def __init__(self, *args, **kwargs): if 'name' in kwargs: #set name as provided self.name = kwargs['name'] else: #set name to filename for generating proper notice commands self.name = inspect.getfile(self.__class__) if 'persistenceFile' in kwargs: #set persistence file as provided self.persistenceFilename = kwargs['persistenceFile'] if 'name' not in kwargs: #If no name is provided, and multiple machines share the persistence file, this can result in a namespace conflict. notice( self, 'Warning: setting persistence without providing a name to the virtual machine can result in a conflict in multi-machine persistence files.' ) else: self.persistenceFilename = None self.persistence = utilities.persistenceManager( filename=self.persistenceFilename, namespace=self.name) if 'interface' in kwargs: self.providedInterface = kwargs[ 'interface'] #interface provided on instantiation of virtual machine. else: self.providedInterface = None self.publishEnabled = True #this should get set explicitly to false in user init by calling disablePublishing #run user initialization self.init(*args, **kwargs) #calls child class init function self.initInterfaces() self.initControllers() self.initCoordinates() self.initKinematics() self.initFunctions() self.initPublish() self.initLast() self.publish()
def waitForNewPort(self, searchTerms='', timeout=10): '''Scans for a new port to appear in /dev/ and returns the name of the port. Search terms is a list that can contain several terms. For now only implemented for one term.''' timerCount = 0 devPorts = self.deviceScan(searchTerms) numDevPorts = len(devPorts) while True: time.sleep(0.25) timerCount += 0.25 if timerCount > timeout: notice(self.owner, 'TIMOUT in acquiring a port.') return False currentDevPorts = self.deviceScan(searchTerms) numCurrentDevPorts = len(currentDevPorts) #port has been unplugged... update number of ports if numCurrentDevPorts < numDevPorts: devPorts = list(currentDevPorts) numDevPorts = numCurrentDevPorts elif numCurrentDevPorts > numDevPorts: return list( set(currentDevPorts) - set(devPorts)) #returns all ports that just appeared