38 votos

Añade un token de hardware pasivo mediante una clavija de 3,5 mm

Tengo una caja que hice para mi sobrina, que le permite intercambiar mensajes de voz conmigo. Funciona con una Raspberry Pi y cuenta con dos botones, un LED, un micrófono y un altavoz.

the box

Ahora, para las Navidades quiero que mi sobrina pueda intercambiar estos mensajes de voz con varios amigos (4, 8 o 16) y familiares conectando un token de hardware al dispositivo, con una foto de esa persona.

Ahora estoy buscando la forma más sencilla de añadir esta funcionalidad.

  • Preferiblemente utilizando una toma de 3,5 mm porque son fáciles de conseguir en dispositivos / auriculares usados
  • Preferiblemente un dispositivo pasivo (Condensadores + Resistencias)
  • Preferiblemente conectándolo directamente a la Raspberry Pi
  • Preferiblemente sin utilizar un convertidor AD, ya que la Raspberry Pi no lo lleva incorporado.
  • Fácil de usar por un niño de 3 años

Así, utilizando un enchufe de 3,5 mm con 3 clavijas, podría añadir la alimentación a una de ellas y conectar o desconectar las otras dos de esa clavija, lo que me dejaría con dos bits, resultando en 4 personas (además de mí por defecto, si el enchufe proporciona un interruptor cuando se inserta una clavija).

Si tuviera un convertidor analógico-digital podría añadir un divisor de tensión a los tres pines y utilizar la tensión como indicador. Sin embargo, la Raspberry Pi no tiene eso incorporado, así que estoy buscando una manera inteligente de lograr esto usando uno de los pines GPIO.

relatives-plug

49voto

VillageTech Puntos 726

Utiliza el bus de 1 hilo y cualquier chip de 1 hilo dentro del botón. Escribí "cualquier", porque cada chip de 1 hilo tiene su propia y única dirección de hardware, por lo que todo lo que necesitas en el lado de RPi es comprobar que el chip fue detectado, por ejemplo, utilizando el comando bash:

ls /sys/bus/w1/devices/

y comprobando en su salida la existencia de un subdirectorio con el nombre exacto de esta dirección de hardware.

En el lado HW de la RPi sólo necesitas conectar el jack adicional a los pines de E/S adecuados (GND + DATA). No hay necesidad de utilizar ninguna conexión de alimentación aquí, por lo que parece ser más seguro para RPi que una solución similar, que utiliza I2C (I2C necesita tener una línea de alimentación dedicada, lo que hace que el riesgo de daño RPi en caso de cortocircuito).

EDIT: Para que funcione de forma fiable debes añadir la resistencia pull-up de 4,7kOhm entre la línea DATA y Vcc (3,3V).

Puede utilizar el chip más popular y barato DS18B20, que además ofrece la posibilidad de medir la temperatura ambiente ;), o el DS2401, que además ofrece un número de serie único.

8voto

shash Puntos 668

Yo haría de cada "ficha" un dispositivo I2C. Utilizando un conector de tipo "tip-ring-ring-shank" tendrías 4 conductores: tierra, alimentación, datos y reloj. Cada token tendría que tener su propia dirección I2C, y escribirías una función que detectara los dispositivos en un bus I2C.

6voto

EinarA Puntos 71

Esto se puede hacer con un conjunto de resistencias y condensadores en paralelo, cada par con un producto RC diferente. Se debe poner la salida de la gpio en alto durante un tiempo suficiente, luego ponerla en una entrada y medir el tiempo que tarda la tapa en descargarse. Con constantes de tiempo que van desde los microsegundos hasta los milisegundos posibles, puedes distinguir cualquier número de personas.

6voto

SAID Puntos 1

Para que quede claro. No odio la idea de los tokens de 1 hilo. De hecho, me gusta. Utilizar 1 hilo de esta manera es exactamente el tipo de cosas para las que se hizo el bus de 1 hilo. Mi preocupación es que el proyecto es de grado de juguete; baja seguridad/presupuesto. Cuando añades las consideraciones de durabilidad, queda claro que puede haber deseo de otras opciones que no impliquen chips especializados. Lo que trae a colación lo siguiente.


Como han dicho otros, la respuesta casi óptima es utilizar el retardo de tiempo RC. El único componente del lado de la ficha sería un condensador.

schematic

simular este circuito - Esquema creado con CircuitLab

¿Por qué? Porque las fichas RC ...

  • no son vulnerables a la ESD. (Edición: Si somos sinceros y prácticos)
  • puede utilizar sólo dos cables.
  • será muy barato y sencillo.
  • tienen mucho espacio para más de 8 personas.

Para la electrónica del lado de la Pi, sólo necesitas dos pines GPIO; un pin de carga, y un pin de detección. También querrás/necesitarás un circuito de carga rápida, que explicaré después del gráfico.

schematic

simular este circuito

El circuito de carga rápida puentea la resistencia de temporización con una resistencia mucho más pequeña. Esto permite que el condensador en el token se cargue casi instantáneamente (bueno, hasta donde los usuarios pueden ver de cualquier manera). También hace que el pin sensor no vea el pin de carga directamente. En su lugar, verá estrictamente el voltaje de los condensadores. Los valores no son críticos, sin embargo, el diodo realmente necesita ser un diodo Schottky/de pequeña señal, o cortará mucho la parte superior de los 3,3v. Esto también podría ser reemplazado con un transistor a 5v, pero el pin de entrada puede necesitar ser protegido.

Después de eso, es todo código, que es bastante trivial también.

(Nota: Se me ocurrió esto en el momento. No se ha probado en absoluto. Se aplican los descargos de responsabilidad habituales; pise bajo su propio riesgo, ajústelo a su gusto, etc. etc.)

import RPi.GPIO as GPIO
import time

#Setup some pins
GPIO.setup(<charging_pin>, GPIO.OUT)
GPIO.setup(<sensing_pin>, GPIO.IN)

# Set "charging" pin to 3.3v
GPIO.output(<charging_pin>,TRUE)

# Wait some time for the capacitor to be fully charged
time.sleep(1.0)

# Set the charging pin to 0v
GPIO.output(<charging_pin>,FALSE)

#count how long the sense pin stays high
counter=0
while GPIO.input(<sensing_pin>) == GPIO.HIGH:
    counter += 1
    time.sleep(0.01)

# Finally our counter is going to have a value proportional to the RC
# time delay of our token. Window match it to bounds, and we're golden.

if (counter > a) and (counter < b):
    print "Is person X"

if (counter > b) and (counter < c):
    print "Is person Y"

[...]

Por último (y sólo como un pensamiento de lado / después) esta misma cosa no sería demasiado terrible reutilizado como un probador de condensadores / medidor, ya que es básicamente todo lo que estamos haciendo aquí.


Crítica

Esto es mucho más difícil que una solución de un solo cable. La solución de 1 cable es simplemente plug-and-play. RC tendrá un montón de cableado y soldadura y así sucesivamente. El circuito del lado de la Pi será tan complejo que el coste total será mayor que el de un solo cable.

No es del todo cierto.

Creo que he mostrado arriba lo trivial que es la solución RC; ~13 líneas de código, 3 componentes del lado Pi, y 1 condensador por persona. Bastante simple en realidad.

Hay que admitir que la configuración de 1 cable es igualmente bastante trivial, pero eso es porque estás comprando tu salida. Cada ficha de 1 hilo añade otro $0.5 chip, where as every RC token added is just a $ 0,01 condensador.

Casi tan simple, pero una fracción del costo. Está bastante claro quién es el ganador aquí.

Su idea es vulnerable a la estática. La Raspberry Pi es vulnerable a la estática. Esto es vulnerable a la estática. Esto es vulnerable a la estática. Tu perro es vulnerable a la estática. etc. etc. etc.

¡Noticias de última hora! Todo es técnicamente vulnerables a la estática/ESD, ¡incluso tú! ¿No me crees? Ve a un campo abierto con un paraguas y demuéstrame que tengo razón. (PD: no lo hagas)

Sin embargo, si no nos hacemos los listillos, entonces tenemos líneas obvias que trazar. El punto de sentido común está en los circuitos integrados CMOS, ya que eso es lo que -en un sentido muy real y práctico- es en realidad vulnerables a la estática. Lo divertido es que podemos eliminar este problema por completo para el token al no usar un IC en absoluto.

Los pasivos son igual de fáciles para la tarea presentada, y más robustos contra la ESD. punto. Por eso es posible que se quiera reconsiderar los otros métodos.

Ahora, por supuesto, la Pi siempre va a ser vulnerable a la electricidad estática, no hay manera de evitarlo a menos que se quite la Pi. Por supuesto, eso tampoco es práctico. Así que lo mejor que podemos hacer es lo que todo el mundo hace con esos limones. Primero, ponemos el enchufe en el lado de la Pi con un anillo de protección adecuado a tierra. Segundo, podemos volvernos locos con diodos TVS y demás. En resumen...

Ahora sólo tenemos que proteger un (1) dispositivo con ESD, así que vuélvete loco si quieres.

Las pasivas simples no son seguras. Son fáciles de falsificar/copiar/hackear/etc.

(-_-) ... esto es un juguete para niños FFS ... ¿por qué estamos trayendo la seguridad de la información en esto? Aún así, ¿realmente crees que las direcciones de hardware de 1 hilo, (o incluso peor, las direcciones SPI/I2C) son un buen mecanismo para reforzar la seguridad? ¿De verdad? ¿Hablas en serio?

OK, que tal esto entonces... llevar esa idea a security.SE. y ver que dicen. (Protip: Lleva vendas, te romperán una nueva).

No. El SOLO El momento en que un cable es seguro, es si se utiliza un token/autenticador seguro. [ 1 ] . Entonces puede ser seguro para el estado-nación... aparte del hecho de que el atacante seguro que tiene acceso físico al dispositivo de autenticación...

La seguridad no es un problema aquí, está totalmente fuera del tema.


Editar: He dividido el resto en su propia respuesta, ya que eso es lo que era; una respuesta diferente.

3voto

John Kuehne Puntos 56

Así es como finalmente puse en práctica el fabuloso enfoque esbozado por VillageTech .

Hardware

Cableado

El pin por defecto para los dispositivos Onewire en el Pi es GPIO 4 . Así que conecté GND al manguito de la clavija y conectó la punta al mencionado pin GPIO.

hardware

Una ficha

Todo lo que necesito para una ficha es el chip DS18B20 y un jack de 3,5mm. Entonces suelda el pin GND y VCC del chip juntos y conéctalo a la funda. Añade un poco de tubo retráctil al pin del medio para evitar cortocircuitos y conéctalo a la punta del jack.

Ambas tomas funcionan las que tienen dos anillos y la que sólo tiene la punta.

token

Resistencia pull up

Decidí no usar una resistencia pull up externa, ya que la Pi tiene resistencias pull up internas.

No friamos los auriculares

Como flawr Se ha señalado correctamente el hecho de que si parece una toma de audio de 3,5 mm, la gente podría verse tentada a introducir los auriculares.

Siempre que utilicemos energía parásita, en la que sólo un cable de tierra y una salida GPIO de alta impedancia estén expuestos al enchufe, deberíamos estar seguros, ya que no tenemos un V DD línea que podría crear un cortocircuito a través de la baja resistencia de los auriculares.

Configuración

Añade la siguiente línea a /boot/config.txt :

dtoverlay=w1-gpio

Hay más opciones. Puede encontrar más en el /boot/overlays/README de su Pi.

Algunas fuentes sugieren añadir los dos módulos w1-gpio y w1_therm à /etc/modules Sin embargo, descubrí que la entrada de la superposición del árbol de dispositivos en el boot/config.txt era suficiente para mis propósitos.

Ahora reinicie el dispositivo.

Añadir un pullup por software en python:

import RPi.GPIO as GPIO
GPIO_PIN_NUMBER=14
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_UP)

En cuanto creé este pull up pude detectar los tokens en /sys/bus/w1/devices/ con el 28 en otra ventana de terminal:

$ ls /sys/bus/w1/devices/
28-00000aabbccd  w1_bus_master1

Después de unos 10 segundos, las entradas en devices desaparecería. Tuve que crear la siguiente configuración, para que los dispositivos desaparecieran después de un segundo más o menos:

sudo nano /etc/modprobe.d/w1.conf

Ahora añade el contenido al archivo y reinicia el dispositivo de nuevo:

options wire timeout=1 slave_ttl=1

En mi configuración este archivo no existía previamente.

Software

Creé una clase de python que buscara cambios en el sistema de archivos y me dijera si un nuevo token estaba conectado o si todos los tokens estaban desconectados.

import os
import thread
import time
from datetime import datetime, timedelta

class W1Service(object):
    __instance = None

    def __new__(cls):
        # Singleton initializer
        if W1Service.__instance is None:
            W1Service.__instance = object.__new__(cls)
        return W1Service.__instance

    on_all_token_removed = None
    on_token_added = None
    is_scanning = False

    def start_scan(self, delay=10):
        return thread.start_new_thread(self.scan, (delay,))

    def scan(self, delay=10):
        W1Service.is_scanning = True
        last_token = None
        current_token = ''
        current_token_timestamp = datetime.now() - timedelta(days=1)

        while W1Service.is_scanning:
            file = open('/sys/devices/w1_bus_master1/w1_master_slaves')
            all_tokens = file.readlines()
            file.close()

            no_token_attached = len(all_tokens) == 0 or 'not found.\n' in all_tokens
            if no_token_attached and self.on_all_token_removed and current_token != last_token:
                self.on_all_token_removed()
                current_token = None
                last_token = None

            for line in all_tokens:
                current_token = line.split("\n")[0]
                time_diff = datetime.now() - current_token_timestamp
                if self.on_token_added and last_token != current_token and time_diff.seconds >= 3:
                    # Test if the token is still attached
                    if os.path.exists('/sys/bus/w1/devices/' + current_token + '/w1_slave'):
                        self.on_token_added(current_token)
                        last_token = current_token
                    else:
                        current_token = None
                else:
                    current_token = None

            time.sleep(delay)

    def stop_scan(self):
        W1Service.is_scanning = False

Ahora utilizar el servicio creado es bastante sencillo:

import time
import w1_service

def token_added(token):
    print("Connected %s" % token)

def all_token_removed():
    print('All tokens were removed')

service = w1_service.W1Service()
service.on_token_added = token_added
service.on_all_token_removed = all_token_removed
service.start_scan(0)

while True:
    # The scan runs in a seperate thread
    time.sleep(1)

Esto producirá la siguiente salida al insertar diferentes fichas

All tokens were removed
Connected 28-00000aabbccd
All tokens were removed
Connected 28-00000ffddeea
All tokens were removed
Connected 28-00000bbddaa1
Connected 28-00000ffddeea
All tokens were removed
Connected 28-00000bbddaa1
All tokens were removed

Tenga en cuenta que mi código tiene en cuenta el hecho de que en mi configuración sólo se puede añadir un token a la vez. Así que sólo el token más nuevo es interesante para mí. Si se añaden múltiples tokens, que el protocolo onewire soporta muy bien, el código tendría que ser actualizado.

Aplicación

Ahora, cada vez que se inserta un token, éste se relaciona con una persona a la que mi nice puede enviar y recibir mensajes

application

Notas y otras consideraciones

En teoría, los tokens de Onewire podrían añadirse en paralelo, lo que ofrecería nuevas capacidades como el chat de grupo o similares. Así que podrías conectar diez tokens en un solo GPIO.

También me gusta el planteamiento con el enfoque R/C pasivo, que es muy pragmático y sencillo de montar también. Puede que lo pruebe en otro proyecto. Sin embargo, un amigo tenía algunos

Consideré añadir iBeacons como tokens, pero entonces tendría que tener en cuenta los diferentes RSSI de los tokens y no estaría 100% claro qué token estaba activo en cada momento.

Un amigo me sugirió que añadiera un lector de tarjetas y que utilizara tarjetas SD antiguas de 1 GB para fotos que pudieran tener la imagen pegada en la parte delantera. La tarjeta podría contener toda la información sobre la persona más un saludo personalizado o algo parecido. Lo mismo se podría hacer con viejas memorias USB como fichas.

Fue muy divertido ponerlo en práctica y ver el interés que despertó mi pregunta en la gente. Os doy las gracias a todos y os deseo un bonito 0x1414 (=2020) :-)

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