Construindo interfaces interativas baseadas em têxteis com Arduino e JavaScript

Tempo de leitura: 8 minutes

Há alguns anos, me deparei com o Projeto Jacquard, um projeto do Google ATAP para criar uma jaqueta jeans interativa para controlar aplicativos em seu telefone, como atender ou recusar chamadas, trocar de música, etc …

Achei a ideia superinteressante e queria replicá-la para entender como funciona, mas nunca achei tempo até recentemente!

Eu realmente adoro explorar tecnologias inovadoras de uma forma que seja acessível a muitas pessoas, então passei alguns dias durante as férias de Natal construindo um protótipo rápido usando alguns componentes do Arduino e JavaScript.

É uma primeira versão muito aproximada, é extremamente hacky tanto no lado do hardware quanto do código, então estou compartilhando esta postagem apenas para explicar o conceito geral, para que qualquer pessoa possa reproduzi-la se estiver interessado :). Definitivamente, não está pronto para produção e há muitas melhorias a serem feitas!

 

Conceito

Antes de iniciar o protótipo, passei algum tempo tentando entender como funciona a jaqueta do Projeto Jacquard, para ter uma ideia melhor de como fazer para construí-la.

Eu sabia que ela usava linha condutora, que é uma linha que se parece e se comporta como linha de costura normal, mas também é condutora. Ele permite que seja usado para substituir fios, mas também pode ser transformado em um sensor capacitivo, para que possa sentir se você está tocando ou não. Na detecção capacitiva “clássica”, quando você está lendo o valor da capacitância, você obtém 0 se um componente não for tocado e 1 se for tocado. Neste projeto, usei um tipo mais avançado de sensoriamento capacitivo, onde podemos obter dados em uma faixa mais ampla.

Se pensarmos em um gesto básico de “deslizar”, poderíamos começar tentando permitir que um usuário execute um “deslizar para a direita”, costurando 2-3 fios em um layout de coluna e conectá-los ao pino 7–9 no Arduino e detectar se estamos tocando-os desde o que está conectado ao pino 7 até o que está conectado ao pino 9, por exemplo.

Vamos entrar em mais detalhes.

 

Material

Para construir isso, no lado do hardware, usei:

  • Um Arduino UNO
  • Fios de ligação
  • Resistores de 10M
  • Uma placa de ensaio
  • Fio condutor
  • Tecido
  • Um bastidor de bordar
  • Pinças de jacaré

E no lado do software:

  • Arduino IDE
  • Node.js
  • Three.js

Passos

Em vez de trabalhar no exemplo “deslizar para a direita” que mencionei acima, fiquei intrigado sobre como eles construíram isso:

Como mencionado acima, tocar nos tópicos em uma determinada ordem da esquerda para a direita teria sido muito fácil, imagino que teria que verificar se os dados que recebo ao tocar no tópico iam de 0 a 1 no pino 7, depois em 8 e então 9; mas na animação 3D acima, eles conseguiram ter uma interação mais interessante.

Depois de fazer algumas pesquisas e ler o artigo deles, percebi que eles costuraram os fios como uma grade, para poder traduzir cada “ponto” (onde os fios horizontais e verticais se cruzam) em coordenadas x e y. Eles podem então ser usados da mesma forma que você pode usar as coordenadas x e y do mouse para animar coisas no navegador.

 

1) Costurando os fios

Nunca costurei nada na minha vida.

Foi a minha primeira vez e isso por si só já foi um desafio … Aconselho você a comprar um bastidor de bordar para evitar que o tecido se mova, torna tudo muito mais fácil!

Para ter certeza de que estava costurando linhas retas, desenhei-as no tecido antes de começar para que pudesse segui-las enquanto costurava.

Além disso, certifique-se de que cada pedaço de fio não esteja em contato com o outro, caso contrário, sua leitura ficará errada.

No final, depois de algumas tentativas, acabei com uma grade como esta:

Como você pode ver, tenho 3 linhas e 3 colunas, portanto, um total de 9 pontos possíveis que posso tocar.

Como esses “pontos” serão traduzidos em coordenadas (x, y), quanto mais colunas e linhas, melhor, pois quanto mais pontos você tiver, mais poderá dividir sua tela e interface para ter uma animação mais suave.

Agora que costurei os fios, vamos prosseguir com a montagem do hardware.

2) Conectando o Arduino ao tecido

A configuração básica é a seguinte:

Um resistor de 10MO (MegaOhms) é conectado aos pinos 4 e 8, e uma garra jacaré faz a ligação entre o pino 4 e tudo o que você decidir prender na outra mão (fio condutor, fio, moeda, banana, etc …).

O resistor de 10MO é necessário para o tipo de detecção capacitiva que estamos fazendo aqui, se você usar um resistor inferior, pode não funcionar tão bem.

Isso funciona para 1 pedaço de thread, mas no meu caso, tenho 6, então tive que deixar de me conectar ao Arduino diretamente e, em vez disso, usar uma placa de ensaio.

Aqui está um exemplo para 2 peças de linha, mas se você precisar conectar mais, basta repetir a mesma configuração para cada linha.

Na verdade, é assim que parece … 😱

Atualmente é muito confuso, mas pode ser diminuído se você quiser deixar de usar a prototipagem.

Cada garra jacaré é conectada a uma mão de cada fio. Agora, vamos passar para o código.

3) Obtendo a capacitância no Arduino

Abaixo estão alguns exemplos de código da minha configuração, mas você pode começar com este script.

Usei a biblioteca CapacitiveSense. Abaixo está a configuração inicial das diferentes variáveis.

#incluide <CapacitiveSensor.h>

// Usa um resistor de alto valor, por exemplo, 10m entre enviar e receber pin
// Sensibilidade de efeitos do resistor, experimente com valores, 50k - 50m. Grandes valores de resistor geram grandes valores de sensor
// O pino de recepção é o ponto do sensor - experimente diferentes quantidades de folha/metal neste pino

CapacitiveSensor cs_4_0 = CapacitiveSensor(2,A0);
// Resistor de 10m entre os pinos 2 e A0, A0 é o pino do sensor e um fio, fio ou folha para ele
CapacitiveSensor cs_4_1 = CapacitiveSensor(2,A1);
CapacitiveSensor cs_4_2 = CapacitiveSensor(2,A2);
CapacitiveSensor cs_4_3 = CapacitiveSensor(2,A3);
CapacitiveSensor cs_4_4 = CapacitiveSensor(2,A4);
CapacitiveSensor cs_4_5 = CapacitiveSensor(2,A5);

int x, y;
int postXCoordinate, pastYCoordinate;
String resultX, resultY;

 

 

Indicamos quais pinos são usados para o sensoriamento capacitivo, declaramos os inteiros xey que manterão as coordenadas que enviaremos para o Node.js, também criamos inteiros para manter as coordenadas anteriores enviadas para não enviar dados desnecessários para Node.js e, finalmente, criamos strings para o resultado enviado. Usei strings porque o Arduino não tem matrizes ou mapas hash embutidos, então, por enquanto, apenas usei strings e encontrarei uma maneira de refatorar mais tarde.

Então, na função de configuração, começamos redefinindo o valor em todos os pinos, iniciamos nossas variáveis de resultado que enviaremos mais tarde por serial e iniciamos a comunicação serial.

void setup()
{ 
   cs_4_0.set_CS_AutocaL_Millis(0xFFFFFFFF);
   cs_4_1.set_CS_AutocaL_Millis(0xFFFFFFFF);
   cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
   cs_4_3.set_CS_AutocaL_Millis(0xFFFFFFFF);
   cs_4_4.set_CS_AutocaL_Millis(0xFFFFFFFF);
   cs_4_5.set_CS_AutocaL_Millis(0xFFFFFFFF);
   
   resultX = String("x");
   resultY = String("y");
   
   Serial.begin(9600);
}

Na função de loop, lemos o valor vindo de todos os pinos do sensor capacitivo, verificamos se eles atingem um certo limite (se o fio conectado a esses pinos foi tocado), e se ainda não enviamos essas coordenadas (x, y) , nós os enviamos via serial.

void loop() {
   long total1 = cs_4_0.capacitiveSensor(30);
   long total2 = cs_4_1.capacitiveSensor(30);
   long total3 = cs_4_2.capacitiveSensor(30);
   
   long total4 = cs_4_3.capacitiveSensor(30);
   long total5 = cs_4_4.capacitiveSensor(30);
   long total6 = cs_4_5.capacitiveSensor(30);
   
   if(total1 >= 500){
      y = 0;
   } else if(total2 >= 500) {
      y = 1;
   } else if(total3 >= 500) {
      y = 2;
   } else {
      y = 10;
   }
   
   if(total4 >= 500){
      x = 0;
   } else if(total5 >= 500) {
      x = 1;
   } else if(total6 >= 500) {
      x = 2;
   } else {
      x = 10;
   }
   
   if(x != postXCoordinate) {
      Serial.println(resultX + x);
   }
   postXCoordinate = x;
   
   if(y != postYCoordinate) {
      Serial.println(resultY + y);
   }
   postYCoordinate = y;
   
   delay(10);
}

É basicamente isso! Como eu disse antes, é uma solução muito rápida e suja que precisa ser melhorada, mas funciona! : D

4) O back-end do JavaScript

No Node.js, meu pensamento original era usar o módulo Serialport para obter os dados e usar soquetes da web para enviá-los do servidor ao navegador para alterar a animação. Já trabalhei com coisas assim antes sem nenhum problema, mas por algum motivo, com essa configuração, a comunicação serialport estava bem no início, mas assim que tentei conectar web sockets também, tudo ficou extremamente lento e muito dos dados foram perdidos, então eu tive que encontrar outra maneira.

Decidi usar processos filho para ter um que lida com a comunicação com o Arduino e um que configura o servidor web e envia os dados para o navegador.

Não acho que seja ideal e ainda não o refatorei, mas tenho certeza de que há uma maneira melhor de fazer isso.

O arquivo Node.js principal tem a seguinte aparência:

var fork = require('child_processs).fork;
var arduino = fork('arduinoData.js');
var webServer = fork('webServer.js');

arduino.on('message', function(response){
   webServer.send(response)
})

O arquivo arduinoData.js tem a seguinte aparência:

var fork = require('child_processs).fork;
var arduino = fork('arduinoData.js');
var webServer = fork('webServer.js');

arduino.on('message', function(response){
   webServer.send(response)
})
-----------------------------------> arduinoData.js <--------------------------
const SerialPort = require('serialport');
const Readline = require('@serialport/parser-readline');

const port = new SerialPort('/dev/cu.usbmodem14621', { boudRate: 9600, lock: false});
const parser = port.pipe(new Readline({ delimiter: '\r\n' }));

// Leia a porta de dados
port.on('open', () => {
  parser.on('data', data => {
    process.send(data)
  });
});

parser.on('error', function(err){
   console.log(err)
})

Neste arquivo, solicitamos os módulos, abra uma comunicação serial na mesma porta do Arduino com a mesma taxa de transmissão e quando recebermos os dados, os enviamos de volta para a função arduino.on('message') no arquivo anterior é acionado e, em seguida, envia os dados para o arquivo webServer.js que se parece com este:

var app = require('express')();
var express = require('express');
var http = require('http');
var WebSocket = require('faye-websocket');

app.use('/', express.static(__dirname + '/public'));

var server = http.createServer(app);

server.on('upgrade', function(request, socket, body) {
  if(WebSocket.ifWebSocket(request)) {
     var ws = new WebSocket(request, socket, body);
     
     process.on("message", function(data){
        console.log('listagem na porta 8000');
     })
  }	 
})

Neste arquivo, criamos um servidor expresso simples e quando recebemos dados de nosso processo, enviamos via web sockets para o front-end.

5) Animando o front-end

Em nosso arquivo de front-end, para receber os dados vindos do servidor, escrevemos algo assim:

var socket = new WebSocket('ws://localhost:8000');

socket.onmessage = function(e){  
   var msg = e.data;
}

Agora, toda a comunicação entre os sensores e o front-end deve ser configurada para que possamos fazer o que quisermos com ela! Decidi trabalhar em uma animação parecida com a que o Google fez, mas você poderia fazer muitas outras coisas! 🙂

Seria muito longo explicar em detalhes como a animação 3D funciona, mas basicamente criei um plano de wireframes usando Three.js, dividi-o em 9 partes e animei qualquer parte que fosse ativada ao tocar no thread.

Espero poder entrar em mais detalhes em um futuro post! 🙂

 

Oportunidades

Para ser honesto, não pensei muito nos diferentes tipos de oportunidades que poderiam surgir com essa tecnologia. Fiquei mais animado com o desafio de recriá-lo!

Porém, como o Google usou em uma jaqueta, uma das oportunidades mais óbvias é ter esse tipo de tecnologia nas roupas, mas não só! Também pode ser embutido em sofás, cobertores, etc … em situações em que você pode interagir com algumas interfaces ou dispositivos sem ter que pegar o telefone.

 

Limites

Como você pode ver, a coisa toda é muito pesada e volumosa no momento, então o principal limite é que não é vestível ou portátil de uma maneira fácil. No entanto, com o tempo, isso poderia ser corrigido, pois você poderia substituir o Arduino por algo bem menor como um ATTiny85, por exemplo.

Outro limite é a quantidade de linha que posso costurar à mão. Se eu pudesse usar uma máquina de costura, isso provavelmente me permitiria usar mais linhas e ter uma interação mais agradável e fluida no front-end.

Além disso, no momento, ele funciona com um Arduino UNO, por isso deve ser conectado ao meu computador. Idealmente, gostaria de mudar isso para um microcontrolador habilitado para wi-fi ou bluetooth para que possa ser totalmente portátil.

Por fim, sinto que a taxa de transmissão de dados entre o Arduino e o JavaScript é um pouco lenta em comparação com outros projetos que construí antes, portanto, seria necessário otimizar o código para melhorá-lo.

 

Aprenda mais de 10 atividades e projetos com nossos ebook´s para Arduino. Programa bem explicado. que o ajudará a aprender eletrônica básica, codificação do Arduino, interface do sensor com o Arduino, Arduino e muito mais. compre nossos Ebooks para Arduino Ebook para aprender e Praticar. (Links da Pagina de nossos Ebooks no PlayStore)