Емулятор лічильника Гейгера GGreg20_V3 засобами ESP8266: Частина 2 Створення емулятора

Емулятор лічильника Гейгера: що нам знадобиться

Для побудови емулятора лічильника Гейгера нам знадобляться наступні деталі та матеріали:

  • ESP8266 #1 як основний (MCU_A, модуль NodeMCU);
  • ESP8266 #2 як емулятор GGreg20_V3 (MCU_B, модуль ESP12.OLED);
  • Дроти для перемичок;
  • USB кабель для програмування та живлення.

Далі нам потрібно буде запрограмувати основний контролер MCU_A та код скрипту емуляції програмного забезпечення GGreg20_V3 для MCU_B.

Примітка 3. Ми будемо наводити приклади у цій публікації на модулях власного виробництва ESP12.OLED. Втім, якщо у вас немає модуля ESP12.OLED, ви також можете застосувати плату розробника на базі ESP8266, наприклад NodeMCU, і самостійно розробити програмне забезпечення керуючись прикладами, що наведено у тексті. Якщо ж ви бажаєте одразу користуватися готовим пристроєм, будь-ласка, дочитайте цю статтю до кінця, адже далі ми даємо посилання на наш готовий до використання модуль емулятора, який можливо придбати.

Примітка 4. У цій, як і у інших наших публікаціях ми будемо наводити приклади простою та потужною скриптовою мовою програмування Lua, що доступна у популярній програмній прошивці NodeMCU.

Бюджет необхідних нам входів/виходів

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

На модулі емулятора лічильника Гейгера нам необхідно буде вже трохи більше портів. Тут необхідно задіяти порти вводу/виводу: для емуляції вихідних імпульсів, для RGB світлодіода та для кнопки перемикання режиму роботи емулятора.



Роль MCU_A (Головний)Роль MCU_B (Емулятор)
1 х GPIO лічильника вхідних імпульсівNodeMCU
1 х GPIO емуляції вихідних імпульсів GGreg20_V3ESP12.OLED
3 х GPIO RGB світлодіода індикації вихідних імпульсів GGreg20_V3ESP12.OLED
1х GPIO кнопки перемикання режимів роботи емулятораESP12.OLED

Схема підключення

Щоб взаємодія головного контролера з емулятором модуля GGreg20_V3 виглядала реалістично, пропонуємо скористатися вбудованими властивостями певних портів вводу/виводу плати ESP12.OLED і обрати на контролері емулятора MCU_B наступні GPIO:

  • для емуляції імпульсного виходу GGreg20_V3 рекомендуємо використовувати GPIO4 / D2 (GPIO D-index в Lua);
  • для перемикання режимів роботи емулятора ми можемо використати вбудовану на платі ESP12.OLED кнопку Flash – GPIO0 / D3;
  • вбудований RGB-світлодіод на модулі ESP12.OLED займає GPIO14 / D5; GPIO12 / D6; GPIO13 / D7.

На модулі головного контролера MCU_A, пропонуємо обрати наступний порт для лічильника вхідних імпульсів:

  • GPIO14 / D5.

Примітка 5. У якості довідкового матеріалу за нумерацією портів рекомендуємо наступні матеріали:

Стандарт планування та застосування пінів, розроблений alterstrategy.lab: ttps://alterstrategy.com/recommended-pin-use-standard/

Документація на прошивку NodeMCU: https://nodemcu.readthedocs.io/en/latest/modules/gpio/

Документація на модуль ESP12.OLED на сайті: https://iot-devices.com.ua/en/product/esp12oled-universal-esp8266-mcuboard-oled-en/

та на Tindie: https://www.tindie.com/products/iotdev/esp12oled-universal-esp8266096oled-mcu-board/

Оновимо таблицю з урахуванням конкретних портів вводу/виводу, які ми обрали:



Роль MCU_AРоль MCU_B
1 х GPIO лічильника вхідних імпульсівNodeMCU GPIO14/ D5
1 х GPIO емуляції вихідних імпульсів GGreg20_V3ESP12.OLED GPIO4 / D2
3 х GPIO RGB світлодіода індикації вихідних імпульсів GGreg20_V3ESP12.OLED GPIO14 / D5 GPIO12 / D6 GPIO13 / D7
1х GPIO кнопки перемикання режимів роботи емулятораESP12.OLED GPIO0 / D3



Рис. Підключення модулів з використанням двох апаратних контролерів ESP8266. У ролі MCU_B – модуль ESP12.OLED. У ролі MCU_A – модуль NodeMCU


Режими роботи емулятора

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

Натискаючи кнопку Flash (D3), користувач може поперемінно перемикати режими, щоб вибрати необхідний.

Для зручності користування емулятором RGB-світлодіод модуля ESP12.OLED блимає різними кольорами, які легко розрізняються людським оком. За кожним режимом роботи емулятора закріплено свій колір. Тож коли емулятор видає на імпульсний вихід сигнал про вдаване “спрацювання”, світлодіод також буде блимати кольором поточного режиму роботи.

Діапазони рівня радіації

Пропонуємо реалізувати емуляцію наступних діапазонів радіаційного випромінювання оточуючого середовища, яке буде імітувати MCU_B:

Режим 0. Немає імпульсів (імітація помилки сенсора);

Режим 1. Природне фонове випромінювання: 0.1 – 0.2 мкЗв/год;

Режим 2. Припустимий рівень: 0.2 – 0.3 мкЗв/год;

Режим 3. Підвищений рівень: 0.3 – 0.6 мкЗв/год;

Режим 4. Небезпечний рівень: 0.6 мкЗв/год – 1.5 мкЗв/год.

За замовчуванням модуль буде стартувати після подачі живлення з “Режиму 1”. Цей режим ми обрали як початковий лише через те, що це зручно, коли подавши живлення ми одразу отримуємо імпульси на рівні фонового випромінювання.

Реальний модуль GGreg20_V3 оснащено трубкою Гейгера радянського виробництва СБМ-20. Ця трубка має наступний коефіцієнт перерахунку імпульсів на хвилину у мікрозіверти на годину:

мкЗв на годину = CPM * 0.0057

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

CPM = мкЗв на годину / 0.0057

Робимо приблизний розрахунок таким чином, щоб утворити діапазони потужності, що не перетинаються за значенням:

Режим 0. 0 CPM;

Режим 1. від 18 CPM до 35 CPM;

Режим 2. від 36 CPM до 52 CPM;

Режим 3. від 53 CPM до 105 CPM;

Режим 4. від 106 CPM до 264 CPM.

Співвіднесення кольору спалахів RGB-світлодіода певному режиму роботи є наступним:

Режим роботиКолір спалахівRGB
Режим 0немає спалахів black000
Режим 1cyan011
Режим 2green010
Режим 3red100
Режим 4magenta101

Тепер нам лишається написати відповідний програмний Lua-код для ролі MCU_A та для ролі MCU_B.

Приклад. Код лічильника Гейгера для головного контролера (роль MCU_A)

Ми візьмемо цей код з GitHub за наступною адресою:

https://github.com/iotdevicesdev/ggreg20-v3-nodemcu-lua-example

Код з GitHub повністю готовий до застосування. Щоб запускати код з GitHub, треба його скачати з інтернет і завантажити у контролер, наприклад у модуль NodeMCU, як у нашому випадку. Також необхідно написати ще один Lua-скрипт і його теж завантажити у контролер:

-- filename: mcu_a.lua
-- MCU_A Lua code example
-- Copyright 2022 IoT-devices LLC, Kyiv, Ukraine
dofile('ggreg20_v3_nodemcu_firmware_lua_example.lua')
init(5, 1, 60000)

function snsrUpd()
ma5_rad_lvl, cpm, minutes = read()
print(ma5_rad_lvl, cpm, minutes)
end

snsrUpd_tmr = tmr.create()
snsrUpd_tmr:register(60000, tmr.ALARM_AUTO, function() snsrUpd() end)
snsrUpd_tmr:start()

Приклад. Код для емулятора модуля GGreg20_V3 (роль MCU_B)

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

local gpio = gpio
local mode = gpio.mode
local trig = gpio.trig
local write = gpio.write
local read = gpio.read
local INT = gpio.INT
local OUTPUT = gpio.OUTPUT
local FLOAT = gpio.FLOAT
local HIGH = gpio.HIGH
local LOW = gpio.LOW
local PULLUP = gpio.PULLUP
local print = print

local tmr = tmr
local create = tmr.create
local now = tmr.now
local delay = tmr.delay
local alarm = tmr.alarm
local ALARM_SINGLE = tmr.ALARM_SINGLE
local ALARM_SEMI = tmr.ALARM_SEMI
local ALARM_AUTO = tmr.ALARM_AUTO
local register = tmr.register
local start = tmr.start
local stop = tmr.stop

local node = node
local heap = node.heap
local random = node.random

Також нам необхідно налаштувати GPIO, які у нас будуть відповідати за свої функції (див. вище):

mode(3,INT,FLOAT)
mode(4,OUTPUT, PULLUP)
write(4, HIGH)

Щоб генерувати імпульси, які імітують вихідний інтерфейс GGreg20_V3, нам потрібно випадковим чином запускати ось таку функцію:

local function pulseOut()
	write(4, LOW)
	delay(10)
	write(4, HIGH)
end

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

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

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

Щоб хаотично розподілити обрану кількість імпульсів в межах однієї хвилини скористаємося таймерами, які можливо створювати у теоретично необмеженій кількості:

create():alarm(timer timeout, timer type, callback function)

Єдиним обмеженням є кількість вільної оперативної пам’яті контролера. Експериментально ми встановили, що у такий спосіб без проблем можливо створювати близько 260 імпульсів на хвилину, що вкладається у наші вимоги до максимального рівня віртуальної радіації, яку може відтворити наш емулятор.

Тож функція, яка у циклі створює випадкові таймаути запуску pulseOut(), має наступний вигляд:

local t_start = 0
local count = 0
local function randGen(pulses)
	for i = 1, pulses do -- pulses
			create():alarm(random(60000), ALARM_SINGLE, 
				function()
						print(heap(), count, i, (now() - t_start)/1000000)
						pulseOut()
				end
			)
	end
end

Працюючи у парі, розроблені нами функції randGen(pulses) та pulseOut() створюють необхідну нам кількість абсолютно випадкових імпульсів на виході ESP8266 тривалістю 10 мікросекунд кожен в межах однієї хвилини.

Кількість імпульсів на хвилину задаємо за допомогою параметра pulses.

Для того, щоб емулятор працював у різних режимах потужності удаваної радіації необхідно забезпечити випадкове значення кількості імпульсів pulses, що потрапляє як завдання на вхід функції randGen(). Це можна зробити наступним чином:

radMode = 1
rand_tmr = create()
rand_tmr:register(1000, ALARM_AUTO, 
	function()
		if radMode == 0 and running == 0 then 
			print(heap(), 'Mode0:Snsr Err emu')
			return 0
		end
		local num = 0
		if radMode == 1 then 
			num = random(math.ceil(18),math.ceil(35))
		elseif radMode == 2 then
			num = random(math.ceil(36),math.ceil(52))
		elseif radMode == 3 then
			num = random(math.ceil(53),math.ceil(105))
		elseif radMode == 4 then
			num = random(math.ceil(106),math.ceil(264))
		end
		if num ~= 0 then print('count:',count + 1,'mode:',radMode, 'num:',num); randGen(num) end
	end
)

rand_tmr:start()

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

Останнє, що нам необхідно передбачити у емуляторі, це перемикання режиму потужності радіації за допомогою вбудованої кнопки Flash / GPIO0 / D3:

trig(3, 'down', 
	function(lvl, ts, cnt)
		if radMode < 4 then radMode = radMode + 1 else radMode = 0 end
		print ('New radMode:', radMode)
	end
)

Повний програмний код емулятора

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

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

Сайт: GCcemu20_V1

Tindie: GCcemu20_V1

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

-- filename: mcu_b.lua
-- MCU_B Lua code example
-- Copyright 2022 IoT-devices LLC, Kyiv, Ukraine
local t_start = 0
local count = 0
radMode = 0

local gpio = gpio
local mode = gpio.mode
local trig = gpio.trig
local write = gpio.write
local read = gpio.read
local INT = gpio.INT
local OUTPUT = gpio.OUTPUT
local FLOAT = gpio.FLOAT
local HIGH = gpio.HIGH
local LOW = gpio.LOW
local PULLUP = gpio.PULLUP
local print = print

local tmr = tmr
local create = tmr.create
local now = tmr.now
local delay = tmr.delay
local alarm = tmr.alarm
local ALARM_SINGLE = tmr.ALARM_SINGLE
local ALARM_SEMI = tmr.ALARM_SEMI
local ALARM_AUTO = tmr.ALARM_AUTO
local register = tmr.register
local start = tmr.start
local stop = tmr.stop

local node = node
local heap = node.heap
local random = node.random

mode(3,INT,FLOAT)
mode(4,OUTPUT, PULLUP)
write(4, HIGH)

local function pulseOut()
	write(4, LOW)
	delay(10)
	write(4, HIGH)
end

local function randGen(pulses)
	for i = 1, pulses do -- pulses
			create():alarm(random(60000), ALARM_SINGLE, 
				function()
						print(heap(), count, i, (now() - t_start)/1000000)
						pulseOut()
				end
			)
	end
end

rand_tmr = create()
rand_tmr:register(1000, ALARM_AUTO, 
	function()
		if radMode == 0 and running == 0 then 
			print(heap(), 'Mode0:Snsr Err emu')
			return 0
		end
		local num = 0
		if radMode == 1 then 
			num = random(math.ceil(18),math.ceil(35))
		elseif radMode == 2 then
			num = random(math.ceil(36),math.ceil(52))
		elseif radMode == 3 then
			num = random(math.ceil(53),math.ceil(105))
		elseif radMode == 4 then
			num = random(math.ceil(106),math.ceil(264))
		end
		if num ~= 0 then print('count:',count + 1,'mode:',radMode, 'num:',num); randGen(num) end
	end
)

rand_tmr:start()

trig(3, 'down', 
	function(lvl, ts, cnt)
		if radMode < 4 then radMode = radMode + 1 else radMode = 0 end
		print ('New radMode:', radMode)
	end
)

Початок статті: Емулятор модуля лічильника Гейгера GGreg20_V3 засобами ESP8266: Частина 1. Вступ та загальний огляд

Завершення статті за кілька днів у наступній публікації:
Емулятор модуля лічильника Гейгера GGreg20_V3 засобами ESP8266: Частина 3. Тестування та висновок