Skip to content

Commit 6009ad6

Browse files
Add 1st exercise on serial port close-loop
Co-authored-by: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
1 parent 0181ae7 commit 6009ad6

3 files changed

Lines changed: 283 additions & 5 deletions

File tree

tutorials/hobgoblin-closeloop.md

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,77 @@
11
# Close-Loop Systems
22

3-
The exercises below will help you become familiar with using the [Harp Hobgoblin](https://github.com/harp-tech/device.hobgoblin) device for close-loop experiments. You will also learn how to use the [Harp Hobgoblin](https://github.com/harp-tech/device.hobgoblin) to interface with external cameras. Before you begin, it is recommended that you review the Bonsai [Acquisition and Tracking](https://bonsai-rx.org/docs/tutorials/acquisition.html) tutorial, which covers key video concepts.
3+
The exercises below will help you become familiar with using the [Harp Hobgoblin](https://github.com/harp-tech/device.hobgoblin) device for close-loop experiments. You will also learn how to use the `Hobgoblin` to interface with external cameras. Before you begin, it is recommended that you review the Bonsai [Acquisition and Tracking](https://bonsai-rx.org/docs/tutorials/acquisition.html) tutorial, which covers key video concepts.
4+
5+
## Prerequisites
6+
7+
- Install the `Bonsai.Dsp` package from the [Bonsai package manager](https://bonsai-rx.org/docs/articles/packages.html).
48

59
## Close-loop latency
610
In a closed-loop experiment, we want the behaviour data to generate feedback in real-time into the external world, establishing a relationship where the output of the system depends on detected sensory input. Many behavioural experiments in neuroscience require some kind of closed-loop interaction between the subject and the experimental setup.
711

812
One of the most important benchmarks to evaluate the performance of a closed-loop system is the latency, or the time it takes for a change in the output to be generated in response to a change in the input. The easiest way to measure the latency of a closed-loop system is to use a digital feedback test.
913

10-
In this test, we measure a binary output from the closed-loop system and feed it directly into the input sensor. We then record a series of measurements where we change the output to `HIGH` if the sensor detects `LOW`, and change it to `LOW` if the sensor detects `HIGH`. The time interval between `HIGH` and `LOW` signals will give us the total closed-loop latency of the system, also known as the round-trip time.
11-
12-
Before begining, set up the `Hobgoblin` with the following `device pattern` that we learned about in the previous tutorial.
14+
Before beginning, set up the `Hobgoblin` with the following `device pattern` that we learned about in the previous tutorial.
1315

1416
:::workflow
1517
![Hobgoblin Device Pattern](../workflows/hobgoblin-closeloop-devicepattern.bonsai)
16-
:::
18+
:::
19+
20+
- Set the `DumpRegisters` property in the `Hobgoblin` [`Device`] operator to `False`. This is to avoid triggering the command loop in the next exercise.
21+
22+
![Hobgoblin LED](../images/hobgoblin-acquisition-led.svg){width=400px}
23+
24+
- Connect one of the LED modules to digital output channel `GP15` on the `Hobgoblin`.
25+
26+
### Exercise 1: Measuring serial port communication latency
27+
28+
We will take advantage of the device's ability to echo back a timestamped message upon command execution to create a simple loop where each echo re-triggers the same command (toggling the digital output channel `HIGH` and `LOW`). The time interval between the echoes will give us the total closed-loop latency of the system, also known as the round-trip time.
29+
30+
:::workflow
31+
![Hobgoblin Closed-Loop Latency](../workflows/hobgoblin-closeloop-latency.bonsai)
32+
:::
33+
34+
- Insert a [`SubscribeSubject`] operator and configure the `Name` property to `Hobgoblin Events`.
35+
- Insert a [`Parse`] operator and select [`TimestampedDigitalOutputTogglePayload`] from the `Register` property dropdown menu.
36+
- Insert a [`CreateMessage`] operator, select [`DigitalOutputTogglePayload`] for the `Payload`, and `GP15` for the [`DigitalOutputToggle`] property.
37+
- Insert a [`MulticastSubject`] operator and configure the `Name` property to `Hobgoblin Commands`.
38+
39+
In order to measure the difference between the timestamps:
40+
41+
- Right-click on the [`Parse`] operator, select the `Output (Bonsai.Harp.Timestamped<Harp.Hobgoblin.DigitalOutputs>)` > `Seconds`.
42+
- Disconnect the `Seconds` node from the [`CreateMessage`] operator.
43+
- Reconnect the [`Parse`] and [`CreateMessage`] operator.
44+
- After the `Seconds` node, insert a [`Difference`] operator from the `Bonsai.Dsp` package.
45+
46+
Lastly, we will use this sequence to initialize the command loop:
47+
48+
- Insert a [`KeyDown`] operator and set the `Filter` property to the key `A`.
49+
- Insert a [`Parse`] operator and select [`DigitalOutputTogglePayload`] from the `Register` property dropdown menu. Set the `DigitalOutputToggle` property to `GP15`
50+
- Insert a [`MulticastSubject`] operator and configure the `Name` property to `Hobgoblin Commands`.
51+
- Run the workflow, and open the visualizer for the [`Difference`] operator.
52+
**What do you observe?**
53+
54+
<!--Reference Style Links -->
55+
[`CreateMessage`]: xref:Harp.Hobgoblin.CreateMessage
56+
[`Device`]: xref:Harp.Hobgoblin.Device
57+
[`Difference`]: xref:Bonsai.Dsp.Difference
58+
[`DigitalOutputToggle`]: xref:Harp.Hobgoblin.DigitalOutputToggle
59+
[`DigitalOutputTogglePayload`]: xref:Harp.Hobgoblin.CreateDigitalOutputTogglePayload
60+
<!-- [`DeviceDataWriter`]: xref:Harp.Hobgoblin.DeviceDataWriter -->
61+
<!-- [`DigitalOutputSet`]: xref:Harp.Hobgoblin.DigitalOutputSet -->
62+
<!-- [`DigitalOutputClear`]: xref:Harp.Hobgoblin.DigitalOutputClear -->
63+
<!-- [`DigitalOutputClearPayload`]: xref:Harp.Hobgoblin.CreateDigitalOutputSetPayload -->
64+
<!-- [`DigitalOutputSetPayload`]: xref:Harp.Hobgoblin.CreateDigitalOutputClearPayload -->
65+
<!-- [`HarpMessage`]: xref:Bonsai.Harp.HarpMessage -->
66+
[`KeyDown`]: xref:Bonsai.Windows.Input.KeyDown
67+
<!-- [`Merge`]: xref:Bonsai.Reactive.Merge -->
68+
[`MulticastSubject`]: xref:Bonsai.Expressions.MulticastSubject
69+
[`Parse`]: xref:Harp.Hobgoblin.Parse
70+
<!-- [`PublishSubject`]: xref:Bonsai.Reactive.PublishSubject -->
71+
<!-- [`RollingGraph`]: xref:Bonsai.Gui.ZedGraph.RollingGraphBuilder -->
72+
[`SubscribeSubject`]: xref:Bonsai.Expressions.SubscribeSubject
73+
<!-- [`TimestampedAnalogData`]: xref:Harp.Hobgoblin.TimestampedAnalogData -->
74+
[`TimestampedDigitalOutputTogglePayload`]: xref:Harp.Hobgoblin.TimestampedDigitalOutputToggle
75+
<!-- [`TimestampedDigitalOutputSet`]: xref:Harp.Hobgoblin.TimestampedDigitalOutputSet -->
76+
<!-- [`TimestampedDigitalOutputClear`]: xref:Harp.Hobgoblin.TimestampedDigitalOutputClear -->
77+
<!-- [`Zip`]: xref:Bonsai.Reactive.Zip -->
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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:dsp="clr-namespace:Bonsai.Dsp;assembly=Bonsai.Dsp"
7+
xmlns:wie="clr-namespace:Bonsai.Windows.Input;assembly=Bonsai.Windows.Input"
8+
xmlns="https://bonsai-rx.org/2018/workflow">
9+
<Workflow>
10+
<Nodes>
11+
<Expression xsi:type="SubscribeSubject">
12+
<Name>Hobgoblin Events</Name>
13+
</Expression>
14+
<Expression xsi:type="p1:Parse">
15+
<harp:Register xsi:type="p1:TimestampedDigitalOutputToggle" />
16+
</Expression>
17+
<Expression xsi:type="p1:CreateMessage">
18+
<harp:MessageType>Write</harp:MessageType>
19+
<harp:Payload xsi:type="p1:CreateDigitalOutputTogglePayload">
20+
<p1:DigitalOutputToggle>GP15</p1:DigitalOutputToggle>
21+
</harp:Payload>
22+
</Expression>
23+
<Expression xsi:type="MulticastSubject">
24+
<Name>Hobgoblin Commands</Name>
25+
</Expression>
26+
<Expression xsi:type="MemberSelector">
27+
<Selector>Seconds</Selector>
28+
</Expression>
29+
<Expression xsi:type="Combinator">
30+
<Combinator xsi:type="dsp:Difference">
31+
<dsp:Order>1</dsp:Order>
32+
</Combinator>
33+
</Expression>
34+
<Expression xsi:type="Combinator">
35+
<Combinator xsi:type="wie:KeyDown">
36+
<wie:Filter>A</wie:Filter>
37+
<wie:SuppressRepetitions>false</wie:SuppressRepetitions>
38+
</Combinator>
39+
</Expression>
40+
<Expression xsi:type="p1:CreateMessage">
41+
<harp:MessageType>Write</harp:MessageType>
42+
<harp:Payload xsi:type="p1:CreateDigitalOutputTogglePayload">
43+
<p1:DigitalOutputToggle>GP15</p1:DigitalOutputToggle>
44+
</harp:Payload>
45+
</Expression>
46+
<Expression xsi:type="MulticastSubject">
47+
<Name>Hobgoblin Commands</Name>
48+
</Expression>
49+
</Nodes>
50+
<Edges>
51+
<Edge From="0" To="1" Label="Source1" />
52+
<Edge From="1" To="2" Label="Source1" />
53+
<Edge From="1" To="4" Label="Source1" />
54+
<Edge From="2" To="3" Label="Source1" />
55+
<Edge From="4" To="5" Label="Source1" />
56+
<Edge From="6" To="7" Label="Source1" />
57+
<Edge From="7" To="8" Label="Source1" />
58+
</Edges>
59+
</Workflow>
60+
</WorkflowBuilder>

0 commit comments

Comments
 (0)