Контакти

Збройний хронограф своїми руками. Дешевий хронограф для пневматики своїми руками. Принцип роботи хронографа власного виготовлення

У своїй першій публікації я хочу розповісти вам, як я зібрав хронограф за пару вечорів із дешевих та доступних усім деталей. Як ви напевно вже здогадалися з назви, цей аксесуар служить для вимірювання швидкості кулі у пневматичних (і не дуже) гвинтівок і буває корисним для контролю її технічного стану.

1. Деталі та приладдя

  • Китайський Digispark - 80 рублів на момент покупки
  • Сегментний дисплей на TM1637 – 90 рублів на момент покупки
  • ІЧ світлодіоди та ІЧ фототранзистори (10 пар) - 110 рублів на момент покупки, нам потрібні 2 пари
  • Резистори 220 Ом (100шт) - 70 рублів на момент покупки, нам потрібно лише 2 штуки
На цьому закінчуються деталі, які потрібно купувати. Резистори можна не замовляти, схожі за номіналом (але не менше!) можна висмикнути з непотрібної побутової електроніки. Таким чином, сумарні витрати менше 350 рублів, це ніщо в порівнянні з ціною нового заводського хронографа (over 1000р за найпростіший, який за фактом ще примітивніший за наш сабж). Крім деталей нам знадобляться:
  • Провід - знайти в офлайні безкоштовно не проблема
  • Шматок пластиковий водопровідної трубидовжиною більше 10см (діаметр за смаком) - так само легко знайти
  • Паяльні приладдя
  • Мультиметр (опціонально)
Перші 3 деталі варті окремого розгляду, тому що мають свої особливості, тому почнемо з міні-оглядів на них.

1.1. Digispark

Є простою мініатюрною Arduino-сумісною платою з ATtiny85 на борту. Як підключити до Arduino IDE читаємо на офіційному сайті проекту, там же можна знайти драйвера для неї. Існує два основних види цієї плати: з microUSB і брутальніший з USB конектором, розведеним прямо на платі.

Мій хронограф не має власного джерела живлення, тож я вибрав перший варіант плати. Вбудована батарея/акумулятор сильно підвищить ціну, не додавши практично нічого до юзабіліті. Power bank та кабель для заряджання телефону валяються практично у кожного.

ХарактеристикиСамо собою успадковані від ATtiny85, його можливостей у разі досить з головою. Фактично МК у хронографі не робить нічого, крім опитування двох датчиків та управління дисплеєм. Для тих, хто вперше стикається з Digispark, я звів найважливіші особливості в таблицю:

Цю табличку я використовую як шпаргалку для розробки різних девайсів на базі цієї плати. Як ви напевно помітили, нумерація пінів для функції analogRead() відрізняється, це слід враховувати. І ще одна особливість: на третьому піні висить резистор, що підтягує, на 1.5кОм, т.к. він використовується у USB.

1.2. Дисплей на базі TM1637

Наступна важлива деталь – цифровий дисплей, на який виводитиметься інформація. Дисплей можна використовувати будь-який, мій вибір обумовлений лише дешевизною та простотою роботи з ним. Від дисплея в принципі взагалі можна відмовитися і виводити дані по кабелю на ПК, тоді девайс стане ще дешевше. Для роботи знадобиться бібліотека DigitalTube. Сабж, на який я дав посилання на початку посту, є клоном дисплея Grove . Вигляд спереду:

Між цифрами відстань однакова, тому при вимкненому двокрапці числові значення читаються нормально. Разом із стандартною бібліотекою постачається приклад, який працює з Digispark-ом без танців із бубном:

Все, що вміє стандартна бібліотека, - виводити числа 0-9 та літери a-f, а також змінювати яскравість всього дисплея повністю. Значення цифри визначається функцією display(int 0-3, int 0-15).

Експрес-курс з використання дисплея

// 1. Оголосити файл заголовка #include // 2. Задати піни #define CLK 0 #define DIO 1 // 3. Оголосити об'єкт TM1637 tm1637 (CLK, DIO); // 4. Проініціалізувати void setup() ( tm1637.init(); tm1637.set(6); // Яскравість ) // 5. Використати void loop() ( // Виведення числа x на дисплей int x = 1234; tm1637 .display(0, x / 1000); tm1637.display(1, x / 100 % 10); );


Якщо спробувати вивести символ із кодом за межами , то дисплей показує нісенітницю, яка при цьому не статична, тому схитрувати для виведення спецсимволів (градусів, мінуса) без бубна не вийде.

Це мене не влаштовувало, так як у своєму хронографі я хотів передбачити виведення не тільки швидкості, а й енергії кулі (обчислюваної на основі прописаної в скетчі маси), ці два значення повинні виводитися послідовно. Щоб зрозуміти, що показує дисплей в даний момент часу, потрібно якось розділяти ці два значення візуально, наприклад, символом «J». Звичайно, можна тупо задіяти символ двокрапки як прапор-індикатор, але це ж не тру і не кошерно. сегменти, закодовані в data:

Void setSegments(byte addr, byte data) ( tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start(); tm1637.stop(); tm1637.start(); tm1637.writeByte(tm1637.Cmd_DispCtrl); tm1637.stop();
Кодуються сегменти гранично просто: молодший біт data відповідає за верхній сегмент, і т.д. за годинниковою стрілкою, сьомий біт відповідає за центральний сегмент. Наприклад, символ "1" кодується як 0b00000110. Восьмий, старший біт використовується тільки в другій цифрі і відповідає за двокрапку, у решті всіх цифр він ігнорується. Щоб полегшити собі життя я, як і належить будь-якому лінивому айтішнику, автоматизував процес отримання кодів символів за допомогою excel:

Тепер можна легко зробити так:

Let's say HELLO

#include #define CLK 0 #define DIO 1 TM1637 tm1637(CLK, DIO); void setSegments(byte addr, byte data) ( tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start(); tm1637.writeByte(addr|te tm1637.stop(); tm1637.start(); tm1637.writeByte(tm1637.Cmd_DispCtrl); tm1637.stop(); () ( // Висновок Hello setSegments(0, 118); setSegments(1, 121); setSegments(2, 54); setSegments(3, 63); delay(500); )

1.3. Датчики

Тут я, на жаль, не можу нічого особливо сказати, тому що на сторінці товару немає жодного слова про характеристики або хоча б маркування, за яким можна було б відкопати даташіт. Типовий noname. Відома лише довжина хвилі 940нм.

Ціною одного світлодіода визначив, що струм більше 40мА для них смертельний, а напруга живлення має бути нижчою за 3.3В. Фототранзистор трохи прозорий і реагує на світ

2. Підготовка деталей та складання

Схема дуже проста і нехитра, з усіх пінів digispark-a нам знадобляться тільки P0, P1 – для роботи з дисплеєм, а також P2 – для роботи з датчиками:

Як видно, один резистор обмежує струм на світлодіодах, другий – стягує P2 до землі. Фототранзистори з'єднані послідовно, тому проходження кулі перед будь-якою оптопарою призводить до зменшення напруги P2. Шляхом реєстрації двох послідовних стрибків напруги та виміру часу між ними ми можемо визначити швидкість руху кулі (знаючи відстань між датчиками, звичайно). Використання одного піна для вимірів має ще один плюс - немає ніякого необхідного напрямку руху кулі, можна стріляти з обох кінців. Збирати будемо з цієї жменьки деталей:

Я пішов шляхом мініатюризації і вирішив зробити бутерброд за допомогою шматка макетної плати:

Весь бутерброд залив термоклеєм для міцності:

Залишається тільки розмістити датчики в трубці і припаяти дроти:

На фото видно, що я розмістив додатковий електроліт на 100мКф паралельно світлодіодам, щоб при живленні від повербанку не було пульсацій ІЧ діодів.

Пін P2 як вход був обраний не просто так. Нагадаю, що P3 та P4 використовуються в USB, тому використання P2 дає можливість прошивати девайс вже у зібраному вигляді. По-друге, P2 - аналоговий вхід, тому можна не використовувати переривання, а просто міряти різницю в циклі між попереднім і поточним значенням на ньому, якщо різниця вища за деякий поріг - значить куля проходить між однією з оптопар. Але є одна програмна хитрість, без якої наведена схема не злетить, про неї поговоримо далі.

3. Прошивка

3.1. Пару слів про prescaler

Prescaler є дільником частоти, за замовчуванням в arduino-подібних платах він дорівнює 128. Від значення цієї величини залежить максимальна частота опитування АЦП, по дефолту для 16 мГц контролера виходить 16/128 = 125 кГц. На кожну оцифровку йде 13 операцій, тому максимальна частота опитування піна - 9600 кГц (теоретично, на практиці реально не вище 7 кГц). Тобто. інтервал між вимірами приблизно 120 мкс, це дуже багато. Куля, що летить зі швидкістю 300 м/с, пролетить за цей час 3,6 см - контролер просто не встигне засікти факт проходження кулі через оптопару. Для нормальної роботи потрібен інтервал між вимірами як мінімум 20 мкс, необхідне значення дільника для цього дорівнює 16. Я пішов ще далі і у своєму девайсі використовую дільник 8, робиться це так:

#ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) # endif void setup() ( sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); cbi(ADCSRA,ADPS0); ... )
Реальні виміри інтервалу analogRead на різних дільниках:

3.2. Підсумковий скетч

Я не докладно описуватиму код, він і так добре задокументований. Натомість я в загальних словахОпишу алгоритм його роботи. Отже, вся логіка зводиться до наступних етапів:
  • Перший цикл - вимірюється різниця між поточним та попереднім значенням на піні
  • Якщо різниця більша за заданий поріг, то виходимо з циклу і запам'ятовуємо поточний час (micros())
  • Другий цикл - аналогічно попередньому + лічильник часу у циклі
  • Якщо лічильник досяг заданої величини, то інформування про помилку та перехід до початку. Це дозволяє не йти циклу у вічність, якщо куля з якихось причин не була помічена другим датчиком
  • Якщо лічильник не переповнився і різниця значень більша за поріг, то заміряємо поточний час (micros())
  • На основі різниці в часі та відстані між датчиками обчислюємо швидкість та виводимо на екран
  • Перехід на початок
Це дуже спрощена модель, в самому коді я додав свистелок, включаючи обчислення та показ енергії кулі на основі введеної заздалегідь у коді маси кулі.

Власне, весь код

/* * Хронограф для вимірювання швидкості руху кулі, SinuX 23.03.2016 */ #include #define CLK 1 // Пін дисплея #define DIO 0 // Пін дисплея #define START_PIN 1 // Аналоговий пін старту #define END_PIN 1 // Аналоговий пін фінішу #define START_LEV 50 // Поріг спрацьовування старту #define END_LE спрацьовування фінішу #define TIMEOUT 10000 // Час очікування фінішу в мікросекундах #define BULLET_WEIGHT 0.00051 // Маса кулі в кілограмах (для обчислення енергії) #define ENCODER_DIST 0.1 // Відстань між DE0 #0 / Час показу результату // Для прискорення analogRead #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr ) |= _BV(bit)) #endif // Службові змінні int prevVal, curVal; unsigned long startTime, endTime; TM1637 tm1637 (CLK, DIO); /* Перероблена функція TM1637::display(), яка дозволяє запалювати окремі сегменти * Нумерація сегментів: молодший біт – верхній сегмент тощо. за годинниковою стрілкою * Центральний сегмент - старший біт */ void setSegments(byte addr, byte data) (tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start();te addr|0xc0), tm1637.writeByte(data); tm1637.stop(); tm1637.start(); Встановлюємо prescaler на 8 для прискорення analogRead cbi(ADCSRA,ADPS2);sbi(ADCSRA,ADPS1);sbi(ADCSRA,ADPS0);// Ініціалізація дисплея tm1637.init(); tm1637.set(6); (0, 118);setSegments(1, 121);setSegments(2, 54);setSegments(3, 63);delay(1000); // Очікування старту curVal = analogRead(START_PIN);do ( prevVal = curVal; curVal = analogRead(START_PIN); )< START_LEV); startTime = micros(); // Ожидание финиша curVal = analogRead(END_PIN); do { prevVal = curVal; curVal = analogRead(END_PIN); // Если превышен интервал ожидания - показ ошибки и выход из цикла if (micros() - startTime >= TIMEOUT) ( showError(); return; ) ) while (curVal - prevVal< END_LEV); endTime = micros(); // Вычисление и отображение результата showResult(); } // Отображение заставки ожидания выстрела void showReady() { setSegments(0, 73); setSegments(1, 73); setSegments(2, 73); setSegments(3, 73); delay(100); } // Вычисление и отображение скорости, энергии пули void showResult() { // Вычисление скорости пули в м/с и вывод на дисплей float bulletSpeed = ENCODER_DIST * 1000000 / (endTime - startTime); tm1637.display(0, (int)bulletSpeed / 100 % 10); tm1637.display(1, (int)bulletSpeed / 10 % 10); tm1637.display(2, (int)bulletSpeed % 10); setSegments(3, 84); delay(SHOW_DELAY); // Вычисление энергии в джоулях и вывод на дисплей float bulletEnergy = BULLET_WEIGHT * bulletSpeed * bulletSpeed / 2; tm1637.point(1); // Вместо точки ":" - костыль, но пойдет) tm1637.display(0, (int)bulletEnergy / 10 % 10); tm1637.display(1, (int)bulletEnergy % 10); tm1637.display(2, (int)(bulletEnergy * 10) % 10); setSegments(3, 30); delay(SHOW_DELAY); tm1637.point(0); } // Вывод ошибки при превышении времени ожидания пули void showError() { setSegments(0, 121); setSegments(1, 80); setSegments(2, 80); setSegments(3, 0); delay(SHOW_DELAY); }

4. Приклади роботи

При правильному підключенні девайс злетів практично відразу, єдиний виявлений недолік - він негативно реагує на світлодіодне та люмінісцентне освітлення (частота пульсацій близько 40 кГц), звідси можуть виникати спонтанні помилки. Всього в девайсі передбачено 3 режими роботи:

Привітання після увімкнення та переходу в режим очікування пострілу (екран заповнюється смужками):

У разі помилки – відображається «Err», і знову перехід у режим очікування:

Ну і сам завмер швидкості:

Після пострілу спочатку показується швидкість кулі (з символом "n"), потім - енергія (символ "J"), причому енергія обчислюється з точністю до одного знака після коми (на гіфці видно, що при показі джоулів горить двокрапка). Корпус красивіше знайти поки не зміг, тому просто залив усе термосоплями:

Мабуть, на цьому у мене все, сподіваюся, комусь був корисним.

У своїй першій публікації я хочу розповісти вам, як я зібрав хронограф за пару вечорів із дешевих та доступних усім деталей. Як ви напевно вже здогадалися з назви, цей аксесуар служить для вимірювання швидкості кулі у пневматичних (і не дуже) гвинтівок і буває корисним для контролю її технічного стану.

1. Деталі та приладдя

  • Китайський Digispark - 80 рублів на момент покупки
  • Сегментний дисплей на TM1637 – 90 рублів на момент покупки
  • ІЧ світлодіоди та ІЧ фототранзистори (10 пар) - 110 рублів на момент покупки, нам потрібні 2 пари
  • Резистори 220 Ом (100шт) - 70 рублів на момент покупки, нам потрібно лише 2 штуки
На цьому закінчуються деталі, які потрібно купувати. Резистори можна не замовляти, схожі за номіналом (але не менше!) можна висмикнути з непотрібної побутової електроніки. Таким чином, сумарні витрати менше 350 рублів, це ніщо в порівнянні з ціною нового заводського хронографа (over 1000р за найпростіший, який за фактом ще примітивніший за наш сабж). Крім деталей нам знадобляться:
  • Провід - знайти в офлайні безкоштовно не проблема
  • Шматок пластикової водопровідної труби довжиною понад 10см (діаметр за смаком) – так само легко знайти
  • Паяльні приладдя
  • Мультиметр (опціонально)
Перші 3 деталі варті окремого розгляду, тому що мають свої особливості, тому почнемо з міні-оглядів на них.

1.1. Digispark

Є простою мініатюрною Arduino-сумісною платою з ATtiny85 на борту. Як підключити до Arduino IDE читаємо на офіційному сайті проекту, там же можна знайти драйвера для неї. Існує два основних види цієї плати: з microUSB і брутальніший з USB конектором, розведеним прямо на платі.

Мій хронограф не має власного джерела живлення, тож я вибрав перший варіант плати. Вбудована батарея/акумулятор сильно підвищить ціну, не додавши практично нічого до юзабіліті. Power bank та кабель для заряджання телефону валяються практично у кожного.

ХарактеристикиСамо собою успадковані від ATtiny85, його можливостей у разі досить з головою. Фактично МК у хронографі не робить нічого, крім опитування двох датчиків та управління дисплеєм. Для тих, хто вперше стикається з Digispark, я звів найважливіші особливості в таблицю:

Цю табличку я використовую як шпаргалку для розробки різних девайсів на базі цієї плати. Як ви напевно помітили, нумерація пінів для функції analogRead() відрізняється, це слід враховувати. І ще одна особливість: на третьому піні висить резистор, що підтягує, на 1.5кОм, т.к. він використовується у USB.

1.2. Дисплей на базі TM1637

Наступна важлива деталь – цифровий дисплей, на який виводитиметься інформація. Дисплей можна використовувати будь-який, мій вибір обумовлений лише дешевизною та простотою роботи з ним. Від дисплея в принципі взагалі можна відмовитися і виводити дані по кабелю на ПК, тоді девайс стане ще дешевше. Для роботи знадобиться бібліотека DigitalTube. Сабж, на який я дав посилання на початку посту, є клоном дисплея Grove . Вигляд спереду:

Між цифрами відстань однакова, тому при вимкненому двокрапці числові значення читаються нормально. Разом із стандартною бібліотекою постачається приклад, який працює з Digispark-ом без танців із бубном:

Все, що вміє стандартна бібліотека, - виводити числа 0-9 і літери a-f, а також змінювати яскравість всього дисплея повністю. Значення цифри визначається функцією display(int 0-3, int 0-15).

Експрес-курс з використання дисплея

// 1. Оголосити файл заголовка #include // 2. Задати піни #define CLK 0 #define DIO 1 // 3. Оголосити об'єкт TM1637 tm1637 (CLK, DIO); // 4. Проініціалізувати void setup() ( tm1637.init(); tm1637.set(6); // Яскравість ) // 5. Використати void loop() ( // Виведення числа x на дисплей int x = 1234; tm1637 .display(0, x / 1000); tm1637.display(1, x / 100 % 10); );


Якщо спробувати вивести символ із кодом за межами , то дисплей показує нісенітницю, яка при цьому не статична, тому схитрувати для виведення спецсимволів (градусів, мінуса) без бубна не вийде.

Це мене не влаштовувало, так як у своєму хронографі я хотів передбачити виведення не тільки швидкості, а й енергії кулі (обчислюваної на основі прописаної в скетчі маси), ці два значення повинні виводитися послідовно. Щоб зрозуміти, що показує дисплей в даний момент часу, потрібно якось розділяти ці два значення візуально, наприклад, символом «J». Звичайно, можна тупо задіяти символ двокрапки як прапор-індикатор, але це ж не тру і не кошерно. сегменти, закодовані в data:

Void setSegments(byte addr, byte data) ( tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start(); tm1637.stop(); tm1637.start(); tm1637.writeByte(tm1637.Cmd_DispCtrl); tm1637.stop();
Кодуються сегменти гранично просто: молодший біт data відповідає за верхній сегмент, і т.д. за годинниковою стрілкою, сьомий біт відповідає за центральний сегмент. Наприклад, символ "1" кодується як 0b00000110. Восьмий, старший біт використовується тільки в другій цифрі і відповідає за двокрапку, у решті всіх цифр він ігнорується. Щоб полегшити собі життя я, як і належить будь-якому лінивому айтішнику, автоматизував процес отримання кодів символів за допомогою excel:

Тепер можна легко зробити так:

Let's say HELLO

#include #define CLK 0 #define DIO 1 TM1637 tm1637(CLK, DIO); void setSegments(byte addr, byte data) ( tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start(); tm1637.writeByte(addr|te tm1637.stop(); tm1637.start(); tm1637.writeByte(tm1637.Cmd_DispCtrl); tm1637.stop(); () ( // Висновок Hello setSegments(0, 118); setSegments(1, 121); setSegments(2, 54); setSegments(3, 63); delay(500); )

1.3. Датчики

Тут я, на жаль, не можу нічого особливо сказати, тому що на сторінці товару немає жодного слова про характеристики або хоча б маркування, за яким можна було б відкопати даташіт. Типовий noname. Відома лише довжина хвилі 940нм.

Ціною одного світлодіода визначив, що струм більше 40мА для них смертельний, а напруга живлення має бути нижчою за 3.3В. Фототранзистор трохи прозорий і реагує на світ

2. Підготовка деталей та складання

Схема дуже проста і нехитра, з усіх пінів digispark-a нам знадобляться тільки P0, P1 – для роботи з дисплеєм, а також P2 – для роботи з датчиками:

Як видно, один резистор обмежує струм на світлодіодах, другий – стягує P2 до землі. Фототранзистори з'єднані послідовно, тому проходження кулі перед будь-якою оптопарою призводить до зменшення напруги P2. Шляхом реєстрації двох послідовних стрибків напруги та виміру часу між ними ми можемо визначити швидкість руху кулі (знаючи відстань між датчиками, звичайно). Використання одного піна для вимірів має ще один плюс - немає ніякого необхідного напрямку руху кулі, можна стріляти з обох кінців. Збирати будемо з цієї жменьки деталей:

Я пішов шляхом мініатюризації і вирішив зробити бутерброд за допомогою шматка макетної плати:

Весь бутерброд залив термоклеєм для міцності:

Залишається тільки розмістити датчики в трубці і припаяти дроти:

На фото видно, що я розмістив додатковий електроліт на 100мКф паралельно світлодіодам, щоб при живленні від повербанку не було пульсацій ІЧ діодів.

Пін P2 як вход був обраний не просто так. Нагадаю, що P3 та P4 використовуються в USB, тому використання P2 дає можливість прошивати девайс вже у зібраному вигляді. По-друге, P2 - аналоговий вхід, тому можна не використовувати переривання, а просто міряти різницю в циклі між попереднім і поточним значенням на ньому, якщо різниця вища за деякий поріг - значить куля проходить між однією з оптопар. Але є одна програмна хитрість, без якої наведена схема не злетить, про неї поговоримо далі.

3. Прошивка

3.1. Пару слів про prescaler

Prescaler є дільником частоти, за замовчуванням в arduino-подібних платах він дорівнює 128. Від значення цієї величини залежить максимальна частота опитування АЦП, по дефолту для 16 мГц контролера виходить 16/128 = 125 кГц. На кожну оцифровку йде 13 операцій, тому максимальна частота опитування піна - 9600 кГц (теоретично, на практиці реально не вище 7 кГц). Тобто. інтервал між вимірами приблизно 120 мкс, це дуже багато. Куля, що летить зі швидкістю 300 м/с, пролетить за цей час 3,6 см - контролер просто не встигне засікти факт проходження кулі через оптопару. Для нормальної роботи потрібен інтервал між вимірами як мінімум 20 мкс, необхідне значення дільника для цього дорівнює 16. Я пішов ще далі і у своєму девайсі використовую дільник 8, робиться це так:

#ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) # endif void setup() ( sbi(ADCSRA,ADPS2); cbi(ADCSRA,ADPS1); cbi(ADCSRA,ADPS0); ... )
Реальні виміри інтервалу analogRead на різних дільниках:

3.2. Підсумковий скетч

Я не докладно описуватиму код, він і так добре задокументований. Натомість я в загальних словах опишу алгоритм його роботи. Отже, вся логіка зводиться до наступних етапів:
  • Перший цикл - вимірюється різниця між поточним та попереднім значенням на піні
  • Якщо різниця більша за заданий поріг, то виходимо з циклу і запам'ятовуємо поточний час (micros())
  • Другий цикл - аналогічно попередньому + лічильник часу у циклі
  • Якщо лічильник досяг заданої величини, то інформування про помилку та перехід до початку. Це дозволяє не йти циклу у вічність, якщо куля з якихось причин не була помічена другим датчиком
  • Якщо лічильник не переповнився і різниця значень більша за поріг, то заміряємо поточний час (micros())
  • На основі різниці в часі та відстані між датчиками обчислюємо швидкість та виводимо на екран
  • Перехід на початок
Це дуже спрощена модель, в самому коді я додав свистелок, включаючи обчислення та показ енергії кулі на основі введеної заздалегідь у коді маси кулі.

Власне, весь код

/* * Хронограф для вимірювання швидкості руху кулі, SinuX 23.03.2016 */ #include #define CLK 1 // Пін дисплея #define DIO 0 // Пін дисплея #define START_PIN 1 // Аналоговий пін старту #define END_PIN 1 // Аналоговий пін фінішу #define START_LEV 50 // Поріг спрацьовування старту #define END_LE спрацьовування фінішу #define TIMEOUT 10000 // Час очікування фінішу в мікросекундах #define BULLET_WEIGHT 0.00051 // Маса кулі в кілограмах (для обчислення енергії) #define ENCODER_DIST 0.1 // Відстань між DE0 #0 / Час показу результату // Для прискорення analogRead #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr ) |= _BV(bit)) #endif // Службові змінні int prevVal, curVal; unsigned long startTime, endTime; TM1637 tm1637 (CLK, DIO); /* Перероблена функція TM1637::display(), яка дозволяє запалювати окремі сегменти * Нумерація сегментів: молодший біт – верхній сегмент тощо. за годинниковою стрілкою * Центральний сегмент - старший біт */ void setSegments(byte addr, byte data) (tm1637.start(); tm1637.writeByte(ADDR_FIXED); tm1637.stop(); tm1637.start();te addr|0xc0), tm1637.writeByte(data); tm1637.stop(); tm1637.start(); Встановлюємо prescaler на 8 для прискорення analogRead cbi(ADCSRA,ADPS2);sbi(ADCSRA,ADPS1);sbi(ADCSRA,ADPS0);// Ініціалізація дисплея tm1637.init(); tm1637.set(6); (0, 118);setSegments(1, 121);setSegments(2, 54);setSegments(3, 63);delay(1000); // Очікування старту curVal = analogRead(START_PIN);do ( prevVal = curVal; curVal = analogRead(START_PIN); )< START_LEV); startTime = micros(); // Ожидание финиша curVal = analogRead(END_PIN); do { prevVal = curVal; curVal = analogRead(END_PIN); // Если превышен интервал ожидания - показ ошибки и выход из цикла if (micros() - startTime >= TIMEOUT) ( showError(); return; ) ) while (curVal - prevVal< END_LEV); endTime = micros(); // Вычисление и отображение результата showResult(); } // Отображение заставки ожидания выстрела void showReady() { setSegments(0, 73); setSegments(1, 73); setSegments(2, 73); setSegments(3, 73); delay(100); } // Вычисление и отображение скорости, энергии пули void showResult() { // Вычисление скорости пули в м/с и вывод на дисплей float bulletSpeed = ENCODER_DIST * 1000000 / (endTime - startTime); tm1637.display(0, (int)bulletSpeed / 100 % 10); tm1637.display(1, (int)bulletSpeed / 10 % 10); tm1637.display(2, (int)bulletSpeed % 10); setSegments(3, 84); delay(SHOW_DELAY); // Вычисление энергии в джоулях и вывод на дисплей float bulletEnergy = BULLET_WEIGHT * bulletSpeed * bulletSpeed / 2; tm1637.point(1); // Вместо точки ":" - костыль, но пойдет) tm1637.display(0, (int)bulletEnergy / 10 % 10); tm1637.display(1, (int)bulletEnergy % 10); tm1637.display(2, (int)(bulletEnergy * 10) % 10); setSegments(3, 30); delay(SHOW_DELAY); tm1637.point(0); } // Вывод ошибки при превышении времени ожидания пули void showError() { setSegments(0, 121); setSegments(1, 80); setSegments(2, 80); setSegments(3, 0); delay(SHOW_DELAY); }

4. Приклади роботи

При правильному підключенні девайс злетів практично відразу, єдиний виявлений недолік - він негативно реагує на світлодіодне та люмінісцентне освітлення (частота пульсацій близько 40 кГц), звідси можуть виникати спонтанні помилки. Всього в девайсі передбачено 3 режими роботи:

Привітання після увімкнення та переходу в режим очікування пострілу (екран заповнюється смужками):

У разі помилки – відображається «Err», і знову перехід у режим очікування:

Ну і сам завмер швидкості:

Після пострілу спочатку показується швидкість кулі (з символом "n"), потім - енергія (символ "J"), причому енергія обчислюється з точністю до одного знака після коми (на гіфці видно, що при показі джоулів горить двокрапка). Корпус красивіше знайти поки не зміг, тому просто залив усе термосоплями:

Мабуть, на цьому у мене все, сподіваюся, комусь був корисним.

Хронограф є універсальним приладом, здатним проводити вимірювання швидкості польоту предметів малого розміру. Налаштування та тестування пневматики найзручніше проводити з хронографами рамкового типу. Вони можуть уловлювати рух куль, болтів арбалета, стріл, скоб рогатки. Хронограф для пневматики можна виготовити своїми руками або придбати у спеціалізованих магазинах.

Типи хронографів

Вимірювання стартової швидкості кулі за допомогою хронографа, дозволяє виявити потужність пістолета або гвинтівки, підібрати кулі, розрахувати балістичні поправки, провести порівняння швидкості на початку і після модернізації зброї.

Існують різні типи хронографів. Надульна модель займає мало місця і легко міститься в кишені чохла, а також вона менше витрачає енергію. Для конкретного типу зброї може знадобитися перехідник. Такий вид не залежить від освітлення та зручний у використанні на природі. Прицільну стрілянину можна вести разом із приладом. Для СО2 така модель не підходить.

При володінні значним арсеналом, краще придбати рамковий хронограф щоб не закуповувати велика кількістьперехідників. Цей тип приладу добре працює із СО2, має роз'єм для зовнішнього джерела живлення. Броня дозволяє проводити вимірювання показників на різній дистанції, не побоюючись пошкодити механізм. Наявність додаткового екрану допомагає оперативно отримувати результати.

Існують також рамкові моделі великого розміру, що розширюють кількість можливостей. Такий варіант підходить для використання з будь-якими видами зброї, зручним при стаціонарному підключенні до мережі. Як альтернатива, хронограф може отримувати живлення від батарей класу АА у кількості восьми штук. На відміну від моделі малого розміру, великий апарат має вбудованим індикатором фронтального типу. Можна додатково встановити знімний екран. За допомогою USB-адаптера можна перенести дані вимірювання з пристрою на комп'ютер.

Купівля хронографа для пневматики

Купити в Москві та Санкт-Петербурзі різні типи хронографів можна в наступних магазинах:

  • Airgun Store – за ціною від 3500 до 24 тис. р.;
  • Diada Arms – за ціною від 4 тис. до 13 тис. р.;
  • Pnevmat 24 – за ціною від 4 тис. до 7 тис. р.;
  • Oxotnika.net - за ціною від 3 тис. до 20 тис. грн.

У цих магазинах також пропонуються різноманітні комплектуючі та аксесуари для хронографів. Можна придбати більш бюджетну модель на AliExpress за ціною від 3 тис. грн. або купити б/в, наприклад, на порталі Guns.ru або Avito за ціною від 1500 грн.

Хронограф рамкового типу для пневматики своїми руками

Хронограф фіксує час прольоту кулі між декількома датчиками та розраховує її швидкість. Пристрій складається з трьох частин:

  • робочої зони, що пропускає через себе кулю;
  • схеми, що проводить обчислення;
  • дисплея, який показує розраховані результати.

Схеми для хронографа можуть бути різні за вартістю, функціональністю та дизайном. Найпростіші датчики зчитують світло, що падає на них, інтенсивність якого змінюється в міру переміщення кулі, що відкидає тінь. Чутливі до світла елементи є частиною багатьох хронографів, зроблених у домашніх умовах та заводських моделях.

Самостійно виготовлений прилад має кілька переваг:

Поряд з цим, апарат має і свої недоліки:

  • громіздкість конструкції;
  • потреба у захисті від влучення для лицьової сторони робочої зони;
  • вплив погодних умов та освітлення на роботу;
  • чутливість схеми оптики до значних механічних впливів, що включають влучення кульових осколків та рикошети;
  • виведення неправдивих показань при появі в камері сторонніх предметів, таких як сніг, комахи або механічні уламки;
  • вплив траєкторії польоту на фіксовану швидкість кулі (рух об'єкта по діагоналі знижує показник).

Компоненти та матеріали для складання

Загальна кількість деталей та їх складність залежать від рівня навичок проектування та встановлення схем у користувача. Деякі компоненти є обов'язковимипри будь-якому вигляді збирання:

  • світлодіоди для створення штучного джерела світла;
  • паяльник з флюсом та припоєм для закріплення проводів та встановлення мікросхеми;
  • оптичні приймачі для зчитування рівня освітленості під час прольоту кулі через світлодіоди;
  • мікросхема для визначення часу польоту кулі та розрахунку швидкості;
  • дисплей для відображення результатів вимірювання;
  • прямокутний порожнистий корпус, закритий з чотирьох сторін (краще вибирати виріб із цільного металу, який буде стійким до ударів).

Етапи монтажу хронографа

Елементи мікросхеми та датчики повинні бути під захистом або розташовуватися в місцях, які не будуть доступні для прямого влучення кулі. Під них потрібно заздалегідь підготувати місце у корпусі. Внутрішня частина виробу покривається темною фарбою, що не створює відблисків, щоб уникнути зайвих спрацьовувань приладу та збільшити його чутливість.

Елементи чутливі до світла і самі світлодіоди монтуються у попередньо розмічені отвори. Фотоприймачі повинні бути трохи заглибленими, а світлодіоди трохи випирати у внутрішню частину хронографа. Таке розміщення дозволить знизити інтенсивність зовнішнього світла, що падає на прилад.

На наступному етапі встановлюється та підключається до датчиків плата, розмічаються секції під введення живлення. Для самостійного складання схем можна використовувати рис. 1.

Рис. 1 Мікросхема хронографа

Коли основні вузли буде зібрано, схему потрібно буде захистити від механічних впливів та вологи. Для цього завдання підійде коробка з пластмаси для друкованої плати, яка матиме виходи до батареї, дисплея і датчиків.

Принцип роботи хронографа власного виготовлення

Як джерело живлення для приладу можуть використовуватися батареї, акумулятори, блок живлення, що підключається до мережі. Автономне джерело більш вигідне і зручне, тому що налаштування зброї в більшості випадків проводиться за межами будинку.

Процес виміру швидкості проходить три етапи:

  • куля проходить через вісь початкового датчика, обнуляючи лічильник часу мікропроцесорі;
  • після перетину кулею осі наступного датчика, час зупиняється і дані передаються щодо розрахунків;
  • мікропроцесор проводить обчислення та виводить показники швидкості на дисплей.

Наочно роботу хронографа рамкового типу можна побачити на рис. 2.

Рис. 2 Схема роботи хронографа

Для того, щоб самостійно зібрати хронограф, знадобляться знання та досвід у електротехніці, пайці та розробці електричних кіл. Полегшити завдання можна, замовивши виготовлення мікросхеми майстру з електроніки. Хронограф, зібраний своїми руками, обійдеться значно дешевше, ніж покупний варіант.


У цій статті ми розглянемо, як можна зробити простий хронограф із недорогих та доступних деталей. Пристосуваннянеобхідно для того, щоб вимірювати швидкість польоту кулі у гвинтівки. Ці цифри потрібні для того, щоб визначити, в якому стані гвинтівка, адже з часом деякі вузли пневматики зношуються і вимагають заміни.

Готуємо необхідні матеріалита інструменти:
- китайський Digispark (обійшовся на момент покупки 80 рублів);
- дисплей сегментного типу на TM1637 (обійшовся при покупці 90 рублів);
- інфрачервоні світлодіоди та фототранзистори (10 пар) - вартість склала 110 рублів;
- Сто резисторів на 220 Ом обійшлися в 70 рублів, але з них будуть потрібні лише два.

Ось і все це весь список елементів, які потрібно буде купити. До речі резистори теж можна знайти у старій побутової техніки. Можна ставити більше за номіналом, але не менше. У результаті можна вкластися в 350 рублів, адже це не так багато, враховуючи, що заводський хронограф обійдеться як мінімум в 1000 рублів, та й складання там куди гірше за нашу саморобки.

Крім того, потрібно запастися такими деталями як:
- дроти;
- Шматок труби довжиною не менше 10 см (підійде пластикова водопровідна);
- все для паяння;
- Мультиметр (бажано).


Перші описані три деталі мають свої нюанси, тому кожну їх потрібно розглянути окремо

Digispark
Цей елемент є мініатюрною платою, яка сумісна з Arduinoна борту вона має ATtiny85. Як підключити цей елемент Arduino IDE, можна почитати на , ще там можна завантажити для неї драйвера.
Ця плата має кілька варіантів, в одній використовується microUSB, а інша обладнана USB-конектором, який розведений прямо на платі. У зв'язку з тим, що саморобка немає індивідуального блоку живлення, автор обрав перший варіант плати. Якщо встановити в саморобку батарею або акумулятор, це підвищить її ціну, причому не сильно вплине на практичність. А кабель для зарядки мобільного та Power bank є майже у кожного.


Що стосується характеристик, то вони подібні до ATtiny85, тут його можливостей вистачає з надлишком. Мікроконтролер у хронографі лише опитує датчики і управляє дисплеєм.
Якщо ви ще жодного разу не зустрічалися з Digispark-ом, найбільш важливі нюансиможна подивитися у таблиці.


Важливо враховувати те що, що нумерація пінів для функції analogRead() має відмінності. А ще на третьому піні знаходиться резистор, що підтягує, номіналом 1.5кОм, оскільки він застосовується в USB.

Пару слів про дисплей
Дисплей для саморобки можна використовувати будь-який, але автор зупинив свій вибір на дешевому варіанті. Щоб зробити пристрій ще дешевшим, від дисплея можна відмовитися зовсім. Дані легко можна через кабель виводити на комп'ютер. Тут буде потрібна. Розглянутий дисплей є копією дисплея.
Як виглядає дисплей спереду та ззаду можна побачити на фото.




Оскільки відстані між цифрами однакові, то при вимкненому двокрапці цифри читаються без проблем. Стандартна бібліотека здатна виводити цифри в діапазоні 0-9. літери в діапазоні a-f, а також є можливість зміни яскравості всього дисплея. Значення цифри можна встановити за допомогою функції display(int 0-3, int 0-15).


Як використовувати дисплей

// 1. Оголосити заголовний файл
#include
// 2. Задати піни
#define CLK 0
#define DIO 1
// 3. Оголосити об'єкт
TM1637 tm1637 (CLK, DIO);
// 4. Проініціалізувати
void setup() (
tm1637.init();
tm1637.set(6); // Яскравість
}
// 5. Використати
void loop() (
// Виведення числа x на дисплей
int x = 1234;
tm1637.display(0, x/1000);
tm1637.display(1, x / 100% 10);
tm1637.display(2, x / 10% 10);
tm1637.display(3, x % 10);
delay(500);
}

Якщо спробувати вийти за межі значень, то дисплей показуватиме плутанину, яка плюс до всього ще й не статична. Тому для виведення спецсимволів, таких як градуси, мінуси тощо, доведеться повозитися.


Автор хотів, щоб на дисплеї виводилася готова енергія польоту кулі, що обчислювалося б залежно від швидкості кулі та її маси. Значення за задумом повинні були виводитися послідовно, щоб зрозуміти, де яке, їх треба якось відзначити, наприклад, з допомогою букви «J». В крайньому випадку, можна просто задіяти двокрапку, але автора це не влаштувало, і він поліз у бібліотеку. У результаті з урахуванням функції display було створено функція setSegments(byte addr, byte data), вона запалює у цифрі з номером addr сегменти, які закодовані в data:


{
tm1637.start();
tm1637.stop();
tm1637.start();
tm1637.writeByte(addr|0xc0);
tm1637.writeByte(data);
tm1637.stop();
tm1637.start();
tm1637.stop();
}

Кодуються такі сегменти досить легко, за верхній сегмент відповідає молодший біт data, ну а далі за годинниковою стрілкою, сьомий біт відповідає за середній сегмент. Символ «1» під час кодування виглядає як 0b00000110. За двокрапку відповідає восьмий старший біт, він використовується у другій цифрі, а у всіх інших ігнорується. Згодом автор автоматизував процес отримання кодів, використовуючи Exсel.


Що ж у результаті вийшло, можна побачити на фото




#include
#define CLK 0
#define DIO 1
TM1637 tm1637 (CLK, DIO);

void setSegments(byte addr, byte data)
{
tm1637.start();
tm1637.writeByte(ADDR_FIXED);
tm1637.stop();
tm1637.start();
tm1637.writeByte(addr|0xc0);
tm1637.writeByte(data);
tm1637.stop();
tm1637.start();
tm1637.writeByte(tm1637.Cmd_DispCtrl);
tm1637.stop();
}

void setup() (
tm1637.init();
tm1637.set(6);
}

void loop() (
// Висновок Hello
setSegments(0, 118);
setSegments(1, 121);
setSegments(2, 54);
setSegments(3, 63);
delay(500);
}



Ну і нарешті, датчики

Про датчики точної інформації не надано, відомо лише, що вони мають довжину хвилі 940 нм. У ході експериментів було з'ясовано, що датчики не здатні витримувати струм понад 40 мА. Що стосується напруги живлення, то воно не повинно бути вищим за 3.3В. Що стосується фототранзистора, він має трохи прозорий корпус і реагує на світло.


Приступаємо до збирання та налаштування саморобки:

Крок перший. Складання

Збирається все за дуже простою схемою. З усіх пінів будуть потрібні всього Р0, Р1 та Р2. Перші два використовуються для дисплея, а Р2 потрібен для роботи датчиків.
Як можна помітити, один резистор використовується для того, щоб обмежити струм для світлодіодів, а другий стягує Р2 на землю. У зв'язку з тим, що фототранзистори підключаються паралельно, то коли куля проходитиме перед будь-якою оптопарою, напруга на Р2 падатиме. Щоб визначити швидкість польоту кулі, потрібно знати відстань між датчиками, заміряти два стрибки напруги та визначити час, за який вони сталися.
У зв'язку з тим, що використовуватиметься лише один пін, не має значення, з якого боку стріляти. Фототранзистори у будь-якому разі помітять кулю.










Збирається всі деталі, які видно на фото. Щоб усе зібрати, автор вирішив використати макетну дошку. Потім вся конструкція для міцності була залита термоклеєм. Датчики розміщуються на трубі і до них припаюються дроти.
Щоб діоди не пульсували при живленні від повербанку, автор установив паралельно світлодіодам електроліт на 100 мКф.




Ще важливо відзначити, що пін Р2 був обраний не просто так, річ у тому, що Р3 та Р4 застосовуються в USB, тому тепер за допомогою Р2 є можливість прошити саморобку вже після збирання.
Ще Р2 є аналоговим входом, тому використовувати переривання немає потреби. Можна просто вимірювати показання між поточним і попереднім значенням, якщо різниця стає вищою за певний поріг, значить, в цей момент куля якраз проходить біля оптопари.

Крок другий. Прошивка

Prescaler є дільником частоти, у стандартних випадках у платах на кшталт Arduino він дорівнює 128. Ця цифра впливає те, як часто йде опитування АЦП. Тобто дефолтних 16 мГц виходить 16/128 = 125 кГц. Кожне оцифрування складається з 13 операцій, тому пін може максимально опитуватись зі швидкістю 9600 кГц. Насправді ж це трохи більше 7 кГц. Через війну інтервал між вимірами становить 120 мкс, що дуже багато роботи саморобки. Якщо куля летітиме зі швидкістю 300 м/с, вона подолає за цей час шлях у 3.6 см, тобто контролер просто не зможе її помітити. Щоб усе працювало нормально, інтервал між вимірами має бути як мінімум 20 мкс. Для цього значення дільника має дорівнювати 16-ти. Автор же зробив дільник 8, як це зробити, можна побачити нижче.
Сподобалась стаття? Поділіться їй