回到顶部 回到顶部
best-icon

用行空板自制桌面盖革计数器——实时核辐射监测 中等

头像 Afra 2023.09.17 199 4

一、介绍

 

当前辐射监测与我们息息相关,它不仅关系到我们的健康与安全,还隐藏着许多神秘和迷人的科学现象。核辐射是指来自放射性物质的粒子或电磁波的释放。它分为三种类型:阿尔法辐射、贝塔辐射和伽马射线。这些辐射与我们日常生活息息相关,比如在医学诊断、能源生产和食品辐照中的应用。然而,它们也带来了一定的危险。了解这些辐射的特点和安全阈值,能帮助我们更好地应对潜在的风险。

 

随手拿起身边的行空板,手搓了一个桌面版的盖格计数器。简单说这是一种专门探测电离辐射强度的记数仪器。通常盖革计数器由一个充气密封管和一个信息显示屏构成,可以测得单位时间内的射线数。我将在下面详细分享自制盖格计数器的各个环节,以帮助我们日常监测辐射值和增加自定义功能。

image.png

 

1. 硬件选型

现在我们一起来看看制作一个辐射监测器所需的硬件!

image.png

材料清单

  • 行空板 X1 链接
  • 盖格计数器模块 X1 链接
  • 温湿度传感器 X1 链接
  • U型公对母TypeC延长线 X1

2. 接线图

 

盖格计数器模块连接至行空板pin23

DHT20温湿度传感器连接至行空板IIC接口

image.png
image.png

 

3. 3D打印外壳

 

3D打印外壳下载链接: https://www.thingiverse.com/thing:6224720/files

image.png
image.png

二、盖格计数器原理

 

1. 如何测量辐射值呢?

 

这里科普一下盖格计数器的原理。

盖格计数器是一种气体放电探测器,内部充有易电离气体,当辐射进入管中,会引起气体电离,从而产生脉冲电流。这些脉冲信号被放大后就成为计数脉冲。我们只需要统计单位时间内的脉冲个数,就可以直接计算出环境辐射量。相比其他探测器,盖格计数管最大的优点是它输出数字电信号,不需要复杂的模拟电路就可以实现辐射的精确计数。所以我们统计好每分钟有多少个辐射粒子经过了气体管,就可以得出当前环境的受辐射程度了。

image.png
image.png

 

2. 如何计算辐射量?

 

这里有三个关键的单位CPM、毫希弗(mSv/h),微希弗(uSv/h)。

CPM (Counts Per.Minute是种测量辐射水平的单位,为次/分钟。它表示在一分内辐射值所接收到的辐射粒子击中的次数。

 

而辐射水平可以用每小时受到辐射量水平的水平衡量:(Sv/h)、毫希弗(mSv/h)、微希弗(uSv/h)表示。

 

换算公式为 151CPM = 1uSv/h

1Sv/h = 1000mSv/h = 1000000uSh/h

 

 

 

3. 如何评价和计量辐射程度?

《放射卫生防护基本标准》中提到,公众中个人受到照射的年剂量当量限值是:全身均匀照射不超过5mSv;任何单个组织和或器官不超过50mSv;一生中每年的全身剂量当量限值应不高于1mSv。

 

室内环境中的核辐射剂量标准值为0.5uSV/h,根据公众年辐射剂量限制5mSv/h进行计算,按照365*24小时的计算方法,剂量率不超过0.5uSv/h,在这个范围内属于正常范围,一般室内环境的正常辐射剂量率在0.20uSv/h以下,大部分在0.13左右,但通常卫生间与厨房中存在的辐射剂量率较高。

 

 

 

 

三、程序编辑

 

1. 用python编程计算微希弗(uSv/h)

计算单位时间间隔内(count)触发多少次引脚中断,判断经过了多少个辐射粒子。这里先设定为五秒计算一次(time_gap)。然后用60秒/5秒*经过的粒子数,计算出一分钟经过的粒子数(cpm)。由于 151CPM = 1uSv/h,最终得出uSv/h的数值。

 

2. 加载pinpong库,用以python控制盖格计数器。

加载GUI库,用以在显示屏上显示数字。

传感器连接引脚p23,作为信号输入。

代码
import time
from pinpong.board import Board,Pin

Board("unihiker").begin()               #初始化,选择板型(uno、leonardo、xugu)和端口号,不输入端口号则进行自动识别
from unihiker import GUI   #导入包
gui=GUI()  #实例化GUI类
btn = Pin(Pin.P23, Pin.IN)

3. 设置变量和函数:

 

time_gap:输入两次计算微希弗(uSv/h)值的时间间隔

start_time:开始计数的时间

count:经过的粒子数

time_gap:两次计算的时间间隔

uSvh:最终得出的辐射值

定义函数zero,确定开始计算时间并计数清零。

定义中断函数,下降中断时粒子计数+1。

定义get_cpm函数,计算出usvh的值。

代码
time_gap = 0
start_time = 0
count = 0
time_gap = 5
uSvh = 0

def zero():
    global start_time,count
    start_time = time.time()
    count = 0

def btn_falling_handler(pin):#中断事件回调函数
    global count
    count += 1

zero()
btn.irq(trigger=Pin.IRQ_FALLING, handler=btn_falling_handler) #设置中断模式为下降沿触发

def get_cpm():
    global uSvh
    if time.time() - start_time >= time_gap: 
        uSvh = round((count/151)*(60/time_gap),2)
        print("uSvh=",uSvh)
        zero()

4. 显示屏显示

 

在150*90像素、黑色20号字显示当前辐射值。

允许get_cpm函数,并更新显示中的text。

代码
dig = gui.draw_digit(x=150, y=90, text=uSvh, origin = "center",color="black",font_size=20,angle=90)#数码管字体显示

while True:
    #start()
    time.sleep(1) #保持程序持续运行
    get_cpm()
    dig.config(text=uSvh)

5. 全部代码

 

image.png

代码
import time
from pinpong.board import Board,Pin

Board("unihiker").begin()               #初始化,选择板型(uno、leonardo、xugu)和端口号,不输入端口号则进行自动识别
from unihiker import GUI   #导入包
gui=GUI()  #实例化GUI类
btn = Pin(Pin.P23, Pin.IN)

time_gap = 0
start_time = 0
count = 0
time_gap = 5
uSvh = 0

def zero():
    global start_time,count
    start_time = time.time()
    count = 0

def btn_falling_handler(pin):#中断事件回调函数
    global count
    count += 1

zero()
btn.irq(trigger=Pin.IRQ_FALLING, handler=btn_falling_handler) #设置中断模式为下降沿触发

def get_cpm():
    global uSvh
    if time.time() - start_time >= time_gap: 
        uSvh = round((count/151)*(60/time_gap),2)
        print("uSvh=",uSvh)
        zero()

dig = gui.draw_digit(x=150, y=90, text=uSvh, origin = "center",color="black",font_size=20,angle=90)#数码管字体显示

while True:
    #start()
    time.sleep(1) #保持程序持续运行
    get_cpm()
    dig.config(text=uSvh)

四、显示优化

 

现在辐射值显示出来了,但画面略显单调。此时我们可以尝试增加温湿度传感器,同时显示温湿度、实时的年月日信息、和辐射值变化的折线图。当辐射值超过0.5uSvh的时候,行空板发出蜂鸣声并且数值显示红色。

 

image.png

 

 

材料清单

  • 温湿度传感器DHT20 X1 链接

~ 温湿度传感器:DHT20

~ 加载温湿度传感器的库:from pinpong.libs.dfrobot_dht20 import DHT20

~ 数字横向显示,在这段代码后面加上‘angle=90’。tem1 = gui.draw_text(x=55, y=263, text="Temperature :", origin = "center",color="white",font_size=8,angle=90)

~ 绘制线段的函数:line1=gui.draw_line(x0=(numberMap((uSvh_list[0]), 0, 1.1, 239, 200)),y0=320,x1=(numberMap((uSvh_list[1]), 0, 1.1, 239, 200)),y1=288,width=2,color="#acacac")

~ 年月日和时间的显示: DigitalTime.config(text=time.strftime("%Y/%m/%d %H:%M"))

~ 折线图始终显示最新的10个数据的变化:def numberMap(x, in_min, in_max, out_min, out_max): return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

代码
import time
from pinpong.board import Board,Pin
from pinpong.libs.dfrobot_dht20 import DHT20
from pinpong.extension.unihiker import *


Board("unihiker").begin()               #初始化,选择板型(uno、leonardo、xugu)和端口号,不输入端口号则进行自动识别
from unihiker import GUI   #导入包
gui=GUI()  #实例化GUI类

btn = Pin(Pin.P23, Pin.IN)
p_dht20 = DHT20()
#global num_pulse1

time_gap = 0
start_time = 0
count = 0
time_gap = 5
uSvh = 0


def zero():
    global start_time,count
    start_time = time.time()
    count = 0
#    print('start',start_time)


def btn_falling_handler(pin):#中断事件回调函数
    global count
    count += 1
    # print("pulse = ", count)

zero()

btn.irq(trigger=Pin.IRQ_FALLING, handler=btn_falling_handler) #设置中断模式为下降沿触发


def get_cpm():
    # print("time:",time.time())
    global uSvh
    global dht1
    global p_dht20
    if time.time() - start_time >= time_gap: 
        print("-------------------")
        print("count=",count)
        uSvh = round((count/151)*(60/time_gap),2)
        print("uSvh=",uSvh)
        zero()

def numberMap(x, in_min, in_max, out_min, out_max):
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

uSvh_list = [0,0,0,0,0,0,0,0,0,0,0]

bg = gui.fill_rect(x=0, y=0, w=240, h=320,  width=3, color=(0, 0, 0),onclick=lambda: print("rect clicked"))
tem1 = gui.draw_text(x=55, y=263, text="Temperature :", origin = "center",color="white",font_size=8,angle=90)#数码管字体显示
tem2 = gui.draw_digit(x=95,y=240,text=(int(float(p_dht20.temp_c()))),origin = "center",color="white",font_size=33,angle=90)
tem3 = gui.draw_digit(x=105, y=190, text="°C", origin = "center",color="white",font_size=10,angle=90)#数码管字体显示
humi1 = gui.draw_text(x=57, y=140, text="Humidity :", origin = "center",color="white",font_size=8,angle=90)#数码管字体显示
humi2 = gui.draw_digit(x=95,y=100,text=(int(float(p_dht20.humidity()))),origin = "center",color="white",font_size=33,angle=90)
humi3 = gui.draw_digit(x=105, y=45, text="%rh", origin = "center",color="white",font_size=10,angle=90)#数码管字体显示

u1 = gui.draw_text(x=143, y=270, text="Radiation :", origin = "center",color="white",font_size=8,angle=90)#数码管字体显示
u2 = gui.draw_digit(x=175, y=150, text=uSvh, origin = "center",color="white",font_size=45,angle=90)#数码管字体显示
u3 = gui.draw_digit(x=190, y=45, text="uSvh", origin = "center",color="white",font_size=12,angle=90)#数码管字体显示

DigitalTime=gui.draw_digit(text=time.strftime("%Y/%m/%d          %H:%M"),x=10,y=310,font_size=15, color="white",angle=90)

if (len(uSvh_list) >= 12):
    uSvh_list.pop((len(uSvh_list) - 1))
print(uSvh_list)
line1=gui.draw_line(x0=(numberMap((uSvh_list[0]), 0, 1.1, 239, 200)),y0=320,x1=(numberMap((uSvh_list[1]), 0, 1.1, 239, 200)),y1=288,width=2,color="#acacac")
line2=gui.draw_line(x0=(numberMap((uSvh_list[1]), 0, 1.1, 239, 200)),y0=288,x1=(numberMap((uSvh_list[2]), 0, 1.1, 239, 200)),y1=256,width=2,color="#acacac")
line3=gui.draw_line(x0=(numberMap((uSvh_list[2]), 0, 1.1, 239, 200)),y0=256,x1=(numberMap((uSvh_list[3]), 0, 1.1, 239, 200)),y1=224,width=2,color="#acacac")
line4=gui.draw_line(x0=(numberMap((uSvh_list[3]), 0, 1.1, 239, 200)),y0=224,x1=(numberMap((uSvh_list[4]), 0, 1.1, 239, 200)),y1=192,width=2,color="#acacac")
line5=gui.draw_line(x0=(numberMap((uSvh_list[4]), 0, 1.1, 239, 200)),y0=192,x1=(numberMap((uSvh_list[5]), 0, 1.1, 239, 200)),y1=160,width=2,color="#acacac")
line6=gui.draw_line(x0=(numberMap((uSvh_list[5]), 0, 1.1, 239, 200)),y0=160,x1=(numberMap((uSvh_list[6]), 0, 1.1, 239, 200)),y1=128,width=2,color="#acacac")
line7=gui.draw_line(x0=(numberMap((uSvh_list[6]), 0, 1.1, 239, 200)),y0=128,x1=(numberMap((uSvh_list[7]), 0, 1.1, 239, 200)),y1=96,width=2,color="#acacac")
line8=gui.draw_line(x0=(numberMap((uSvh_list[7]), 0, 1.1, 239, 200)),y0=96,x1=(numberMap((uSvh_list[8]), 0, 1.1, 239, 200)),y1=64,width=2,color="#acacac")
line9=gui.draw_line(x0=(numberMap((uSvh_list[8]), 0, 1.1, 239, 200)),y0=64,x1=(numberMap((uSvh_list[9]), 0, 1.1, 239, 200)),y1=32,width=2,color="#acacac")
line10=gui.draw_line(x0=(numberMap((uSvh_list[9]), 0, 1.1, 239, 200)),y0=32,x1=(numberMap((uSvh_list[10]), 0, 1.1, 239, 200)),y1=0,width=2,color="#acacac")


while True:
    #start()
    time.sleep(1) #保持程序持续运行
    get_cpm()
    # tem1.config(text="温度:")
    tem2.config(text=(int(float(p_dht20.temp_c()))))
    # humi1.config(text="湿度:")
    humi2.config(text=(int(float(p_dht20.humidity()))))
    # u1.config(text="辐射量:")
    u2.config(text=uSvh,color="white")
    DigitalTime.config(text=time.strftime("%Y/%m/%d          %H:%M"))

    print(uSvh_list)
    uSvh_list.insert(0,uSvh)
    line1.config(x0=(numberMap((uSvh_list[0]), 0, 1.1, 239, 200)),y0=320,x1=(numberMap((uSvh_list[1]), 0, 1.1, 239, 200)),y1=288)
    line2.config(x0=(numberMap((uSvh_list[1]), 0, 1.1, 239, 200)),y0=288,x1=(numberMap((uSvh_list[2]), 0, 1.1, 239, 200)),y1=256)
    line3.config(x0=(numberMap((uSvh_list[2]), 0, 1.1, 239, 200)),y0=256,x1=(numberMap((uSvh_list[3]), 0, 1.1, 239, 200)),y1=224)
    line4.config(x0=(numberMap((uSvh_list[3]), 0, 1.1, 239, 200)),y0=224,x1=(numberMap((uSvh_list[4]), 0, 1.1, 239, 200)),y1=192)
    line5.config(x0=(numberMap((uSvh_list[4]), 0, 1.1, 239, 200)),y0=192,x1=(numberMap((uSvh_list[5]), 0, 1.1, 239, 200)),y1=160)
    line6.config(x0=(numberMap((uSvh_list[5]), 0, 1.1, 239, 200)),y0=160,x1=(numberMap((uSvh_list[6]), 0, 1.1, 239, 200)),y1=128)
    line7.config(x0=(numberMap((uSvh_list[6]), 0, 1.1, 239, 200)),y0=128,x1=(numberMap((uSvh_list[7]), 0, 1.1, 239, 200)),y1=96)
    line8.config(x0=(numberMap((uSvh_list[7]), 0, 1.1, 239, 200)),y0=96,x1=(numberMap((uSvh_list[8]), 0, 1.1, 239, 200)),y1=64)
    line9.config(x0=(numberMap((uSvh_list[8]), 0, 1.1, 239, 200)),y0=64,x1=(numberMap((uSvh_list[9]), 0, 1.1, 239, 200)),y1=32)
    line10.config(x0=(numberMap((uSvh_list[9]), 0, 1.1, 239, 200)),y0=32,x1=(numberMap((uSvh_list[10]), 0, 1.1, 239, 200)),y1=0)

    i = uSvh
    if (i > 0.5):
        u2.config(text=uSvh,color="red")
        buzzer.pitch(466,8)
        i = 0

    time.sleep(1)

 

 

 

使用行空板DIY自制的桌面盖格计数器,可以非常便捷地实时监测环境中的辐射水平。它具有制作简单、使用方便、成本低廉等优点,通过简单的脉冲统计就可以计算出辐射剂量率,帮助我们实时了解周围的辐射情况。同时,项目中使用的行空板不仅具备了可以触摸的屏幕,还可以与其他硬件传感器连接。直接使用python编程也极大的增加了创造的灵活度。与一般商业检测设备相比,这种自制设备更加灵活和可定制化,我们可以添加报警功能、数据记录功能等,让辐射检测更智能化。总之,在核污染日渐被熟知的当下,制作一台桌面版盖格计数器,让辐射监测触手可及,既可提高辐射安全意识,也是一件有意义的创造。

 

 

盖格在手,辐射逃走

评论

user-avatar
  • _深蓝_

    _深蓝_2023.09.24

    好,这篇值得推荐,收藏了

    0
    • hacker_

      hacker_2023.09.22

      666

      0
      • 宗静

        宗静2023.09.20

        OK

        0
        • Amos Young

          Amos Young2023.09.20

          666

          0
          icon 他的勋章
            展开更多

            你可能感兴趣的