Skip to content

Commit c3dfbd6

Browse files
committed
Add 5th exercise on timeout and choice
1 parent 7a49752 commit c3dfbd6

3 files changed

Lines changed: 226 additions & 13 deletions

File tree

tutorials/hobgoblin-reaction.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ Next, we will set up our `Hobgoblin`.
3737
- Insert a [`Device`] operator and set the `PortName` property.
3838
- Insert a [`DeviceDataWriter`] and set the `Path` property. Connecting it directly to the device ensures thats all events are logged.
3939
- During this tutorial we will need to have the ability to send/receive commands from distinct places in the workflow. To allow this kind of "many-to-one"/"one-to-many" communication, we will:
40-
- Insert a [`PublishSubject`] operator and name it `Hobgoblin Events`. This operator broadcasts events from the `Hobgoblin`, which you can receive at multiple points in the workflow using a [SubscribeSubject].
41-
- Right-click the [`Device`] operator, select `Create Source (Bonsai.Harp.HarpMessage)` > [`BehaviorSubject`]. Name the generated ``BehaviourSubject`1`` operator `Hobgoblin Commands`. Connect it as input to the [`Device`] operator.
40+
- Insert a [`PublishSubject`] operator and name it `Hobgoblin Events`. This operator broadcasts events from the `Hobgoblin`, which you can receive at multiple points in the workflow using a [`SubscribeSubject`].
41+
- Right-click the [`Device`] operator, select `Create Source (Bonsai.Harp.HarpMessage)` > [`BehaviorSubject`]. Name the generated ``BehaviourSubject`1`` operator `Hobgoblin Commands`. Connect it as input to the [`Device`] operator.
4242

4343
>[!NOTE]
4444
> A [source subject](https://bonsai-rx.org/docs/articles/subjects.html#source-subjects) is an operator that is set up to receive commands from multiple places in the workflow and pass them on to the `Hobgoblin`. When choosing a type for the `source subject`, choosing a [`BehaviorSubject`] instead of a [`PublishSubject`] ensures that the connection remains open until the workflow is stopped.
@@ -138,7 +138,7 @@ In order to translate our simple reaction time task in the previous exercises in
138138
- Right-click, select `Group` > `Sink (Reactive)`. Set the `Name` property to `StimOff`.
139139

140140
> [!Note]
141-
> The [`Sink`] operator allows you to specify arbitrary processing side-effects without affecting the original flow of events. It is often used to trigger and control stimulus presentation in response to events in the task. Inside the nested specification, `Source1` represents input events arriving at the sink. In the specific case of `Sink` operators, the `WorkflowOutput` node can be safely ignored.
141+
> The [`Sink`] operator allows you to specify arbitrary processing side-effects without affecting the original flow of events. It is often used to trigger and control stimulus presentation in response to events in the task. Inside the nested specification, `Source1` represents input events arriving at the sink. In the specific case of [`Sink`] operators, the `WorkflowOutput` node can be safely ignored.
142142
143143
- Delete the [`Delay`] operator.
144144
- Insert a [`SelectMany`] operator after `StimOn`, and set its `Name` property to `Response`.
@@ -158,12 +158,26 @@ In order to translate our simple reaction time task in the previous exercises in
158158
- Run the workflow a couple of times and validate the state machine is responding to the button press.
159159

160160
> [!Note]
161-
> [`DigitalInputState`] sends a [`HarpMessage`] when it detects a change on any of the digital input pins on the `Hobgoblin`. Using a [`Condition`] with a nested [`Equal`] operator allows us to filter only messages from that pin. It also has the nice effect of only detecting a button press (when the value goes fron `None` > `GP2`) instead of a button release (`GP2`>`None`).
161+
> The [`Condition`] operator allows you to specify arbitrary rules for accepting or rejecting inputs. Only inputs which pass the filter specified inside the [`Condition`] are allowed to proceed. Using an [`Equal`] operator allows us to filter only messages from that pin. It also has the beneficial side effect of only detecting a button press (when the value changes fron `None` > `GP2`) instead of a button release (`GP2`>`None`).
162+
163+
### Exercise 5: Timeout and choice
164+
165+
:::workflow
166+
![Stimulus presentation](../workflows/hobgoblin-reactiontime-stimulus-response-timeout.bonsai)
167+
:::
168+
169+
**`Response`**:
170+
- Inside the `Response` node, insert a [`Timer`] source and set its `DueTime` property to be about 1 second.
171+
- Insert a [`Boolean`] operator and set the `Value` property to `False`
172+
- Insert another [`Boolean`] operator after the [`Condition`] operator and set the `Value` property to `True`
173+
- Join both [`Boolean`] operators with a [`Merge`] combinator.
174+
- Run the workflow a couple of times, opening the visualizer of the `Response` node.
175+
176+
_Describe in your own words what the above modified workflow is doing._
162177

163178
<!--Reference Style Links -->
164-
<!-- [`AnalogData`]: xref:Harp.Hobgoblin.AnalogData -->
165-
<!-- [`AnalogDataPayload`]: xref:Harp.Hobgoblin.AnalogDataPayload -->
166179
[`BehaviorSubject`]: xref:Bonsai.Reactive.BehaviorSubject
180+
[`Boolean`]: xref:Bonsai.Expressions.BooleanProperty
167181
[`Condition`]: xref:Bonsai.Reactive.Condition
168182
[`CreateMessage`]: xref:Harp.Hobgoblin.CreateMessage
169183
[`Delay`]: xref:Bonsai.Reactive.Delay
@@ -176,20 +190,15 @@ In order to translate our simple reaction time task in the previous exercises in
176190
[`DigitalOutputClearPayload`]: xref:Harp.Hobgoblin.CreateDigitalOutputClearPayload
177191
[`Equal`]: xref:Bonsai.Expressions.EqualBuilder
178192
[`HarpMessage`]: xref:Bonsai.Harp.HarpMessage
179-
<!-- [`KeyDown`]: xref:Bonsai.Windows.Input.KeyDown -->
180-
<!-- [`Merge`]: xref:Bonsai.Reactive.Merge -->
193+
[`Merge`]: xref:Bonsai.Reactive.Merge
181194
[`MulticastSubject`]: xref:Bonsai.Expressions.MulticastSubject
182195
[`Parse`]: xref:Harp.Hobgoblin.Parse
183196
[`PublishSubject`]: xref:Bonsai.Reactive.PublishSubject
184-
[`SubscribeSubject`]: xref:Bonsai.Reactive.SubscribeSubject
185197
[`Repeat`]: xref:Bonsai.Reactive.Repeat
186198
[`SelectMany`]: xref:Bonsai.Reactive.SelectMany
187199
[`Sink`]: xref:Bonsai.Reactive.Sink
188200
[`SubscribeSubject`]: xref:Bonsai.Expressions.SubscribeSubject
189201
[`Take`]: xref:Bonsai.Reactive.Take
190202
[`Timer`]: xref:Bonsai.Reactive.Timer
191-
<!-- [`TimestampedAnalogData`]: xref:Harp.Hobgoblin.TimestampedAnalogData -->
192203
[`TimestampedDigitalOutputSet`]: xref:Harp.Hobgoblin.TimestampedDigitalOutputSet
193-
[`TimestampedDigitalInputState`]: xref:Harp.Hobgoblin.TimestampedDigitalInputState
194-
<!-- [`TimestampedDigitalOutputClear`]: xref:Harp.Hobgoblin.TimestampedDigitalOutputClear -->
195-
<!-- [`Zip`]: xref:Bonsai.Reactive.Zip -->
204+
[`TimestampedDigitalInputState`]: xref:Harp.Hobgoblin.TimestampedDigitalInputState
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<WorkflowBuilder Version="2.8.5"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:p1="clr-namespace:Harp.Hobgoblin;assembly=Harp.Hobgoblin"
5+
xmlns:harp="clr-namespace:Bonsai.Harp;assembly=Bonsai.Harp"
6+
xmlns:rx="clr-namespace:Bonsai.Reactive;assembly=Bonsai.Core"
7+
xmlns="https://bonsai-rx.org/2018/workflow">
8+
<Workflow>
9+
<Nodes>
10+
<Expression xsi:type="SubscribeSubject">
11+
<Name>Hobgoblin Events</Name>
12+
</Expression>
13+
<Expression xsi:type="p1:Parse">
14+
<harp:Register xsi:type="p1:DigitalInputState" />
15+
</Expression>
16+
<Expression xsi:type="rx:Condition">
17+
<Workflow>
18+
<Nodes>
19+
<Expression xsi:type="WorkflowInput">
20+
<Name>Source1</Name>
21+
</Expression>
22+
<Expression xsi:type="Equal">
23+
<Operand xsi:type="WorkflowProperty" TypeArguments="p1:DigitalInputs">
24+
<Value>GP2</Value>
25+
</Operand>
26+
</Expression>
27+
<Expression xsi:type="WorkflowOutput" />
28+
</Nodes>
29+
<Edges>
30+
<Edge From="0" To="1" Label="Source1" />
31+
<Edge From="1" To="2" Label="Source1" />
32+
</Edges>
33+
</Workflow>
34+
</Expression>
35+
<Expression xsi:type="Combinator">
36+
<Combinator xsi:type="BooleanProperty">
37+
<Value>true</Value>
38+
</Combinator>
39+
</Expression>
40+
<Expression xsi:type="Combinator">
41+
<Combinator xsi:type="rx:Timer">
42+
<rx:DueTime>PT1S</rx:DueTime>
43+
<rx:Period>PT0S</rx:Period>
44+
</Combinator>
45+
</Expression>
46+
<Expression xsi:type="Combinator">
47+
<Combinator xsi:type="BooleanProperty">
48+
<Value>false</Value>
49+
</Combinator>
50+
</Expression>
51+
<Expression xsi:type="Combinator">
52+
<Combinator xsi:type="rx:Merge" />
53+
</Expression>
54+
<Expression xsi:type="Combinator">
55+
<Combinator xsi:type="rx:Take">
56+
<rx:Count>1</rx:Count>
57+
</Combinator>
58+
</Expression>
59+
<Expression xsi:type="WorkflowOutput" />
60+
</Nodes>
61+
<Edges>
62+
<Edge From="0" To="1" Label="Source1" />
63+
<Edge From="1" To="2" Label="Source1" />
64+
<Edge From="2" To="3" Label="Source1" />
65+
<Edge From="3" To="6" Label="Source1" />
66+
<Edge From="4" To="5" Label="Source1" />
67+
<Edge From="5" To="6" Label="Source2" />
68+
<Edge From="6" To="7" Label="Source1" />
69+
<Edge From="7" To="8" Label="Source1" />
70+
</Edges>
71+
</Workflow>
72+
</WorkflowBuilder>

0 commit comments

Comments
 (0)