Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
co2ampel
ampel-firmware
Commits
ef911533
Commit
ef911533
authored
May 01, 2021
by
Eric Duminil
Browse files
Merge branch 'refactor/fixstartup' into develop
parents
701ac714
79f137e8
Changes
1
Hide whitespace changes
Inline
Side-by-side
ampel-firmware/co2_sensor.cpp
View file @
ef911533
...
...
@@ -3,10 +3,12 @@
namespace
config
{
// Values should be defined in config.h
uint16_t
measurement_timestep
=
MEASUREMENT_TIMESTEP
;
// [s] Value between 2 and 1800 (range for SCD30 sensor)
const
uint16_t
measurement_timestep_bootup
=
2
;
// [s] Measurement timestep during acclimatization
const
uint16_t
altitude_above_sea_level
=
ALTITUDE_ABOVE_SEA_LEVEL
;
// [m]
uint16_t
co2_calibration_level
=
ATMOSPHERIC_CO2_CONCENTRATION
;
// [ppm]
int8_t
max_deviation_during_calibration
=
30
;
// [ppm]
int8_t
enough_stable_measurements
=
60
;
const
uint8_t
max_deviation_during_bootup
=
20
;
// [%]
#ifdef TEMPERATURE_OFFSET
// Residual heat from CO2 sensor seems to be high enough to change the temperature reading. How much should it be offset?
// NOTE: Sign isn't relevant. The returned temperature will always be shifted down.
...
...
@@ -28,31 +30,27 @@ namespace sensor {
/**
* Define sensor states
* INITIAL -> initial state
* BOOTUP -> state after initializing the sensor, i.e. after scd.begin()
* BOOTUP -> initial state, until first >0 ppm values are returned
* READY -> sensor does output valid information (> 0 ppm) and no other condition takes place
* NEEDS_CALIBRATION -> sensor measurements are too low (< 250 ppm)
* PREPARE_CALIBRATION -> forced calibration was initiated,
waiting for stable measurements
* CALIBRATION
-> the sensor does calibrate itself
* PREPARE_CALIBRATION
_UNSTABLE
-> forced calibration was initiated,
last measurements were too far apart
*
PREPARE_
CALIBRATION
_STABLE -> forced calibration was initiated, last measurements were close to each others
*/
enum
state
{
INITIAL
,
BOOTUP
,
READY
,
NEEDS_CALIBRATION
,
PREPARE_CALIBRATION_UNSTABLE
,
PREPARE_CALIBRATION_STABLE
,
CALIBRATION
PREPARE_CALIBRATION_STABLE
};
const
char
*
state_names
[]
=
{
"INITIAL"
,
"BOOTUP"
,
"READY"
,
"NEEDS_CALIBRATION"
,
"PREPARE_CALIBRATION_UNSTABLE"
,
"PREPARE_CALIBRATION_STABLE"
,
"CALIBRATION"
};
state
current_state
=
INITIAL
;
"PREPARE_CALIBRATION_STABLE"
};
state
current_state
=
BOOTUP
;
void
switchState
(
state
);
void
initialize
()
{
...
...
@@ -78,28 +76,33 @@ namespace sensor {
ESP
.
restart
();
}
switchState
(
BOOTUP
);
// SCD30 has its own timer.
//NOTE: The timer seems to be inaccurate, though, possibly depending on voltage. Should it be offset?
Serial
.
print
(
F
(
"Setting SCD30 timestep to "
));
Serial
.
print
(
config
::
measurement_timestep
);
Serial
.
println
(
" s."
);
scd30
.
setMeasurementInterval
(
config
::
measurement_timestep
);
// [s]
// Changes of the SCD30's measurement timestep do not come into effect
// before the next measurement takes place. That means that after a hard reset
// of the ESP the SCD30 sometimes needs a long time until switching back to 2 s
// for acclimatization. Resetting it after startup seems to fix this behaviour.
scd30
.
reset
();
Serial
.
print
(
F
(
"Setting temperature offset to -"
));
Serial
.
print
(
abs
(
config
::
temperature_offset
));
Serial
.
println
(
" K."
);
Serial
.
println
(
F
(
" K."
)
)
;
scd30
.
setTemperatureOffset
(
abs
(
config
::
temperature_offset
));
// setTemperatureOffset only accepts positive numbers, but shifts the temperature down.
delay
(
100
);
Serial
.
print
(
F
(
"Temperature offset is : -"
));
Serial
.
print
(
scd30
.
getTemperatureOffset
());
Serial
.
println
(
" K"
);
Serial
.
println
(
F
(
" K"
)
)
;
Serial
.
print
(
F
(
"Auto-calibration is "
));
Serial
.
println
(
config
::
auto_calibrate_sensor
?
"ON."
:
"OFF."
);
// SCD30 has its own timer.
//NOTE: The timer seems to be inaccurate, though, possibly depending on voltage. Should it be offset?
Serial
.
println
();
Serial
.
print
(
F
(
"Setting SCD30 timestep to "
));
Serial
.
print
(
config
::
measurement_timestep_bootup
);
Serial
.
println
(
F
(
" s during acclimatization."
));
scd30
.
setMeasurementInterval
(
config
::
measurement_timestep_bootup
);
// [s]
sensor_console
::
defineIntCommand
(
"co2"
,
setCO2forDebugging
,
F
(
" 1500 (Sets co2 level, for debugging purposes)"
));
sensor_console
::
defineIntCommand
(
"timer"
,
setTimer
,
F
(
" 30 (Sets measurement interval, in s)"
));
sensor_console
::
defineCommand
(
"calibrate"
,
startCalibrationProcess
,
F
(
" (Starts calibration process)"
));
...
...
@@ -117,10 +120,20 @@ namespace sensor {
int32_t
now
=
millis
();
Serial
.
print
(
F
(
"Measurement time offset : "
));
Serial
.
print
(
now
-
previous_measurement_at
-
config
::
measurement_timestep
*
1000
);
Serial
.
println
(
" ms."
);
Serial
.
println
(
F
(
" ms."
)
)
;
previous_measurement_at
=
now
;
}
bool
hasSensorSettled
()
{
static
uint16_t
last_co2
=
0
;
uint16_t
delta
;
delta
=
abs
(
co2
-
last_co2
);
last_co2
=
co2
;
// We assume the sensor has acclimated to the environment if measurements
// change less than a specified percentage of the current value.
return
(
co2
>
0
&&
delta
<
((
uint32_t
)
co2
*
config
::
max_deviation_during_bootup
/
100
));
}
bool
countStableMeasurements
()
{
// Returns true, if a sufficient number of stable measurements has been observed.
static
int16_t
previous_co2
=
0
;
...
...
@@ -151,7 +164,6 @@ namespace sensor {
}
void
calibrateAndRestart
()
{
switchState
(
CALIBRATION
);
Serial
.
print
(
F
(
"Calibrating SCD30 now..."
));
scd30
.
setAltitudeCompensation
(
config
::
altitude_above_sea_level
);
scd30
.
setForcedRecalibrationFactor
(
config
::
co2_calibration_level
);
...
...
@@ -177,19 +189,25 @@ namespace sensor {
if
(
config
::
debug_sensor_states
)
{
Serial
.
print
(
F
(
"Changing sensor state: "
));
Serial
.
print
(
state_names
[
current_state
]);
Serial
.
print
(
" -> "
);
Serial
.
print
(
F
(
" -> "
)
)
;
Serial
.
println
(
state_names
[
new_state
]);
}
current_state
=
new_state
;
}
void
switchStateForCurrentPPM
()
{
if
(
co2
==
0
)
{
// NOTE: Data is available, but it's sometimes erroneous: the sensor outputs
// zero ppm but non-zero temperature and non-zero humidity.
Serial
.
println
(
F
(
"Invalid sensor data - CO2 concentration supposedly 0 ppm"
));
switchState
(
BOOTUP
);
}
else
if
((
current_state
==
PREPARE_CALIBRATION_UNSTABLE
)
||
(
current_state
==
PREPARE_CALIBRATION_STABLE
))
{
if
(
current_state
==
BOOTUP
)
{
if
(
!
hasSensorSettled
())
{
return
;
}
switchState
(
READY
);
Serial
.
println
(
F
(
"Sensor acclimatization finished."
));
Serial
.
print
(
F
(
"Setting SCD30 timestep to "
));
Serial
.
print
(
config
::
measurement_timestep
);
Serial
.
println
(
F
(
" s."
));
scd30
.
setMeasurementInterval
(
config
::
measurement_timestep
);
// [s]
}
if
((
current_state
==
PREPARE_CALIBRATION_UNSTABLE
)
||
(
current_state
==
PREPARE_CALIBRATION_STABLE
))
{
// Check for pre-calibration states first, because we do not want to
// leave them before calibration is done.
bool
ready_for_calibration
=
countStableMeasurements
();
...
...
@@ -236,8 +254,6 @@ namespace sensor {
case
PREPARE_CALIBRATION_STABLE
:
led_effects
::
showWaitingLED
(
color
::
green
);
break
;
case
CALIBRATION
:
// Nothing to do, will restart soon.
break
;
default:
Serial
.
println
(
F
(
"Encountered unknown sensor state"
));
// This should not happen.
}
...
...
@@ -264,7 +280,9 @@ namespace sensor {
showState
();
return
freshData
;
// Report data for further processing only if the data is reliable
// (state 'READY') or manual calibration is necessary (state 'NEEDS_CALIBRATION').
return
freshData
&&
(
current_state
==
READY
||
current_state
==
NEEDS_CALIBRATION
);
}
/*****************************************************************
...
...
@@ -288,7 +306,7 @@ namespace sensor {
if
(
timestep
>=
2
&&
timestep
<=
1800
)
{
Serial
.
print
(
F
(
"Setting Measurement Interval to : "
));
Serial
.
print
(
timestep
);
Serial
.
println
(
"s."
);
Serial
.
println
(
F
(
"s."
)
)
;
sensor
::
scd30
.
setMeasurementInterval
(
timestep
);
config
::
measurement_timestep
=
timestep
;
led_effects
::
showKITTWheel
(
color
::
green
,
1
);
...
...
@@ -300,7 +318,7 @@ namespace sensor {
Serial
.
print
(
F
(
"Force calibration, at "
));
config
::
co2_calibration_level
=
calibrationLevel
;
Serial
.
print
(
config
::
co2_calibration_level
);
Serial
.
println
(
" ppm."
);
Serial
.
println
(
F
(
" ppm."
)
)
;
sensor
::
startCalibrationProcess
();
}
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment