Bareconductive: Convirtiendo el papel en un dispositivo táctil

por | Feb 24, 2020 | Arduino, Bareconductive, IoT | 0 Comentarios

Bareconductive Introducción Logo Thumb

¿Qué es Bareconductive?

Bareconductive es una empresa de Inglaterra dedicada a fabricar productos electrónicos impresos. El más llamativo de todos ellos quizá sea la pintura conductiva que ofrecen, junto con el microcontrolador que han diseñado (compatible con Arduino) específicamente para trabajar con su pintura. Además, tienen disponibles varios kits y packs de desarrollo para que la iniciación con sus productos sea más fácil.

La capacidad de innovación y flexibilidad que nos ofrecen ambos productos es amplísima, pudiendo trabajar en conjunto, o por separado. Esto nos permite desde arreglar las teclas del mando, a convertir cualquier objeto en un interruptor táctil.

Objetivo

El objetivo que nos vamos a poner será el de una primera toma de contacto con esta tecnología, ya que en futuros posts profundizaremos y desarrollaremos cosas más avanzadas. Por el momento veremos el funcionamiento básico, y cómo algo tan común como una hoja de papel se puede convertir en nuestro próximo interruptor.

Materiales

Para llevar a cabo el proyecto haremos uso del microcontrolador Touch Board, y de una cartulina que ya trae impreso un diseño con pintura conductiva. Para poder recibir los datos de la hoja con la placa, utilizaremos unos cables con pinza de cocodrilo.

Bareconductive: Convirtiendo el papel en un dispositivo táctil
Bareconductive: Convirtiendo el papel en un dispositivo táctil
Bareconductive: Convirtiendo el papel en un dispositivo táctil

Tecnologías

Como entorno de desarrollo utilizaremos Arduino IDE. Adicionalmente, tendremos que instalar los controladores para poder utilizar nuestra placa Touch Board.

Esquema

El esquema de conexiones para el circuito que vamos a implementar es muy sencillo. Sólo debemos conectar el papel al pin 0 de la placa con los cables de pinza de cocodrilo y ¡voilà! Nada más.

Bareconductive: Convirtiendo el papel en un dispositivo táctil

Desarrollo

No sólo convertiremos nuestra hoja prediseñada en un interruptor, sino que además, también la convertiremos en un sensor de proximidad. Primero abordaremos el caso del interruptor y, por último, el del sensor de proximidad.

Un papel como interruptor

Lo primero que vamos a hacer es conectar la Touch Board al ordenador y abrir el IDE de Arduino. Una vez abierto deberemos seleccionar nuestra placa y el puerto en el que se encuentra. Ambas opciones se encuentran bajo el menú Herramientas: Herramientas > Placa > Bare Conductive Touch Board y Herramientas > Puerto > COM7 (en mi caso).

Bareconductive: Convirtiendo el papel en un dispositivo táctil

Código

Al principio del código incluiremos las librerías necesarias y declararemos las variables globales para el programa.

#include <MPR121.h>
#include <Wire.h>

// Pin que usaremos para monitorizar los toques
#define SENSOR_PIN 0

// Dirección I2C por defecto en la placa Bare Touch Board
#define MPR121_I2C 0x5C

Ya dentro de la función setup(), inicializaremos el Serial para poder mostrar mensajes por consola, inicializaremos el LED y el sensor de la Touch Board.

void setup() {
  // Se inicializa el Serial
  Serial.begin(115200);

  // Se establece el LED incorporado como de salida
  pinMode(LED_BUILTIN, OUTPUT);

  // Se deja apagado el LED al iniciar
  digitalWrite(LED_BUILTIN, LOW);

  // Se inicializa el sensor, y en caso de que falle se gestiona el error
  if (!MPR121.begin(MPR121_I2C)) {
    Serial.println("Error iniciando el sensor MPR121");

    // Se recupera y muestra el error generado
    switch (MPR121.getError()) {
      case NO_ERROR:
        Serial.println("Sin error");
        break;
      case ADDRESS_UNKNOWN:
        Serial.println("Dirección incorrecta");
        break;
      case READBACK_FAIL:
        Serial.println("Error de lectura");
        break;
      case OVERCURRENT_FLAG:
        Serial.println("Sobrecorriente en el pin REXT");
        break;
      case OUT_OF_RANGE:
        Serial.println("Pin fuera de rango");
        break;
      case NOT_INITED:
        Serial.println("No inicializado");
        break;
      default:
        Serial.println("Error desconocido");
        break;
    }
    while(1);
  }
}

En caso de que se haya iniciado todo correctamente, terminaremos el código de setup() estableciendo los valores de sensibilidad de la Touch Board.

void setup() {
  ...

  // Umbral de sensibilidad al pulsar
  // Cuanto más pequeño sea el valor más sensible será el sensor
  MPR121.setTouchThreshold(100);

  // Umbral de sensibilidad al soltar
  // Cuanto más pequeño sea el valor más sensible será el sensor
  // Este valor SIEMPRE deberá ser menor al umbral de pulsación
  MPR121.setReleaseThreshold(90);

  // Se actualizan los datos del sensor al iniciar
  MPR121.updateTouchData();
}

En nuestra función loop() estaremos comprobando si ha cambiado el estado de algún pin, y en caso afirmativo, actualizaremos los datos del sensor y comprobaremos el estado de nuestro pin definido. De ser nuestro pin el que ha cambiado de estado, encenderemos o apagaremos el LED en base a ello (si es otro pin no hacemos nada).

void loop() {
  // Se detecta si ha cambiado el estado de algún pin
  if (MPR121.touchStatusChanged()) {
    // Se actualizan los datos del sensor
    MPR121.updateTouchData();

    // Se comprueba si es un nuevo toque en nuestro pin
    if (MPR121.isNewTouch(SENSOR_PIN)) {
      digitalWrite(LED_BUILTIN, HIGH);  // Se enciende el LED
      Serial.print("Se ha tocado el pin ");
      Serial.println(SENSOR_PIN);
    }
    // Se comprueba si se ha dejado de pulsar sobre nuestro pin
    else if (MPR121.isNewRelease(SENSOR_PIN)) {
      digitalWrite(LED_BUILTIN, LOW);  // Se apaga el LED
      Serial.print("Se ha soltado el pin ");
      Serial.println(SENSOR_PIN);
    }
  }
}

Resultado como interruptor

No tiene complicación este sketch. Llegados hasta aquí ya podemos cargar el programa en la placa y ver como se comporta.

Bareconductive: Convirtiendo el papel en un dispositivo táctil
Bareconductive: Convirtiendo el papel en un dispositivo táctil

Un papel como sensor de proximidad

Esta es la parte más interesante del artículo, en ella veremos cómo convertir nuestro papel en un sensor de proximidad. Encenderemos y apagaremos el LED integrado según acerquemos o alejemos la mano.

Código

Siguiendo el formato del anterior sketch, lo primero que haremos será importar las librerías necesarias y declarar las variables globales.

#include <MPR121.h>
#include <Wire.h>

// Inicio del rango personalizado de lectura
#define LOW_DIFF 0

// Fin del rango personalizado de lectura
#define HIGH_DIFF 50

// Valor del filtro (de 0.0f a 1.0f)
// Valor más alto => más suave y lento detectando cambios de proximidad
#define filterWeight 0.2f

// Pin que usaremos para monitorizar los toques
#define SENSOR_PIN 0

// Dirección I2C por defecto en la placa Bare Touch Board
#define MPR121_I2C 0x5C

// Último valor filtrado
float filteredValue = 0;

Seguido tenemos la función setup(), y la primera parte es igual que el sketch anterior, literalmente copiar y pegar.

void setup() {
  // Se inicializa el Serial
  Serial.begin(115200);

  // Se establece el LED incorporado como de salida
  pinMode(LED_BUILTIN, OUTPUT);

  // Se deja apagado el LED al iniciar
  digitalWrite(LED_BUILTIN, LOW);

  // Se inicializa el sensor, y en caso de que falle se gestiona el error
  if (!MPR121.begin(MPR121_I2C)) {
    Serial.println("Error iniciando el sensor MPR121");

    switch (MPR121.getError()) {
      case NO_ERROR:
        Serial.println("Sin error");
        break;
      case ADDRESS_UNKNOWN:
        Serial.println("Dirección incorrecta");
        break;
      case READBACK_FAIL:
        Serial.println("Error de lectura");
        break;
      case OVERCURRENT_FLAG:
        Serial.println("Sobrecorriente en el pin REXT");
        break;
      case OUT_OF_RANGE:
        Serial.println("Pin fuera de rango");
        break;
      case NOT_INITED:
        Serial.println("No inicializado");
        break;
      default:
        Serial.println("Error desconocido");
        break;
    }
    while(1);
  }
}

La parte final cambia un poquito. Debido a que el programa comprobará constantemente el estado de los pines, y no sólo cuando alguno cambie de estado; no hará falta la comprobación inicial. En vez de eso, ajustaremos dos valores base de la placa, para intentar reducir las falsas detecciones.

El primer valor es el Noise half delta, una variable que registra el ruido medio de la señal. El segundo es el Filter delay limit, y aumenta o disminuye el tiempo que tiene que pasar para que la placa considere la señal como ruido (y la filtre).

void setup() {
  ...

  // Se disminuyen un par de valores base del sensor para evitar falsas detecciones
  MPR121.setRegister(MPR121_NHDF, 0x01);  // noise half delta (falling)
  MPR121.setRegister(MPR121_FDLF, 0x10);  // filter delay limit (falling)
}

Realmente, esas últimas dos líneas pueden ser prescindibles. Una vez tengáis el código completo subido a la placa, es cuestión de probar cambiando los valores, y/o eliminando las líneas. Puede depender mucho de la conexión física y colocación que hagamos, el necesitar ese ajuste o no. Veamos como debería quedar la función loop().

  • En primer lugar actualizaremos los datos del sensor
  • Después obtendremos la diferencia entre el valor inicial de lectura y el valor actual de lectura
  • Restringimos el valor de la lectura anterior para que no se salga del rango que hemos predefinido
  • Seguidamente le aplicamos una función de filtrado Lowpass para suavizar la velocidad con la que aumenta y disminuye de valor
  • Mapeamos el valor filtrado a uno que esté comprendido en el rango 0-255
  • Debido a que las funciones analógicas de Arduino son de 8-bits (rango 0-255), simplemente usamos el valor mapeado como intensidad del LED
void loop() {
  // Se actualizan los datos del sensor
  MPR121.updateAll();

  // Diferencia entre el valor inicial del sensor y el valor actual de lectura de proximidad
  int difference = MPR121.getBaselineData(SENSOR_PIN) - MPR121.getFilteredData(SENSOR_PIN);

  // Se restringe la lectura anterior a nuestros valores límite
  unsigned int value = constrain(difference, LOW_DIFF, HIGH_DIFF);

  // Implementación simple de un filtro IIR lowpass
  // Suaviza la velocidad de detección de proximidad
  filteredValue = (filterWeight * filteredValue) + ((1 - filterWeight) * (float) value);

  // Se mapea la lectura filtrada a un rango de 0 - 255
  // Resolución de 8 bits para poder usar el valor como intensidad del LED
  uint8_t mappedValue = (uint8_t) map(filteredValue, LOW_DIFF, HIGH_DIFF, 0, 255);

  // Se usa el valor filtrado y mapeado como intensidad del LED
  analogWrite(LED_BUILTIN, mappedValue);
}

Resultado como sensor de proximidad

Ya tenemos el código completado y, aunque la segunda parte puede resultar más difícil de entender, el resultado valdrá la pena.

Bareconductive: Convirtiendo el papel en un dispositivo táctil

Recursos

A continuación os dejo el enlace donde podréis descargar los recursos del post. Quién sabe, lo mismo más de uno se piensa en quitar los interruptores de casa y fabricarse los suyos 😜.