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

Estoy tratando de hacer mi propia lámpara de despertador. Tengo una lámpara con una base de metal grande para ocultar todos los componentes. También tengo un kit de atenuación controlada por CC Velleman K8064 que armé y funciona. Tengo una Raspberry pi para controlarlo todo (también planeo usar la Pi como base de Android)

Me gustaría que la base de la lámpara funcione como un interruptor táctil para encender y apagar la lámpara. He intentado probar un interruptor táctil que encontré en www.talkingelectronics.com , sin embargo, cuando lo pruebo, la lámpara siempre está encendida.

¿Alguien puede señalarme la dirección de un diagrama de cableado de un interruptor táctil más simple que funcionará con una frambuesa pi?

Respuestas (4)

Si tiene acceso de bajo nivel a los GPIO ásperos, entonces hay una manera fácil de hacerlo, todo lo que necesita es un resistor. Sí, leíste eso bien.

Simplemente conecte un pin a la base de la lámpara y ate la resistencia entre la base y V C C , ese es el riel de 3.3V, recuerde que los pines no son tolerantes a 5 voltios.

Aquí está en pseudocódigo lo que necesita 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
}

¿Lo que está sucediendo? En primer lugar, reinicia un temporizador. Tiene que ser rápido, algo así como un temporizador de CPU que se incrementa en cada ciclo de reloj más o menos.

Configura su pin como salida, escribe un cero en él y luego espera a que realmente llegue a cero. Eso se puede hacer dentro de la escritura dependiendo del controlador/HAL que esté usando, pero para que esto funcione, no necesitará usar ninguno. Después de que el pin es realmente cero, lo configura como una entrada y comienza el temporizador. La capacitancia parásita de la base de la lámpara y la entrada del pin y, si está presente, su dedo comienza a cargarse a través de la resistencia. Cuando el voltaje a través de la capacitancia se lee como una lógica alta, detiene el temporizador: el truco es que si su dedo está presente, la capacitancia es mayor, por lo que lleva mucho más tiempo cargar la lógica, por lo que puede decir el presencia de los dedos leyendo el temporizador.

¿Qué problemas podría encontrar?
Bueno, tal vez no tengas un nivel tan bajo de acceso a los pines ásperos de GPIO... Pero eso es algo que debes 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 sea muy grande, por lo que tocarla no supondrá una gran diferencia.

De todos modos, vale la pena probar este método porque cuesta unos centavos. Acerca de la resistencia, desea algo que cargue la capacitancia lo suficientemente lento como para que su temporizador mida realmente el tiempo que lleva, pero lo suficientemente rápido como para poder probar el "botón" tal vez 20 veces por segundo. La lámpara más el cuerpo más el pin pueden estar alrededor de 1nF, desea un τ = R C de unos 20 ms por lo que

R = τ C = 20 10 3 s 1 10 9 F = 20 METRO Ω
Bueno, eso es demasiado. Necesitarás un temporizador rápido e ir por algo alrededor. 1 METRO Ω

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

esquemático

simular este circuito : esquema creado con CircuitLab

C i norte es la capacitancia de entrada del puerto digital más la capacitancia de la base de la lámpara hacia tierra, generalmente alrededor de unos 100pF, mientras que C H (como en 'humano') es la capacidad que tenemos hacia el suelo. Cuando toca la base de la lámpara, cierra el interruptor con la etiqueta 'toque', mientras que la frambuesa solo puede actuar sobre S W i norte . empiezas con S W i norte cerrado, entonces V C i norte = 0 . Cuando se abre la frambuesa S W i norte la capacitancia de entrada comienza a cargarse V C C a través de R pag con una constante de tiempo τ = R pag C i norte . La ley V(t) es bastante conocida:

V C i norte ( t ) = V C C ( 1 mi t τ )
La frambuesa detectará una entrada alta cuando el voltaje alcance algo alrededor 2 3 V C C , por lo que tomará:

t H I GRAMO H = τ en ( V C C V C C 2 3 V C C ) = τ en ( 3 )

En este punto, detendría el temporizador y verificaría cuánto tiempo tardó: si hay algo alrededor 1.1 τ no se está produciendo ningún contacto. La frambuesa cerraría S W i norte y esperar a que se descargue el capacitor, es decir, esperar a que el pin marque cero, para finalmente abrir el interruptor y comenzar de nuevo.
Pero y si cerramos S W h ? Bien, τ cambios: τ = R pag ( C i norte + C H ) ahora, y si C i norte es lo suficientemente pequeño, y con suerte lo es, t a tu incluso podría ser diez veces más grande que τ . La frambuesa iniciará su temporizador, pero ahora llevará mucho más tiempo leer una entrada alta:

t H I GRAMO H = . . . = τ en ( 3 ) 10 τ en ( 3 ) = 10 τ

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

¿Y por qué funciona tu solución?
Eso es porque tu cuerpo está actuando como una antena. Básicamente, está 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 sola, pero esa sería una forma poco confiable de alternar su lámpara. Por lo que puedo leer, su sistema está funcionando de manera bastante aleatoria... Inténtelo de la manera adecuada.

Me gusta su idea, sin embargo, ¿cree que la Raspberry Pi será lo suficientemente potente como para usarse como un interruptor táctil y un pwm? También esperaba usar el Pi como un Android Dock para poder reproducir música también.
Seguro que es lo suficientemente potente, la pregunta es: ¿puedes operar a un nivel tan bajo?
Creo que sí, lo probaré y te responderé.
Solo estoy probando esto y tengo algunos problemas para entender el lado electrónico de las cosas. ¿Tengo razón al pensar que cuando toco la lámpara bajará el voltaje? Si es así, ¿no debería la salida comenzar alta y luego se toca la lámpara y los voltajes bajan, la Raspberry Pi debería encender la lámpara?
@TheLukeMcCarthy no tienes razón. El voltaje es oscilante, cuando toca la base, la constante de tiempo cambia. Si está muy interesado en esto, puedo incluir algunos gráficos en los próximos días.
Estoy interesado en saber más, sin embargo, eso suena como un montón de problemas para ti. Si conoce un sitio web bueno y simple que explique el concepto, sería un buen comienzo.
Me complacería ayudar y mejorar mi respuesta, ya que también está obteniendo algunos votos y las personas en la web pueden terminar aquí de vez en cuando. Lo haré tan pronto como pueda.
@TheLukeMcCarthy aquí tienes

Escribí una implementación en C (ver más abajo) basada en el pseudocódigo en la respuesta de Vladimir .

Funciona de maravilla en mi Pi Zero W, lo estoy usando para alternar la luz de fondo de una pantalla LCD tocando su bisel. Utilicé una resistencia de 1 MΩ, que tarda ~20 μs en cargarse cuando está inactiva y entre 45 y 110 μs cuando se toca. Incluso puede sentir el tacto a través del revestimiento no conductor del bisel, por lo que la RasPi debe protegerse de descargas estáticas.

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


// 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

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

esquemático

simular este circuito : esquema creado con CircuitLab

El código de 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 sujetar la placa táctil después de entre 5 y 12 detecciones de un toque, el toque no se detectará durante un tiempo y luego se volverá a detectar. Dado que solo lo estoy usando para una lámpara táctil, la solución es lo suficientemente buena para mis necesidades.

Es posible que desee tocar tierra (tornillo de placa de pared o similar) antes de tocar la lámpara. Solo para evitar que una chispa estática arruine su entrada GPIO23. Felicitaciones, siempre es divertido llegar a una solución muy simple.
@Marla, ¿crees que debería usar una resistencia para proteger el R-Pi? El único problema que vería es que el voltaje solo llega a ~ 0v5 al tocar la lámpara. Lo cual es lo suficientemente alto como para registrar un alto voltaje en el R-Pi.

Esto parece funcionar sin demora (usando el circuito de TheLukeMcCarthy pero con GPIO 18 como entrada y 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 ;
}
Podría valer la pena agregar 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.