4 votos

Cómo crear un interruptor táctil para utilizarlo con una Raspberry Pi

Estoy tratando de hacer mi propia lámpara de despertar. Tengo una lámpara con una gran base de metal para ocultar todos los componentes. También tengo un Kit de regulador de intensidad controlado por CC Velleman K8064 que he montado y está funcionando. Tengo una Raspberry pi para controlarlo todo (también planeo usar la Pi como un Dock Android)

Me gustaría que la base de la lámpara funcionara como un interruptor táctil para encender y apagar la lámpara. He probado a hacer un prototipo de interruptor táctil que he encontrado en www.talkingelectronics.com sin embargo al probarlo la lámpara siempre está encendida.

¿Puede alguien indicarme un diagrama de cableado de un interruptor táctil más sencillo que funcione con una raspberry pi?

7voto

Sammo034 Puntos 26

Si tienes acceso de bajo nivel a los GPIO's de Raspy, hay una manera fácil de hacerlo, todo lo que necesitas es un reisistor. Sí, has leído bien.

Sólo hay que conectar una clavija a la base de la lámpara y atar la resistencia entre la base y \$V_{cc}\$ , ese es el riel de 3.3V, recuerda que los pines no son tolerantes a 5 voltios.

Aquí está en pseudocódigo lo que necesitas hacer del lado del software:

while(1) {
    timer.reset()
    gpiox.direction = GPIO.OUT
    gpiox.write(GPIO.LOW)
    while(gpiox.read != GPIO.LOW)
    gpiox.direction = GPIO.IN
    timer.start()
    while(gpiox.read == GPIO.LOW)
    timer.stop()
    out = timer.read()
    if (out > THRESHOLD)
        pressed = true
    else
        pressed = false
}

¿Qué ocurre? En primer lugar, reinicias un temporizador. Tiene que ser rápido, algo así como un temporizador de la cpu que se incrementa en cada ciclo de reloj más o menos.

Estableces tu pin como ouput, escribes un cero en él y luego esperas a que realmente se ponga a cero. Eso puede hacerse dentro de la escritura dependiendo del driver/HAL que estés usando, pero para que esto funcione necesitarás no usar ninguno. Después de que el pin esté realmente a cero lo pones como entrada y arrancas el temporizador. La capacitancia parásita de la base de la lámpara y de la entrada del pin y, si está presente, tu dedo comienza a cargarse a través de la resistencia. Cuando el voltaje a través de la capacitancia se lee como un alto lógico paras el temporizador: el truco es que si tu dedo está presente la capacitancia es mayor por lo que tarda mucho más en cargarse hasta el uno lógico, por lo que puedes saber la presencia del dedo leyendo el temporizador.

¿Qué problemas puede encontrar?
Bueno, tal vez no tengas un acceso de tan bajo nivel a los pines GPIO de la raspa... Pero eso es algo que tienes que averiguar. Tal vez no tengas un temporizador de tan bajo nivel. El mayor problema es que tal vez la capacitancia de la base de la lámpara es muy grande para que al tocarla no haya una gran diferencia.

De todos modos, vale la pena probar este método porque cuesta unos pocos céntimos. Sobre la resistencia, quieres algo que cargue la capacitancia lo suficientemente lento para que tu temporizador pueda realmente medir el tiempo que tarda, pero lo suficientemente rápido para poder realmente muestrear el "botón" quizás 20 veces por segundo. La lámpara más el cuerpo más la clavija pueden ser alrededor de 1nF, usted quiere un \$\tau=RC\$ de unos 20ms por lo que $$R=\frac{\tau}{C}=\frac{20\cdot10^{-3}s}{1\cdot10^{-9}F}=20M\Omega$$ Bueno, eso es demasiado. Necesitarás un temporizador rápido e irás por algo alrededor de \$1M\Omega\$

¿Pero cómo funciona?
Todo lo que nos rodea tiene una capacidad con respecto a otra cosa. Es común referirse a la tierra como "algo más", por lo que todo tiene una capacitancia con respecto a la tierra. Dicho esto, consideremos el siguiente circuito:

schematic

simular este circuito - Esquema creado con CircuitLab

\$C_{in}\$ es la capacitancia de la entrada del puerto digital más la capacitancia de la base de la lámpara hacia tierra, normalmente unos 100pF, mientras que \$C_H\$ (como en "humano") es la capacidad que tenemos hacia la tierra. Cuando se toca la base de la lámpara se cierra el interruptor etiquetado como 'toque', mientras que la frambuesa sólo puede actuar sobre \$SW_{in}\$ . Se comienza con \$SW_{in}\$ cerrado, así que \$V_{C_{in}} = 0\$ . Cuando la frambuesa abre \$SW_{in}\$ la capacitancia de entrada comienza a cargarse hasta \$V_{cc}\$ a través de \$R_p\$ con un coste de tiempo \$\tau=R_p\cdot C_{in}\$ . La ley V(t) es bastante conocida: $$V_{C_{in}}(t) = V_{cc}(1-e^{-\frac{t}{\tau}})$$ La frambuesa detectará una entrada alta cuando el voltaje alcance algo alrededor de \$\frac{2}{3}V_{cc}\$ así que eso tomará:

$$t_{HIGH}=\tau\ln\Big(\frac{V_{cc}}{V_{cc}-\frac{2}{3}V_{cc}}\Big)=\tau\ln(3)$$

En este punto se detendría el temporizador y se comprobaría cuánto tiempo ha tardado: si es algo alrededor de \$1.1\tau\$ no se produce ningún toque. La frambuesa se cerraría \$SW_{in}\$ y esperar a que el condensador se descargue, es decir, esperar a que el pin lea cero, para finalmente abrir el interruptor y empezar de nuevo.
Pero, ¿y si cerramos \$SW_h\$ ? Bueno, \$\tau\$ cambios: \$\tau'=R_p\cdot (C_{in}+C_H)\$ ahora, y si \$C_{in}\$ es lo suficientemente pequeño, y espero que lo sea, \$tau'\$ puede ser incluso diez veces mayor que \$\tau\$ . La frambuesa iniciará su temporizador pero ahora tardará bastante más en leer una entrada alta:

$$t'_{HIGH}=...=\tau'\ln(3)\approx 10\cdot\tau\ln(3)=10\tau$$

La penúltima relación es una especie de relación "esperamos que sea verdad". Cuando la frambuesa finalmente leerá una entrada alta, detendrá el temporizador y dirá "bueno, eso tomó mucho tiempo, ¡vamos a encender la luz para mi programador! Y eso es todo.

¿Y por qué funciona su solución?
Esto se debe a que tu cuerpo está actuando como una antena. Básicamente estás alimentando la frecuencia de la red en el pin de entrada de la frambuesa, y eso puede hacer que la entrada se lea como una, pero eso sería una forma poco fiable de alternar tu lámpara. Por lo que puedo leer tu sistema está funcionando de forma bastante aleatoria... Intenta hacerlo de la forma adecuada.

0 votos

Me gusta tu idea, sin embargo, ¿crees que la Raspberry Pi será lo suficientemente potente como para ser utilizada como interruptor táctil y pwm? También esperaba utilizar la Pi como un Dock Android para poder reproducir música también.

0 votos

Seguro que es lo suficientemente potente, la pregunta es: ¿puede operar a un nivel tan bajo?

0 votos

Creo que sí, lo probaré y te informaré.

4voto

agentcd Puntos 41

He escrito una implementación en C (ver más abajo) basada en el pseudocódigo de La respuesta de Vladimir .

Funciona como un encanto en mi Pi Zero W, lo estoy usando para cambiar la luz de fondo de una pantalla LCD tocando su bisel. Utilicé una resistencia de 1MΩ, que tarda ~20μs en cargarse cuando está en reposo y 45-110μs cuando se toca. Incluso puede detectar el tacto a través del revestimiento no conductor del bisel, por lo que la Pi debería estar protegida de las descargas estáticas.

Hasta ahora no he tenido ningún problema con los toques repetidos que no se detectan.


// Filename: touch_toggle.c

/* Compile with gcc -lwiringPi touch_toggle.c -o touch_toggle
 * Run with sudo ./touch_toggle
 * Do not touch while starting the program so it can initialize properly
 */

/* SCHEMATIC
 * 
 * ,----------------------,
 * |   Raspberry Pi       |
 * |                      |
 * | TOUCH_PIN        VCC |
 * `-----+-------------+--'
 *       |             |
 *       +---[1MΩ]-----+
 *       |
 *   Touch surface
 * 
 */
#include <wiringPi.h>
#include <stdio.h>
// Note: Pin numbers are in BCM notation (pin number format is set by wiringPiSetupGpio)
// See pinout.xyz
#define TOUCH_PIN 20
#define OUTPUT_PIN 21
// How long to pull the touch pin low
// Controls loop speed and affects CPU usage
#define DELAY 15

int main(void) {
    wiringPiSetupGpio();
    unsigned int timer;
    unsigned int threshold = 0;
    unsigned char state = 0; // Currently being touched?
    unsigned char out_state = 0; // State of output pin
    signed char hysteresis = 0; // Counter for consecutive readings
    pullUpDnControl(TOUCH_PIN, PUD_OFF); // Not sure if this would ever be set, just to be safe
    pinMode(OUTPUT_PIN, OUTPUT);
    digitalWrite(OUTPUT_PIN, out_state);

    // Measure capacitance to calibrate touch sensitivity
    for (char i=0; i < 10; i++) {
        // Pull touch pin low to discharge
        pinMode(TOUCH_PIN, OUTPUT);
        digitalWrite(TOUCH_PIN, LOW);
        // Wait a bit
        delay(DELAY);
        // Start timer
        timer = micros();
        pinMode(TOUCH_PIN, INPUT);
        // Wait for pin to become high
        while (!digitalRead(TOUCH_PIN));
        // Get time elapsed
        threshold += micros() - timer;
    }
    // Set threshold to twice the average capacitance
    threshold /= 5; // This number might need to be increased if the touch is not sensitive enough
    printf("threshold=%d\n",threshold);

    while (1) {
        pinMode(TOUCH_PIN, OUTPUT);
        digitalWrite(TOUCH_PIN, LOW);
        delay(DELAY);

        timer = micros();
        pinMode(TOUCH_PIN, INPUT);
        while (!digitalRead(TOUCH_PIN));
        timer = micros() - timer;

        if (timer > threshold) {
            if (hysteresis < 0) hysteresis = 0;
            hysteresis++;
        } else {
            if (hysteresis > 0) hysteresis = 0;
            hysteresis--;
        }

        // 3 consecutive readings are required to toggle touch state
        if (hysteresis > 2) {
            if (state == 0) {
                out_state = !out_state;
                digitalWrite(OUTPUT_PIN, out_state);
                state = 1;

                // Print when touch starts and the measured value
                // Can be commented out
                printf("START %d", timer);
                fflush(stdout); // Display instantly (by default only flushed on newline)
            }
            hysteresis = 0;
        } else if (hysteresis < -2) {
            if (state == 1) {
                state = 0;

                printf(" END\n");
            }
            hysteresis = 0;
        }
    }
    return 0;
}

Código también en: https://pastebin.com/FrsYCtXu

1voto

Paul Nendick Puntos 96

Gracias a Vladimir por su respuesta que me permitió llegar a esta solución.

schematic

simular este circuito - Esquema creado con CircuitLab

El código python es el siguiente

import time  
import RPi.GPIO as GPIO  

GPIO.setmode(GPIO.BCM)  

touchSwitch = 23  
outputPin = 24  

GPIO.setup(touchSwitch, GPIO.IN)
GPIO.setup(outputPin, GPIO.OUT)  
GPIO.output(outputPin, False)  

while True:  
    switchTouched = GPIO.input(touchSwitch)  

    if switchTouched:  
        print "touch detected"  
        time.sleep(0.3) # sleep again here so not to toggle the lamp to quickly  
    else:  
        print "not touched"  

    time.sleep(0.15) # 0.10 seems to give the best results but 0.15 uses less CPU  

El problema con esta solución es que, al sostener la placa táctil después de entre 5 y 12 detecciones de un toque, el toque no será detectado por un tiempo y luego será detectado de nuevo. Dado que sólo lo estoy usando para una lámpara táctil la solución es lo suficientemente buena para mis necesidades.

0 votos

Es posible que desee tocar la tierra (tornillo de la placa de pared o similar) antes de tocar la lámpara. Sólo para evitar que una chispa estática arruine tu entrada GPIO23. Felicitaciones, siempre es divertido llegar a una solución muy simple.

0 votos

@Marla ¿crees que debería usar una resistencia para proteger la R-Pi? El único problema que vería es que el voltaje solo llega a ~0v5 al tocar la lámpara. Lo cual es apenas lo suficientemente alto para registrar un alto voltaje en el R-Pi.

1voto

user50582 Puntos 23

Esto parece funcionar sin retraso (usando el circuito de TheLukeMcCarthy pero con el GPIO 18 como entrada y el GPIO 17 como pin de salida)

#include <wiringPi.h>
int main (void)
{
    register unsigned char on = 0 ;
    wiringPiSetup () ;
    pinMode ( 1, INPUT) ;
    pinMode ( 0, OUTPUT) ;
    pinMode ( 4, OUTPUT) ;
    digitalWrite ( 4, LOW) ;
    digitalWrite ( 0, LOW) ;

    while ( 1 )
    {
            if ( digitalRead (1) )
            {
                    if ( on )
                    {
                            on=0;
                            digitalWrite ( 4, LOW) ;
                    }
                    else
                    {
                            on=1;
                            digitalWrite ( 4, HIGH) ;
                    }
                    delay ( 300 ) ;
            }
            delay ( 50 ) ;
    }

    return 0 ;
}

0 votos

Tal vez valga la pena añadir una referencia en esta respuesta al circuito anterior para que, si el orden de las respuestas cambia, quede más claro con qué se relaciona.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X