Bagà. Omplir els dipòsits del rec

De wikijoan
Salta a la navegació Salta a la cerca

Introducció

(TBD)

Desenvolupament

Resum esquema.png

Hi ha 4 pins per a l'alimentació:

  • 5V (els relés s'activen a 5V, s'agafa de la RPi. Es podria agafar de la font d'alimentació. La RPi s'alimenta de la font d'alimentació.)
  • 3,3V. Les entrades GPIO van a 3,3V, i per tant l'alimentació dels sensors de nivell i de llum van a 3,3V
  • 12V. És el secundari dels relés. La tensió ve d'una font d'alimentació de 12V.
  • GND. És el comú de la RPi i de les fonts d'alimentació.

Sensor de nivell

El sensor de nivell és un interruptor, i per tant la manera de connectar-ho als pins GPIO és de la mateixa manera que amb les màquines Arcade.

               ______       _______
    GPIO >----|__1K__|--+--|__10K__|----< +3V3
                        |
                        |
                        o |
                          |=#
                        o |
                        |
                        |
     GND >--------------+

Sensor LDR de crepuscle

IhznT.png

Per tal d'ajustar la sensibilitat de quan commuta, he de substituir la resistència de 1K per un potenciòmetre trimmer de 1K. A 1K per tal de què commuti quasi bé he de tapar la LDR. Si baixés a 500ohm no caldria tapar tant la LDR. És un divisor de tensió.

Raspberry i relés

Relay-Sample.png

El problema d'activar un relé amb un pin GPIO també interessa al projecte Interface_GPIO-relés_per_a_efectes_de_LEDs.

La idea és segui l'esquema de

El pin GPIO són 3.5V, i el coil primari del relé són 5V. Per tant, les dues senyals les agafo de la RPi. El secundari de la bobina seran 12V o 220V depenent del projecte.

Software

instal.lació de la llibreria wiringPi

$ sudo apt-get install git-core
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build

Primera prova des de la línia de comandes a la RPi:

$ gpio mode 7 input

$ gpio read 7
0
$ gpio read 7
1
$ mkdir rec_baga
$ cd rec_baga

portàtil:

$ cd /home/joan/projectes/rec_baga
$ scp rec_baga_v1.c pi@192.168.1.35:/home/pi/rec_baga

RPi:

$ gcc -o rec_baga -Wall -I/usr/local/include -L/usr/local/lib rec_baga_v1.c -lwiringPi
$ sudo ./rec_baga

fitxer rec_baga_v1.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

#define	SENSOR_NIVELL	7 //GPIO7, pin 7 del header
#define	SENSOR_LDR	0 //GPIO0, pin 11 del header
#define	RELE	2 //GPIO2, pin 13 del header

int estat_nivell; 
int estat_ldr; 

void setup (void)
{

	if (geteuid () != 0)
	{
		fprintf (stderr, "prova1_gpio: Need to be root to run (sudo?)\n") ;
		exit (0) ;
	}

	if (wiringPiSetup () == -1)
		exit (1) ;

	printf ("Setup ... ") ; 
	fflush (stdout) ;
	//pinMode (0, OUTPUT) ;
	//digitalWrite (0, 0) ;

 	pinMode (SENSOR_NIVELL, INPUT) ;
	pinMode (SENSOR_LDR, INPUT) ;
	pinMode (RELE, OUTPUT) ;

	estat_nivell = digitalRead (SENSOR_NIVELL);
	printf("Estat inicial del nivell: %d\n", estat_nivell);

	estat_ldr = digitalRead (SENSOR_LDR);
	printf("Estat inicial del LDR: %d\n", estat_ldr);

}


void waitCanviEstat (void)
{
	if (digitalRead (SENSOR_NIVELL) != estat_nivell) {
		estat_nivell = !estat_nivell;
		printf("Estat del nivell: %d\n", estat_nivell);
		digitalWrite (RELE,  estat_nivell);
	}
	if (digitalRead (SENSOR_LDR) != estat_ldr) {
		estat_ldr = !estat_ldr;
		printf("Estat del LDR: %d\n", estat_ldr);
		digitalWrite (RELE,  estat_ldr);
	}
	delay(100);
}

int main (void)
{
	setup () ;
	for (;;)
	{
		waitCanviEstat () ;
	}
}

fitxer rec_baga_v2_a.c:

// gcc -o rec_baga -Wall -I/usr/local/include -L/usr/local/lib rec_baga_v2_a.c -lwiringPi
// sudo ./rec_baga

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

//http://opensourceecology.org/w/images/e/e5/Rasp_pinout.png
#define	SENSOR_NIVELL	7 //GPIO7, pin 7 del header
#define	SENSOR_LDR	6 //pin22 //5 //pin 18 //0 //GPIO0, pin 11 del header
#define	RELE1	2 //GPIO2, pin 13 del header. electrovalvula
#define	RELE2	3 //GPIO3, pin 15 del header. electrovalvula
#define RELE3    4 //GPIO4, pin 16 del header. sensor LDR

int estat_nivell; 
int estat_ldr; 

void setup (void)
{

	if (geteuid () != 0)
	{
		fprintf (stderr, "prova1_gpio: Need to be root to run (sudo?)\n") ;
		exit (0) ;
	}

	if (wiringPiSetup () == -1)
		exit (1) ;

	printf ("Setup ... ") ; 
	fflush (stdout) ;
	//pinMode (0, OUTPUT) ;
	//digitalWrite (0, 0) ;

 	pinMode (SENSOR_NIVELL, INPUT);
	pinMode (SENSOR_LDR, INPUT);
	pinMode (RELE1, OUTPUT);
	pinMode (RELE2, OUTPUT);
	pinMode (RELE3, OUTPUT);

	estat_nivell = digitalRead (SENSOR_NIVELL);
	printf("Estat inicial del nivell: %d\n", estat_nivell);

	estat_ldr = digitalRead (SENSOR_LDR);
	printf("Estat inicial del LDR: %d", estat_ldr);
	if (estat_ldr == 0) {
                printf(" dia. apagar el vailet");
        } else {
                printf(" nit. encendre el vailet");
        }

}


void waitCanviEstat (void)
{
	if (digitalRead (SENSOR_NIVELL) != estat_nivell) {
		estat_nivell = !estat_nivell;
		printf("Estat del nivell: %d\n", estat_nivell);

        	if (estat_nivell == 0) {
                        digitalWrite (RELE1, !estat_nivell);
                        delay(1000);
                        digitalWrite (RELE1, estat_nivell);
                } else {
                        digitalWrite (RELE2, estat_nivell);
                        delay(1000);
                        digitalWrite (RELE2, !estat_nivell);                        
                }

	}
	if (digitalRead (SENSOR_LDR) != estat_ldr) {
		estat_ldr = !estat_ldr;
		printf("Estat del LDR: %d\n", estat_ldr);
        	if (estat_ldr == 0) {
                        printf(" dia. apagar el vailet");
                } else {
                        printf(" nit. encendre el vailet");
                }

		digitalWrite (RELE3,  estat_ldr);
	}
	delay(100);
}

int main (void)
{
	setup () ;
	for (;;)
	{
		waitCanviEstat () ;
	}
}

versió 3

En la versiò 2 volia posar tot junt el sensor de llum/vailet i el sensor de nivell/electrovàlvula. La conseqüència és que hi ha molta incompatibiltat electromagnètica de l'alternador del vailet que ha generat molta inestabilitat en la RPi (model B) i al final s'han cascat els pints d'E/S.

Per tant, elimino tot el temap de sensor de llum/vailet i em centro amb el sensor de nivell per activar l'electrovàlvula. Ho faig amb una Raspberry Pi A+.

NOTA. Aquest projecte, tal com ha quedat, seria ideal per fer-ho amb un microcontrolador. És a dir, no caldria fer-lo amb la RPi. En definitiva és un interruptor que activen dos relés. També es pot fer més barato amb la plataforma que està sortint: C.H.I.P (https://www.kickstarter.com/projects/1598272670/chip-the-worlds-first-9-computer), que per 9$ tens el micro i tots els pins GPIO, i no cal xarxa ni HDMI...

En aquesta versió 3 he utilitzat dos relés DPDT (doble pol, double throw) que em pemeten tenir a la sortida els +12/-12V que buscava en la versió 2. Sense cap relé actiu la sortida en els bornes de l'electrovàlvula està flotant. Quan es tanca l'interruptor s'activa un relé apareix els +12V, i torno a obrir al cap d'un segon. Quan s'obre l'interruptor es tanca l'altre relé i apareixen els -12V, i es torna a obrir al cap d'un segon. Per tant, l'estat normal de l'electrovàlvula és que té els bornes flotant.

Per testejar els +/-12V amb un tester doncs ho faig directament amb el tester. Ara bé, el que no es pot fer és connectar un dels bornes de l'electrovàlvula al terra comú (!). Mirar l'esquema, els bornes de l'electrovàlvula han d'estar flotant.

NOTA. Una altra cosa que m'ha despistat és que fent proves amb la RPi és que en comptes d'utilitzar una font de 12V he utilitzat el pin 5V de la RPi (el pin 3 que també és de 12V). I en ficar el tester no m'apareixien els +/-12V.

La idea és que el circuit de la RPi i els sensors sigui TOTALMENT INDEPENDENT de la font d'alimentació de 12V.

rec_baga_v3.c

// gcc -o rec_baga -Wall -I/usr/local/include -L/usr/local/lib rec_baga_v3.c -lwiringPi
// sudo ./rec_baga

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

//raspberry pi A+
//http://pi4j.com/pins/model-a-plus.html
#define    EV  1     //GPIO1, pin 12 del header
#define    RELE1    0 //GPIO0, pin 11 del header. electrovalvula
#define    RELE2    2 //GPIO2, pin 13 del header. electrovalvula

int estat_ev;

void setup (void)
{

    if (geteuid () != 0)

    {
        fprintf (stderr, "prova1_gpio: Need to be root to run (sudo?)\n") ;
        exit (0) ;
    }

    if (wiringPiSetup () == -1)
        exit (1) ;

    printf ("Setup ... ") ;
    fflush (stdout) ;

    pinMode (EV, INPUT);
    pinMode (RELE1, OUTPUT);
    pinMode (RELE2, OUTPUT);

    estat_ev = digitalRead (EV); //normalment l'interruptor està obert, i el valor que es llegeix és un 1
    printf("Estat inicial de l'electrovalvula: %d\n", estat_ev);

}


void waitCanviEstat (void)
{
    if (digitalRead (EV) != estat_ev) {
        estat_ev = !estat_ev;
        printf("Estat de la electrovalvula: %d\n", estat_ev);


        if (estat_ev == 0) {
            printf("rele1\n");
            digitalWrite (RELE1, !estat_ev);
            delay(1000);
            digitalWrite (RELE1, estat_ev);
            delay(1000);
        } else {
            printf("rele2\n"); 
            digitalWrite (RELE2, estat_ev);
            delay(1000);
            digitalWrite (RELE2, !estat_ev);
            delay(1000);                  
        }

    }

    delay(100);
}

int main (void)
{
    setup () ;
    for (;;)
    {
        waitCanviEstat () ;
    }
}

Aprofitant aquest projecte també testejo l'interruptor del moneder (el del filferro), que funciona correctament. moneder_v3.c:

// gcc -o moneder -Wall -I/usr/local/include -L/usr/local/lib moneder_v3.c -lwiringPi
// sudo ./moneder

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

//raspberry pi A+
//http://pi4j.com/pins/model-a-plus.html
#define    MONEDER  1     //GPIO1, pin 12 del header
#define    RELE1    2 //GPIO0, pin 11 del header. electrovalvula
#define    RELE2    3 //GPIO2, pin 13 del header. electrovalvula

int estat_moneder;

void setup (void)
{

    if (geteuid () != 0)
    {
        fprintf (stderr, "prova1_gpio: Need to be root to run (sudo?)\n") ;
        exit (0) ;
    }

    if (wiringPiSetup () == -1)
        exit (1) ;

    printf ("Setup ... ") ;
    fflush (stdout) ;

    pinMode (MONEDER, INPUT);
    pinMode (RELE1, OUTPUT);
    pinMode (RELE2, OUTPUT);

    estat_moneder = digitalRead (MONEDER); //normalment l'interruptor està obert, i el valor que es llegeix és un 1
    printf("Estat inicial del moneder: %d\n", estat_moneder);

}


void waitCanviEstat (void)
{
    if (digitalRead (MONEDER) != estat_moneder) {
        estat_moneder = !estat_moneder;
        printf("Estat del moneder: %d\n", estat_moneder);

        digitalWrite (RELE1, 1);
        delay(1000);
        digitalWrite (RELE1, 0);
        delay(1000);
    }

    //delay(100);
}

int main (void)
{
    setup () ;
    for (;;)
    {
        waitCanviEstat () ;
    }
}

Ara que ja tenim el sistema en funcionament, hem de millorar el software.

rec_baga_v6.c:

// gcc -o rec_baga -Wall -I/usr/local/include -L/usr/local/lib rec_baga_v6.c -lwiringPi
// sudo ./rec_baga
// funcionament de l'electrovàlvula: http://www.infojardin.com/foro/showthread.php?t=17559

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

//raspberry pi A+
//http://pi4j.com/pins/model-a-plus.html
#define    EV  1     //GPIO1, pin 12 del header
#define    RELE1    0 //GPIO0, pin 11 del header. electrovalvula
#define    RELE2    2 //GPIO2, pin 13 del header. electrovalvula

int estat_ev;
int regant;
int esperant;
int esperant2;
int comptador;
int comptador2;

void setup (void)
{

    if (geteuid () != 0)
    {
        fprintf (stderr, "prova1_gpio: Need to be root to run (sudo?)\n") ;
        exit (0) ;
    }

    if (wiringPiSetup () == -1)
        exit (1) ;

    printf ("Setup ... ") ;
    fflush (stdout) ;

    pinMode (EV, INPUT);
    pinMode (RELE1, OUTPUT);
    pinMode (RELE2, OUTPUT);

    estat_ev = digitalRead (EV); //normalment l'interruptor està obert, i el valor que es llegeix és un 1
    printf("Estat inicial de l'electrovalvula: %d\n", estat_ev); 
    printf("en estat normal, boia a l'extrem,  ha de valdre 0\n");
    regant = 0;
    esperant = 0;
    comptador = 0;
    comptador2 = 0;
}



//en la posició normal del sensor de nivell (sense aigua) l'interruptor està tancar (R=0) i el pin EV=0
void waitCanviEstat (void)
{
    //arriba aigua al sensor de nivell, s'obre el sensor (R=inf) i s'ha d'obrir la vàlvula
    if ( (digitalRead(EV)==1) && (regant==0) ) {
        digitalWrite (RELE1, 1);
        printf("rele1\n");
        delay(5000);
        digitalWrite (RELE1, 0);
        delay(5000);
        //i ara està passant aigua... Però això s'ha de comprovar tres vegades cada 5 min.    
        regant = 1;
        esperant = 1;
        esperant2 = 1; //estic regant
        comptador = 0;
    }

    if ((regant == 1) && (esperant == 1)) {
        if (comptador == 60) { //25 min: 60. test: 3
            printf("hem arribat als 25min\n");
            comptador = 0;
            esperant = 0;
        } else {
            comptador++;
            printf("rele1*\n");
            digitalWrite (RELE1, 1);
            delay(20000);
            digitalWrite (RELE1, 0);
            delay (5000);    
        }
    }
     

    if (esperant2 == 1) {
        if (comptador2 <= 1440) { //4 hores: 1440. test: 15
            delay (5000);
            comptador2++;
        } else { //s'ha omplert els dipòsits durant una hora i mitja, i ja podem tancar
            printf("ja han passat 4 hores\n");
            printf("rele2\n");
            digitalWrite (RELE2, 1);
            delay (5000);
            digitalWrite (RELE2, 0);
            delay (5000);
            //ja no rego. Torno a començar el procés.
            regant = 0;
            esperant = 0;
            esperant2 = 0;
            comptador = 0;
            comptador2 = 0;
        }
    }

    delay (100);
}

int main (void)
{
    setup () ;
    for (;;)
    {
        waitCanviEstat () ;
    }
}

En aquesta versió del hardware el vailet està totalment separat a nivell electrònic, però comparteixen la mateixa capsa. Sembla ser que l'alternador del vailet ha espatllat la RPi A+ (TBD). Més motiu per fer una nova versió de hardware feta amb microcontrolador, no pas a amb la RPi.

Versió 4 de hardware (ATMEGA168)

la versió 3 funcionava correctament. Ara bé, si he utilitzat la RPi (finalment una A+) és perquè últimament estava desenvolupant i programant la RPi i fent interfaces amb els pins GPIO. Però si ens posem a pensar amb perspectiva, és massa hardware per al projecte que es vol realitzar. El millor és utilitzar directament un microcontrolador com el ATMega168 que ja havia utilitzat. És millor econòmicament i com a solució tècnica. És al cap i a la fi com utilitzar un Arduino però sense l'arduino, fent una placa a mida de les necessitats, i gravant el software al microcontrolador). Ja havia fet un projecte amb el ATMega168 en la primera versió de la màquina de marcianitos, quan vaig fer una interface USB per fer un gamepad, i en aquell cas ja vaig documentar de com es grava el xip (sense el cable FTDI).

Al cap i a la fi en aquest projecte tenim un interruptor d'entrada i dos pins de sortida que han d'habilitar dos relés.

Fent un resum de diversos projectes basats en ATMega168 la configuració bàsica per fer començar a funcionar un petit projecte amb el ATMega168 (AVR): ATMega168 pin mapping:

Un cop tenim dissenyat en el Eagle CadSoft el citcuit bàsic del ATmel168 (que ens pot servir de plantilla), ara només cal fer la interfície de l'interruptor del sensor de nivell, i els dos relés. Per cercar esquemes de com es connecten al ATmel168, en el Google no he de cercar per Atmel168 sinó que buscaré per Arduino, i així obtinc molts més exemples.

El botó el connecto el puc connectar amb la configuració normalment a 1 (que utilitza la resistència interna de pull-up i no cal cap resistència externa):

o bé normalment a 0 (que utlitza una resistència externa):

En el cas de connectar un relé sí que hi ha una diferència important amb la RPi. El Atmel168 té en els pins de sortida 5V que poden drive directament el relé. Per tant, no cal l'amplificació dels transistor que feia amb els pins GPIO.

software

Un bon tutorial introductori:

En el projecte de la interface USB d'un gamepad ja vaig programar codi escrit amb C per als microcontroladors ATMEL, i tinc el programador. Amb la qual cosa ja tinc les eines i els coneixements per compilar, només cal repassar amb aquest tutorial els coneptes específics del microcontrolador (rellotge, etc).

Finalment ja sé fer pampallugues d'un LED controlat amb un switch:

  • Atmel_ISP_MCU_programmer_ATmega._Programador_AVR_USBasp#Blink_LED

i ja puc migrar la v6 (software) basada en RPi A+, a la v7 (software) amb codi nadiu per a microcontrolador ATMega168.

rec_baga_v7.c:

/*
ATMEGA168
fuses:
sudo avrdude -b19200 -P usb -c usbasp -p m168 -U lfuse:w:0xE2:m -U hfuse:w:0xDF:m

avr-gcc -g -mmcu=atmega168 -c rec_baga_v7.c -Wa,-alh,-L -Os -o rec_baga_v7.o > rec_baga_v7.asm
avr-gcc -g -mmcu=atmega168 -Wl,-Map,rec_baga_v7.map -o rec_baga_v7.elf rec_baga_v7.o
avr-objdump -h -S rec_baga_v7.elf > rec_baga_v7.lst
avr-objcopy -j .text -j .data -O ihex rec_baga_v7.elf rec_baga_v7.hex
avr-size rec_baga_v7.elf
cat rec_baga_v7.hex
ja podem programar el xip:
sudo avrdude -b19200 -P usb -c usbasp -p m168 -U flash:w:rec_baga_v7.hex

// funcionament de l'electrovàlvula: http://www.infojardin.com/foro/showthread.php?t=17559
*/

#ifndef F_CPU
   #define F_CPU 8000000UL //el rellotge intern va a 8MHz
#endif

#include <avr/io.h>
#include <util/delay.h>

int estat_ev;
int regant;
int esperant;
int esperant2;
int comptador;
int comptador2;

int main(void)
{
	//setup del microcontrolador
	DDRD &= ~(1<<PD2); //Interruptor sensor de nivell. Tercer pin del PORTD as Input
	PORTD |= (1 << PD2);       // Enable pull-up for switch on PORTD bit 
	DDRD |= (1<<PD3); //RELE1. Quart pin del PORTD as Output
	DDRD |= (1<<PD4); //RELE2. Cinquè pin del PORTD as Output

	//valors inicials
    regant = 0;
    esperant = 0;
    comptador = 0;
    comptador2 = 0;

	delay(1000);

	while(1) //infinite loop
	{

	    //arriba aigua al sensor de nivell, s'obre el sensor (R=inf), i el pin valdrà 1. S'ha d'obrir la vàlvula
	    if ( ((PIND & (1<<PIND2)) == 1) && (regant==0) ) {
	        PORTD |= (1<<PD3); //RELE1 ON
	        delay(1000); //5000
	        PORTD &= ~(1<<PD3); //RELE1 OFF
	        delay(1000); //5000
	        //i ara està passant aigua... Però això s'ha de comprovar tres vegades cada 5 min.    
	        regant = 1;
	        esperant = 1;
	        esperant2 = 1; //estic regant
	        comptador = 0;
	    }

	    if ((regant == 1) && (esperant == 1)) {
	        if (comptador == 3) { //25 min: 60. test: 3
	            //hem arribat als 25min
	            comptador = 0;
	            esperant = 0;
	        } else {
	            comptador++;
	        	PORTD |= (1<<PD3); //RELE1 ON
		        delay(5000); //20000
		        PORTD &= ~(1<<PD3); //RELE1 OFF
		        delay(1000); //5000  
	        }
	    }

	    if (esperant2 == 1) {
	        if (comptador2 <= 15) { //4 hores: 1440. test: 15
	            delay (1000); //5000
	            comptador2++;
	        } else { //s'ha omplert els dipòsits durant una hora i mitja, i ja podem tancar
	            //ja han passat 4 hores
		        PORTD |= (1<<PD4); //RELE2 ON
		        delay(1000); //5000
		        PORTD &= ~(1<<PD4); //RELE2 OFF
		        delay(1000); //5000
	            //ja no rego. Torno a començar el procés.
	            regant = 0;
	            esperant = 0;
	            esperant2 = 0;
	            comptador = 0;
	            comptador2 = 0;
	        }
	    }

		delay (100);
	}
}

creat per Joan Quintana Compte, febrer 2015, juny 2015