|
|
The `SensorManager` component manages all the sensors connected to the board.
|
|
|
Periodically, sensors are sampled and their corresponding callback is called, so that further operations can be performed on the retrieved data.
|
|
|
|
|
|
Sensors are periodically sampled and their corresponding callback is called, so that further operations can be performed on the retrieved data.
|
|
|
|
|
|
# Main Components
|
|
|
|
|
|
## Sensor
|
|
|
### Sensor
|
|
|
|
|
|
The `Sensor.h` header file contains the base classes that every new sensor in the system must inherit from it.
|
|
|
The `Sensor.h` header file contains the base classes used to define sensors: every new sensor must inherit from one of them.
|
|
|
|
|
|
`Sensor` is the top-level virtual class.
|
|
|
Sub-classes are provided for different types of sensors, e.g. `GyroSensor`, `AccelSensor`, `PressureSensor` and some others.
|
|
|
Since these classes are a bit limited, you can always directly extend `Sensor`, defining your own data structures to store sensor's samples and methods to read them.
|
|
|
|
|
|
Each `Sensor` object has to override some methods:
|
|
|
* `init()`: this is the first method to be called before using the sensor. It sets up the sensor, e.g. registers.
|
... | ... | @@ -14,21 +19,22 @@ Each `Sensor` object has to override some methods: |
|
|
* `selfTest()`: check if the sensor is correctly working.
|
|
|
All these methods return a boolean value indicating whether the operation succeded or not.
|
|
|
|
|
|
The `getLastError()` method can be useful to get the last error generated by the sensor driver.
|
|
|
|
|
|
Subclasses are provided for different types of sensors, e.g. `GyroSensor`, `AccelSensor`, `PressureSensor` and some others.
|
|
|
Since these classes are a bit limited, you can always directly extend `Sensor`, defining your own data structures to store data sampled from the sensor and methods to read them.
|
|
|
The `getLastError()` method can be useful to get the last error generated by the sensor driver.
|
|
|
|
|
|
## Sensor Sampler
|
|
|
### Sensor Sampler
|
|
|
|
|
|
Sensors are grouped by type (simple or DMA) and the required sampling frequency.
|
|
|
Sensors are grouped according to the required sampling frequency and to the fact that they use DMA or not.
|
|
|
|
|
|
A `SensorSampler` is characterized by a type (`SIMPLE_SAMPLER` or `DMA_SAMPLER`), the sampling frequency and a set of sensors.
|
|
|
|
|
|
In particular, the `SensorSampler` class maintains a `map<Sensor*, function<void()>>` that maps each sensor to its corresponding callback function.
|
|
|
Every time the `sampleAndCallback()` method of the `SensorSampler` is called, the sampler cycles through all its sensors, samples them and calls their corresponding callback, where these samples can be processed and dispatched.
|
|
|
Every time the `sampleAndCallback()` method of the `SensorSampler` is called, the sampler cycles through all its sensors, samples them and calls their corresponding callback, where these samples can be processed and dispatched.
|
|
|
|
|
|
Since `SensorSampler` is a virtual class, two sub-classes exist:
|
|
|
* `SimpleSensorSampler`: its type is `SIMPLE_SAMPLER`. In order to perform a sampling it calls the sensor's `onSimpleUpdate()` method.
|
|
|
* `DMASensorSampler`: its type is `DMA_SAMPLER`. It only manages sensors that use DMA. In order to perform a sampling it calls the sensor's `onDMAUpdate()` method.
|
|
|
|
|
|
## Sensor Manager
|
|
|
### Sensor Manager
|
|
|
In order to add a sensor to the `SensorManager`, the `addSensor()` method is provided: simply pass it the sensor, the required sampling frequency, the callback function and the sampler type (that has default value equal to `SIMPLE_SAMPLER`).
|
|
|
|
|
|
Every time a sensor is added, the `SensorManager` assigns it to a `SensorSampler`, according to the required sampling frequency and the sampling type.
|
... | ... | @@ -39,12 +45,20 @@ The sensor will be added only if both the initialization and the test succeed. |
|
|
|
|
|
When `start()` is called, the `SensorManager` initializes the `TaskScheduler`: for each `SensorSampler`, it adds to the scheduler the `sampleAndCallback()` method to be called periodically according to the sampler's frequency.
|
|
|
|
|
|
# Overall Behavior
|
|
|
It might seem tricky and complex, so in order to simplify the understanding we can schematize the component's behavior.
|
|
|
|
|
|
We outline three phases:
|
|
|
1. In the first phase sensors are added to the `SensorManager`, that assigns them to the correct `SensorSampler`, along with the corresponding callback.
|
|
|
2. When the `SensorManager` is started, for each sampler it schedules a periodic task, according to the required frequency.
|
|
|
3. From that point on, the `TaskScheduler` periodically calls the `SensorSampler` objects. When called, each sampler performs the sampling of all the sensors it manages and for each of them calls the associated callback.
|
|
|
|
|
|
## Component Structure
|
|
|
# Module Structure
|
|
|
For simplicity, each arrow in the diagram describes an action and reports the phase number that action belongs to (according to the above defined phases).
|
|
|
|
|
|

|
|
|

|
|
|
|
|
|
## Example
|
|
|
# Example
|
|
|
### Step 1: Creating a sensor
|
|
|
```cpp
|
|
|
#include <cmath>
|
... | ... | @@ -88,7 +102,7 @@ class TestSensor : public virtual Sensor |
|
|
// define methods to get the sampled data
|
|
|
float getData()
|
|
|
{
|
|
|
return &sample;
|
|
|
return sample;
|
|
|
}
|
|
|
|
|
|
private:
|
... | ... | |