-
Notifications
You must be signed in to change notification settings - Fork 1
Automation
In certain cases an action or a series of actions might be required whenever a condition or a certain command occurs, which would result in a lot of micromanagement if handled by the server. In those cases the firmware allows for a limited amount of automation in one of two forms:
- Macro: define a state consisting of several commands. All commands get executed whenver the state is activated.
- Events: wait for a predifined condition to occur and execute a single command whenever it does.
Using this basic principles, most simple and common automation usecases are covered. Below are 3 examples showing how to approach using either events, macros or a combination of both.
Whenever several actuators work together to achieve a certain state of the experiment, macros are the way to go. Imagine the following situation:
- An experiment can be used with 3 different light sources that need to be placed into the beam path
- 2 of these are simple LEDs
- the third is a broad band light source that can be used with or without a filter
- light sources are placed by a single servo rotating into the corresponding angle
- filter is placed by a second servo
- servos should not move simultaneously to avoid blocking each other
This results in 6 states the experiment can be in, of which only 4 are useful:
| state name | light source | filter |
|---|---|---|
| unfiltered | broad band | No |
| filtered | broad band | Yes |
| red led | LED1 | No |
| blue led | LED2 | No |
Additionally, the servo position of the light sources (servo1) and the filter (servo2) were measured to the following:
| state name | servo1 position | servo2 position |
|---|---|---|
| unfiltered | 0 | 0 |
| filtered | 0 | 90 |
| red led | 30 | 0 |
| blue led | 60 | 0 |
Now that all necessary information are gathered and we can define a macro module named lightSource containing 4 states, one for each experimental state. For each state 4 commands are needed to achieve the positions defined above. All states only differ by the servo position, here by the example of the first state "unfiltered":
| controlId | control key | control value | purpose |
|---|---|---|---|
| servo1 | moveTo | 0 | bring broad band light source in position |
| lightSource | complete | 15000 | wait for servo, 15 s timeout |
| servo2 | moveTo | 0 | remove filter |
| lightSource | complete | 5000 | wait for servo, 5 s timeout |
Note that after each movement command the macro module instructs itself to wait for the completion of the last command, i.e. it will wait for the last controlId to give a ready signal either by internal events or by emitting a status (the servos do not need to be located on the same hardware). This effectively avoids moving both servos simultaneously. It also means the macro module will only report back to the server with its final state once all motors finished moving.
Whenever an action like actuator movements or even just status updates are required on a specific condition like connection or input state of the ESP32, events should be used. Here, we will use a simple button to demonstrate the principle:
- the voltage on a button is monitored by a module
input - once the button is pushed, the voltage rises considerably
- current state of the button should be relayed to the server robustly
- state of the button should either be
loworhigh
First, input needs to be configured with suitable thresholds. The lower voltage treshold should be low enough to reliably detect the button push, while high enough to avoid noise triggering it. Same applies to the upper treshold with the added condition that there should be enough distance between lower and upper treshold to avoid jumping from low to high frequently (robust against noise). The following configuration was tested and determined to work:
| setting | value | comment |
|---|---|---|
| averageTime | 500 | avoid excessive noise |
| rangeChecking | true | enable thresholds |
| deadMicroSeconds | 10000 | 10 ms, avoiding noise |
| loBound | 500 | 0.5 V, fictitious |
| hiBound | 1500 | 1.5 V, fictitious |
| isBinary | true | only trigger if changes from one to the other bound occur |
With these settings, the module will only issue an internal event if the voltage changes from low to high or vice versa, suitable events we can now react on. We define 2 event hooks, one for each state of the the button:
| listeningId | event type | controlId | control key | control value |
|---|---|---|---|---|
| input | 10 | input | getStatus | true |
| input | 11 | input | getStatus | true |
Now the input module will be instructed to report its status to the server whenever the state changes -- effectively mirroring the button state to the server.
In some situations it is advisable to mix events and macros to reach a goal. This is for example advantageous if a condition requires more than a single command (although this can also be achieved by multiple event hooks) and mandatory if a waiting period is required.