rele comandato da seriale [RISOLTO]

Ciao a tutti, sono alle prese con un progetto domotico e volevo avere la possibilità di accendere e spegnere un rele tramite arduino.
Il progetto è così composto.

  • Raspberry pi che fa da web server
  • Arduino uno (a) collegato usb al raspberry pi che legge i comandi da seriale
  • Altra scheda arduino uno (b) con collegati un sensore di temperatura, un rele e un nrf24l01 che comunica senza fili con arduino uno (a).

Su raspberry ho caricato uno script in python che viene eseguito ogni 3 minuti e verifica su un database mysql se il rele dev'essere acceso o spento. In base a questo valore invia via seriale sulla porta di arduino un valore 'H' se acceso e 'L' se spento. Arduino leggendo il valore accende o spegne il rele. Il tutto funziona a meraviglia a parte un piccolo problema.

Quando arduino legge da seriale tramite raspberry (una volta ogni 3 minuti) la lettura provoca lo spegnimento momentaneo del relè.. che poi in base al valore letto si riaccende o si rispegne. E' risolvibile tutto ciò? Oppure devo cambiare strada?

thanks

La sfera di cristallo non arriverà prima di fine mese. :sweat_smile:
Mi spiace. :~

Però se pubblichi il codice e una foto dei collegamenti, forse, risolviamo anche senza sfera. :wink:

La sfera di cristallo non arriverà prima di fine mese.

La mia mi ritorna una settimana prima, ma piú veloce é darci gli sketch e il programma che gira su rasberry.
Ciao Uwe

avete ragione.. ora posto tutto.

Questo è il codice in python che gira su RPi

import serial
import string
import MySQLdb
import pprint

db = MySQLdb.connect(host="localhost", # your host, usually localhost
                     user="root", # your username
                      passwd="pass", # your password
                      db="arduino") # name of the data base
cur = db.cursor() 

arduinoPort = '/dev/ttyACM1' #check in the /dev folder the Arduino Serial Port
ser = serial.Serial()

ser.setPort(arduinoPort) #boundRate 9600 automatically set

ser.setTimeout(2)

try:
	ser.open()
except: 
	print('Port Error!')

else:
	for i in range (6):
		ardString = ser.readline()
		#print(ardString)
		valueMatrix= ardString.split(' ')
		if len(valueMatrix)> 1 :
			pprint.pprint(valueMatrix)
		#pprint.pprint(valueMatrix)
			projectId = valueMatrix[0]
			value = valueMatrix[1]
			#inserire variabile sql che cambia con lo stato della stufa e determina se H o L 
			cur.execute('SELECT `cucina`, `camera` FROM `stati` WHERE 1')
			a=cur.fetchone()
			if a[0] == 1:
				print a[0]
				ser.write('H');
			else:
				ser.write('L');
			#print("value received:"+string+ " interpreted as: project Id = "+projectId+" and value = "+value)
			cur.execute('INSERT INTO ard_project_data (value) VALUES ("'+value+'")')
			db.commit()	
		

	ser.close()
	print('connection closed')
	db.close()
	print('database closed')
print('end')

questo è il codice caricato nell'arduino uno collegata a RPi:

#include <SPI.h>
#include <nRF24L01p.h>
nRF24L01p receiver(7,8);//CSN,CE
 float dati;
float incomingByte;
float dati2;

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  receiver.channel(90);
  receiver.RXaddress("Artur");  
  receiver.TXaddress("Artur");  
  receiver.init();
  pinMode(2, OUTPUT);      
        
}
void loop()
  {
    incomingByte=Serial.read();
 if (incomingByte =='L') {
   digitalWrite(2, LOW);
  dati2 = 0;
} 
  if (incomingByte =='H') {
    digitalWrite(2, HIGH);
      dati2 = 1;}        
  delay(50);
 if(receiver.available()){
    receiver.read();
    receiver.rxPL(dati);
    Serial.print("xyz123 ");
    Serial.println(dati);
    delay(10);
    receiver.txPL(dati2);
    receiver.send(SLOW);
    Serial.println(dati2);
    delay (100);
    
 
 }}

questo è il codice caricato su arduino uno mobile dove è collegato il sensore di temperatura e il rele

#include <SPI.h>
#include <nRF24L01p.h>
#include <OneWire.h> 

int DS18S20_Pin = A1; //DS18S20 Signal pin on digital 2
OneWire ds(DS18S20_Pin);  // on digital pin 2
float dati;
float dati2;
nRF24L01p transmitter(7,8);//CSN,CE
float incomingByte;


void setup(){
    delay(150);
  Serial.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  transmitter.channel(90);
  transmitter.TXaddress("Artur");
  transmitter.RXaddress("Artur");
  transmitter.init();
  pinMode(2, OUTPUT);      

}

void loop(){
   float temperature = getTemp();
   float dati= temperature;   
   Serial.println(dati);
   transmitter.txPL(dati);
   transmitter.send(SLOW);
   delay(10);
   transmitter.read();
   transmitter.rxPL(dati2);
   delay(10);
   Serial.println(dati2);
   if (dati2 == 1.00 ) {
   digitalWrite(2, HIGH);
   } else {
     digitalWrite(2, LOW);}
     delay(200);
 
 }
 
 
 
 
 float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
  
}

Il problema è qui

if (dati2 == 1.00 ) {

è molto difficile paragonare due float.

PaoloP:
Il problema è qui

if (dati2 == 1.00 ) {

è molto difficile paragonare due float.

quindi dici di sostituire con un int?

Si, se non ti servono decimali.
Nel caso prima di fare il confronto moltiplicalo per 10, 100 o 1000, poi fai il cast e lo controlli.

Esempio.
Se vuoi che il tuo relè scatti solo quando dati2 è uguale a 1 con la precisione di 2 decimali puoi fare così

dati2 *= 100;
if ((int)dati2 == 100 ) {...

Non sono molto sicuro del casting. Non ho provato a compilarlo.

Ho cambiato da float a int come mi hai consigliato ma il problema non è quello.
Pare come che quando vi sia la lettura in seriale il tutto si ferma e il rele sospende il suo funzionamento per poi giustamente tornare a funzionare se nel database il valore del campo è su '1' o spegnersi se è su '0'.

Prova cambiando pin.
Il 2 è collegato ad un interrupt. Potrebbe esserci conflitto con una libreria.

PaoloP:
Prova cambiando pin.
Il 2 è collegato ad un interrupt. Potrebbe esserci conflitto con una libreria.

ho messo sul pin 4 e sembra uguale.. quando viene eseguito lo script python il rele si accende e si spegne senza motivo..

ho tolto questa riga dallo script python e ora sembra funzionare a dovere

pprint.pprint(valueMatrix)

python è un linguaggio posizionale, se il tuo codice ha la stessa indentazione di quello messo nel post all'esecuzione della pprint veniva chiuso l'if ... lascia la pprint ma indenta bene ....

no purtroppo non è un problema di indentatura.. e non si è ancora risolto.. sembrava funzionare ma ogni tanto il rele si spegne per poi riaccendersi..
ragionando il rele si attiva o disattiva in base a ciò che python scrive.. se scrive H si attiva mentre se scrive L si disattiva. Questo valore viene preso dal database. Se nel database c'è 1 python stampa H -> arduino uno (a) legge H e quindi invia all'arduino remoto un valore 1 (in questo caso). Verificando tutti i passaggi ho notato che ogni tanto il valore che arriva ad arduino remoto è pari a zero. Nel database tuttavia il valore è 1 quindi il problema è più avanti. Python scriverà sempre H però lo scrive solo una volta al minuto quando si esegue lo script. Da qui deduco che il problema è un problema di sincronia.. ovvero ogni tanto arduino legge H mentre ogni tanto non legge niente e quindi molto probabilmente invia 0 al posto di uno.
Si potrebbe supporre quindi che lo script python debba sempre essere in esecuzione.. ma se provo ad eseguire in continuazione lo script il risultato è identico e il relè ha una certa intermittenza.
A questo punto credo che il problema sia legato al trasferimento del dato che determina lo stato del rele (dati2). Perchè andando ad aprire uno schermo seriale ogni tanto stampa zero anzichè uno sulla board remota pur stampando 1 sul rele principale. Secondo voi può essere che ogni tanto si perdano dati nel trasferimento? Ho anche aggiunto dei delay ma questo non fa altro che ritardare gli intervalli di spegnimento del rele ovviamente.

Non riesco a risalire alla libreria che stai usando per i moduli nrlf24 .. in generale io controllerei i valori di ritorno di transmitter.read() e
transmitter.rxPL(dati2)

quello che succede probabilmente è che fai una read e non viene ricevuto nulla, tu ignori questo fatto e leggi da un buffer vuoto (probabilmente 0)

Io controllerei la libreria per vedere che valori ritornano le read, se non ne ritornano nessuno cambierei la logica di acceso-spento in 1 e 2 invece che 0 e 1, così nel caso in cui tu leggi 0 ignori il valore e vai avanti.

Inoltre, perchè mandi il valore via seriale/rf se non è cambiato ?

madmatt71:
Non riesco a risalire alla libreria che stai usando per i moduli nrlf24 .. in generale io controllerei i valori di ritorno di transmitter.read() e
transmitter.rxPL(dati2)

quello che succede probabilmente è che fai una read e non viene ricevuto nulla, tu ignori questo fatto e leggi da un buffer vuoto (probabilmente 0)

Io controllerei la libreria per vedere che valori ritornano le read, se non ne ritornano nessuno cambierei la logica di acceso-spento in 1 e 2 invece che 0 e 1, così nel caso in cui tu leggi 0 ignori il valore e vai avanti.

Inoltre, perchè mandi il valore via seriale/rf se non è cambiato ?

Ho modificato lo sketch del trasmettitore e ora funziona tutto liscio! Il relè non perde più colpi ma è comandato a dovere!

Il problema è come dicevi tu madmatt71 il fatto che ogni tanto in ricezione veniva letto senza ricevere nulla e quindi lo zero provocava lo spegnimento. Cambiando la variabile da 0 a 2 tutto si è risolto, ogni tanto comunque viene letto zero ma questo non provoca nulla al processo di controllo del relè!

Grazie mille!