aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar rcoh <rcoh@mit.edu>2011-02-16 15:26:29 -0500
committerGravatar rcoh <rcoh@mit.edu>2011-02-16 15:26:29 -0500
commit3c405fa182b1e524f5724e65266667d8f65dc179 (patch)
tree2e1320d152f4ae8579eb8f651be0af12da25c6cb
parentd8ba03006e2ea1400e80caded738e79c186e8de3 (diff)
parentf34e1c732036553e4a68534dfc1b24a13ccd33ce (diff)
Merge branch 'master' into behavior-factory
-rw-r--r--behaviors/Square.py7
-rw-r--r--config/C5Sign.xml234
-rw-r--r--docs/Behaviors/Behavior.jpgbin0 -> 21577 bytes
-rw-r--r--docs/Behaviors/Behaviors.pdfbin0 -> 148809 bytes
-rw-r--r--docs/Behaviors/Behaviors.tex155
-rw-r--r--docs/Behaviors/BehaviorwithRecursiveHook.jpgbin0 -> 27186 bytes
-rw-r--r--docs/ClassOverview.pdfbin0 -> 132526 bytes
-rw-r--r--docs/designDocs.pdfbin129631 -> 0 bytes
-rw-r--r--docs/tex/Behaviors.tex143
-rw-r--r--docs/tex/ClassOverview.tex (renamed from docs/designDocs.tex)16
-rwxr-xr-xga1
-rw-r--r--layouts/SpecifiedLayout.py21
-rw-r--r--operationscore/Behavior.py29
-rw-r--r--renderers/C5Renderer.xml10
-rw-r--r--tests/TestBQS.py4
-rw-r--r--util/BehaviorQuerySystem.py8
16 files changed, 613 insertions, 15 deletions
diff --git a/behaviors/Square.py b/behaviors/Square.py
index 9d3223a..5fdaeef 100644
--- a/behaviors/Square.py
+++ b/behaviors/Square.py
@@ -7,6 +7,7 @@ class Square(Behavior):
def processResponse(self, sensorInputs, recursiveInputs):
for sensory in sensorInputs:#TODO: consider replicating the dict
+ sensory['CenterLoc'] = list(sensory['Location'])
xLoc = sensory['Location'][0]
yLoc = sensory['Location'][1]
width = self['Width']
@@ -15,3 +16,9 @@ class Square(Behavior):
'{x}<'+str(xLoc+width)+',{x}>'+str(xLoc-width)+\
',{y}<'+str(yLoc+width)+',{y}>'+str(yLoc-width)
return (sensorInputs, recursiveInputs)
+
+ def setLastOutput(self, output):
+ coutput = Behavior.deepCopyPacket(output)
+ for data in coutput:
+ data['Location'] = data['CenterLoc']
+ return coutput
diff --git a/config/C5Sign.xml b/config/C5Sign.xml
new file mode 100644
index 0000000..6550067
--- /dev/null
+++ b/config/C5Sign.xml
@@ -0,0 +1,234 @@
+<!---All configuration items contain a "Class" tag specifying the python class they represent, and an "Args" tag specifying the args to be passed in.-->
+<LightInstallation>
+ <InstallationConfiguration>
+ <Defaults>
+ <PixelMapper>simplemap</PixelMapper>
+ </Defaults>
+ </InstallationConfiguration>
+ <PixelConfiguration>
+ <InheritsFrom>layouts/C5SignLayout.xml</InheritsFrom>
+ </PixelConfiguration>
+ <PixelMapperConfiguration>
+ <PixelMapper>
+ <Class>pixelmappers.SimpleMapper</Class>
+ <Args>
+ <Id>simplemap</Id>
+ <CutoffDist>20</CutoffDist>
+ </Args>
+ </PixelMapper>
+ <PixelMapper>
+ <Class>pixelmappers.GaussianMapper</Class>
+ <Args>
+ <Id>gaussmap</Id>
+ <CutoffDist>30</CutoffDist>
+ <MinWeight>0.1</MinWeight>
+ <Width>10</Width>
+ <Height>1</Height>
+ </Args>
+ </PixelMapper>
+ </PixelMapperConfiguration>
+ <RendererConfiguration>
+ <Renderer>
+ <InheritsFrom>renderers/C5Renderer.xml</InheritsFrom>
+ </Renderer>
+ <Renderer>
+ <InheritsFrom>renderers/Pygame.xml</InheritsFrom>
+ </Renderer>
+ </RendererConfiguration>
+ <InputConfiguration>
+ <InputElement>
+ <Class>inputs.PygameInput</Class>
+ <Args>
+ <Id>pygameclick</Id>
+ <RefreshInterval>10</RefreshInterval>
+ <Clicks>True</Clicks>
+ </Args>
+ </InputElement>
+ <InputElement>
+ <Class>inputs.PygameInput</Class>
+ <Args>
+ <Id>pygamekey</Id>
+ <RefreshInterval>10</RefreshInterval>
+ <Keyboard>True</Keyboard>
+ </Args>
+ </InputElement>
+ <InputElement>
+ <Class>inputs.UDPInput</Class>
+ <Args>
+ <Id>udp</Id>
+ <Port>3344</Port>
+ <RefreshInterval>50</RefreshInterval>
+ </Args>
+ </InputElement>
+ <!--<InputElement>
+ <Class>inputs.TCPInput</Class>
+ <Args>
+ <Id>tcp</Id>
+ <Port>20120</Port>
+ <RefreshInterval>10</RefreshInterval>
+ </Args>
+ </InputElement>-->
+ <InputElement Id="followmouse" RefreshInterval="1000">
+ <InheritsFrom>inputs/MouseFollower.xml</InheritsFrom>
+ </InputElement>
+ </InputConfiguration>
+ <BehaviorConfiguration>
+ <Behavior Id="colorchange">
+ <InheritsFrom>behaviors/RandomColor.xml</InheritsFrom>
+ <Args>
+ <ColorList>
+ <Val>(255,0,0)</Val>
+ <Val>(0,0,255)</Val>
+ </ColorList>
+ </Args>
+ </Behavior>
+ <Behavior Id="decay">
+ <InheritsFrom>behaviors/PixelDecay.xml</InheritsFrom>
+ </Behavior>
+ <Behavior Id="singleframe">
+ <InheritsFrom>behaviors/SingleFrame.xml</InheritsFrom>
+ </Behavior>
+ <Behavior Id="slowdecay">
+ <InheritsFrom>behaviors/PixelDecay.xml</InheritsFrom>
+ <Args>
+ <Coefficient>.01</Coefficient>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.XYMove</Class>
+ <Args>
+ <Id>xymove</Id>
+ <XStep>5</XStep>
+ <YStep>2</YStep>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.RestrictLocation</Class>
+ <Args>
+ <Id>xbounce</Id>
+ <Action>{val}*-1</Action>
+ <ParamName>XStep</ParamName>
+ <LocationRestriction>{x}&lt;0 or {x}&gt;200</LocationRestriction>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.RestrictLocation</Class>
+ <Args>
+ <Id>ybounce</Id>
+ <Action>{val}*-1</Action>
+ <ParamName>YStep</ParamName>
+ <LocationRestriction>{y}&lt;0 or {y}&gt;100</LocationRestriction>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>movebounce</Id>
+ <ChainedBehaviors>
+ <Id>xymove</Id>
+ <Id>colorshift</Id>
+ <Id>ybounce</Id>
+ <Id>xbounce</Id>
+ </ChainedBehaviors>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.ModifyParam</Class>
+ <Args>
+ <Id>ysin</Id>
+ <ParamName>YStep</ParamName>
+ <ParamType>Sensor</ParamType>
+ <ParamOp>4*math.sin({x}/float(40))</ParamOp>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.DebugBehavior</Class>
+ <Args>
+ <Id>debug</Id>
+ <z-index>0</z-index>
+ <Inputs>
+ <Id>pygamekey</Id>
+ <Id>udp</Id>
+ </Inputs>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.AllPixels</Class>
+ <Args>
+ <Id>square</Id>
+ <Width>20</Width>
+ </Args>
+ </Behavior>
+ <Behavior Id="recursivedecay">
+ <InheritsFrom>behaviors/LoopAndDie.xml</InheritsFrom>
+ <Args>
+ <InitialResponseCount>80</InitialResponseCount>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>runcolordecay</Id>
+ <Inputs>
+ <Id>pygameclick</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>colorchange</Id>
+ <Id>mover</Id>
+ <Id>decay</Id>
+ </ChainedBehaviors>
+ <RecursiveHooks>{'mover':'movebounce'}</RecursiveHooks>
+ <RenderToScreen>True</RenderToScreen>
+ <Mapper>gaussmap</Mapper>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.ResponseMover</Class>
+ <Args>
+ <Id>mover</Id>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.RandomWalk</Class>
+ <Args>
+ <Id>randmovement</Id>
+ <StepSize>2</StepSize>
+ </Args>
+ </Behavior>
+ <Behavior Id="accelerate">
+ <InheritsFrom>behaviors/Accelerate.xml</InheritsFrom>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.EchoBehavior</Class>
+ <Args>
+ <Id>echo</Id>
+ <z-index>0</z-index>
+ <RenderToScreen>False</RenderToScreen>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.ColorShift</Class>
+ <Args>
+ <Id>colorshift</Id>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>mousechaser</Id>
+ <Inputs>
+ <Id>followmouse</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>echo</Id>
+ <Id>square</Id>
+ <Id>singleframe</Id>
+ </ChainedBehaviors>
+ <RenderToScreen>False</RenderToScreen>
+ </Args>
+ </Behavior>
+ <Behavior Id="running">
+ <InheritsFrom>behaviors/RunningBehavior.xml</InheritsFrom>
+ </Behavior>
+ </BehaviorConfiguration>
+</LightInstallation>
diff --git a/docs/Behaviors/Behavior.jpg b/docs/Behaviors/Behavior.jpg
new file mode 100644
index 0000000..c96ee84
--- /dev/null
+++ b/docs/Behaviors/Behavior.jpg
Binary files differ
diff --git a/docs/Behaviors/Behaviors.pdf b/docs/Behaviors/Behaviors.pdf
new file mode 100644
index 0000000..32c5b75
--- /dev/null
+++ b/docs/Behaviors/Behaviors.pdf
Binary files differ
diff --git a/docs/Behaviors/Behaviors.tex b/docs/Behaviors/Behaviors.tex
new file mode 100644
index 0000000..5105588
--- /dev/null
+++ b/docs/Behaviors/Behaviors.tex
@@ -0,0 +1,155 @@
+\documentclass{article}
+\usepackage{fullpage}
+\usepackage{graphicx}
+\begin{document}
+ \title{Behaviors: An Introduction and Exercises}
+ \author{Russell Cohen}
+ \date{\today}
+ \maketitle
+ \section{What is a behavior?}
+ At its most basic, a behavior is machine with two input terminals and two
+ output terminals. One of these input terminals is external input. The
+ other is feedback from the behavior. Similarly, the behavior has two output
+ terminals. One gets released externally as output, and the other gets fed
+ back to the behavior. At their core, behaviors have nothing to do with
+ pixels are light effects -- this is merely how we commonly use them.
+ \begin{center}
+ \includegraphics[width=4 in]{Behavior.jpg}
+ \end{center}
+ \section{How do I write a behavior?}
+ At the core of a behavior is its \texttt{ProcessResponse} method which
+ tells a behavior what to get on input. As you might expect, it has 2
+ input ports, and two output ports. The `type' of inputs and outputs can be
+ anything -- numbers, strings, lists, however, in our system, the inputs
+ and outputs are all python dictionaries. This allows us to have an
+ arbitrary number of named parameters. As sample input might look
+ something like \texttt{{'Location':(20,20), 'Height':10}}. When we
+ return a value, we return a tuple of \texttt{(list<dict>,list<dict>)}. Note that on a
+ process response method you will actually be given a \textbf{List of
+ dictionaries} and you should iterate over them.
+ \textbf{Important:} You should not directly modify the inputs! Use
+ \texttt{dict(input)} to create a copy of them!
+ \section{Exercise 1: addFive}
+ Our goal: Create a behavior that will add 5 to the 'Value' field of the
+ input. If no 'Value' field exists, we will set it to five. Below is a
+ sample \verb processResponse method to do this. Note that process
+ response is the only part of a behavior that must be written (everything
+ else happens behind the scenes when you \textbf{inherit} from the
+ \texttt{Behavior} class.
+ \begin{verbatim}
+ def processResponse(self, inputs, recurrences):
+ output = [] #empty list
+ for inp in inputs:
+ inpCopy = dict(inp)
+ if not ('Value' in inpCopy):
+ inpCopy['Value'] = 0
+ inpCopy['Value'] += 5
+ output.append(inpCopy)
+ return (output, []) #empty list, no recurrences
+ \end{verbatim}
+ \section{Exercise 2: A Sum-er}
+ Create a behavior that outputs the sum of all previous input. Hint:
+ You will need to use recurrences!
+ \section{Declaring and Configuring Behaviors}
+ Once you've written your behavior (or are using an already written
+ behavior, you will need to tell the light installation to use the
+ behavior. This is done via XML in the configuration file. When you
+ run the system, you specify a configuration file eg:
+ \texttt{python LightInstallation.py config/ConfigFile.xml}
+
+ Behaviors are specified in the \verb BehaviorConfiguration section.
+ A sample behavior follows:
+ \begin{verbatim}
+ <Behavior>
+ <Class>behaviors.EchoBehavior</Class>
+ <Args>
+ <Id>echo</Id>
+ <RenderToScreen>False</RenderToScreen>
+ </Args>
+ </Behavior>
+ \end{verbatim}
+
+ The ``Class'' attribute specifies the \textbf{Python} class for this
+ behavior. (The \verb behaviors. prefix tells Python to look in the
+ behaviors folder). You may recall that all classes SmootLight take a
+ single python dictionary as an argument -- this is embodied by the
+ \texttt{Args} tag. A dictionary is created from the XML at runtime
+ -- this dictionary would be: \texttt{{'Id':'echo',
+ 'RenderToScreen':False}}
+ The id we specify is the id that we can reference this behavior by
+ later. The \verb RenderToScreen attribute specifies whether or not
+ outputs from this behavior should be directed to the screen (some
+ behaviors act only as the building blocks for other
+ behaviors, and are never rendered directly to the screen)
+
+ \section{Behavior Chains}
+ I have mentioned several times that the system allows for behaviors to
+ be chained together to create many different effects -- often the
+ ``motion'' effect and the ``coloring'' effects are two separate
+ behaviors. The result you see on the screen are these two pieces
+ connected together. This allows us to build up many different behaviors
+ from a library of simple pieces. Let's look at how we actually
+ accomplish this.
+
+ Behavior Chaining is accomplished through the behavior chain class.
+ Here is an example of a behavior we declare (in XML) via a behavior
+ chain:
+ \begin{verbatim}
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>runcolordecay</Id>
+ <Inputs>
+ <Id>pygame</Id>
+ <Id>randomLoc</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>colorchange</Id>
+ <Id>running</Id>
+ <Id>decay</Id>
+ </ChainedBehaviors>
+ <RecursiveHooks>{'running':'acceleratedie'}</RecursiveHooks>
+ <RenderToScreen>True</RenderToScreen>
+ <Mapper>gaussmap</Mapper>
+ </Args>
+ </Behavior>
+ \end{verbatim}
+
+ Note the importance of the `Id' field -- that is how we reference all
+ other components of the system. Let's walk through what is going on
+ here. We declare this behavior just like any other -- however, for
+ class, we specify \verb BehaviorChain . The \verb Inputs tag specifies
+ which inputs will be routed to this behavior. In this case, it is
+ \verb pygame and \verb randomLoc , two previously declared behaviors.
+ Inputs from these behaviors will be passed to the behavior chain via
+ sensorInputs. Next, we have the meet of this chain, the behaviors it is
+ composed of. This states that first, an input is routed through
+ \texttt{colorchange}. \verb colorchange adds a color field to the
+ sensor data. Next, the input is routed to \verb running a behavior
+ that makes pixels run back and forth. Finally, the input is routed to
+ \verb decay , a behavior that adds a decay ``PixelEvent'' that makes
+ individual pixels turn on and then decay.
+
+ The next item we see is \verb RecursiveHooks . This is a special
+ feature of the \verb BehaviorChain that allows us to augment the
+ reccurences recursive events have. We specify that we will augment the
+ recursive behavior of \verb running with another behavior,
+ \verb acceleratedie which modifies increases the speed of the running
+ behavior, and stops the behavior after a certain number of iterations.
+ Note that recursive hooks take data in via their \textbf{external input}
+ port, and \textbf{not} their recursive port.
+ \begin{center}
+ \includegraphics[width=4 in]{BehaviorwithRecursiveHook.jpg}
+ \end{center}
+ Finally, we state that this behavior will indeed be rendered directly to
+ the screen, by specifying:
+ \begin{center}\texttt{<RenderToScreen>True</RenderToScreen>} \end{center}
+ We also specify which PixelMapper we want to use (gaussmap):
+ \texttt{<Mapper>gaussmap</Map>}. \verb gaussmap is the id we assigned to the mapper when
+ we declared in the \verb PixelMappers section of the xml.
+ \begin{center}
+ Phew. This isn't as complicated as it sounds. I promise.
+ \end{center}
+ Browse around the behaviors to get an idea of what is possible and what has been done. They
+ all live in the behaviors folder. Enjoy!
+ \end{document}
diff --git a/docs/Behaviors/BehaviorwithRecursiveHook.jpg b/docs/Behaviors/BehaviorwithRecursiveHook.jpg
new file mode 100644
index 0000000..84e99d6
--- /dev/null
+++ b/docs/Behaviors/BehaviorwithRecursiveHook.jpg
Binary files differ
diff --git a/docs/ClassOverview.pdf b/docs/ClassOverview.pdf
new file mode 100644
index 0000000..530dfa6
--- /dev/null
+++ b/docs/ClassOverview.pdf
Binary files differ
diff --git a/docs/designDocs.pdf b/docs/designDocs.pdf
deleted file mode 100644
index 78eb646..0000000
--- a/docs/designDocs.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/tex/Behaviors.tex b/docs/tex/Behaviors.tex
new file mode 100644
index 0000000..9021581
--- /dev/null
+++ b/docs/tex/Behaviors.tex
@@ -0,0 +1,143 @@
+\documentclass{article}
+\usepackage{fullpage}
+\begin{document}
+ \title{Behaviors: An Introduction and Exercises}
+ \author{Russell Cohen}
+ \date{\today}
+ \maketitle
+ \section{What is a behavior?}
+ At its most basic, a behavior is machine with two input terminals and two
+ output terminals. One of these input terminals is external input. The
+ other is feedback from the behavior. Similarly, the behavior has two output
+ terminals. One gets released externally as output, and the other gets fed
+ back to the behavior. At their core, behaviors have nothing to do with
+ pixels are light effects -- this is merely how we commonly use them.
+ \section{How do I write a behavior?}
+ At the core of a behavior is its \texttt{ProcessResponse} method which
+ tells a behavior what to get on input. As you might expect, it has 2
+ input ports, and two output ports. The `type' of inputs and outputs can be
+ anything -- numbers, strings, lists, however, in our system, the inputs
+ and outputs are all python dictionaries. This allows us to have an
+ arbitrary number of named parameters. As sample input might look
+ something like \texttt{{'Location':(20,20), 'Height':10}}. When we
+ return a value, we return a tuple of (list<dict>,list<dict>). Note that on a
+ process response method you will actually be given a \textbf{List of
+ dictionaries} and you should iterate over them.
+ \textbf{Important:} You should not directly modify the inputs! Use
+ \texttt{dict(input)} to create a copy of them!
+ \section{Exercise 1: addFive}
+ Our goal: Create a behavior that will add 5 to the 'Value' field of the
+ input. If no 'Value' field exists, we will set it to five. Below is a
+ sample \verb processResponse method to do this. Note that process
+ response is the only part of a behavior that must be written (everything
+ else happens behind the scenes when you \textbf{inherit} from the
+ \texttt{Behavior} class.
+ \begin{verbatim}
+ def processResponse(self, inputs, recurrences):
+ output = [] #empty list
+ for inp in inputs:
+ inpCopy = dict(inp)
+ if not ('Value' in inpCopy):
+ inpCopy['Value'] = 0
+ inpCopy['Value'] += 5
+ output.append(inpCopy)
+ return (output, []) #empty list, no recurrences
+ \end{verbatim}
+ \section{Exercise 2: A Sum-er}
+ Create a behavior that outputs the sum of all previous input. Hint:
+ You will need to use recurrences!
+ \section{Declaring and Configuring Behaviors}
+ Once you've written your behavior (or are using an already written
+ behavior, you will need to tell the light installation to use the
+ behavior. This is done via XML in the configuration file. When you
+ run the system, you specify a configuration file eg:
+ \texttt{python LightInstallation.py config/ConfigFile.xml}
+
+ Behaviors are specified in the \verb BehaviorConfiguration section.
+ A sample behavior follows:
+ \begin{verbatim}
+ <Behavior>
+ <Class>behaviors.EchoBehavior</Class>
+ <Args>
+ <Id>echo</Id>
+ <RenderToScreen>False</RenderToScreen>
+ </Args>
+ </Behavior>
+ \end{verbatim}
+
+ The ``Class'' attribute specifies the \textbf{Python} class for this
+ behavior. (The \verb behaviors. prefix tells Python to look in the
+ behaviors folder). You may recall that all classes SmootLight take a
+ single python dictionary as an argument -- this is embodied by the
+ \texttt{Args} tag. A dictionary is created from the XML at runtime
+ -- this dictionary would be: \texttt{{'Id':'echo',
+ 'RenderToScreen':False}}
+ The id we specify is the id that we can reference this behavior by
+ later. The \verb RenderToScreen attribute specifies whether or not
+ outputs from this behavior should be directed to the screen (some
+ behaviors act only as the building blocks for other
+ behaviors, and are never rendered directly to the screen)
+
+ \section{Behavior Chains}
+ I have mentioned several times that the system allows for behaviors to
+ be chained together to create many different effects -- often the
+ ``motion'' effect and the ``coloring'' effects are two separate
+ behaviors. The result you see on the screen are these two pieces
+ connected together. This allows us to build up many different behaviors
+ from a library of simple pieces. Let's look at how we actually
+ accomplish this.
+
+ Behavior Chaining is accomplished through the behavior chain class.
+ Here is an example of a behavior we declare (in XML) via a behavior
+ chain:
+ \begin{verbatim}
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Id>runcolordecay</Id>
+ <Inputs>
+ <Id>pygame</Id>
+ <Id>randomLoc</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>colorchange</Id>
+ <Id>running</Id>
+ <Id>decay</Id>
+ </ChainedBehaviors>
+ <RecursiveHooks>{'running':'acceleratedie'}</RecursiveHooks>
+ <RenderToScreen>True</RenderToScreen>
+ <Mapper>gaussmap</Mapper>
+ </Args>
+ </Behavior>
+ \end{verbatim}
+
+ Note the importance of the `Id' field -- that is how we reference all
+ other components of the system. Let's walk through what is going on
+ here. We declare this behavior just like any other -- however, for
+ class, we specify \verb BehaviorChain . The \verb Inputs tag specifies
+ which inputs will be routed to this behavior. In this case, it is
+ \verb pygame and \verb randomLoc , two previously declared behaviors.
+ Inputs from these behaviors will be passed to the behavior chain via
+ sensorInputs. Next, we have the meet of this chain, the behaviors it is
+ composed of. This states that first, an input is routed through
+ \texttt{colorchange}. \verb colorchange adds a color field to the
+ sensor data. Next, the input is routed to \verb running a behavior
+ that makes pixels run back and forth. Finally, the input is routed to
+ \verb decay , a behavior that adds a decay ``PixelEvent'' that makes
+ individual pixels turn on and then decay.
+
+ The next item we see is \verb RecursiveHooks . This is a special
+ feature of the \verb BehaviorChain that allows us to augment the
+ reccurences recursive events have. We specify that we will augment the
+ recursive behavior of \verb running with another behavior,
+ \verb acceleratedie which modifies increases the speed of the running
+ behavior, and stops the behavior after a certain number of iterations.
+ Note that recursive hooks take data in via their \textbf{external input}
+ port, and \textbf{not} their recursive port.
+
+ Finally, we state that this behavior will indeed be rendered directly to
+ the screen. We also specify which PixelMapper we want to use.
+
+ Phew. This isn't as complicated as it sounds. I promise.
+
+ \end{document}
diff --git a/docs/designDocs.tex b/docs/tex/ClassOverview.tex
index 8e62edc..00d55ec 100644
--- a/docs/designDocs.tex
+++ b/docs/tex/ClassOverview.tex
@@ -56,8 +56,7 @@
be named classname.params and look like a python dict
(\texttt{\{'key':value, 'key2':value2\}} )
\end{itemize}
- Note that at this point, the only class using this functionality
- is the PixelEvent class.}
+ }
{No required parameters in argDict}
\classDoc{PixelAssembler}{SmootCoreObject}{LineLayout, ZigzagLayout}{
PixelAssembler is a class that defines the positions of lights. It
@@ -103,17 +102,11 @@
\classDoc{Behavior}{SmootCoreObject}{EchoBehavior, DebugBehavior}{
Abstract class for a behavior. On every time step, the behavior is passed the
inputs from all sensors it is bound to as well as any recursive inputs that it
-spawned during the last time step. Inheriting classes MUST define
-\texttt{processBehavior}. \texttt{processBehavior} should return a list of dictionaries which
-define the properties of the light response. The must return a location
-\texttt{PixelEvent} class. Soon be be deprecated:\textit{They must give a location and
-color. They may define a function pointer which defines a custom mapping.
-[More on this later. Bug Russell if you want to do it].}
-Call \texttt{recursiveResponse} to queue a input on the next iteration with a dictionary
-argument. This will be passed in via recursive inputs.}
+spawned during the last time step. Inheriting classes MUST define \texttt{processResponse}. Look
+at the Behaviors documentation for more details.}
{\begin{itemize}
\item \texttt{Inputs}: A list of input Ids specifying input to the
- behavior. In the future, this may also contain behavior ids.
+ behavior.
\end{itemize}}
\classDoc{PixelEvent}{SmootCoreObject}{StepResponse}{
Abstract class defining the behavior of a light after it has been turned on.
@@ -155,6 +148,7 @@ argument. This will be passed in via recursive inputs.}
directly, unless you really know what you're doing. Well, actually you
should never need to do that.
never. Don't do it.}{Takes a \texttt{LayoutBuilder} as an argument.}
+ \end{itemize}
\section{Best Practices}
\subsection{Variable and function naming}
I'm pretty bad about being consistent. However, in all future
diff --git a/ga b/ga
index 7bed4ad..4ec4cc4 100755
--- a/ga
+++ b/ga
@@ -1 +1,2 @@
git add *.py */*.py *.xml */*.xml tests/*.py tests/testdata/*
+git add docs/*.tex docs/*.pdf docs/*/*.tex docs/*/*.pdf
diff --git a/layouts/SpecifiedLayout.py b/layouts/SpecifiedLayout.py
new file mode 100644
index 0000000..5a6e963
--- /dev/null
+++ b/layouts/SpecifiedLayout.py
@@ -0,0 +1,21 @@
+from operationscore.PixelAssembler import *
+class SpecifiedLayout(PixelAssembler):
+ """SpecifiedLayout is a class that allows precise specification of each individual LED.
+ Configure with a <Locations> tag in the args dict as follows':
+ <Args>
+ <Locations>
+ <Loc>(1,1)</Loc>
+ <Loc>(50,50)</Loc>
+ </Locations>
+ etc.
+ </Args>
+ You may put attributes on the Locs so that you don't get confused.
+ """
+
+ def layoutInit(self):
+ self.lightNum = -1
+
+ def layoutFunc(self, lastLocation):
+ self.lightNum += 1
+ return self['Locations'][self.lightNum]
+
diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py
index 7090a23..507f750 100644
--- a/operationscore/Behavior.py
+++ b/operationscore/Behavior.py
@@ -12,6 +12,7 @@ class Behavior(SmootCoreObject):
specifically designed to do this (like AddPixelEvent).
timeStep is called on every iteration of the LightInstallation
addInput is called on each individual input received, and the inputs queue"""
+
def init(self):
self.validateArgs('Behavior.params')
if type(self['Inputs']) != type([]):
@@ -21,34 +22,55 @@ class Behavior(SmootCoreObject):
self.outGoingQueue = []
self.lastState = None
self.behaviorInit()
+
def behaviorInit(self):
pass
+
def addMapper(fn):
def withmap(fn):
return self.addMapperToResponse(fn())
return withmap
+
def processResponse(self, sensorInputs, recursiveInputs):
raise Exception('ProcessResponse not defined!')
+
def addInput(self, sensorInput):
self.sensorResponseQueue.append(sensorInput)
+
#used for behavior chaining
+
def immediateProcessInput(self, sensorInputs, recursiveInputs=[]):
(outputs,recursions) = self.processResponse(sensorInputs, \
recursiveInputs)
return self.addMapperToResponse((outputs,recursions))
+
def addInputs(self, sensorInputs):
if type(sensorInputs) == type([]):
[self.addInput(sensorInput) for sensorInput in sensorInputs]
else:
self.addInput(sensorInputs)
- #private
+
+ @staticmethod
+ def deepCopyPacket(datapacket):
+ """Returns a deep copy of a behavior data packet (a list of dicts) so that modifying the
+ returned packet will not modify the incoming packet."""
+ ret = []
+ for d in datapacket:
+ d = dict(d)
+ ret.append(d)
+ return ret
+
def getLastOutput(self):
return self.lastState
+
def setLastOutput(self, output):
"""Override to modify state. For example: if you are using a behavior that does uses
strings for location specification, you will want to override this to point to a single
- location. Make sure you keep lastState as a [] of {}. (List of dicts)"""
- self.lastState = output
+ location. Make sure you keep lastState as a [] of {}. (List of dicts). Additonally,
+ ensure that you call Behavior.deepCopyPacket on the packet before hand to avoid inadvertent
+ down-stream modifications. Look at Square.py for an example of this."""
+ self.lastState = Behavior.deepCopyPacket(output)
+
def addMapperToResponse(self, responses):
if self['Mapper'] != None:
if type(responses) == type(tuple):
@@ -59,6 +81,7 @@ class Behavior(SmootCoreObject):
r['Mapper'] = self['Mapper']
return responses
return responses
+
def timeStep(self): #TODO: type checking. clean this up
(outputs, recursions) = self.processResponse(self.sensorResponseQueue, \
self.recursiveResponseQueue)
diff --git a/renderers/C5Renderer.xml b/renderers/C5Renderer.xml
new file mode 100644
index 0000000..d9fc9b0
--- /dev/null
+++ b/renderers/C5Renderer.xml
@@ -0,0 +1,10 @@
+<Renderer>
+ <Class>renderers.IndoorRenderer</Class>
+ <Args>
+ <Id>indoorRenderer</Id>
+ <PowerSupply>
+ <IP>10.32.97.17</IP>
+ <PortMapping>{'strip1':1}</PortMapping>
+ </PowerSupply>
+ </Args>
+</Renderer>
diff --git a/tests/TestBQS.py b/tests/TestBQS.py
index 7316c31..c46b917 100644
--- a/tests/TestBQS.py
+++ b/tests/TestBQS.py
@@ -13,13 +13,16 @@ class TestBQS(unittest.TestCase):
c.addInput({'Location':(5,12)})
b.timeStep()
c.timeStep()
+
def tearDown(self):
bqs.initBQS()
+
def test_simple_query(self):
validQuery = lambda args:args['Color']==(255,0,0)
invalidQuery = lambda args:args['Color']==(254,0,0)
assert bqs.query(validQuery) == [{'Color':(255,0,0), 'Location':(3,4)}]
assert bqs.query(invalidQuery) == []
+
def test_dist_query(self):
validDist = lambda args:geo.dist(args['Location'], (0,0)) <= 5
invalidDist = lambda args:geo.dist(args['Location'], (0,0)) <= 2
@@ -30,7 +33,6 @@ class TestBQS(unittest.TestCase):
assert bqs.query(doubleDist) == [{'Color':(255,0,0), 'Location':(3,4)}, {'Color':(0,0,255),\
'Location':(5,12)}]
def test_complex_queries(self):
-
validQuery = lambda args:args['Color']==(255,0,0)
doubleDist = lambda args:geo.dist(args['Location'], (0,0)) <= 20
diff --git a/util/BehaviorQuerySystem.py b/util/BehaviorQuerySystem.py
index 643b95c..688eecb 100644
--- a/util/BehaviorQuerySystem.py
+++ b/util/BehaviorQuerySystem.py
@@ -7,6 +7,7 @@ def initBQS():
initialized = True
def addBehavior(behavior):
+ """Add a behavior to the behavior registry."""
behaviorList.append(behavior)
def query(predicateList):
@@ -36,4 +37,11 @@ def query(predicateList):
ret.append(output)
return ret
+def getDistLambda(loc, maxDist):
+ """Returns a lambda function that checks if for behaviors within maxDist of loc. Can be passed
+ in as an arg to query."""
+ return lambda args:geo.dist(args['Location'], loc) <= maxDist
+def getBehaviorsNear(loc, maxdist):
+ """A premade method to do the common task of finding behavior near a location."""
+ return query(getDistLambda(loc, maxDist))