Controlador de Respiração Arduino Acessível com Integração USB-MIDI
Componentes e Materiais
| Arduino Micro | × | 1 | Você poderia reduzir o custo com um clone, mas recomendo o original. Apenas o Micro (ATmega32U4) funcionará devido às capacidades USB nativas. |
| Protoboard Meia Tamanho | × | 1 | |
| Sensor de Pressão MPS20N0040D-D | × | 1 | Muito barato e fácil de encontrar. |
| Amplificador Operacional LM358-N | × | 1 | Usaremos o popular LM358 para amplificar o sinal do sensor. |
| Resistor 1M ohm | × | 2 | |
| Kit de Fios 22 AWG | × | 1 | Não precisa do kit completo, apenas alguns cm de fio sólido. |
| Aspirador Nasal para Bebê | × | 1 | Sim, você leu certo. Usaremos o bocal do lado dos pais e o aspirador do lado do bebê. Existem dezenas de aspiradores manuais do mesmo tipo (ex: Physiomer, Chicco Physioclean). Escolha o tipo de bocal que achar mais confortável. |
| Tubo de aquário 5mm | × | 1 | Opcional, se o tubo do aspirador não for longo suficiente. Tubo padrão de aquário serve. |
| Conector em T para tubo de ar | × | 1 | Este conector OEM chinês específico pode ser encontrado facilmente em lojas de aquário sob diferentes nomes. Encaixa diretamente no sensor. |
Ferramentas Necessárias
| Alicate Descascador e Cortador, 32-20 AWG / 0.05-0.5mm² |
Aplicativos e Serviços Online
| Arduino IDE |
Sobre o Projeto
Introdução
Neste projeto, construiremos um controlador de respiração USB MIDI plug-and-play simples. Ele é projetado com componentes baratos e fáceis de encontrar para que o custo total permaneça acessível e bem abaixo de equivalentes comerciais. Esta é a versão básica que usa apenas o sensor de pressão de ar, mas o plano é atualizá-lo no futuro para incluir sensor de mordida e inclinação/aceno.
O projeto assume conhecimentos muito básicos de eletrônica e Arduino, mas mesmo um iniciante pode construí-lo, pois não há solda envolvida. Usuários mais avançados podem soldar tudo em uma protoboard permanente. Não cobro instalação da IDE/bibliotecas e instruções de upload de código, pois existem excelentes tutoriais na internet.
Oversampling é usado para suavizar a entrada do sensor com excelentes resultados. Você também pode ajustar a faixa ao seu gosto e até definir curvas personalizadas para ajustar o comportamento do controlador.
Como o sensor pode medir pressão negativa também, há um segundo fluxo de mensagens de controlador que é emitido quando você puxa ar em vez de soprar. Ambos os tipos de mensagens podem ser configurados pelo usuário. Por exemplo, você pode definir sopro para pitch bend up e puxar ar para pitch bend down. Por padrão, ambos são definidos para controlador nº 2.
Passos para Construir
- Insira o Arduino na protoboard conforme mostrado na foto/esquemático.
- Insira o sensor e o amplificador operacional em suas respectivas posições, note a orientação baseada nos pequenos entalhes em seus lados.
- Insira os resistores após cortar seus terminais no comprimento apropriado.
- Corte/descasque os cabos de núcleo sólido e coloque-os em suas posições. Usei vermelho para 5V, preto para terra e amarelo para sinal para facilitar o entendimento, mas você pode usar o que tiver disponível.
- Conecte o bocal, tubos, conector em T e aspirador conforme mostrado na foto. Você precisará cortar um pedaço do tubo para o "exaustor".
- Pressione o conector em T para que ele se encaixe no sensor. Deve ficar firme.
- Instale a Arduino IDE e instale as duas bibliotecas necessárias (Oversampling e USB-MIDI) em Ferramentas → Gerenciar Bibliotecas. Conecte o Arduino com cabo USB ao computador. Faça upload do código anexado.
- Você deve estar pronto. O Arduino deve aparecer como um dispositivo MIDI no seu DAW/Software de Música. Ative-o e roteie junto com seu teclado para um plugin que suporte controlador de respiração.
Informações Avançadas
Um inconveniente físico deste design é a saliva que inevitavelmente fluirá no tubo e pode causar flutuações perceptíveis no fluxo de ar. O conector em T é usado para resolver este problema direcionando a saliva para o tubo de "exaustão". Para minimizar saliva presa no tubo, certifique-se de que há uma inclinação contínua do bocal ao conector em T ajustando o comprimento do tubo. Se o tubo ficar pendente abaixo do nível do conector em T, a saliva ficará presa no ponto mais baixo causando flutuações. A parte do aspirador do lado do bebê, incluindo seu filtro, é anexada ao exaustor para minimizar gotejamento, ruído e aumentar o fluxo de ar para o sensor.
No código existem valores que você pode ajustar ao seu gosto, incluindo curvas personalizadas. Comentários descrevem como fazer isso. Se achar difícil atingir o ponto 127, diminua a faixa máxima, ou se estiver muito fácil, aumente-a. Sempre que alterar valores, precisará fazer upload do código novamente.
As primeiras leituras após o boot do Arduino são médias para calibrar a posição de repouso. Não sopre no tubo enquanto conecta/reseta o dispositivo.
Você pode alterar o nome do dispositivo MIDI editando o arquivo boards.txt (informações sobre como fazer isso para cada plataforma estão disponíveis na internet).
Código
Código do Controlador de Respiração (Arduino)
Faça upload deste código para seu controlador de respiração via Arduino IDE
/* Controlador de Respiração */
// Bibliotecas usadas - instale em Ferramentas → Gerenciar Bibliotecas
#include <Oversampling.h>
#include <USB-MIDI.h>
// Modo Debug (descomente para habilitar)
//#define DEBUG 1
// Criação da interface USB MIDI
USBMIDI_CREATE_DEFAULT_INSTANCE();
// Inicialização do Oversampling
Oversampling adc(10, 13, 6);
// ***************** Configuração do Usuário *****************
// Valores terminando em 1 correspondem a soprar, enquanto terminando em 2 correspondem a puxar ar
// Configuração de pinos
const int sensorPin1 = A0; // pino de entrada do Arduino para saída do Sensor/Op Amp
// Calibração de Faixa. Ajuste manualmente para que você possa atingir o máximo mas não muito facilmente.
int sensorRange1 = 800;
int sensorRange2 = 800;
// Número do controlador de saída. Selecione na tabela abaixo
// 0-127: mensagens regulares de control change
// 128: aftertouch monofônico
// 129: Pitch Bend Up
// 130: Pitch Bend Down
int controllerNumber1 = 2; // Controlador enviado ao soprar
int controllerNumber2 = 2; // Controlador enviado ao puxar ar
// Canais do controlador de saída
int controllerChannel1 = 1;
int controllerChannel2 = 1;
// Limiares de segurança para valores mais baixos e mais altos para evitar flutuações em repouso ou no máximo.
// Se múltiplas mensagens são enviadas em repouso, aumente o lowThreshold.
// Se múltiplas mensagens são enviadas no máximo, aumente o highThreshold.
const int lowThreshold1 = 5;
const int lowThreshold2 = 5;
const int highThreshold1 = 0;
const int highThreshold2 = 0;
// Definição de curva. Tabelas podem ter qualquer comprimento igual ou maior que 2. Valores podem ser 0-127.
// As tabelas devem ter o mesmo número de elementos e tabelas "in" devem estar em ordem crescente.
// Conversões são feitas no nível de leituras para minimizar perda de definição.
int in1[] = {0, 127};
int out1[] = {0, 127};
int in2[] = {0, 127};
int out2[] = {0, 127};
// Curvas de exemplo (modifique o número do sensor conforme necessário)
// Suave
//int in1[] = {0, 6, 24, 78, 127};
//int out1[] = {0, 32, 64, 96, 127};
// Faixa reduzida
//int in1[] = {50, 100};
//int out1[] = {50, 100};
// Ciclo de Atualização (milisegundos). Valores menores significam mais mensagens enviadas durante operação.
int refreshCycle = 0;
// ***************** Implementação *****************
// Não modifique a partir deste ponto se não pretende alterar a operação do sensor.
// Valor Interno dos Sensores
int sensorValue1 = 0;
int sensorValue2 = 0;
// Valores mínimos dos sensores
int sensorMin1;
int sensorMin2;
// Valores do controlador de saída
int controllerValue1 = 0;
int controllerValue2 = 0;
// Valores do ciclo anterior para evitar repetição de mensagens idênticas
int previousControllerValue1 = 0;
int previousControllerValue2 = 0;
// Variável de conversão de faixa
int outputRange1;
int outputRange2;
int sensorLow1;
int sensorLow2;
int sensorHigh1;
int sensorHigh2;
void setup() {
MIDI.begin(1);
#ifdef DEBUG
Serial.begin(115200); // Apenas para modo debug
#endif
// Calibrar ponto de repouso do sensor fazendo média das 10 primeiras leituras.
// Não use o sensor durante o boot do dispositivo.
sensorMin1 = adc.read(sensorPin1);
sensorMin2 = 0;
// Determinar faixas de saída para os controladores escolhidos
outputRange1 = outputRange(controllerNumber1);
outputRange2 = outputRange(controllerNumber2);
}
void loop() {
// ler valor do sensor:
sensorValue1 = adc.read(sensorPin1); // Soprar ar
sensorValue2 = sensorMin1 - sensorValue1; // Puxar ar
// Armazenar valores anteriores
previousControllerValue1 = controllerValue1;
previousControllerValue2 = controllerValue2;
// Limites de faixa utilizável para sensor cima/baixo
sensorLow1 = sensorMin1 + lowThreshold1;
sensorLow2 = sensorMin2 + lowThreshold2;
sensorHigh1 = sensorLow1 + sensorRange1 - highThreshold1;
sensorHigh2 = min(sensorMin1, sensorRange2) - highThreshold2;
// Converter valores internos para faixa de saída (0..127 para controladores/aftertouch, 0..+/-8191 para Pitchbend Up/Down) usando curvas definidas nas tabelas "in" e "out".
controllerValue1 = map(mapToCurve(constrain(sensorValue1, sensorLow1, sensorHigh1), sensorLow1, sensorHigh1, in1, out1, sizeof(in1)/sizeof(int)), sensorLow1, sensorHigh1, 0, outputRange1);
controllerValue2 = map(mapToCurve(constrain(sensorValue2, sensorLow2, sensorHigh2), sensorLow2, sensorHigh2, in2, out2, sizeof(in2)/sizeof(int)), sensorLow2, sensorHigh2, 0, outputRange2);
// Enviar mensagens MIDI
if (controllerValue1 != previousControllerValue1) sendSensorOutput(controllerNumber1, controllerValue1, controllerChannel1);
if (controllerValue2 != previousControllerValue2) sendSensorOutput(controllerNumber2, controllerValue2, controllerChannel2);
// Debug
#ifdef DEBUG
// Valores do sensor (entrada) (descomente para debug)
// Serial.print(sensorValue1);
// Serial.print(",");
// Serial.print(sensorValue2);
// Serial.print(",");
// Valores do controlador (saída)
Serial.print(controllerValue1);
Serial.print(",");
Serial.println(controllerValue2);
#endif
// parar programa por milissegundos:
delay(refreshCycle);
}
// Função para enviar mensagens MIDI de acordo com número do controlador
void sendSensorOutput(int number, int value, int channel) {
if (number < 128) MIDI.sendControlChange(number, value, channel);
else if (number == 128) MIDI.sendAfterTouch(value, channel);
else if (number == 129) MIDI.sendPitchBend(value, channel);
else if (number == 130) MIDI.sendPitchBend(-value, channel);
}
// Função para determinar a faixa de um controlador específico. Devido ao pitch bend ter faixa maior que controladores regulares.
int outputRange(int number) {
if (number > 128) return 8191;
else return 127;
}
// Função multiMap modificada para criar curvas. Original por Rob Tillaart.
int mapToCurve(int val, int sensorLow, int sensorHigh, int* _in, int* _out, uint8_t size) {
// garantir que valor está dentro da faixa
// val = constrain(val, _in[0], _in[size-1]);
if (val <= map(_in[0], 0, 127, sensorLow, sensorHigh)) return map(_out[0], 0, 127, sensorLow, sensorHigh);
if (val >= map(_in[size-1], 0, 127, sensorLow, sensorHigh)) return map(_out[size-1], 0, 127, sensorLow, sensorHigh);
// buscar intervalo correto
uint8_t pos = 1; // _in[0] já testado
while(val > map(_in[pos], 0, 127, sensorLow, sensorHigh)) pos++;
// ajustar faixa de ..127 para faixa do sensor
int inPos = map(_in[pos], 0, 127, sensorLow, sensorHigh);
int outPos = map(_out[pos], 0, 127, sensorLow, sensorHigh);
int inPrv = map(_in[pos-1], 0, 127, sensorLow, sensorHigh);
int outPrv = map(_out[pos-1], 0, 127, sensorLow, sensorHigh);
// lidar com pontos exatos no array _in
if (val == inPos) return outPos;
// interpolar no segmento correto para o resto
return ((long)val - (long)inPrv) * ((long)outPos - (long)outPrv) / ((long)inPos - (long)inPrv) + (long)outPrv;
}
Esquemáticos
Processo de manufatura
- Painel de Controle para Flight Simulator 2020 com Arduino Nano – Display LCD e CDI
- Sistema de Iluminação DMX Controlado via Web – Controlador Mestre Arduino
- Controle USB para Jogos DIY com Arduino – Construa Seu Próprio Gamepad de Alto Desempenho
- Unopad: Controlador MIDI Arduino Perfeito para Ableton Live
- Teletransportador de Texto Bluetooth: Arduino + Android
- Kit Controlador de Display Fluorescente a Vácuo (VFD) Baseado em Arduino
- Controlador Residencial Arduino com Alexa: Automação Inteligente Simplificada
- Sistema Inteligente de Monitoramento de Temperatura para Escolas: Preciso, Tempo Real e Seguro
- Circuito de Entrada Analógica Isolada para Arduino
- Kit de Robô de Navegação Interna Inteligente para Projetos Arduino