|
1 | 1 | # Close-Loop Systems |
2 | 2 |
|
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). |
4 | 8 |
|
5 | 9 | ## Close-loop latency |
6 | 10 | 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. |
7 | 11 |
|
8 | 12 | 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. |
9 | 13 |
|
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. |
13 | 15 |
|
14 | 16 | :::workflow |
15 | 17 |  |
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 | +{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 | + |
| 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 --> |
0 commit comments