The SensorManager
component manages all the sensors connected to the board.
Sensors are periodically sampled and their corresponding callback is called, so that further operations can be performed on the retrieved data.
Main Elements
Sensor Info
The SensorInfo
structure defines an information set needed by the SensorManager
along with the sensor itself
It contains:
- The sampling period for the given sensor.
- A callback function to be called after the sensor is sampled.
- A boolean value indicating whether the sensor uses DMA or not.
- A boolean value indicating whether the sensor is enabled or not (i.e. the sensor has to be sampled or not).
- A boolean value indicating whether the sensor has been correctly initialized or not.
Sensor Sampler
Sensors are grouped according to the required sampling period and to the fact that they use DMA or not.
A SensorSampler
is characterized by the sampling period and a set of sensors.
In particular, the SensorSampler
class maintains a vector<pair<AbstractSensor*, SensorInfo>>
that maps each sensor to its corresponding information.
Every time the sampleAndCallback()
method of the SensorSampler
is called, the sampler cycles through all its sensors, samples them (the enabled ones) and calls their corresponding callback, where these samples can be processed and dispatched.
Since SensorSampler
is a virtual class, two sub-classes exist:
-
SimpleSensorSampler: for sensors that does not use DMA. In order to perform a sampling it calls the sensor's
sample()
method. -
DMASensorSampler: not implemented yet
Sensor Manager
In order to add sensors to the SensorManager
a map correlating each sensor to its SensorInfo
object has to be passed to the constructor.
When the SensorManager
is instantiated, each sensor is assigned to a SensorSampler
, according to the required sampling period and the sampling type (DMA or not).
If a SensorSampler
for that sampling period and type doesn't exist, the SensorManager
manages its creation.
Note that when a sensor is added to a sampler, it is also initialized (via init()
) and selfTest()
is performed.
The is_initialized
boolean in SensorInfo
is set to true
or false
according to the result of the init()
and selfTest()
. If a sensor fails to initialize, it will not be sampled.
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 period.
Samplers with lower period are added to the TaskScheduler
before the ones that have higher period (see TaskScheduler
's warning).
The SensorManager
also exposes method to enable/disable sensors at runtime, but the list of existing sensors in theSensorManager
can not be changed after its creation.
An externally created TaskScheduler
can be passed to theSensorManager
constructor. In this caseSensorSampler
will be added to the existing scheduler, instead of creating a new one, starting from the higher task ID existing.
Component 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:
- In the first phase sensors are added to the
SensorManager
, that assigns them to the correctSensorSampler
, along with the corresponding period, callback and booleans indicating if it is enabled or if it uses DMA. - When the
SensorManager
is started, for each sampler it schedules a periodic task, according to the required sampling period. - From that point on, the
TaskScheduler
periodically calls theSensorSampler
objects. When called, each sampler performs the sampling of all the enabled sensors it manages and for each of them calls the associated callback.
Example
Step 1: Creating a sensor
This example refers to the TestSensor
class defined in Sensor.h.
For more details see how to create a sensor, visit that page.
Step 2: Sampling the sensor
Define the callbacks that will be passed to the SensorSampler
, along with the sensors.
Inside the callback you can get the sampled data from the sensor and perform operations on it.
void testCallback1() {
float data = sensor1.getLastSample().value;
printf("Test data 1: %f \n", data);
}
void testCallback2() {
float data = sensor2.getLastSample().value;
printf("Test data 2: %f \n", data);
}
You can use std::bind()
in order to bind your callback to an std::function<void()>>
object.
Select the required period for the sampling and create a map that associates each sensor to its SensorInfo
.
You can now create and start the SensorManager
.
#include <miosix.h>
#include <sensors/SensorManager.h>
#include "TestSensor.h"
int main() {
TestSensor sensor1;
uint32_t period1 = 1000; // 1 Hz
std::function<void()> callback1 = std::bind(&testCallback1);
SensorInfo info1(/*Period=*/period1, /*Callback=*/callback1, /*DMA=*/false, /*Enabled=*/true);
TestSensor sensor2;
uint32_t period2 = 500; // 2 Hz
std::function<void()> callback2 = std::bind(&testCallback2);
SensorInfo info2(/*Period=*/period2, /*Callback=*/callback2, /*DMA=*/false, /*Enabled=*/true);
std::map<AbstractSensor*, SensorInfo> sensors_map = {
{ &sensor1, info1 },
{ &sensor2, info2 }
};
SensorManager SM(sensors_map);
sensor_manager.start();
for (;;)
{
}
}