【得捷电子Follow me第3期】任务6-1:寻找WiFi发射源的位置
[复制链接]
本次活动,任务6:综合实践之分任务1:寻找WiFi发射源的位置。
因为Seeed Studio XIAO ESP32C3有WiFI通讯功能,所以可以通过WiFi信号的强度,来判断离WiFi发射源(通常是无线路由器)的位置远近。
一、前提知识
参考以下网址:https://www.netspotapp.com/cn/wifi-signal-strength/ 可以了解相关的知识:
无线网络中接收的无线电信号功率电平的通用名称是RSSI(接收信号强度指示符)。WiFi信号强度通常以分贝毫瓦(dBm)为单位,这是一个以分贝(dB)和毫瓦特(mW)来指代功率的绝对值。
在我们的程序中,换算为以下的结果:
另外,在Seeed Studio XIAO ESP32C3的官方也有对应的演示程序,具体网址为:https://wiki.seeedstudio.com/XIAO_ESP32C3_MicroPython/。
所以本次这个分任务的完成,参考了官方的代码,并结合一直使用的nanogui进行整合。
二、获取RSSI信息
通过micropython在ESP32C3上提供的无线网络调用,可以获取对应的结果:
station = network.WLAN(network.STA_IF)
rssi = station.status('rssi')
通过上述步骤,最后能得到rssi的值
另外,演示程序中,还驱动蜂鸣器,根据信号的强弱,发出不同的声音,这也是通过rssi的值换算后,输出不同的方波来驱动蜂鸣器的:
rssi_duty = 160 + 2 * int(rssi)
rssi_duty_2 = int(rssi_duty / 2)
rssi_abs = abs(int(rssi)) / 100
buzzer.duty(rssi_duty)
time.sleep(rssi_abs)
buzzer.duty(0)
time.sleep(rssi_abs)
buzzer.duty(rssi_duty_2)
time.sleep(rssi_abs)
buzzer.duty(0)
time.sleep(rssi_abs)
务必要注意的是,这个分任务,请务必把天线给接上,否则完全无法准确获得RSSI值,甚至可能连不上WiFi。
三、显示元素
在官方的演示程序中,使用micropython的OLED,这个分享中,则使用了一直使用的nanogui,实际用到的显示元素如下:
1. 文本元素:Label(wri, 0, 0, "Starting up..."),直接在指定位置显示文本
2. LED元素:LED(wri, int(y/rate), int(x/rate), bdcolor=BLACK, height=8),用于显示圆形点状进度条
3. 仪表元素:Meter(wri, 10, 80, divisions = 5, ptcolor=YELLOW, width = 15, height = 50, label='', style=Meter.BAR, legends=('0', '1', '2', '3', '4')),用于显示信号的强度
上述三个显示元素,均可以通过 元素.value()更新:
1. lable.value(要显示的文本)
2. led.value(颜色/也就是是否显示)
3. meter.value(仪表刻度值)
四、实际代码
前提知识介绍完了,下面废话少说,上代码:
import network
import time
from time import sleep
import machine
from machine import Pin, SoftI2C
import math
from color_setup import ssd,oled_width,oled_height # Create a display instance
import cmath
import utime
import uos
from gui.core.writer import Writer, CWriter
from gui.core.nanogui import refresh
from gui.widgets.led import LED
from gui.widgets.meter import Meter
from gui.widgets.label import Label
# Fonts
import gui.fonts.arial10 as arial10
import gui.fonts.freesans20 as freesans20
from gui.core.colors import *
# Network settings
wifi_ssid = "OpenBSD"
wifi_password = "********"
machine.freq(160000000) # Set CPU frequency to 160 MHz (ESP8266 specific)
ssd.fill(0)
refresh(ssd)
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
wri.set_clip(True, True, False)
Label(wri, 0, 0, "Starting up...")
refresh(ssd)
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(wifi_ssid, wifi_password)
time.sleep(1)
while not station.isconnected():
time.sleep(1)
ssd.fill(0)
refresh(ssd)
Label(wri, 0, 0, "Connecting to")
Label(wri, 20, 0, wifi_ssid)
refresh(ssd)
time.sleep(2)
ssd.fill(0)
refresh(ssd)
ip_address = station.ifconfig()[0] # Get the IP address
Label(wri, 0, 0, "Connected! ")
Label(wri, 20, 0, "IP Address:")
Label(wri, 40, 0, ip_address)
refresh(ssd)
time.sleep(2)
# Buzzer settings
buzzer_pin = machine.Pin(5, machine.Pin.OUT)
buzzer = machine.PWM(buzzer_pin)
buzzer.freq(1047)
buzzer.duty(0)
center_x = oled_width // 2
center_y = oled_height // 2
square_size = 6 # Size of each square
num_squares = 12 # Number of squares
angle_increment = 2 * math.pi / num_squares
x_pos = [12, 38, 64, 90]
statuses = ["Weak", "Fair", "Good", "Excellent"]
def calculate_block_count(rssi):
# Determine the number of blocks based on RSSI values
if -80 <= rssi < -60:
return 1
elif -60 <= rssi < -40:
return 2
elif -40 <= rssi < -20:
return 3
elif -20 <= rssi <= 10:
return 4
loop_count = 0 # Initialize loop count
while loop_count < 2: # Execute the loop 24 times
ssd.fill(0) # Clear the screen
refresh(ssd)
for i in range(num_squares):
angle = i * angle_increment
x = int(center_x + (center_x - square_size-30) * math.cos(angle))
y = int(center_y + (center_x - square_size-30) * math.sin(angle))
# Draw all squares
rate = 1.2
l0 = LED(wri, int(y/rate), int(x/rate), bdcolor=BLACK, height=8)
l0.color(GREEN)
refresh(ssd)
time.sleep_ms(100) # Pause before next iteration
loop_count += 1 # Increase loop count
ssd.fill(0)
refresh(ssd)
Label(wri, 5, 0, "RSSI:")
Label(wri, 30, 0, "Quality:")
l1 = Label(wri, 15, 20, "")
l2 = Label(wri, 45, 20, "")
m0 = Meter(wri, 10, 80, divisions = 5, ptcolor=YELLOW, width = 15, height = 50,
label='', style=Meter.BAR, legends=('0', '1', '2', '3', '4'))
while True:
station = network.WLAN(network.STA_IF)
time.sleep(0.1)
rssi = station.status('rssi')
rssi_duty = 160 + 2 * int(rssi)
rssi_duty_2 = int(rssi_duty / 2)
rssi_abs = abs(int(rssi)) / 100
block_count = calculate_block_count(rssi)
status = statuses[block_count - 1] # Get the status text based on block count
m0.value(block_count/4)
l1.value(str(rssi)+" ")
l2.value(status+" ")
refresh(ssd)
buzzer.duty(rssi_duty)
time.sleep(rssi_abs)
buzzer.duty(0)
time.sleep(rssi_abs)
buzzer.duty(rssi_duty_2)
time.sleep(rssi_abs)
buzzer.duty(0)
time.sleep(rssi_abs)
代码的核心逻辑比较简单,就是启动,联网,然后在循环中,获取RSSI值,并换算到仪表的刻度值进行显示,同时跟去RSSI值的强度,驱动蜂鸣器以不同的频率发生。
五、运行测试
实际测试的效果见下面的视频:
4469_1702116898
当Seeed Studio XIAO ESP32C3离路由器一般距离时,屏幕显示为Good,仪表可读显示为3格,蜂鸣器接近1秒一次滴滴
当Seeed Studio XIAO ESP32C3离路由器非常近距离时,屏幕显示为Excellent,仪表可读显示为4格,蜂鸣器接近1秒2次滴滴
当Seeed Studio XIAO ESP32C3离路由器距离拉开时,屏幕显示为Fair甚至Weak,仪表可读显示为2格或1格,蜂鸣器滴滴声则间隔时间较长切感觉无力。
通过上述的屏幕显示和提示音,在路由器附近的区域走动时,越接近路由器,则信号越好,提示音越急促,从而可以快速定位到实际路由器的位置,也就是寻找WiFi发射源的位置。
也可以让手机开启热点,然后设置连接信息到手机,进行类似的测试。
六、总结
通过RSSI来寻找WiFi发射源的位置,是一个有趣的任务,让通常的WiFi功能外,还能够利用WiFi信号做更多的事情。
同样的,也可以利用蓝牙信号,来进行类似的任务或者工作,感兴趣的同学,可以试一试。
不过,需要注意的是,这个信号,会收到现场环境的影响,并不是完全准确的。例如不同的墙壁,对信号的衰减作用不同;有的电气信号,也能够产生干扰。在实际使用中,需要特别注意。
|