# Running a real-time experiment

You can open a real-time connection to a chamber and use it to send instructions and collect data. This is particularly suited for situations that require interaction, e.g., to test active learning, experiment design, or control algorithms—learn more in our [case studies](https://app.gitbook.com/o/WlGCd39uI1U9EW8METkZ/s/LGlWOZRUBOtN2PzbIhYS/).

### Basic workflow

You can find a [complete example](#a-complete-example) below.

{% stepper %}
{% step %}

#### Open a real-time connection to a chamber

Begin by opening a connection to a chamber—specified by its `chamber_id`—and loading a hardware [configuration](https://docs.causalchamber.ai/the-chambers/how-they-work#hardware-configurations) (given by `config`). The chamber will reset and set all inputs and sensor parameters to their [default values](https://docs.causalchamber.ai/the-chambers/how-they-work#hardware-configurations).

{% tabs %}
{% tab title="Credentials file" %}
If you stored your credentials in a [file](https://docs.causalchamber.ai/quickstart#set-up-your-credentials)

```python
import causalchamber.lab as lab

chamber = lab.Chamber(chamber_id, config, credentials_file = 'path/to/file')
```

{% endtab %}

{% tab title="Environment variables" %}
If you stored your credentials in environment variables, e.g., `USER` and `KEY`

```python
import os
import causalchamber.lab as lab

rlab = lab.Lab(credentials=(os.getenv('USER'), os.getenv('KEY')))
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

#### Send instructions and receive data

You can now send instructions to the chamber and receive data in real time. There are three types of [instructions](https://docs.causalchamber.ai/the-chambers/how-they-work#chamber-control-language).

{% tabs %}
{% tab title="SET instruction" %}
{% code fullWidth="true" %}

```python
chamber.set(target, value)
```

{% endcode %}

This sets the variable `target` to the given `value`, returning when the change has been made in the hardware. The above call returns `None`.

See the [configuration docs](https://docs.causalchamber.ai/the-chambers/how-they-work) for a list of variables and their valid / default values.
{% endtab %}

{% tab title="MEASURE instruction" %}

```python
data = chamber.measure(n, delay)
```

The chamber returns `n` successive measurements of all variables, including images if it produces them. Setting `delay` (in milliseconds) adds an additional delay between measurements, i.e., allowing you to change the measurement frequency.

If the chamber produces images, `data = (dataframe, images)` is a tuple of a pandas dataframe and an image array; otherwise it is just a pandas dataframe. See the [API Reference](https://docs.causalchamber.ai/remote-lab/broken-reference) for more details.
{% endtab %}

{% tab title="WAIT instruction" %}

```python
chamber.wait(milliseconds)
```

The chamber acts as a precise clock and waits the given `milliseconds` before executing the next instruction.
{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

{% hint style="info" %}
To ensure experimental consistency, the chamber accepts only one active connection at a time; starting a new connection will invalidate the previous one. For long-running experiments and multiple users, we recommend using the [experiment queue](https://docs.causalchamber.ai/remote-lab/using-the-experiment-queue).
{% endhint %}

### A complete example

Let's connect to a [Light Tunnel Mk2](https://docs.causalchamber.ai/the-chambers/light-tunnel-mk2) and collect images in real time.

```python
import causalchamber.lab as lab

# Open a real-time connection
chamber = lab.Chamber(chamber_id = 'lt-demo-ch4lu',
                      config = 'camera_fast',
                      credentials_file = '.credentials')

# Turn on the light source to red and take one image
chamber.set('red', 255)
df, images = chamber.measure(n=1)
```

The returned data consists of two parts: `df` is a dataframe containing the sensor measurements, and `images` an array with the collected images (only one in this case).

Let's have a look at the resulting image.

```python
# Plot the image
import matplotlib.pyplot as plt
plt.imshow(images[0])
```

<div data-with-frame="true"><figure><img src="https://3492874807-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUqYDL9yvLTNUYW7H1Q6t%2Fuploads%2FeBWEvJkbr2MDg8Ytcoer%2Fpackage_rt_sample_image.png?alt=media&#x26;token=41f5e8d3-767b-4f10-b44b-c053705729a0" alt="" width="332"><figcaption></figcaption></figure></div>

### Submitting multiple instructions at once

You can submit multiple instructions in a single batch. This saves you the round-trip to the chamber for each instruction and ensures consistent timing between instructions.

The data produced during the execution of the batch will be returned in `batch.submit()`.

```python
# Start a new batch
batch = chamber.new_batch()

# Add instructions
batch.set('red', 128)
batch.measure(n=1) # Image 1: red
batch.set('blue', 128)
batch.measure(n=1) # Image 2: purple
batch.set('pol_1', 90)
batch.measure(n=1) # Image 3: purple + crossed polarizers

# Submit the batch and receive the data
df, images = batch.submit()
```

To plot the resulting images:

<pre class="language-python"><code class="lang-python"><strong># Plot the images
</strong>plt.figure(figsize=(9,3))
for i,im in enumerate(images):
    plt.subplot(1,3,i+1)
    plt.imshow(im)
</code></pre>

<figure><img src="https://3492874807-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUqYDL9yvLTNUYW7H1Q6t%2Fuploads%2Fjbc90DGB5gSnjijDfZyL%2Fpackage_rt_sample_images.png?alt=media&#x26;token=cda6d748-380c-4322-91e7-200b234188b3" alt=""><figcaption></figcaption></figure>
