diff options
author | eugue <eug.sun@gmail.com> | 2011-01-27 17:31:02 -0500 |
---|---|---|
committer | eugue <eug.sun@gmail.com> | 2011-01-27 17:31:02 -0500 |
commit | 32fdbbb7512576cb8a54556640b18be160d655d1 (patch) | |
tree | c776387e432ef11cbe801745f881e515dd0706c4 /behaviors | |
parent | 328464219a02c014caf1608a27a898900cad8456 (diff) | |
parent | 5fb3ea060025241105dc8e9a174513c112f9a133 (diff) |
Merge branch 'biginstall' of github.com:rcoh/SmootLight into mobileapp
Diffstat (limited to 'behaviors')
-rw-r--r-- | behaviors/AddPixelEvent.py | 5 | ||||
-rw-r--r-- | behaviors/AllPixels.py | 9 | ||||
-rw-r--r-- | behaviors/AllPixelsLeft.py | 1 | ||||
-rw-r--r-- | behaviors/BehaviorChain.py | 23 | ||||
-rw-r--r-- | behaviors/ColorChangerBehavior.py | 18 | ||||
-rw-r--r-- | behaviors/DebugBehavior.py | 5 | ||||
-rw-r--r-- | behaviors/DecayBehavior.py | 1 | ||||
-rw-r--r-- | behaviors/DimColor.xml | 8 | ||||
-rw-r--r-- | behaviors/EchoBehavior.py | 2 | ||||
-rw-r--r-- | behaviors/Expand.py | 21 | ||||
-rw-r--r-- | behaviors/MITDoors.py | 20 | ||||
-rw-r--r-- | behaviors/ModifyParam.py | 9 | ||||
-rw-r--r-- | behaviors/MoveBehavior.py | 3 | ||||
-rw-r--r-- | behaviors/RandomWalk.py | 3 | ||||
-rw-r--r-- | behaviors/RecursiveDecay.py | 5 | ||||
-rw-r--r-- | behaviors/ResponseMover.py | 6 | ||||
-rw-r--r-- | behaviors/RestrictLocation.py | 12 | ||||
-rw-r--r-- | behaviors/RiseFall.py | 40 | ||||
-rw-r--r-- | behaviors/RiseFall.xml | 7 | ||||
-rw-r--r-- | behaviors/RunningBehavior.py | 5 | ||||
-rw-r--r-- | behaviors/SingleFrame.xml | 7 | ||||
-rw-r--r-- | behaviors/Square.py | 24 | ||||
-rw-r--r-- | behaviors/TimedDie.py | 15 | ||||
-rw-r--r-- | behaviors/Timeout.py | 16 | ||||
-rw-r--r-- | behaviors/XYMove.py | 24 |
25 files changed, 271 insertions, 18 deletions
diff --git a/behaviors/AddPixelEvent.py b/behaviors/AddPixelEvent.py index 7f134e1..821f432 100644 --- a/behaviors/AddPixelEvent.py +++ b/behaviors/AddPixelEvent.py @@ -2,6 +2,9 @@ from operationscore.Behavior import * import util.Strings as Strings from logger import main_log class AddPixelEvent(Behavior): + """AddPixelEvent is a behavior to append an arbitrary PixelEvent to a behavior response. The + classname of the PixelEvent should be specified in the Class field of Args. All arguments normally + passed to the PixelEvent should also be specified in Args.""" def behaviorInit(self): [module, className] = self['Class'].split('.') try: @@ -18,6 +21,8 @@ class AddPixelEvent(Behavior): ret = [] for sensory in sensors: outDict = {} + if not 'Location' in sensory: + pdb.set_trace() outDict[Strings.LOCATION] = sensory[Strings.LOCATION] settingsDict = dict(self.argDict) settingsDict['Color'] = sensory['Color'] diff --git a/behaviors/AllPixels.py b/behaviors/AllPixels.py new file mode 100644 index 0000000..7f66ad6 --- /dev/null +++ b/behaviors/AllPixels.py @@ -0,0 +1,9 @@ +from operationscore.Behavior import * +class AllPixels(Behavior): + """Turns on all Pixels in the installation. Must use SimpleMapper, or other Mapper supporting + conditional pixel locations.""" + + def processResponse(self, sensorInputs, recursiveInputs): + for sensory in sensorInputs:#TODO: consider replicating the dict + sensory['Location'] = 'True' + return (sensorInputs, recursiveInputs) diff --git a/behaviors/AllPixelsLeft.py b/behaviors/AllPixelsLeft.py index b48bfc1..b223156 100644 --- a/behaviors/AllPixelsLeft.py +++ b/behaviors/AllPixelsLeft.py @@ -2,6 +2,7 @@ from operationscore.Behavior import * import util.ComponentRegistry as compReg import pdb class AllPixelsLeft(Behavior): + """Behavior which returns all points left of its input. No Args.""" def processResponse(self, sensorInputs, recursiveInputs): for sensory in sensorInputs: xLoc = sensory['Location'][0] diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py index 39f4402..631ad98 100644 --- a/behaviors/BehaviorChain.py +++ b/behaviors/BehaviorChain.py @@ -3,6 +3,24 @@ import util.ComponentRegistry as compReg from logger import main_log import pdb class BehaviorChain(Behavior): + """BehaviorChain is a class which chains together multiple behavior. BehaviorChain is in itself a + behavior, and behaves and can be used accordingly. BehaviorChain also supports recursive hooks to + be set on its constituent behaviors. ChainedBehaviors should be specified in <Args> as follows: + + <ChainedBehaviors> + <Id>behavior1Id</Id> + <Id>behavior2Id</Id> + </ChainedBehaviors> + + Behaviors may also be appended programmatically via the appendBehavior method. + + Recursive hooks should be specified with Python dict syntax as follows: + + <RecursiveHooks>{'behavior1Id':'hookid'}</RecursiveHooks> + + Behavior Chain manages all recurrences that its constituents propogate. At this point, it does not + support recurrences in its hooks.""" + def behaviorInit(self): self.feedback = {} #dictionary to allow feedback of recursives self.hooks = self['RecursiveHooks'] @@ -27,11 +45,10 @@ class BehaviorChain(Behavior): hookBehavior.immediateProcessInput(recurrence, \ []) if hookRecurrence != []: - main_log.warn('Hook recurrences are not currently supported. Implement it\ -yourself or bug russell') + main_log.warn('Hook recurrences are not currently supported.') self.feedback[behaviorId] = recurrence return (response, []) - + def appendBehavior(behavior): bid = compReg.registerComponent(behavior) #register behavior (will make #a new id if there isn't one) diff --git a/behaviors/ColorChangerBehavior.py b/behaviors/ColorChangerBehavior.py index 2a8d974..e2f8bd3 100644 --- a/behaviors/ColorChangerBehavior.py +++ b/behaviors/ColorChangerBehavior.py @@ -2,12 +2,26 @@ from operationscore.Behavior import * import util.ColorOps as color import pdb class ColorChangerBehavior(Behavior): + """ColorChangerBehavior is a behavior for adding colors to responses. If given no arguments, it + will generate a random color. If it is given a list of colors [as below] it will pick randomly + from them. + + <ColorList> + <Color>(255,0,0)</Color> + <Color>(30,79,200)</Color> + </ColorList> + + ColorList also supports specification of a single color.""" + def processResponse(self, sensorInputs, recursiveInputs): ret = [] for sensory in sensorInputs: - newDict = dict(sensory) #don't run into shallow copy issues + newDict = dict(sensory) if self['ColorList'] != None: - newDict['Color'] = color.chooseRandomColor(self['ColorList']) #TODO: this doesn't work. + if isinstance(self['ColorList'], list): + newDict['Color'] = color.chooseRandomColor(self['ColorList']) #Pick randomly + else: + newDict['Color'] = self['ColorList'] #Unless there is only one else: newDict['Color'] = color.randomColor() ret.append(newDict) diff --git a/behaviors/DebugBehavior.py b/behaviors/DebugBehavior.py index 34f4106..8f81954 100644 --- a/behaviors/DebugBehavior.py +++ b/behaviors/DebugBehavior.py @@ -2,7 +2,10 @@ from operationscore.Behavior import * from logger import main_log import pdb class DebugBehavior(Behavior): + """DebugBehavior simply writes all of its inputs to the logs, currently at the ERROR level for + easy visibility. Will be changed to DEBUG or INFO in the future""" + def processResponse(self, sensorInputs, recursiveInputs): if sensorInputs != []: - main_log.debug('Sensor Inputs: ' + str(sensorInputs)) + main_log.error('Sensor Inputs: ' + str(sensorInputs)) return ([], []) diff --git a/behaviors/DecayBehavior.py b/behaviors/DecayBehavior.py index c1f6f92..f19ffc8 100644 --- a/behaviors/DecayBehavior.py +++ b/behaviors/DecayBehavior.py @@ -3,6 +3,7 @@ from pixelevents.DecayEvent import * import util.Strings as Strings import pdb class DecayBehavior(Behavior): + """DecayBehavior is obsolete. Use AddPixelEvent instead""" def processResponse(self, sensorInputs, recursiveInputs): ret = [] for sensory in sensorInputs: diff --git a/behaviors/DimColor.xml b/behaviors/DimColor.xml new file mode 100644 index 0000000..58b0673 --- /dev/null +++ b/behaviors/DimColor.xml @@ -0,0 +1,8 @@ +<Behavior> + <Class>behaviors.ModifyParam</Class> + <Args> + <ParamType>Sensor</ParamType> + <ParamName>Color</ParamName> + <ParamOp>[chan*.95 for chan in {val}]</ParamOp> + </Args> +</Behavior> diff --git a/behaviors/EchoBehavior.py b/behaviors/EchoBehavior.py index 589c42b..6ef4fcb 100644 --- a/behaviors/EchoBehavior.py +++ b/behaviors/EchoBehavior.py @@ -2,6 +2,8 @@ from operationscore.Behavior import * import util.Strings as Strings import pdb class EchoBehavior(Behavior): + """EchoBehavior generates a RED response at all locations specified in sensorInputs. Useful for + debugging""" def processResponse(self, sensorInputs, recursiveInputs): ret = [] for sensory in sensorInputs: diff --git a/behaviors/Expand.py b/behaviors/Expand.py new file mode 100644 index 0000000..323e71f --- /dev/null +++ b/behaviors/Expand.py @@ -0,0 +1,21 @@ +from operationscore.Behavior import * +class Expand(Behavior): + """Expand is a behavior that generates a response that grows horizontally starting a location + specifed in input. Required Args: + <ExpandRate>123</ExpandRate> which is the expandrate in units/response""" + + def processResponse(self, sensorInputs, recurs): + ret = [] + for data in sensorInputs: + if not 'Left' in data: #If this is the first time we have seen this input + data['Left'] = data['Location'][0] + data['Right'] = data['Location'][0] + data['ExpandRate'] = self['ExpandRate'] + + data = dict(data) + data['Left'] -= data['ExpandRate'] + data['Right'] += data['ExpandRate'] + data['Location'] = "{x}>" + str(data['Left']) + ", {x}<" + str(data['Right']) + ret.append(data) + return (ret, []) + diff --git a/behaviors/MITDoors.py b/behaviors/MITDoors.py new file mode 100644 index 0000000..d602a55 --- /dev/null +++ b/behaviors/MITDoors.py @@ -0,0 +1,20 @@ +from operationscore.Behavior import * +class MITDoors(Behavior): + """MITDoors is a case-specific behavior to map keypresses to specific locations. Written for + Kuan 1/26/11 by RCOH""" + + def behaviorInit(self): + self.keymapping = {'q':[2,19], 'w':[22,36], 'e':[37,49], 'r':[52,69], 't':[76,91], 'y':[94,105], + 'u':[106,117], 'i':[123,154], 'o':[158,161], 'p':[164,167], '[':[172,184]} + def processResponse(self, sensorInputs, recursiveInputs): + ret = [] + for data in sensorInputs: + key = chr(data['Key']) + if key in self.keymapping: + bounds = self.keymapping[key] + data = dict(data) + data['Left'], data['Right'] = bounds + data['Bottom'] = self['Bottom'] + data['Location'] = (sum(bounds) / 2., self['Bottom']) + ret.append(data) + return (ret, []) diff --git a/behaviors/ModifyParam.py b/behaviors/ModifyParam.py index f589e05..4f45be0 100644 --- a/behaviors/ModifyParam.py +++ b/behaviors/ModifyParam.py @@ -2,8 +2,17 @@ from operationscore.Behavior import * import pdb #Class to perform a given operation on some element of an argDict. Designed to be used a recursive hook, but can serve sensor-based functions as well. Specify ParamType (Sensor or Recurse), ParamName, and ParamOp, (a valid python statement with the old value represented as {val}) class ModifyParam(Behavior): + """ModifyParam is a powerful class to perform an action on a specified key in the Argument + Dictionary of a response. Specify: + <ParamType> -- Sensor or Recurse + <ParamName> -- The name of the parameter you wish to modify + <ParamOp> -- The modification you wish to do. Use {val} to specify the current value of the + parameter in question. Special hooks for {x} and {y} exist in some versions""" + def processResponse(self, sensorInputs, recursiveInputs): paramType = self['ParamType'] + if paramType == None: + paramType = 'Sensor' paramName = self['ParamName'] paramOp = str(self['ParamOp']) if paramType == 'Sensor': diff --git a/behaviors/MoveBehavior.py b/behaviors/MoveBehavior.py index be41b52..e504ca9 100644 --- a/behaviors/MoveBehavior.py +++ b/behaviors/MoveBehavior.py @@ -4,6 +4,9 @@ from operationscore.Behavior import * #import util.Strings as Strings class MoveBehavior(Behavior): + """Moves current location by the x and y components of sensorInput. Uses recurrences to track + current input. @Author: Euguene""" + def processResponse(self, sensorInputs, recursiveInputs): if recursiveInputs: currRecLocs = recursiveInputs diff --git a/behaviors/RandomWalk.py b/behaviors/RandomWalk.py index fd6c2c8..c9049af 100644 --- a/behaviors/RandomWalk.py +++ b/behaviors/RandomWalk.py @@ -5,6 +5,9 @@ import util.Strings as Strings import random import pdb class RandomWalk(Behavior): + """Behavior to move the curent location by a random distance specified by + <StepSize> -- StepSize in units/response""" + def processResponse(self, sensors, recursives): ret = [] s = self['StepSize'] diff --git a/behaviors/RecursiveDecay.py b/behaviors/RecursiveDecay.py index 218813d..0ae21ea 100644 --- a/behaviors/RecursiveDecay.py +++ b/behaviors/RecursiveDecay.py @@ -1,6 +1,11 @@ from operationscore.Behavior import * import pdb class RecursiveDecay(Behavior): + """RecursiveDecay is an event to allow recursive hooks to stop recursing after a certain number + of iterations specified in + <InitialResponseCount> -- Int, number of total responses. + Designed to be used as part of a recursive hook. + """ def processResponse(self, sensorInputs, recursiveInputs): ret = [] for response in sensorInputs: diff --git a/behaviors/ResponseMover.py b/behaviors/ResponseMover.py index e1faccb..59e353a 100644 --- a/behaviors/ResponseMover.py +++ b/behaviors/ResponseMover.py @@ -1,9 +1,11 @@ import pdb from operationscore.Behavior import * import util.ComponentRegistry as compReg -#ResponseMover is a scaffold for behaviors that spawn 'walkers' which act autonomously on input. -#Add a recursive hook to control the movement. class ResponseMover(Behavior): + """ResponseMover is a scaffold for behaviors that spawn 'walkers' which act autonomously on input. + To control the movment, use the behavior as part of a BehaviorChain and add a recursive hook which + modulates the location.""" + def processResponse(self, sensorInputs, recursiveInputs): newResponses = sensorInputs ret = [] diff --git a/behaviors/RestrictLocation.py b/behaviors/RestrictLocation.py index febc9ed..5e12440 100644 --- a/behaviors/RestrictLocation.py +++ b/behaviors/RestrictLocation.py @@ -6,6 +6,16 @@ import util.Strings as Strings import random import pdb class RestrictLocation(Behavior): + """RestrictLocation is a Behavior which does an action -- A ModifyParam, actually, when a certain + location based condition is met. It takes arguments as follows: + + <Action> -- Operation to perform, using ModifyParam syntax. Use {val} to reference the variable + specified by ParamName. + <ParamName> -- the name of the parameter to modify. + <LocationRestriction> -- either a tuple of (xmin,ymin,xmax,ymax) or a python-correct conditional. Use {x} and + {y} to reference x and y. Use < and > to get < and > in XML. EG: + <LocationRestriction>{x}<0 or {x}>800</LocationRestriction>""" + def behaviorInit(self): action = self['Action'] modifyParamArgs = {'ParamType': 'Sensor', @@ -25,7 +35,7 @@ class RestrictLocation(Behavior): def processResponse(self, sensorInputs, recursiveInputs): ret = [] for data in sensorInputs: - if not self.locEval(data['Location']): + if self.locEval(data['Location']): (dataOut, recur) = self.paramModifier.immediateProcessInput([data], []) #behaviors expect lists ^[] ret += dataOut diff --git a/behaviors/RiseFall.py b/behaviors/RiseFall.py new file mode 100644 index 0000000..109cd10 --- /dev/null +++ b/behaviors/RiseFall.py @@ -0,0 +1,40 @@ +from operationscore.Behavior import * +import math +import util.TimeOps as timeOps +#Required Args: +#Period (ms), MaxHeight, Width +class RiseFall(Behavior): + """RiseFall is a behavior that creates a rising and falling column of light. Specify: + <MaxHeight> -- the maximum height that it rises to. + <Width> -- the width of the column OR <Left> and <Right> + <Period> -- the period of oscillation in ms + + Designed to be used as part of a recursive hook. + """ + + def processResponse(self, sensorInputs, recurInputs): + ret = [] + for data in sensorInputs: + #first time with behavior: + data = dict(data) + if not 'StartTime' in data: + data['StartTime'] = timeOps.time() + data['Period'] = self['Period'] + data['MaxHeight'] = self['MaxHeight'] #Consider just using += + if not 'Bottom' in data: + data['Bottom'] = data['Location'][1] + if 'Width' in self: #TODO: improve + data['Width'] = self['Width'] + data['Left'] = data['Location'][0]-data['Width']/2. + data['Right'] = data['Location'][0]+data['Width']/2. + currentTime = timeOps.time() + deltaTime = currentTime-data['StartTime'] + data['Height'] = data['MaxHeight']*math.sin(deltaTime/data['Period']*(math.pi*2)) + data['Location'] = "{x}>"+str(data['Left']) + ", " +\ + "{x}<"+str(data['Right'])+", {y}<" + str(data['Bottom']) + ",\ + {y}>"+str(data['Bottom']-data['Height']) + + ret.append(data) + return (ret, []) + + diff --git a/behaviors/RiseFall.xml b/behaviors/RiseFall.xml new file mode 100644 index 0000000..eaadd7b --- /dev/null +++ b/behaviors/RiseFall.xml @@ -0,0 +1,7 @@ +<Behavior> + <Class>behaviors.RiseFall</Class> + <Args> + <Period>2000</Period> + <MaxHeight>50</MaxHeight> + </Args> +</Behavior> diff --git a/behaviors/RunningBehavior.py b/behaviors/RunningBehavior.py index 5eb33f7..ab3dc80 100644 --- a/behaviors/RunningBehavior.py +++ b/behaviors/RunningBehavior.py @@ -3,6 +3,11 @@ import util.ComponentRegistry as compReg import util.Geo as Geo import pdb class RunningBehavior(Behavior): + """RunningBehavior is a straightforward behavior that makes a Location run back and forth across + a screen. Specify: + <StepSize> -- the length of movment in units when the response moves. + """ + def processResponse(self, sensorInputs, recursiveInputs): newResponses = sensorInputs ret = [] diff --git a/behaviors/SingleFrame.xml b/behaviors/SingleFrame.xml new file mode 100644 index 0000000..49b5dcf --- /dev/null +++ b/behaviors/SingleFrame.xml @@ -0,0 +1,7 @@ +<Behavior> + <Class>behaviors.AddPixelEvent</Class> + <Args> + <Class>pixelevents.SingleFrameEvent</Class> + <z-index>0</z-index> + </Args> +</Behavior> diff --git a/behaviors/Square.py b/behaviors/Square.py index a6e9401..9d3223a 100644 --- a/behaviors/Square.py +++ b/behaviors/Square.py @@ -1,11 +1,17 @@ from operationscore.Behavior import * class Square(Behavior): - def processResponse(self, sensorInputs, recursiveInputs): - for sensory in sensorInputs:#TODO: consider replicating the dict - xLoc = sensory['Location'][0] - yLoc = sensory['Location'][1] - width = self['Width'] - sensory['Location'] =\ - '{x}<'+str(xLoc+width)+',{x}>'+str(xLoc-width)+\ - ',{y}<'+str(yLoc+width)+',{y}>'+str(yLoc-width) - return (sensorInputs, recursiveInputs) + """Square is a simple behavior that makes a square with side lengths Width*2 around locations in + the sensor input. Specify: + <Width> -- the sidelength/2 + """ + + def processResponse(self, sensorInputs, recursiveInputs): + for sensory in sensorInputs:#TODO: consider replicating the dict + xLoc = sensory['Location'][0] + yLoc = sensory['Location'][1] + width = self['Width'] + #sensory['Location'] = 'True' + sensory['Location'] =\ + '{x}<'+str(xLoc+width)+',{x}>'+str(xLoc-width)+\ + ',{y}<'+str(yLoc+width)+',{y}>'+str(yLoc-width) + return (sensorInputs, recursiveInputs) diff --git a/behaviors/TimedDie.py b/behaviors/TimedDie.py new file mode 100644 index 0000000..e75e9dd --- /dev/null +++ b/behaviors/TimedDie.py @@ -0,0 +1,15 @@ +from operationscore.Behavior import * +class Timeout(Behavior): + """Timeout is a behavior designed to be used in recursive hooks to stop responses after a certain + amount of time. It is the Time-version of RecursiveDecay. Specify: + <TimeOut> -- the time in ms that the response will run. + """ + + def processResponse(self, sensorInputs, recur): + ret = [] + for data in sensorInputs: + if not 'StartTime' in data: + data['StartTime'] = timeops.time() + if timeops.time()-data['StartTime'] < self['Timeout']: + ret.append(data) + return (ret, []) diff --git a/behaviors/Timeout.py b/behaviors/Timeout.py new file mode 100644 index 0000000..14d4873 --- /dev/null +++ b/behaviors/Timeout.py @@ -0,0 +1,16 @@ +from operationscore.Behavior import * +import util.TimeOps as timeops +class Timeout(Behavior): + """Timeout is a behavior designed to be used in recursive hooks to stop responses after a certain + amount of time. It is the Time-version of RecursiveDecay. Specify: + <TimeOut> -- the time in ms that the response will run. + """ + + def processResponse(self,sensorInputs, recur): + ret = [] + for data in sensorInputs: + if not 'StartTime' in data: + data['StartTime'] = timeops.time() + if timeops.time()-data['StartTime'] < self['Timeout']: + ret.append(data) + return (ret,[]) diff --git a/behaviors/XYMove.py b/behaviors/XYMove.py new file mode 100644 index 0000000..11cee96 --- /dev/null +++ b/behaviors/XYMove.py @@ -0,0 +1,24 @@ +from operationscore.Behavior import * +import util.Geo as Geo +class XYMove(Behavior): + """XYMove is a behavior designed to be used as a recursive hook to ResponseMover to move pixels by + XStep and YStep. As XStep and YStep are maintained in the responses itself, they can be + modulated to facilitate, acceleration, modulation, bouncing, etc. Specify: + <XStep> -- the starting XStep + <YStep> -- the starting YStep + """ + + def processResponse(self, sensor, recurs): + ret = [] + for loc in sensor: + oploc = dict(loc) + self.insertStepIfMissing(oploc) + oploc['Location'] = Geo.addLocations((oploc['XStep'], oploc['YStep']), oploc['Location']) + ret.append(oploc) + return (ret, []) + def insertStepIfMissing(self, data): + if not 'XStep' in data: + data['XStep'] = self['XStep'] + if not 'YStep' in data: + data['YStep'] = self['YStep'] + |