ho realizzato un prototipo con Arduino Uno, che legge tramite un DHT22 l'umidità relativa ed in base ad essa imposta il setpoint in termini di RPM di una ventolina a 4 terminali. Il sistema tramite un banale sistema PID insegue tale setpoint.
Il sistema funziona perfettamente ma... (e qui cominciano le stranezze) a patto che il pc portatile con cui carico il software tramite cavo USB rimanga collegato ad Arduino, anche a PC spento ma collegato con l'alimentatore alla rete. Preciso che Arduino è correttamente alimentato da un alimentatore 12 VDC... se io scollego suddetto PC, quando il setpoint si alza verso i 2500 rpm, il regime letto viene letto in modo erroneo verso il basso (2000 - 2100 RPM), di conseguenza il livello del PWM mi si alza verso il valore massimo.
Problema di assenza di filtri? A qualcuno è capitato qualcosa del genere?
Sì... in pratica se l'umidità relativa aumenta, il software fa aumentare anche il setpoint. Se questo va oltre i circa 2500 rpm, la il valore letto comincia a diminuire verso i 2000 rpm circa. A qual punto il PID spinge al 100% il PWM (ovviamente il sistema legge un valore basso di regime di rotazione e cerca quindi di far si che venga raggiunto il setpoint...)... e ad orecchio sento che in realtà la ventola accelera, il rumore infatti sebbene lieve si fa più acuto.
//parte dichiarativa per gestire il display con bus I2C
#include <Wire.h> //necessario per il funzionamento dell'I2C
#include <LiquidCrystal_I2C.h> //necessario per il funzionamento dell'I2C
LiquidCrystal_I2C lcd(0x27,20,4); //dichiarazione indirizzo e dimensioni del display
//parte dichiarativa per gestire il sensore DHT22
#include <SimpleDHT.h> //necessario per il funzionamento del DHT22
int pinDHT22 = 7; //pin ingresdo del DHT22
SimpleDHT22 dht22; //creazione oggetto dht22
float TEMPERATURA;
float UMIDITA;
//parte dichiarativa per gestire PWM ventola e relativo sensore Hall (tachimetrico)
int PWM = 10; //pin uscita PWM pilotaggio motore
int TACH = 2; //pin ingresso sensore Hall (tachimetrico)
float RPM; // velocità ventola in rpm
volatile int GIRI; // memorizza il numero di giri compiuti
int IMPULSI = 4; //numero di cambiamenti per giro
float SETPOINT;
float ERRORE = 0;
float ERRORE_PRECEDENTE = 0;
float i, j;
float KP = 0.3; //costante proporzionale
float KI = 0; //costante integrativa
float KD = 0; //costante derivativa
int TEMPO = 1000;
float INTEGRALE = 0;
float DERIVATIVO = 0;
void incremento(){ //funzione chiamata dall'interrupt per il conteggio dei giri ed il calcolo del regime
GIRI = GIRI+1;
}
void scrittura_dati_display(){
lcd.home();
lcd.setCursor(2,0);
lcd.print(TEMPERATURA);
lcd.setCursor(14,0);
lcd.print(UMIDITA);
lcd.setCursor(11,1);
lcd.print((int)SETPOINT);
lcd.setCursor(11,2);
lcd.print(i/253*100);
lcd.print(" ");
lcd.setCursor(11,3);
lcd.print((int)RPM);
}
void setup() {
Serial.begin (9600);
pinMode(PWM, OUTPUT);
pinMode(TACH, INPUT);
attachInterrupt(1, incremento, CHANGE); //interrupt sul pin 2
i=100; //valore del PWM iniziale
j=100;
analogWrite (PWM,i);
lcd.init(); //inizializzazione display
lcd.backlight(); //accensione retroilluminazione
lcd.home();
delay (3000);
lcd.clear();
lcd.home();
lcd.print("T=");
lcd.print(" ");
lcd.print("^C ");
lcd.print("UR=");
lcd.print(" ");
lcd.print("%");
lcd.setCursor(0,1);
lcd.print("SETPOINT ");
lcd.print(" ");
lcd.print(" rpm");
lcd.setCursor(0,2);
lcd.print("LIV. PWM ");
lcd.print(" ");
lcd.print(" %");
lcd.setCursor(0,3);
lcd.print("REGIME ");
lcd.print(" ");
lcd.print(" rpm");
}
void loop() {
i=j;
analogWrite (PWM,i);
GIRI=0; //azzeramento della veriabile giri compiuti
interrupts(); // attiva l'interrupt per la misurazione del regime
delay (TEMPO); // tempo di misurazione regime di rotazione
dht22.read2(pinDHT22, &TEMPERATURA, &UMIDITA, NULL);
if (UMIDITA <=20){
SETPOINT = 300;
}
else if (UMIDITA >=80){
SETPOINT = 3000;
}
else SETPOINT = 45 * UMIDITA - 600;
//con questo if si fa in modo che per UR<=20% regime=300rpm, per UR>=80% regime=3000rpm, nel range intermedio si interpola linearmente tra 300 e 3000 rpm
scrittura_dati_display();
noInterrupts(); // disattiva l'interupt
RPM = ((GIRI * 60)/IMPULSI); // il regime è dato dal numero di giri contati nel tempo di misurazione moltiplicati per il rapporto tra 60 secondi ed il tempo di misurazione
ERRORE_PRECEDENTE = ERRORE;
ERRORE = SETPOINT - RPM;
INTEGRALE = INTEGRALE + ERRORE * TEMPO / 1000; //divisione per 1000 per usare KI espressa in secondi
DERIVATIVO = (ERRORE - ERRORE_PRECEDENTE) / (TEMPO / 1000); //divisione per 1000 per usare KD espressa in secondi
j = i * (1 + KP * (ERRORE / RPM) + KI * INTEGRALE + KD * DERIVATIVO); // aliquota proporzionale del PID
if (j > 253){
j = 253;
}
else if (j < 25){
j = 25;
} // limitazione PWM min e max
}
>JerryBurner: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).
In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.
Guglielmo
P.S.: Ti ricordo che, purtroppo, fino a quando non avrai sistemato il codice come richiesto, nessuno ti potrà rispondere, quindi ti consiglio di farlo al più presto.