Dispositivo para prevenir o sono nas costas e controlar a postura do "Positioner" UPSNS-KO



Um dia, descobri que as mulheres que esperam um bebê correm o risco de dormir de costas em estágios mais ou menos tardios da gravidez. O problema é que, neste caso, a artéria sanguínea é comprimida sob o peso do feto, o que ameaça conseqüências muito sérias, se não mais.

Portanto, pensei que provavelmente não seria muito difícil para mim fazer algum tipo de coisa que poderia impedir que ela entrasse nessa situação potencialmente perigosa. É claro que, depois de um curto período de tempo, meus olhos se abriram para o fato de que mulheres sábias evitam riscos de uma maneira completamente natural - elas simplesmente ficam desconfortáveis ​​dormindo de costas nessas datas muito tardias.

Mas não jogue fora microcontroladores, acelerômetros e ideias brilhantes que já escravizam a mente, certo?

A propósito, havia outros desmotivadores. Começando com a opção hardcore:



E terminando com corretores de postura completamente fascinantes , que, honestamente, aprendi mais tarde do que meu próprio insight.

Em geral, no começo eu queria simplesmente e sem frescuras, como a Occam normal, com navalhas normais. Ou seja, o dispositivo deve simplesmente fixar a posição e, se não mudar dentro de um determinado período, transmitir essas informações valiosas ao proprietário por vibração. A escolha desse aviso foi natural para mim, porque pelo segundo ano eu uso uma pulseira de pedômetro com um alarme de vibração, o que (um despertador) é um milagre.

Obviamente, todos entendemos que o sinal de vibração não é adequado para todos. Mas não tive queixas sobre o dispositivo universal - em todos os lugares, você vê, um equilíbrio razoável deve ser mantido. A propósito, é por isso que no design final já existe o nosso ambiente favorito do Arduino, e muitas soluções bárbaras e até a lendária fita elétrica azul (realmente azul, trazida pelo encanador).

Em geral, a lâmina de Occam quebrou quando comecei a triturar os contornos do futuro despertador. O que subitamente revelou outros talentos em potencial, a saber: controle da postura e advertência [plâncton de escritório] sobre imobilidade por muito tempo. A razão para expandir a funcionalidade é comum - foi uma pena ver como os recursos do microcontrolador mais poderoso, mas ainda muito sério, desaparecem.

Como funciona


Como você já sabe, o Positioner tem três modos de operação:

1) Prevenção do sono nas costas (bem, ou em qualquer outra posição, isso não importa para ele)
2) Controle da postura
3) Aviso sobre baixa mobilidade

E, como você ainda não sabe, apenas um botão, que executa a função de redefinir o microcontrolador.

Portanto, para selecionar o modo desejado, basta executar duas ações: pressione o botão e mantenha o Posicionador em uma das três posições, se for o caso, figurativamente - nas costas, nas laterais ou em pé. E, para colocar uma coisa simplesmente no modo de espera (análogo de desativá-la), você não precisa fazer nada. Ou seja, eles pressionaram um botão, colocaram-no no chão - e o posicionador adormeceu.

Qual é o truque? Depois de escolher um modo ou durante a eutanásia, o Posicionador precisa permanecer imóvel, pois no primeiro caso ele precisa de tempo para memorizar a posição e no segundo - ao entender que é hora de dormir. Existem dois intervalos principais: os primeiros cinco segundos após a ativação servem para selecionar um modo e os próximos dez para receber uma posição.

Ao mesmo tempo, a propósito, dez segundos é um conceito condicional, pois o Posicionador lembra as “coordenadas” apenas se, dentro do tempo especificado, a posição estiver relativamente inalterada. Isso permite que você escolha o modo operacional e se apegue calmamente ao dispositivo sem se preocupar com um tempo limite difícil para esta operação. Mas assim que eu liguei - congele por dez segundos para que o posicionador entenda que é hora de começar a trabalhar.

Em outras palavras, o leitor atento já adivinhou que as leituras do acelerômetro são usadas para selecionar o modo, e eu ainda estou me espalhando pela árvore.

Aqui, você pode ver como funciona no exemplo de um protótipo em uma placa de ensaio:



Como você pode ver, tudo é bem simples.

Em uma versão mais ou menos final, o alarme funciona da seguinte forma:

1) Na prevenção de sono nas costas, o Positioner é acionado após cerca de um minuto e acorda com uma série de 8 sinais, que não interrompem sob nenhuma circunstância, exceto pela descarga da bateria. E para que ele pare de fazer isso, você deve deitar-se de alguma maneira diferente e esperar o fim de uma série de sinais. Caso contrário, uma série de sinais será repetida.

2) No modo de controle de postura, o Posicionador garante que a postura correta seja mantida por aproximadamente 60% do tempo, a partir de um intervalo de 5 minutos. Caso contrário, ele começa a vibrar até você voltar à postura correta.

3) No modo de aviso de baixa mobilidade, o Positioner garante que pelo menos 8% do tempo do intervalo de 30 minutos seja dedicado ao movimento. Caso contrário, uma vez produz uma série de 10 sinais, que não são interrompidos e começa a contar um novo intervalo.

Obviamente, o alarme em qualquer modo pode ser interrompido pressionando o botão de reset.

Quanto aos intervalos e notificações que podem parecer estranhos, procedi do seguinte. Um minuto atrás, na minha opinião, é longo o suficiente, e 8 sinais sem interrupção (e a perspectiva de receber a mesma quantidade repetidamente) parecem ser motivos suficientes para acordar.

Por outro lado, o controle da postura não é tão crítico; portanto, em primeiro lugar, não é necessário um controle de cem por cento e, segundo, é improvável que o controle da postura ocorra em um sonho; portanto, são suficientes sinais que param quando você retorna à posição desejada. Bem, sentar o tempo todo como se ele tivesse engolido arshin - um pouco estúpido e não muito possível. Portanto, o intervalo de controle é ajustável.

Finalmente, quando pesquisei sobre o mínimo necessário de atividade motora, me deparei com uma menção de que 15 a 20 minutos a cada três horas parece mais ou menos adequado. As configurações do posicionador levam essas informações em consideração, mas, se desejado, elas são modificadas no estágio de "piscar" o microcontrolador. Novamente, não há necessidade de abalar uma pessoa até que ela perca a consciência, pois ir ou não é voluntário. Portanto, apenas um lembrete delicado na forma de dez sinais de vibração.

Obviamente, todos esses intervalos não são dogmas e podem ser facilmente alterados. Seria um desejo.

O posicionador é alimentado por uma bateria de lítio CR2032. O consumo atual no modo de suspensão (algum quarto pseudo-modo do posicionador, não do controlador) é de 4 μA, o que considerei motivo suficiente para simplificar o design em termos de recusa do interruptor de energia dedicado. No início e ao determinar diretamente a posição, o consumo pode exceder 2 mA por frações de segundo, mas é principalmente dentro de 1 mA, exceto nos momentos da operação do sinal.

Nos intervalos entre a determinação da posição, o controlador está no modo de desligamento, onde o consumo é semelhante ao modo de suspensão do posicionador - 4 μA. O controlador é ativado por um temporizador aproximadamente a cada 8 segundos - isso é ao mesmo tempo a economia máxima de bateria e é aceitável para uma operação mais ou menos correta de todos os modos.



Infelizmente, não consigo calcular a autonomia total, porque não sei como.

Como isso é feito


Em primeiro lugar, tudo está fora de minha cabeça, em segundo lugar, de improviso e em terceiro lugar de maneira amadora, uma vez que era mais interessante para mim fechar essa gestalt do que elevá-la ao grau de absoluto.

Portanto, no futuro, teremos em mente que estamos falando de uma implementação muito específica e única. Para o que você precisa:

1) Microcontrolador ATtiny85 (por exemplo, tal )
2) Acelerômetro ADXL335 montado (por exemplo, tal ou imediatamente com fonte de alimentação de 3.3V)
3) Motor de vibração de um telefone celular (eu tenho muitos reparos para reparar)
4) Botão (levou de um controle remoto desmontado)
5) Resistor 2.2Kohm
6) Diodo tipo 1N4007 (eu tenho algo como KD522
7) Transistor NPN, por exemplo, 2N2222 (peguei algo de um DVD quebrado)
8) Bateria (CR2032)
9) Um caso adequado

O esquema é o seguinte:



Eu honestamente roubei a parte referente à conexão do motor em um projeto ELSE muito interessante .

A propósito, eu recomendo uma imagem tão bonita da Sparkfun que é impossível não citá-la:



Há mais um truque. A conclusão é que existem pelo menos duas versões de placas com um acelerômetro ADXL335: 3.3V e até 5V. Na verdade, a faixa de tensão operacional do acelerômetro é de 1,8V a 3,6V, portanto a segunda versão difere da primeira pela presença de um estabilizador de tensão.

. aqui está um com um estabilizador (uma barata de três pernas à esquerda do acelerômetro). fotoTinydeal


. e este está sem estabilizador. Foto por Hobby Electronics


. há também uma opção híbrida - onde você pode alimentar separadamente de 3,3V (após o estabilizador e de 5V através do estabilizador). Foto de Adafruit


Agora eu tinha uma placa com um estabilizador que funciona tanto a partir de 5V, o que não é surpreendente, e a partir de 3,3V (verifiquei). Mas como não vejo razão para aquecer o estabilizador e, consequentemente, desperdiçar a bateria em vão, na versão final do dispositivo, conectei a energia do acelerômetro diretamente a mim, ignorando o estabilizador.

. para ignorar o estabilizador, você pode navegar na placa e na folha de dados do ADXL335


Provavelmente ainda faz sentido falar sobre o fato de que os microcontroladores ATtiny85 também são diferentes. Os chips com marcações do tipo ATtiny85-20 costumam ser mais baratos e baratos nas lojas, e o ATtiny85-10 é cada vez menos caro. Do ponto de vista da fabricação do posicionador (e de acordo com a folha de dados ), a diferença mais importante é que o ATtiny85-20 opera na faixa de tensão de 2,7V - 5,5V e o ATtiny85-10 - na faixa de 1,8V - 5,5V. Essa. o segundo é muito mais preferível do ponto de vista do uso mais completo da capacidade da bateria.

A segunda diferença é a frequência do relógio de 20 MHz versus 10 MHz. Embora para o Positioner isso não seja, em geral, sem importância: funciona a 1 MHz e não se queixa da vida. Mas desde que peguei a primeira coisa que apareceu e mais barata, só tenho o ATtiny85-20.

Por fim, se é um mistério para alguém, conectei o acelerômetro ao controlador pelo motivo de ser mais fácil desligá-lo (o acelerômetro) no modo de suspensão do posicionador. Caso contrário, vazaremos constantemente até 350 μA (de acordo com a folha de dados ADXL335).

Ele montou tudo com uma instalação na parede, conectando os elementos com um fio esmaltado de 0,1 mm (marcado com fio Jumper), um par de bobinas que os bons chineses me deram juntamente com uma estação de solda. E que não sei há um ano, para onde ir. O resultado foi o ideal: o fio é perfeitamente rasgado com um ferro de soldar 300C com resina convencional e é conveniente o suficiente para soldar o ATtiny85 e o transistor no pacote SOT23.

Isso resulta em uma paisagem bastante utilitária:

. quais componentes foram - e definidos. É muito inútil comprar uma peça de cada vez em uma boutique de B & D


Algoritmo e Código



O algoritmo básico do trabalho do Positioner é o seguinte:



como ambiente de programação, escolhi completamente o Arduino como alternativa, já que agora ele é pelo menos ruim, mas só o conheço. Bem, mencionei a gestalt no início - isso também explica o fato de eu não estudar C ++ para criar um Positioner.

Quanto ao código, devo fazer alguns comentários.

Com base no modelo de uso do dispositivo (ligado e esquecido até lembrar), seria extremamente desejável esquecer a substituição diária das baterias. E para isso, você precisa economizar seriamente energia, o que é muito possível, pois a folha de dados ATtiny85 menciona que o consumo mínimo é décimo de um microamer. Devo dizer imediatamente - a tais alturas eu não subi (ou não caí?).

Aqui eu novamente escolhi a maneira mais fácil. Ou seja - pesquisou no Google o que era necessário. O primeiro é o código para colocar o ATtiny85 no modo de sono profundo máximo ao acordar com um temporizador de vigilância .

Ao mesmo tempo, o consumo atual de unidades de miliamperes caiu para centenas de microamperes. Já era bonito, mas ainda não era bonito o suficiente.

Eu tive que procurar mais. E então descobriu-se que o sono era um sonho, e os periféricos precisavam ser desligados manualmente. Ao mesmo tempo, a maior parte da energia, mesmo no modo de suspensão, é consumida pelo ADC. Aqui está escrito .

Depois de desligar o ADC durante o sono, a fonte de alimentação do Positioner tornou-se o mais harmoniosa possível. Ou seja, como escrevi acima, o consumo mínimo é de 4 μA, durante o despertar durante a medição - dezenas ou centenas de microamperes, com o vibromotor funcionando, ele pode exceder 2 mA.

A viabilidade dessa mistura de código pode ser estimada pelo fato de o CR2032 estar trabalhando há uma semana no Positioner no modo de teste há muito tempo desde o primeiro frescor. Na maioria das vezes, é claro, no modo de espera, mas o tempo ativo é decente. Em uma palavra, é quase um modelo de uso real.

Em relação ao trabalho com o acelerômetro. O fato é que, na medida do possível, abstraí dos valores absolutos. Há várias razões para isso. Primeiro, os acelerômetros podem ser alterados dessa maneira sem pensar em como uma determinada peça de hardware funciona. Em segundo lugar, desculpe pela tautologia, o ferro garante que, no caso de queda inevitável da tensão durante a descarga da bateria, as leituras do acelerômetro associadas ao processamento do ADC no microcontrolador não "flutuam".

Finalmente, as configurações são colocadas na seção de declaração de variáveis. É assim que me elogio: porque para ajustar o Positioner, você não precisa digitar todo o código e lembrar-me de palavrões enquanto procura todos os fragmentos em que precisa substituir os valores.

O código foi carregado no ATtiny85 via Arduino Mega de acordo com instruções comuns. Essa. baixei primeiro o suporte ATtiny para sua versão do ambiente Arduino aqui .

E, como sempre, ele descompactou o conteúdo do arquivo (diretório minúsculo com todo o conteúdo) na pasta de hardware do diretório Arduino:



Então entrei nesse diretório e, de acordo com as instruções, criei o arquivo boards.txt no qual copiei o Prospective Boards.txt do arquivo existente o que eu precisava - ou seja, Descrições minúsculas de 1 MHz e, apenas no caso, 8 MHz.

Aqui está o boards.txt
attiny85at8.name=ATtiny85 @ 8 MHz  (internal oscillator; BOD disabled)

# The following do NOT work...
# attiny85at8.upload.using=avrispv2
# attiny85at8.upload.using=Pololu USB AVR Programmer

# The following DO work (pick one)...
attiny85at8.upload.using=arduino:arduinoisp
# attiny85at8.upload.protocol=avrispv2
# attiny85at8.upload.using=pololu

attiny85at8.upload.maximum_size=8192

# Default clock (slowly rising power; long delay to clock; 8 MHz internal)
# Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 64 ms; [CKSEL=0010 SUT=10]; default value
# Brown-out detection disabled; [BODLEVEL=111]
# Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0]

attiny85at8.bootloader.low_fuses=0xE2
attiny85at8.bootloader.high_fuses=0xD7
attiny85at8.bootloader.extended_fuses=0xFF
attiny85at8.bootloader.path=empty
attiny85at8.bootloader.file=empty85at8.hex

attiny85at8.build.mcu=attiny85
attiny85at8.build.f_cpu=8000000L
attiny85at8.build.core=tiny
 
###########################################################################
###########################################################################

attiny85at1.name=ATtiny85 @ 1 MHz  (internal oscillator; BOD disabled)

# The following do NOT work...
# attiny85at1.upload.using=avrispv2
# attiny85at1.upload.using=Pololu USB AVR Programmer

# The following DO work (pick one)...
attiny85at1.upload.using=arduino:arduinoisp
# attiny85at1.upload.protocol=avrispv2
# attiny85at1.upload.using=pololu

attiny85at1.upload.maximum_size=8192

# Default clock (slowly rising power; long delay to clock; 8 MHz internal; divide clock by 8)
# Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 64 ms; [CKSEL=0010 SUT=10]; default value
# Divide clock by 8 internally; [CKDIV8=0]
# Brown-out detection disabled; [BODLEVEL=111]
# Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0]

attiny85at1.bootloader.low_fuses=0x62
attiny85at1.bootloader.high_fuses=0xD7
attiny85at1.bootloader.extended_fuses=0xFF
attiny85at1.bootloader.path=empty
attiny85at1.bootloader.file=empty85at1.hex

attiny85at1.build.mcu=attiny85
attiny85at1.build.f_cpu=1000000L
attiny85at1.build.core=tiny
 
###########################################################################
###########################################################################



Depois disso, iniciei o Arduino, certificando-me de que o ATtiny necessário aparecesse no menu Serviço - Placa:



Conectei (e, é claro, escolhi a placa certa) o Arduino Mega 2560, escrevi o esboço do ISP do Arduino a partir dos exemplos:



Em seguida, conectei o ATtiny ao Mega, guiado pela pinagem do Mega 2560 e instruções do esboço do ISP do Arduino:

// pin name:    not-mega:         mega(1280 and 2560)
// slave reset: 10:               53 
// MOSI:        11:               51 
// MISO:        12:               50 
// SCK:         13:               52 


Obviamente, conectei o ATtiny à energia e ao terra, no meu caso, as duas linhas foram compartilhadas com o programador, ou seja, Mega 2560, embora todos entendamos que o mínimo necessário do total é o SPI, reset e linhas de terra.

E quando tudo estava pronto, então primeiro (não esquecendo de escolher a placa ATtiny85), o gerenciador de inicialização escreveu:



E depois dele - na verdade, um esboço
// 
// http://donalmorrissey.blogspot.ru/2010/04/sleeping-arduino-part-5-wake-up-via.html
// http://www.technoblogy.com/show?KX0

/* 
 . 			
 - . 		
 - ..		
 - ...		
 - 			    
 ...			 
 --			, 
 .......... 	
 */


#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

volatile int f_wdt=1;

#define xPin A1 //   X
#define yPin A2 //   Y
#define zPin A3 //   Z
#define alPin 0 //   
#define posPowPin 1 //   
#define timeLimit 10000 //    
 #define posCountSleep 9 //      (*8 ) 8
#define posCountMove 231 //      (*8 ) 230
#define posCountBack 41 //      40
#define tresholdSleep 25 //     
#define tresholdMove 25 //    
#define tresholdBack 20 //     
#define movPercentMove 92 //   ( %)   
#define movPercentBack 40 //    ( %)   
#define startTimeOut 5000//         
#define motionTimeOut 1500//        

unsigned long timeOut; //    
byte treshold = 15; //    
int posCounter = 1; //    
byte posMode = 0; //   (  -  = 0;    - 1;  - 2;  - 3)
int posTolerance = 0; //         ( 009b).
int x, y, z, x1, y1, z1; // 
int relX, relY, relZ; //    
int posCount; //     
boolean alarmRaised = false; //  
boolean standBy = false; //    

// http://www.technoblogy.com/show?KX0
#define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off) 
#define adc_enable()  (ADCSRA |=  (1<<ADEN)) // re-enable ADC

ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
  }
}

void enterSleep(void)
{
  pinMode(alPin, INPUT);
  pinMode(posPowPin, INPUT);

  adc_disable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  

  sleep_enable();

  sleep_mode();

  sleep_disable(); 

  power_all_enable();
  adc_enable();

  pinMode(alPin, OUTPUT);
  digitalWrite(alPin, LOW);

  pinMode(posPowPin, OUTPUT);
  digitalWrite(posPowPin, LOW);
}


void setup() {

  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCR |= _BV(WDIE);

  //   
  pinMode(alPin, OUTPUT);
  digitalWrite(alPin, LOW);

  //   
  pinMode(posPowPin, OUTPUT);
  digitalWrite(posPowPin, LOW);

  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(zPin, INPUT);

  delay(1000); // -
  blinker(500, 1); //   

  if (motionDetect(startTimeOut) == true) {

    getPos(); //  	

    if (abs(x1-y1) > abs(x1-z1)) {
      if (abs(x1-z1) > abs(y1-z1)) {
        selectX(); // x
      } 
      else {
        posMode = 2; // y
        posCount = posCountMove; //   
        treshold = tresholdMove;		
        blinker(1000, 1);
        blinker(500, 2);  
      }
    } 
    else {
      if (abs(x1-y1) > abs(z1-y1)) {
        selectX(); //x
      } 
      else {
        posMode = 1; // z
        posCount = posCountSleep; //    		
        treshold = tresholdSleep;
        blinker(1000, 1);
        blinker(500, 1);    
      }
    }
  }

  if (posMode > 0) {

    getPos(); //  
    x = x1; //  
    y = y1;
    z = z1;
    timeOut = millis();	

    while ((millis() - timeOut) < timeLimit) {
      getPos();
      if (comparePos(x, y, z, x1, y1, z1) == false) { //    -  
        blinker(1000, 1); //    
        x = x1; 
        y = y1; 
        z = z1;
        timeOut = millis();
      }
    }

    //       
    standBy = true;
    blinker(500, 3); //   
  }
  else {
    blinker(1500, 2);
  }	


}

void loop() {

  if(f_wdt == 1) {

    if (posMode == 0) {
      /* Don't forget to clear the flag. */
      f_wdt = 0;

      /* Re-enter sleep mode. */
      enterSleep();
    }
    else {

      getPos();

      if (posCounter <= posCount && alarmRaised == false) { //          
      
      if (posMode == 2) { //    
        if (motionDetect(motionTimeOut) == true) { //      
          posTolerance = posTolerance++; //   
        }

        if ((posCounter - posTolerance) > (posCount*movPercentMove)/100) { //      %   
          alarmRaised = true; //   
        } 

      } else { //   
          if (comparePos(x, y, z, x1, y1, z1) == true) { //    
            posTolerance = posTolerance++; //   ""  (       )
          }
        }
      
        
        if (posMode == 1) { //   
          if (posTolerance >= (posCount - 1)) { //     
            alarmRaised = true; //   
          } 
        }

        if (posMode == 3) { //    
          if ((posCounter - posTolerance) > (posCount*movPercentBack)/100) { //       %   
            alarmRaised = true; //   
          } 
        }

       posCounter++;

      } 
      else { //    

       posCounter = 1; //   
       posTolerance = 0;
       
      }

      if (alarmRaised == true) { //   

        if (posMode == 1) { //   
          blinker(500, 8); // 8  ...
          getPos(); 
          if (comparePos(x, y, z, x1, y1, z1) == false) { // ... 
            alarmRaised = false; //  
            posCounter = 0;
          }
        }

        if (posMode == 2) { //   
          blinker(500, 10); // 10 
          alarmRaised = false; //   
          posCounter = 0;
        } 

        if (posMode == 3) { //   
          blinker(500, 1); //    ...
          getPos();
          if (comparePos(x, y, z, x1, y1, z1) == true) { // ...  
            alarmRaised = false; //   
            posCounter = 0;
          }
        }
        
        posTolerance = 0; //    
      } 
      else {
        /* Don't forget to clear the flag. */
        f_wdt = 0;

        /* Re-enter sleep mode. */
        enterSleep();
      }
    } // posMode == 0
  } // wdt
} // loop

// 

void blinker(unsigned int impulse, byte times) {

  for (byte ttimes = 0; ttimes < times; ttimes++) {

    digitalWrite(alPin, HIGH);
    delay(impulse);
    digitalWrite(alPin, LOW);
    delay(impulse);

  }

}


//     
boolean comparePos(int xOne, int yOne, int zOne, int xTwo, int yTwo, int zTwo) {

  boolean compareRes = false;

  relX = xOne - xTwo;
  relY = yOne - yTwo;
  relZ = zOne - zTwo;

  if (abs(relX) < treshold && abs(relY) < treshold && abs(relZ) < treshold) {
    compareRes = true; //      
  }
  return compareRes;

}

boolean motionDetect(int detectTimeOut) {
 
  boolean motionDetected = false;
  
  getPos();
  x = x1; y = y1; z = z1; //   ,       ,    
  timeOut = millis();
  
  while (((millis() - timeOut) < detectTimeOut)) { //    detectTimeOut ,       
   if (motionDetected == false) { //    
    if (comparePos(x, y, z, x1, y1, z1) == false) { //     
      motionDetected = true; //   
    } 
    else {
      getPos();
    }
   }
  }
  
  return motionDetected;
}

//   
void getPos(){

  digitalWrite(posPowPin, HIGH);
  delay(10);

  byte i;
  unsigned int posX = 0;
  unsigned int posY = 0;
  unsigned int posZ = 0;

  for (i = 0; i < 100; i++) {
    posX = posX + analogRead(xPin);
    posY = posY + analogRead(yPin);
    posZ = posZ + analogRead(zPin);
  }

  x1 = posX/100;
  y1 = posY/100;
  z1 = posZ/100;

  digitalWrite(posPowPin, LOW); 
}

void selectX() {
  posMode = 3;
  posCount = posCountBack; //   		
  treshold = tresholdBack;
  blinker(1000, 1);
  blinker(500, 3);
}






Habitação


Desde o início, eu não tinha ilusões sobre o fato de que o caso teria que ser resolvido do zero, pelo que está à mão. A primeira idéia, que eu rapidamente rejeitei, foi pegar uma caixa de várias placas de poliestireno coladas. Seria patético - bem, como uma caixa tipográfica de um relógio suíço - e bastante confiável devido à resistência e rigidez suficientemente altas do material.

No entanto, meu fervor diminuiu um pouco depois que cortei uma tampa do poliestireno especificado (apenas 1,5 mm de espessura) para a segunda encarnação de Eulampia . Acabou sendo difícil - cortar poliestireno com apenas uma faca de carpete.

Portanto, fiquei muito feliz quando outra iluminação aconteceu - você precisa usar argila de polímero, que é fácil de obter a forma desejada, e depois assar até ficar firme. Mais precisamente, pareceu-me assim, porque não levei em conta um detalhe importante: tenho que o epóxi não endurece, que a argila do polímero não endurece particularmente bem. Mas isso é letra.

Decompi os componentes da maneira mais compacta, estimei as dimensões do corpo e fiz cofragens de papelão da forma correspondente, preenchi-o com argila de polímero. Então ele cortou os furos necessários em uma massa ainda macia e começou a assar de acordo com as instruções. E então, pela mesma quantidade de tempo, já que o barro não queria endurecer.

A propósito, era lógico que a bateria fizesse um furo com um diâmetro um pouco maior; portanto, tendo estudado o site do Banco da Rússia, descobri que uma moeda de 10 rublos é adequada para esse papel, que é cunhado desde 2010, já que seu diâmetro é 22 mm. Apenas uma margem para que o CR2032 caia normalmente no compartimento da bateria, que carrego com um contato removido há muito tempo de outro compartimento da bateria.

Obviamente, também emprestei o design do compartimento da bateria, pois mal consigo encontrar algo melhor, o que elimina a dor de cabeça ao reverter.

. algo assim no processo


. e então depois eu tive que desmontar o corpo já colado


Ou seja, tudo é bem simples: prendi o componente, pressionei-o levemente, removi-o - recorte-o ao longo do contorno. Bem, além de slots e canais para postagem. O que é bom: uma argila muito pequena foi para o posicionador. Naturalmente, comprei o menor pacote de 57 e ainda tenho 50 gramas dessa valiosa matéria-prima. Este é o primeiro. E a segunda: para não perturbar a geometria do layout de plástico parado, você pode assá-lo sem removê-lo do papelão, já que a temperatura necessária é de 100 ° C a 110 ° C, ou seja, longe do fogo do papel.

Depois que a moldura da caixa, de alguma forma, assou ligeiramente as bordas com uma faca. E depois de experimentar os componentes, descobri que essa argila # $% & * # não é apenas endurecida como deveria, mas também "frita" no processo de cozimento. Portanto, tive que expandir cuidadosamente os recortes. Felizmente, o material resultante não era uma pedra.

O problema das paredes superior e inferior foi resolvido com a ajuda de fragmentos de um cartão de plástico que, diferentemente de um poliestireno de meio milímetro, é perfeitamente cortado com uma tesoura simples. Eu imediatamente colei a parede inferior (e a parte superior também, mas em vão), mas no final agi de maneira diferente da parte superior. A saber: coloque a armação e empacote cuidadosamente a estrutura resultante em um tubo termo-retrátil. A vantagem dessa abordagem é que, se necessário, tudo pode ser facilmente desmontado para piscar e também fácil de montar novamente.

. espetáculo de partir o coração




Bem, o olhar - o que há de errado com ele? De qualquer forma, eu ia fazer um estojo têxtil para o Positioner, já que isso é mais racional para o dispositivo, que teoricamente leva para a cama. E o caso apenas melhorará a aparência e as sensações táteis.

A propósito, eu não recomendo o psiquiatra branco se você seguir meus passos: elegante, é claro, mas fica sujo muito rapidamente.

Por que não imprimir em uma impressora 3D? Em primeiro lugar, eu não tenho isso. E os proprietários não sabem. Em segundo lugar, não sei desenhar modelos. Em terceiro lugar, eu teria que imprimir muito, desde que planejei esse quadro 30x70 mm e, no processo, ele foi transformado em pouco menos de 30 mm de largura e cerca de 65 mm de comprimento. Além disso, no barro que ainda não tinha tempo de agarrar, consegui cortar o entalhe do botão, do qual havia esquecido a princípio.

E o plástico é sempre reimpresso. Embora eu não discuta, seria muito mais legal que a minha versão da modelagem 3D do Redneck.

Isenção de Garantia


Antes de tudo, quero dizer que o posicionador não apenas não tem a menor relação com dispositivos médicos, mas também com suplementos alimentares para ele como com a lua. Este é um experimento. Esta é uma fuga da preguiça e do tédio. Esta é uma tentativa de inventar e fazer algo assim com suas próprias mãos.

Portanto, é claro, não pode ser considerado um salva-vidas ou algo parecido. Companheiro engraçado, assistente - sim. E, é claro, pode ser enganado de propósito, mas é possível - não de propósito. Especialmente se estiver errado escolher um local para fixação.

Por exemplo, para impedir o sono nas costas, o Posicionador, depois de artificial, deve fixar-se na parte do corpo que ocupa uma posição muito inequívoca quando o resto do corpo se vira de costas. E ao controlar a mobilidade, é melhor se o Positioner estiver na parte mais móvel do corpo, embora eu tenha verificado que ele lida bem com as configurações atuais no bolso das horas. Bem, se se trata de postura, o Posicionador precisa ser consertado para que, se você estiver torto, ele estivesse nessa parte torta.

Caso contrário, não adianta.

Eu concordo que seria possível usar outro controlador e outro acelerômetro, seria possível ter mais C ++ e mais com meus próprios cérebros e ... Então, eu não proíbo - faça, tente. Tenho certeza que você terá sucesso, melhor que o meu.

Na verdade, é por isso que escrevo no Geek, e não no Habré. Para, por assim dizer, não comprometer o último, que é realmente o primeiro.

Source: https://habr.com/ru/post/pt381771/


All Articles