aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LightInstallation.py9
-rw-r--r--Util.py7
-rw-r--r--behaviors/BehaviorChain.py9
-rw-r--r--behaviors/ColorChangerBehavior.py6
-rw-r--r--behaviors/DecayBehavior.py2
-rw-r--r--behaviors/RecursiveDecay.py12
-rw-r--r--config/GaussianMapper.params3
-rw-r--r--config/LightInstallationConfig.xml52
-rw-r--r--config/RecursiveDecay.params2
-rw-r--r--operationscore/Behavior.py1
-rw-r--r--operationscore/SmootCoreObject.py10
-rw-r--r--pixelmappers/GaussianMapper.py13
12 files changed, 114 insertions, 12 deletions
diff --git a/LightInstallation.py b/LightInstallation.py
index 7d8b7b0..849e41f 100644
--- a/LightInstallation.py
+++ b/LightInstallation.py
@@ -80,14 +80,20 @@ class LightInstallation:
return True
def mainLoop(self):
#self.screen.allOn()
+ lastLoopTime = Util.time()
+ refreshInterval = 30
while 1:
- time.sleep(.1)
+ loopStart = Util.time()
responses = self.evaluateBehaviors() #inputs are all queued when they
#happen, so we only need to run the behaviors
[self.screen.respond(response) for response in responses if
response != []]
self.screen.timeStep()
[r.render(self.screen) for r in self.renderers]
+ loopElapsed = Util.time()-loopStart
+ sleepTime = max(0,refreshInterval-loopElapsed)
+ if sleepTime > 0:
+ time.sleep(sleepTime/1000)
#evaluates all the behaviors (including inter-dependencies) and returns a
#list of responses to go to the screen.
def evaluateBehaviors(self):
@@ -114,7 +120,6 @@ class LightInstallation:
if inputId in self.inputBehaviorRegistry: #it could be a behavior
self.inputBehaviorRegistry[inputId].append(behavior['Id'])
def processResponse(self,inputDict, responseDict):
- print inputDict, responseDict
inputId = inputDict['Id']
boundBehaviorIds = self.inputBehaviorRegistry[inputId]
[self.componentDict[b].addInput(responseDict) for b in boundBehaviorIds]
diff --git a/Util.py b/Util.py
index 48ad3c5..377c2e3 100644
--- a/Util.py
+++ b/Util.py
@@ -41,12 +41,19 @@ def addPixelEventIfMissing(responseDict):
else:
raise Exception('Need Color. Probably')
responseDict['PixelEvent'] = StepEvent.generate(300, color)
+def gaussian(x,height,center,width):
+ a=height
+ b=center
+ c=width
+ return a*math.exp(-((x-b)**2)/(2*c**2))
def dist(l1, l2):
return math.sqrt(sum([(l1[i]-l2[i])**2 for i in range(len(l1))]))
def time():
return clock.time()*1000
def randomColor():
return [random.randint(0,255) for i in range(3)]
+def chooseRandomColor(colorList):
+ return random.choice(colorList)
def loadParamRequirementDict(className):
return fileToDict(CONFIG_PATH + className)
def loadConfigFile(fileName):
diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py
index 8bf97bb..8b5cb1d 100644
--- a/behaviors/BehaviorChain.py
+++ b/behaviors/BehaviorChain.py
@@ -4,6 +4,9 @@ import pdb
class BehaviorChain(Behavior):
def behaviorInit(self):
self.feedback = {} #dictionary to allow feedback of recursives
+ self.hooks = self['RecursiveHooks']
+ if self.hooks == None:
+ self.hooks = {}
def processResponse(self, sensorInputs, recursiveInputs):
response = sensorInputs
for behaviorId in self['ChainedBehaviors']:
@@ -14,5 +17,11 @@ class BehaviorChain(Behavior):
recurrence = []
(response,recurrence) = behavior.immediateProcessInput(response,\
recurrence)
+
+ if behaviorId in self.hooks: #process recursive hook if there is one
+ hookBehavior = Util.getComponentById(self.hooks[behaviorId])
+ (response, recurrence) = \
+ hookBehavior.immediateProcessInput(response,
+ recurrence)
self.feedback[behaviorId] = recurrence
return response
diff --git a/behaviors/ColorChangerBehavior.py b/behaviors/ColorChangerBehavior.py
index 8ecc5f2..ca80eb4 100644
--- a/behaviors/ColorChangerBehavior.py
+++ b/behaviors/ColorChangerBehavior.py
@@ -6,7 +6,9 @@ class ColorChangerBehavior(Behavior):
ret = []
for sensory in sensorInputs:
newDict = dict(sensory) #don't run into shallow copy issues
- #TODO: support for PixelEvents
- newDict['Color'] = Util.randomColor()
+ if self['ColorList'] != None:
+ newDict['Color'] = Util.randomColor(self['ColorList'])
+ else:
+ newDict['Color'] = Util.chooseRandomColor()
ret.append(newDict)
return ret
diff --git a/behaviors/DecayBehavior.py b/behaviors/DecayBehavior.py
index 7956cbc..edc833d 100644
--- a/behaviors/DecayBehavior.py
+++ b/behaviors/DecayBehavior.py
@@ -11,4 +11,4 @@ class DecayBehavior(Behavior):
outDict['PixelEvent'] = \
DecayEvent.generate(self['DecayType'],self['Coefficient'], sensory['Color'])
ret.append(outDict)
- return ret
+ return (ret, recursiveInputs)
diff --git a/behaviors/RecursiveDecay.py b/behaviors/RecursiveDecay.py
new file mode 100644
index 0000000..b119b85
--- /dev/null
+++ b/behaviors/RecursiveDecay.py
@@ -0,0 +1,12 @@
+from operationscore.Behavior import *
+class RecursiveDecay(Behavior):
+ def processResponse(self, sensorInputs, recursiveInputs):
+ ret = []
+ for response in recursiveInputs:
+ if not 'ResponsesLeft' in response:
+ response['ResponsesLeft'] = self['InitialResponseCount']
+ else:
+ response['ResponsesLeft'] -= 1
+ if response['ResponsesLeft'] > 0:
+ ret.append(response)
+ return (sensorInputs, ret) #no direct ouput
diff --git a/config/GaussianMapper.params b/config/GaussianMapper.params
new file mode 100644
index 0000000..288ec1d
--- /dev/null
+++ b/config/GaussianMapper.params
@@ -0,0 +1,3 @@
+{'CutoffDist':'CutoffDist, the distance at which a light will not be turned
+on','Height':'The height of the gaussian','Width':'The width of the
+gaussian'}
diff --git a/config/LightInstallationConfig.xml b/config/LightInstallationConfig.xml
index 441b7e4..aa331af 100644
--- a/config/LightInstallationConfig.xml
+++ b/config/LightInstallationConfig.xml
@@ -31,13 +31,24 @@
</Args>
</PixelStrip>
</PixelConfiguration>
- <PixelMapperConfiguration>
+ <!--<PixelMapperConfiguration>
<PixelMapper>
<Class>pixelmappers.SimpleMapper</Class>
<Args>
<Id>simplemap</Id>
</Args>
</PixelMapper>
+ </PixelMapperConfiguration>-->
+ <PixelMapperConfiguration>
+ <PixelMapper>
+ <Class>pixelmappers.GaussianMapper</Class>
+ <Args>
+ <Id>gaussmap</Id>
+ <CutoffDist>30</CutoffDist>
+ <Width>5</Width>
+ <Height>.5</Height>
+ </Args>
+ </PixelMapper>
</PixelMapperConfiguration>
<RendererConfiguration>
<Renderer>
@@ -47,7 +58,7 @@
<displaySize>(1300,50)</displaySize>
</Args>
</Renderer>
- <!-- <Renderer>
+ <Renderer>
<Class>renderers.IndoorRenderer</Class>
<Args>
<Id>indoorRenderer</Id>
@@ -56,7 +67,7 @@
<PortMapping>{'strip1':1, 'strip2':2}</PortMapping>
</PowerSupply>
</Args>
- </Renderer>-->
+ </Renderer>
</RendererConfiguration>
<InputConfiguration>
<InputElement>
@@ -67,6 +78,14 @@
</Args>
</InputElement>
<InputElement>
+ <Class>inputs.PygameInput</Class>
+ <Args><!--Passed as a dictionary-->
+ <Id>followmouse</Id>
+ <RefreshInterval>100</RefreshInterval>
+ <FollowMouse>True</FollowMouse>
+ </Args>
+ </InputElement>
+ <InputElement>
<Class>inputs.UDPInput</Class>
<Args>
<Id>UDP</Id>
@@ -102,7 +121,7 @@
<Args>
<Id>decay</Id>
<DecayType>Exponential</DecayType>
- <Coefficient>.005</Coefficient>
+ <Coefficient>.001</Coefficient>
<z-index>0</z-index>
<RenderToScreen>False</RenderToScreen>
<Inputs>
@@ -120,6 +139,13 @@
</Args>
</Behavior>
<Behavior>
+ <Class>behaviors.RecursiveDecay</Class>
+ <Args>
+ <Id>recursivedecay</Id>
+ <InitialResponseCount>20000</InitialResponseCount>
+ </Args>
+ </Behavior>
+ <Behavior>
<Class>behaviors.BehaviorChain</Class>
<Args>
<Id>runcolordecay</Id>
@@ -131,6 +157,22 @@
<Id>running</Id>
<Id>decay</Id>
</ChainedBehaviors>
+ <RecursiveHooks>{'running':'recursivedecay'}</RecursiveHooks>
+ <RenderToScreen>True</RenderToScreen>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>mousechaser</Id>
+ <Inputs>
+ <Id>followmouse</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>echo</Id>
+ <Id>colorchange</Id>
+ <Id>decay</Id>
+ </ChainedBehaviors>
<RenderToScreen>True</RenderToScreen>
</Args>
</Behavior>
@@ -141,7 +183,7 @@
<Inputs>
<Id>pygame</Id>
</Inputs>
- <StepSize>10</StepSize>
+ <StepSize>1</StepSize>
<RenderToScreen>False</RenderToScreen>
</Args>
</Behavior>
diff --git a/config/RecursiveDecay.params b/config/RecursiveDecay.params
new file mode 100644
index 0000000..fe9d553
--- /dev/null
+++ b/config/RecursiveDecay.params
@@ -0,0 +1,2 @@
+{'InitialResponseCount':'Initial response count, the number of times a
+recursive response can occur, must be specified.'}
diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py
index 8db2d88..e300f6b 100644
--- a/operationscore/Behavior.py
+++ b/operationscore/Behavior.py
@@ -37,7 +37,6 @@ class Behavior(SmootCoreObject):
except:
return (self.processResponse(sensorInputs, recursiveInputs),[])
def addInputs(self, sensorInputs):
- print sensorInputs
if type(sensorInputs) == type([]):
[self.addInput(sensorInput) for sensorInput in sensorInputs]
else:
diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py
index 2901ef6..84319af 100644
--- a/operationscore/SmootCoreObject.py
+++ b/operationscore/SmootCoreObject.py
@@ -3,9 +3,14 @@ import pdb
class SmootCoreObject:
def __init__(self, argDict):
self.argDict = argDict
+ self.validateArgs(self.className()+'.params')
self.init() #call init of inheriting class
+ # self.__setitem__ = self.argDict.__setitem__
+ # self.__getitem__ = self.argDict.__getitem__
def init(self):
pass
+ def className(self):
+ return str(self.__class__).split('.')[-1]
def __setitem__(self,k, item):
self.argDict[k] = item
def __getitem__(self, item):
@@ -16,7 +21,10 @@ class SmootCoreObject:
def __getiter__(self):
return self.argDict.__getiter__()
def validateArgs(self, argFileName):
- self.validateArgDict(Util.loadParamRequirementDict(argFileName))
+ try:
+ self.validateArgDict(Util.loadParamRequirementDict(argFileName))
+ except IOError:
+ print 'No Arg Dict found for ' + self.className()
def validateArgDict(self, validationDict):
for item in validationDict:
if not item in self.argDict:
diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py
new file mode 100644
index 0000000..552f5c9
--- /dev/null
+++ b/pixelmappers/GaussianMapper.py
@@ -0,0 +1,13 @@
+from operationscore.PixelMapper import *
+import Util
+class GaussianMapper(PixelMapper):
+ def mappingFunction(self, eventLocation, screen):
+ returnPixels = []
+ for pixel in screen:
+ pixelDist = Util.dist(pixel.location, eventLocation)
+ if pixelDist < self['CutoffDist']:
+ w = Util.gaussian(pixelDist, self['Height'], 0, self['Width'])
+ if w>1:
+ pdb.set_trace()
+ returnPixels.append((pixel, w))
+ return returnPixels