Perangkat untuk mencegah tidur terlentang dan mengendalikan postur "Positioner" UPSNS-KO



Suatu hari saya menemukan bahwa wanita yang sedang mengandung bayi dalam bahaya tidur terlentang pada tahap akhir kehamilan. Masalahnya adalah dalam hal ini, arteri darah terjepit di bawah berat janin, yang mengancam konsekuensi yang sangat serius, jika tidak lebih,.

Karena itu, saya berpikir bahwa mungkin tidak terlalu sulit bagi saya untuk melakukan beberapa hal yang dapat mencegahnya masuk ke dalam situasi yang berpotensi berbahaya ini. Tentu saja, setelah waktu yang cukup singkat, mata saya terbuka pada kenyataan bahwa wanita bijak menghindari risiko dengan cara yang sepenuhnya alami - mereka hanya tidak nyaman tidur telentang di kencan yang sangat terlambat ini.

Tapi jangan membuang mikrokontroler yang sudah dibeli, akselerometer, dan ide-ide brilian yang memperbudak pikiran, kan?

Omong-omong, ada demotivator lain. Dimulai dengan opsi hardcore:



Dan diakhiri dengan pengoreksi postur tubuh yang benar-benar glamor , yang, sejujurnya, saya pelajari kemudian daripada wawasan saya sendiri.

Secara umum, pada awalnya saya ingin sederhana dan tanpa embel-embel, seperti Occam normal, dengan pisau cukur normal. Artinya, perangkat hanya harus memperbaiki posisi dan, jika tidak berubah dalam waktu tertentu, untuk menyampaikan informasi yang tak ternilai ini kepada pemiliknya dengan getaran. Pilihan pemberitahuan semacam itu wajar bagi saya, karena untuk tahun kedua saya telah mengenakan gelang pedometer dengan alarm getaran, yang (jam alarm) adalah keajaiban.

Tentu saja, kita semua mengerti bahwa sinyal getaran tidak cocok untuk semua orang. Tapi saya tidak punya keluhan tentang perangkat universal - di mana-mana, Anda tahu, keseimbangan yang wajar harus dipertahankan. Omong-omong, itulah sebabnya dalam desain akhir sudah ada lingkungan Arduino favorit kami, dan banyak solusi biadab, dan bahkan pita listrik biru (benar-benar biru, tukang ledeng yang dibawa).

Secara umum, pisau cukur Occam patah ketika saya mulai menggiling kontur jam alarm di masa depan. Yang tiba-tiba mengungkapkan bakat potensial lainnya, yaitu: kontrol postur dan peringatan [office plankton] tentang imobilitas yang terlalu lama. Alasan untuk memperluas fungsionalitas adalah hal biasa - sangat disayangkan melihat bagaimana sumber daya mikrokontroler yang paling kuat, tetapi masih cukup serius menghilang.

Bagaimana itu bekerja


Seperti yang sudah Anda ketahui, Positioner memiliki tiga mode operasi:

1) Pencegahan tidur telentang (baik, atau dalam posisi lain, itu tidak masalah baginya)
2) Kontrol postur
3) Peringatan tentang mobilitas rendah

Dan, karena Anda masih tidak tahu, hanya satu tombol, yang melakukan fungsi reset mikrokontroler.

Oleh karena itu, untuk memilih mode yang diinginkan, cukup untuk melakukan dua tindakan: tekan tombol dan tahan Positioner di salah satu dari tiga posisi, jika secara kiasan - di belakang, samping atau berdiri. Dan untuk menempatkan sesuatu dalam mode siaga (analog mematikan), Anda tidak perlu melakukan apa pun. Artinya, mereka menekan tombol, meletakkannya - dan positioner tertidur.

Apa masalahnya? Setelah memilih mode atau selama euthanasia, Positioner perlu dijaga agar tetap diam, karena dalam kasus pertama ia perlu waktu untuk menghafal posisi tersebut, dan pada yang kedua - untuk memahami bahwa sudah waktunya tidur. Ada dua interval utama: lima detik pertama setelah mengaktifkan servis untuk memilih mode, dan sepuluh berikutnya untuk menerima posisi.

Pada saat yang sama, omong-omong, sepuluh detik adalah konsep kondisional, karena Positioner mengingat "koordinat" hanya jika, dalam waktu yang ditentukan, posisi relatif tidak berubah. Ini agar Anda dapat memilih mode operasi dan dengan tenang berpegang pada perangkat tanpa khawatir akan waktu tunggu yang sulit untuk operasi ini. Tetapi begitu saya mengaitkannya - diam selama sepuluh detik sehingga Positioner memahami bahwa sudah waktunya untuk turun ke bisnis.

Dengan kata lain, pembaca yang penuh perhatian sudah menebak bahwa pembacaan accelerometer digunakan untuk memilih mode, dan saya masih menyebar melalui pohon.

Di sini, Anda dapat melihat cara kerjanya pada contoh prototipe di papan tempat memotong roti:



Seperti yang Anda lihat, semuanya cukup sederhana.

Dalam versi final yang kurang lebih, alarm bekerja sebagai berikut:

1) Dalam pencegahan tidur di belakang, Positioner dipicu setelah sekitar satu menit dan bangun dengan serangkaian 8 sinyal, yang tidak mengganggu dalam keadaan apa pun, kecuali untuk pelepasan baterai. Dan agar dia berhenti melakukan ini, Anda harus berbaring entah bagaimana secara berbeda dan menunggu berakhirnya serangkaian sinyal. Jika tidak, serangkaian sinyal akan diulang.

2) Dalam mode kontrol postur, Positioner memastikan bahwa postur yang benar dipertahankan sekitar 60% dari interval 5 menit. Kalau tidak, itu mulai bergetar sampai Anda kembali ke postur yang tepat.

3) Dalam mode peringatan mobilitas rendah, Positioner memastikan bahwa setidaknya 8% dari waktu dari interval 30 menit dikhususkan untuk pergerakan. Jika tidak demikian, ia pernah menghasilkan serangkaian 10 sinyal, yang tidak terputus dan mulai menghitung interval baru.

Tentu saja, alarm dalam mode apa pun dapat terganggu dengan menekan tombol reset.

Adapun interval dan pemberitahuan yang mungkin tampak aneh, saya melanjutkan dari yang berikut ini. Satu menit di belakang dalam pandangan saya cukup panjang, dan 8 sinyal tanpa gangguan (dan prospek menerima jumlah yang sama berulang kali) tampaknya menjadi alasan yang cukup untuk bangun.

Di sisi lain, kontrol postur tidak begitu kritis, oleh karena itu, pertama, kontrol seratus persen tidak diperlukan dan, kedua, kontrol postur tidak mungkin terjadi dalam mimpi, oleh karena itu, sinyal yang berhenti ketika Anda kembali ke posisi yang diinginkan sudah cukup. Nah, duduk sepanjang waktu, seolah-olah dia menelan arshin - sedikit bodoh dan tidak mungkin. Oleh karena itu, interval kontrol dapat disesuaikan.

Akhirnya, ketika saya mencari informasi tentang minimum yang diperlukan untuk aktivitas motorik, saya menemukan bahwa 15-20 menit setiap tiga jam sepertinya kurang lebih memadai. Pengaturan positioner mempertimbangkan informasi ini, tetapi jika diinginkan, mereka dimodifikasi pada tahap "flashing" mikrokontroler. Sekali lagi, tidak perlu mengguncang seseorang sampai mereka kehilangan kesadaran, karena pergi atau tidak pergi adalah sukarela. Oleh karena itu, hanya pengingat halus dalam bentuk sepuluh sinyal getaran.

Tentu saja, semua interval ini bukan dogma dan dapat dengan mudah diubah. Itu akan menjadi keinginan.

Positioner ini ditenagai oleh baterai lithium CR2032. Konsumsi saat ini dalam mode tidur (beberapa mode pseudo keempat dari Positioner, bukan controller) adalah 4 μA, yang saya anggap sebagai alasan yang cukup untuk menyederhanakan desain dalam hal menolak saklar daya khusus. Pada awal dan ketika langsung menentukan posisi, konsumsi dapat melebihi 2 mA untuk sepersekian detik, tetapi terutama dalam 1 mA kecuali untuk saat-saat operasi sinyal.

Dalam interval antara penentuan posisi, pengontrol berada dalam mode Power down, di mana konsumsinya mirip dengan mode tidur Positioner - 4 μA. Pengontrol bangun dengan pengatur waktu kira-kira setiap 8 detik - ini pada saat yang sama merupakan penghematan baterai maksimum dan dapat diterima untuk operasi semua mode yang kurang lebih benar.



Sayangnya, saya tidak bisa menghitung otonomi penuh, karena saya tidak tahu caranya.

Bagaimana ini dilakukan


Pertama, semuanya di luar kepala saya, kedua, dadakan, dan ketiga amatir, karena itu lebih menarik bagi saya untuk menutup gestalt ini daripada menaikkannya ke tingkat absolut.

Oleh karena itu, di masa depan kita akan ingat bahwa kita berbicara tentang implementasi yang sangat spesifik dan satu. Untuk yang Anda perlu:

1) ATtiny85 mikrokontroler (misalnya, seperti )
2) Accelerometer ADXL335 dirakit (misalnya, seperti atau segera dengan 3.3V power supply)
3) Getaran motor dari ponsel (saya mendapat banyak perbaikan untuk perbaikan)
4) Button (saya mengambil dari remote control yang dibongkar)
5) 2.2Kohm resistor
6) Jenis 1N4007 dioda (saya punya sesuatu seperti KD522
7) NPN transistor, misalnya 2N2222 (saya mengambil sesuatu dari DVD yang rusak)
8) Baterai (CR2032)
9 ) Kasing yang sesuai

Skema adalah sebagai berikut:



Saya jujur mencuri bagian mengenai koneksi motor dalam proyek ELSE yang sangat menarik .

Ngomong-ngomong, saya sangat merekomendasikan gambar yang begitu indah dari Sparkfun sehingga tidak mungkin untuk tidak mengutipnya:



Ada satu trik lagi. Intinya adalah bahwa setidaknya ada dua versi papan dengan accelerometer ADXL335: 3.3V dan hingga 5V. Sebenarnya, rentang tegangan operasi accelerometer adalah dari 1.8V ke 3.6V, sehingga versi kedua berbeda dari yang pertama dengan adanya penstabil tegangan.

. di sini adalah satu dengan stabilizer (kecoa berkaki tiga di sebelah kiri accelerometer). FotoTinydeal


. dan yang ini tanpa stabilizer. Foto oleh Hobby Electronics


. ada juga opsi hybrid - di mana Anda dapat menyalakan secara terpisah dari 3.3V (melewati stabilizer, dan dari 5V melalui stabilizer). Foto oleh Adafruit


Saya sekarang memiliki papan dengan stabilizer yang bekerja baik dari 5V, yang tidak mengejutkan, dan dari 3.3V (saya periksa). Tetapi karena saya tidak melihat alasan untuk menghangatkan stabilizer dan, karenanya, membuang baterai dengan sia-sia, pada versi terakhir perangkat saya menghubungkan sendiri daya akselerometer langsung ke sana, melewati stabilizer.

. untuk melewati stabilizer, Anda dapat menavigasi di papan tulis dan pada lembar data ADXL335


Mungkin masih masuk akal untuk berbicara tentang fakta bahwa mikrokontroler ATtiny85 juga berbeda. Keripik dengan tanda tipe ATtiny85-20 paling sering dan lebih murah di toko, dan ATtiny85-10 lebih murah. Dari sudut pandang pembuatan Positioner (dan menurut lembar data ), perbedaan yang paling penting adalah bahwa ATtiny85-20 beroperasi pada kisaran tegangan 2.7V - 5.5V, dan ATtiny85-10 - dalam kisaran 1.8V - 5.5V. Itu yang kedua jauh lebih disukai dari sudut pandang penggunaan kapasitas baterai yang paling penuh.

Perbedaan kedua adalah frekuensi clock 20 MHz versus 10 MHz. Meskipun untuk Positioner ini, secara umum, tidak penting: ia bekerja pada 1 MHz dan tidak mengeluh tentang kehidupan. Tapi karena saya baru saja meraih hal pertama yang muncul dan lebih murah, saya hanya punya ATtiny85-20.

Akhirnya, jika itu merupakan misteri bagi seseorang, saya menghubungkan accelerometer ke controller untuk alasan yang paling mudah untuk mematikannya (accelerometer) dalam mode tidur Positioner. Jika tidak, kami akan terus bocor hingga 350 μA (menurut datasheet ADXL335).

Dia merakit segala sesuatu dengan instalasi yang terpasang di dinding, menghubungkan elemen-elemen dengan kawat 0,1 mm berenamel (ditandai dengan kawat Jumper), sepasang gulungan yang diberikan oleh orang Cina yang baik kepada saya bersama dengan stasiun solder. Dan yang saya belum tahu selama satu tahun, ke mana harus pergi. Ternyata idealnya: kawat sobek sempurna dengan besi solder 300C dengan rosin konvensional, dan cukup nyaman untuk menyolder ATtiny85 dan transistor dalam paket SOT23.

Hal ini menghasilkan lanskap yang cukup utilitarian:

. komponen apa yang - dan diatur. Sangat tidak menguntungkan untuk membeli satu per satu di butik B & D


Algoritma dan Kode



Algoritme dasar dari pekerjaan Positioner adalah sebagai berikut:



Sebagai lingkungan pemrograman, saya sepenuhnya memilih Arduino sebagai alternatif, karena sekarang paling tidak buruk, tetapi saya hanya mengenalnya. Yah, saya menyebutkan gestalt di awal - ini juga menjelaskan fakta mengapa saya tidak belajar C ++ untuk membuat Positioner.

Adapun kode, saya harus memberikan beberapa komentar.

Berdasarkan model penggunaan perangkat (dihidupkan dan dilupakan sampai mengingatkan), akan sangat diinginkan untuk melupakan penggantian baterai setiap hari. Dan untuk ini, Anda perlu menghemat energi secara serius, yang sangat mungkin, karena lembar data ATtiny85 menyebutkan bahwa konsumsi minimum adalah sepersepuluh mikroamer. Saya harus mengatakan segera - ke ketinggian seperti itu saya tidak naik (atau tidak jatuh?).

Di sini saya kembali memilih cara termudah. Yaitu - googled apa yang dibutuhkan. Yang pertama adalah kode untuk menempatkan ATtiny85 ke mode tidur terdalam dengan terbangun oleh pengawas waktu .

Pada saat yang sama, konsumsi saat ini dari unit milliamps turun menjadi ratusan microamps. Sudah cantik, tapi masih belum cukup cantik.

Saya harus melihat lebih jauh. Dan kemudian ternyata bahwa tidur adalah mimpi, dan periferal perlu dimatikan secara manual. Pada saat yang sama, bagian terbesar dari energi, bahkan dalam mode tidur, dimakan oleh ADC. Di sini ada tertulis .

Setelah mematikan ADC saat tidur, catu daya Positioner menjadi serasi yang saya bisa google sama sekali. Yaitu, seperti yang saya tulis di atas, konsumsi minimum adalah 4 μA, selama bangun selama pengukuran - puluhan atau ratusan microamp, dengan menjalankan vibromotor dapat melebihi 2 mA.

Kelangsungan dari campuran kode ini dapat diperkirakan oleh fakta bahwa CR2032 telah bekerja selama seminggu di Positioner dalam mode pengujian jauh dari kesegaran pertama. Sebagian besar waktu, tentu saja, dalam mode siaga, tetapi waktu aktifnya layak. Singkatnya, itu dekat dengan model penggunaan nyata.

Mengenai bekerja dengan accelerometer. Faktanya adalah, sejauh yang saya bisa, saya mengambil abstrak dari nilai-nilai absolut. Ada beberapa alasan untuk ini. Pertama, akselerometer dapat diubah dengan cara ini tanpa memikirkan cara kerja perangkat keras tertentu. Kedua, saya tidak punya, maaf untuk tautologi, besi menjamin bahwa jika terjadi penurunan tegangan yang tak terhindarkan selama pelepasan baterai, pembacaan accelerometer yang terkait dengan pemrosesan ADC dalam mikrokontroler tidak akan "mengambang".

Akhirnya, pengaturan ditempatkan di bagian deklarasi variabel. Begitulah cara saya memuji diri sendiri - karena untuk menyempurnakan Positioner, Anda tidak perlu menggali semua kode dan mengingat saya dengan kata-kata buruk saat mencari semua fragmen di mana Anda perlu mengganti nilainya.

Kode diunggah ke ATtiny85 melalui Arduino Mega sesuai dengan instruksi umum. Itu dukungan ATtiny yang pertama diunduh untuk versi lingkungan Arduino di sini .

Dan, seperti biasa, ia membongkar isi arsip (direktori kecil dengan semua konten) ke folder perangkat keras direktori Arduino-nya:



Lalu aku masuk ke direktori ini dan, sesuai instruksi, membuat file boards.txt ke mana aku menyalin Prospective Boards.txt dari file yang ada apa yang saya butuhkan - yaitu Deskripsi ATtiny 1 MHz dan, untuk berjaga-jaga, 8 MHz.

Ini adalah 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
 
###########################################################################
###########################################################################



Setelah itu saya mulai Arduino, memastikan ATtiny yang diperlukan muncul di menu Board - Service: Saya



terhubung (dan, tentu saja, memilih board yang tepat) Arduino Mega 2560, menulis sketsa Arduino ISP dari contoh:



Lalu saya menghubungkan ATtiny ke Mega, dipandu oleh Mega 2560 pinout dan instruksi dari sketsa Arduino ISP:

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


Tentu saja, saya menghubungkan ATtiny ke power dan ground, dalam kasus saya kedua baris dibagikan dengan programmer, yaitu Mega 2560, meskipun kita semua mengerti bahwa minimum total yang diperlukan adalah SPI, reset, dan garis tanah.

Dan ketika semuanya sudah siap, maka pertama (tidak lupa untuk memilih board ATtiny85), bootloader menulis:



Dan setelah dia - sebenarnya sketsa
// 
// 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);
}






Perumahan


Sejak awal, saya tidak punya ilusi tentang fakta bahwa kasus ini harus dilakukan dari awal dari apa yang ada. Gagasan pertama, yang dengan cepat saya tolak, adalah untuk mendapatkan sekotak beberapa pelat polystyrene yang direkatkan. Itu akan menyedihkan - baik, seperti kasus pengaturan jam tangan dari Swiss - dan cukup dapat diandalkan karena kekuatan dan kekakuan material yang cukup tinggi.

Namun, semangat saya memudar sedikit setelah saya memotong tutup dari polystyrene yang ditentukan (hanya 1,5 mm) untuk inkarnasi Eulampia kedua . Ternyata menjadi sulit - potong polystyrene hanya dengan satu pisau karpet.

Oleh karena itu, saya sangat senang ketika penerangan lain terjadi - Anda perlu mengambil tanah liat polimer, yang mudah untuk memberikan bentuk yang diinginkan, dan kemudian dipanggang hingga padat. Lebih tepatnya, menurut saya seperti ini, karena saya tidak memperhitungkan detail penting: Saya berpendapat bahwa epoksi tidak mengeras, bahwa tanah liat polimer tidak mengeras dengan baik. Tapi ini liriknya.

Saya menguraikan komponen dengan cara yang paling kompak, memperkirakan dimensi tubuh dan membuat bekisting kardus dari bentuk yang sesuai, mengisinya dengan tanah liat polimer. Kemudian dia memotong lubang yang diperlukan dalam massa yang masih lunak dan mengatur untuk memanggang sesuai dengan instruksi. Dan kemudian untuk jumlah waktu yang sama, karena tanah liat tidak mau mengeras.

Ngomong-ngomong, logis bagi baterai untuk membuat lubang dengan diameter sedikit lebih besar, oleh karena itu, setelah mempelajari situs Bank of Russia, saya menemukan bahwa koin 10 rubel telah cocok untuk peran ini, yang telah dicetak sejak 2010, karena diameternya 22 mm. Hanya selisih sehingga CR2032 biasanya masuk ke dalam kompartemen baterai, yang telah saya sambungkan dengan kontak yang sudah lama dihapus dari beberapa kompartemen baterai lainnya.

Tentu saja, saya juga meminjam desain kompartemen baterai, karena saya tidak dapat menemukan sesuatu yang lebih baik, yang menghilangkan sakit kepala saat membalikkan.

. sesuatu seperti ini dalam proses


. dan setelah saya harus membongkar tubuh yang sudah terpaku


Artinya, semuanya cukup sederhana: Saya memasang komponen, sedikit menekannya, melepaskannya - memotongnya sepanjang kontur. Nah, plus slot dan saluran untuk posting. Apa yang baik: tanah liat yang sangat kecil pergi ke Positioner. Secara alami, saya membeli paket terkecil dari 57, dan saya masih memiliki 50 gram bahan baku yang berharga ini. Ini yang pertama. Dan yang kedua: agar tidak mengganggu geometri dari tata letak plastik yang masih, Anda dapat memanggangnya tanpa mengeluarkannya dari kardus, karena suhu yang diperlukan adalah 100C - 110C, mis. jauh dari api kertas.

Setelah bingkai kasing, entah bagaimana, sedikit memanggang pinggirannya dengan pisau. Dan setelah mencoba komponen-komponen saya menemukan bahwa tanah liat # $% & * # ini tidak hanya tidak mengeras sebagaimana mestinya, tetapi juga "digoreng" dalam proses memanggang. Karena itu, saya harus hati-hati memperluas guntingan. Untungnya, bahan yang dihasilkan bukan batu.

Masalah dinding atas dan bawah diselesaikan dengan bantuan serpihan kartu plastik, yang, tidak seperti polistiren setengah milimeter, dipotong sempurna dengan gunting sederhana. Saya langsung terjebak di dinding bawah (dan atas juga, tetapi sia-sia), tetapi pada akhirnya saya bertindak berbeda dari atas. Yaitu: letakkan di bingkai dan hati-hati dikemas struktur yang dihasilkan ke dalam tabung panas menyusut. Keuntungan dari pendekatan ini adalah, jika perlu, semuanya dapat dengan mudah dibongkar untuk dipasang dan mudah dipasang kembali.

. tontonan memilukan




Nah, lihat - apa yang salah dengan dia? Ngomong-ngomong, saya akan membuat kasing tekstil untuk Positioner, karena ini paling rasional untuk perangkat, yang secara teoritis dibawa ke tempat tidur. Dan kasing hanya akan meningkatkan penampilan dan sensasi sentuhan.

Ngomong-ngomong, saya tidak merekomendasikan psikiater putih jika Anda mengikuti jejak saya: elegan, tentu saja, tetapi menjadi kotor dengan sangat cepat.

Mengapa tidak dicetak pada printer 3D? Pertama, saya tidak memilikinya. Dan pemiliknya tidak tahu. Kedua, saya tidak tahu cara menggambar model. Ketiga, saya harus banyak mencetak, karena saya pertama kali merencanakan bingkai ini 30x70 mm, dan dalam prosesnya diubah menjadi sedikit kurang dari 30 mm dan sekitar 65 mm. Selain itu, di tanah liat yang belum memiliki waktu untuk memahami, saya berhasil memotong takik untuk tombol, yang saya lupa pada awalnya.

Dan plastik setiap kali dicetak ulang. Meskipun saya tidak berdebat, itu akan jauh lebih keren daripada versi saya pemodelan 3D Redneck.

Penafian Garansi


Pertama-tama, saya ingin mengatakan bahwa Positioner tidak hanya tidak memiliki hubungan sekecil apa pun dengan peralatan medis, tetapi bahkan dengan suplemen makanan baginya seperti ke bulan. Ini adalah eksperimen. Ini merupakan pelarian dari kemalasan dan kebosanan. Ini adalah upaya untuk menciptakan dan melakukan sesuatu seperti ini dengan tangan Anda sendiri.

Karena itu, tentu saja, itu tidak bisa dianggap sebagai penyelamat atau semacamnya. Teman lucu, asisten - ya. Dan, tentu saja, itu bisa dibohongi dengan sengaja, tetapi itu mungkin - bukan dengan sengaja. Apalagi jika salah memilih tempat untuk penambat.

Sebagai contoh, untuk mencegah tidur telentang, Positioner harus, setelah membuat, memperbaiki bagian tubuh yang menempati posisi yang sangat tegas ketika bagian tubuh lainnya telah mengaktifkan bagian belakang ini. Dan ketika mengendalikan mobilitas, lebih baik jika Positioner berada di bagian tubuh yang paling bergerak, walaupun saya memeriksa bahwa dia dapat mengatasi dengan baik pengaturan saat ini di saku jam jeans. Nah, jika soal postur, maka Positioner perlu diperbaiki sehingga jika Anda bengkok, maka ia berada di bagian yang sangat bengkok ini.

Kalau tidak, tidak ada gunanya.

Saya setuju bahwa akan mungkin untuk menggunakan pengontrol lain dan accelerometer lain, akan mungkin untuk memiliki lebih banyak C ++, dan lebih banyak lagi dengan otak saya sendiri dan ... Jadi saya tidak melarang - lakukan, coba saja. Saya yakin Anda akan berhasil, lebih baik dari saya.

Sebenarnya, itu sebabnya saya menulis di Geek, dan bukan di Habré. Agar, demikian untuk berbicara, bukan untuk kompromi yang terakhir, yang sebenarnya yang pertama.

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


All Articles