Browse Source

added LDR evaluation + sensor edge detection

tags/v1.0.0
Dominik Bartsch 2 years ago
parent
commit
2f6502ce20
2 changed files with 222 additions and 126 deletions
  1. 213
    122
      lib/treppe/treppe.cpp
  2. 9
    4
      lib/treppe/treppe.h

+ 213
- 122
lib/treppe/treppe.cpp View File

@@ -1,6 +1,5 @@
#include "treppe.h"


/*
dimm_stufe
- dimmt stufe (0 - 15, PCA9685 outputs) mit linearen ticks
@@ -10,16 +9,16 @@
*/
bool Treppe::dimm_stufe(uint8_t stufe)
{
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
current_pwm += differenz_pwm_pro_tick;
else
current_pwm -= differenz_pwm_pro_tick;
pwmController.setChannelPWM(stufe, static_cast<uint16_t> (current_pwm));
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
current_pwm += differenz_pwm_pro_tick;
else
current_pwm -= differenz_pwm_pro_tick;
pwmController.setChannelPWM(stufe, static_cast<uint16_t>(current_pwm));

current_tick++;
if (current_tick >= ticks_pro_stufe)
return false;
return true;
current_tick++;
if (current_tick >= ticks_pro_stufe)
return false;
return true;
}

/*
@@ -29,150 +28,242 @@ bool Treppe::dimm_stufe(uint8_t stufe)
*/
void Treppe::anim_tick()
{
if (!dimm_stufe(stufe))
if (!dimm_stufe(stufe))
{
Serial.printf("anim_tick(): stufe: %d, start: %d, ziel: %d, current %f\n",
stufe, start_pwm, ziel_pwm, current_pwm);

if (fsm_outputs.laufrichtung == LR_HOCH)
{
if (stufe >= stufen - 1)
{
anim_beendet = true;
return;
}
stufe++;
}
else
{
Serial.printf("anim_tick(): stufe: %d, start: %d, ziel: %d, current %f\n",
stufe, start_pwm, ziel_pwm, current_pwm);

if (fsm_outputs.laufrichtung == LR_HOCH)
{
if (stufe >= stufen-1) {
anim_beendet = true;
return;
}
stufe++;
}
else
{
if (stufe <= 0) {
anim_beendet = true;
return;
}
stufe--;
}
current_tick = 0;
current_pwm = start_pwm;
if (stufe <= 0)
{
anim_beendet = true;
return;
}
stufe--;
}
current_tick = 0;
current_pwm = start_pwm;
}
}

// startbedingunen für animation
void Treppe::start_animation() {
anim_beendet = false;
void Treppe::start_animation()
{
anim_beendet = false;

if(fsm_outputs.laufrichtung == LR_HOCH)
stufe = 0;
else
stufe = stufen-1;
if(fsm_outputs.dimmrichtung == DR_AUFDIMMEN) {
start_pwm = idle_brightness;
ziel_pwm = active_brightness;
} else {
start_pwm = active_brightness;
ziel_pwm = idle_brightness;
}
if (fsm_outputs.laufrichtung == LR_HOCH)
stufe = 0;
else
stufe = stufen - 1;

current_tick = 0;
current_pwm = start_pwm;
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
{
start_pwm = idle_brightness;
ziel_pwm = active_brightness;
}
else
{
start_pwm = active_brightness;
ziel_pwm = idle_brightness;
}

current_tick = 0;
current_pwm = start_pwm;
}

void Treppe::print_state_on_change()
{
static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
if (
fsm_inputs.anim_beendet != last_in.anim_beendet ||
fsm_inputs.sensor_oben != last_in.sensor_oben ||
fsm_inputs.sensor_unten != last_in.sensor_unten ||
fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
fsm_outputs.laufrichtung != last_out.laufrichtung ||
fsm_outputs.status != last_out.status)
{
last_in.anim_beendet = fsm_inputs.anim_beendet;
last_in.sensor_oben = fsm_inputs.sensor_oben;
last_in.sensor_unten = fsm_inputs.sensor_unten;
last_out.dimmrichtung = fsm_outputs.dimmrichtung;
last_out.laufrichtung = fsm_outputs.laufrichtung;
last_out.status = fsm_outputs.status;

Serial.printf("FSM IN: s_u: %d, s_o: %d, beendet: %d =>",
fsm_inputs.sensor_oben, fsm_inputs.sensor_unten, fsm_inputs.anim_beendet);
Serial.print(" step => ");
Serial.printf("OUT: LR: %d DR: %d ST: %d\n",
fsm_outputs.laufrichtung, fsm_outputs.dimmrichtung, fsm_outputs.status);
}
static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
if (
fsm_inputs.anim_beendet != last_in.anim_beendet ||
fsm_inputs.sensor_oben != last_in.sensor_oben ||
fsm_inputs.sensor_unten != last_in.sensor_unten ||
fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
fsm_outputs.laufrichtung != last_out.laufrichtung ||
fsm_outputs.status != last_out.status)
{
last_in.anim_beendet = fsm_inputs.anim_beendet;
last_in.sensor_oben = fsm_inputs.sensor_oben;
last_in.sensor_unten = fsm_inputs.sensor_unten;
last_out.dimmrichtung = fsm_outputs.dimmrichtung;
last_out.laufrichtung = fsm_outputs.laufrichtung;
last_out.status = fsm_outputs.status;

Serial.printf("FSM IN: s_u: %d, s_o: %d, beendet: %d =>",
fsm_inputs.sensor_oben, fsm_inputs.sensor_unten, fsm_inputs.anim_beendet);
Serial.print(" step => ");
Serial.printf("OUT: LR: %d DR: %d ST: %d\n",
fsm_outputs.laufrichtung, fsm_outputs.dimmrichtung, fsm_outputs.status);
}
}

bool Treppe::read_sensor(int sensor)
{

/*
reads sensors with edge detection
returns true if motion was detected
returns false if no motion was detected
returns false if motion was detected, but state did not change back to not detected
*/
uint8_t pegel = digitalRead(sensor);
static uint8_t pegel_alt[2] = {0, 0};

uint8_t index = 0;
if (sensor == SENSOR_OBEN)
index = 0;
else
index = 1;

if (pegel == 1 && pegel_alt[index] == 0)
{
pegel_alt[index] = pegel;
return true;
}
else
{
pegel_alt[index] = pegel;
return false;
}
//return static_cast<bool>(pegel);
}

float Treppe::read_ldr(){
/*
Reads Illuminance in Lux

FUTURE USE : show current Illuminance on Webserver in order to calibrate

Voltage Divider 1 (R13, R14):
R13 = 220k, R14 = 82k
V(ADC) = V(in1) * R14/(R13+R14)
-> V(in1) = V(ADC) * (R13+R14)/R14
V(ADC) = analogRead(A0)/1023.00
-> V(in1) = analogRead(A0)/1023.00 * (R13+R14)/R14
= analogRead(A0) * (R13+R14)/(R14*1023.00)
= analogRead(A0) * (220k+82k)/(82k*1023.00)
= analogRead(A0) * 0.0036
Voltage Divider 2 (LDR, R1 || (R13+R14))
R1 = 47k, R13+R14 = 302k -> R1||(R13+R14) = 40,67k
Vcc/V(in1) = R(LDR) / (R1||(R13+R14))
-> R(LDR) = Vcc/V(in1) * (R1||(R13+R14))
R(LDR) = 3.3V * 40.67k / V(in1)

Join formulas:

R(LDR) = 3.3V * 40.67k / (0.0036 * analogRead(A0))
= 37280.00/analogRead(A0)
ldr_ohm = R(LDR)

E(LDR) = 79.735 * R(LDR)^-0.498 (see Excel Regression)
ldr_value = E(LDR)
*/
float ldr_ohm = 37280.00 / analogRead(A0);
float ldr_value = 79.735 * pow(ldr_ohm, -0.498);
return ldr_value;
}


bool Treppe::check_ldr()
{
uint8_t active = 0;

#ifdef LDRDEBUG
Serial.printf("R(LDR) = %f kOhm %f lux\n", ldr_value, lux);
return true;
#endif

// follow up: averaging over many samples?
if(read_ldr() < ldr_schwelle) active = 1;
if(read_ldr() > ldr_schwelle + LDR_HYS) active = 0;

return active;
}

void Treppe::task()
{
//Serial.printf("LDR: %f\n", ((float)analogRead(A0))/1023.*3.68);
fsm_inputs.ldr_schwelle = true; // <=== LDR implementierung !!

fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
fsm_inputs.anim_beendet = static_cast<bool>(anim_beendet);

FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
FSMTreppe_Obj.step();
fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
print_state_on_change();

if(fsm_outputs.status > ST_RUHEZUSTAND) {
if( anim_beendet == true &&
( fsm_outputs.status == ST_AUFDIMMEN_HOCH || fsm_outputs.status == ST_ABDIMMEN_HOCH ||
fsm_outputs.status == ST_AUFDIMMEN_RUNTER || fsm_outputs.status == ST_ABDIMMEN_RUNTER ))
{
start_animation();
}
if( !anim_beendet )
anim_tick();
//Serial.printf("LDR: %f\n", ((float)analogRead(A0))/1023.*3.68);
fsm_inputs.ldr_schwelle = read_ldr(); // <=== LDR implementierung !!

fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
fsm_inputs.anim_beendet = static_cast<bool>(anim_beendet);

FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
FSMTreppe_Obj.step();
fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
print_state_on_change();

if (fsm_outputs.status > ST_RUHEZUSTAND)
{
if (anim_beendet == true &&
(fsm_outputs.status == ST_AUFDIMMEN_HOCH || fsm_outputs.status == ST_ABDIMMEN_HOCH ||
fsm_outputs.status == ST_AUFDIMMEN_RUNTER || fsm_outputs.status == ST_ABDIMMEN_RUNTER))
{
start_animation();
}
if (!anim_beendet)
anim_tick();
}
}

void Treppe::berechne_dimmer() {
ticks_pro_stufe = time_per_stair / INT_TIME; // [ms]
differenz_pwm_pro_tick = (float) (active_brightness - idle_brightness)
/ (float) ticks_pro_stufe;
void Treppe::berechne_dimmer()
{
ticks_pro_stufe = time_per_stair / INT_TIME; // [ms]
differenz_pwm_pro_tick = (float)(active_brightness - idle_brightness) / (float)ticks_pro_stufe;
}

void Treppe::setup()
{
pwmController.resetDevices();
// Deactive PCA9685 Phase Balancer due to LED Flickering
// https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
// see also lib/PCA9685-Arduin/PCA9685.h:204
pwmController.init(PCA9685_PhaseBalancer_None);
//pwmController.init(PCA9685_PhaseBalancer_Linear);
pwmController.setPWMFrequency(100);
pwmController.setAllChannelsPWM(idle_brightness);

pinMode(A0, INPUT);
pinMode(SENSOR_OBEN, INPUT);
pinMode(SENSOR_UNTEN, INPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, 0);

Serial.printf("differenz_pwm_pro_tick %f\n", differenz_pwm_pro_tick);
Serial.printf("Treppe: initial parameters: stufen=%d\n", stufen);
pwmController.resetDevices();
// Deactive PCA9685 Phase Balancer due to LED Flickering
// https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
// see also lib/PCA9685-Arduin/PCA9685.h:204
pwmController.init(PCA9685_PhaseBalancer_None);
//pwmController.init(PCA9685_PhaseBalancer_Linear);
pwmController.setPWMFrequency(100);
pwmController.setAllChannelsPWM(idle_brightness);
pinMode(A0, INPUT);
pinMode(SENSOR_OBEN, INPUT);
pinMode(SENSOR_UNTEN, INPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, 0);
Serial.printf("differenz_pwm_pro_tick %f\n", differenz_pwm_pro_tick);
Serial.printf("Treppe: initial parameters: stufen=%d\n", stufen);
}

// ###################################################################################################################
// GEBUFFERT => Erst im Ruhezustand übernehmen !!!!
void Treppe::set_idle_pwm(uint16_t _idle_brightness)
{
idle_brightness = _idle_brightness;
berechne_dimmer();
Serial.printf("Treppe: idle_brightness=%d\n", idle_brightness);
idle_brightness = _idle_brightness;
berechne_dimmer();
Serial.printf("Treppe: idle_brightness=%d\n", idle_brightness);
}
void Treppe::set_active_pwm(uint16_t _active_brightness)
{
active_brightness = _active_brightness;
berechne_dimmer();
Serial.printf("Treppe: active_brightness=%d\n", active_brightness);
active_brightness = _active_brightness;
berechne_dimmer();
Serial.printf("Treppe: active_brightness=%d\n", active_brightness);
}
void Treppe::set_time_per_stair(uint16_t _time_per_stair)
{
time_per_stair = _time_per_stair;
berechne_dimmer();
Serial.printf("Treppe: time_per_stair=%d\n", time_per_stair);
time_per_stair = _time_per_stair;
berechne_dimmer();
Serial.printf("Treppe: time_per_stair=%d\n", time_per_stair);
}

+ 9
- 4
lib/treppe/treppe.h View File

@@ -3,6 +3,10 @@
#include "FSMTreppe2/FSMTreppe2.h"
#include "PCA9685.h"

// #define LDRDEBUG // comment in to override LDR measurement

#define LDR_HYS 5.0 // Hysteresis for switching off FSM [lux]

#define SENSOR_OBEN 2
#define SENSOR_UNTEN 12
#define OE 14
@@ -16,6 +20,8 @@ private:
uint16_t idle_brightness = 0;
uint16_t active_brightness = 500;

uint16_t ldr_schwelle = 7; // activation value for FSM [lx]

uint16_t start_pwm = 0;
uint16_t ziel_pwm = 0;
@@ -56,10 +62,9 @@ private:
DR_AUFDIMMEN=1
};

bool read_sensor(int sensor) {
int pegel = digitalRead(sensor);
return static_cast<bool>(pegel);
}
bool read_sensor(int sensor);
float read_ldr();
bool check_ldr();
public:
Treppe(uint8_t _stufen) : stufen(_stufen){
FSMTreppe_Obj.initialize();

Loading…
Cancel
Save