回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

基于行空板M10及扩展版的便携式气象站(可以比较天气预报与实际数值) 简单

头像 孙洪尧1985 2025.06.29 57 0

一、作品背景

天气状况与人们的生产生活关系密切,天气预报是我们获取气象信息的主要途径。但是一个城市的天气预报对校园这种小的气候环境而言,有时候并不那么准确。

本作品将结合数学、物理、地理等学科知识,为校园搭建数字气象站,动态积累数据并进行数据分析,使学生掌握气象观测的基本方法,激发学生学习自然地理的兴趣,培养和提高学生的气象科学知识,推动校园气象科普工作,优化校园的素质教育环境。668ac858-90ad-4727-9502-de59f212c01e.jpg

二、作品方案

“在线数字气象站”跨学科主题学习单元包括跨学科学习主题、单元目标、单元过程、单元评价和单元主题活动资源五部分。

跨学科主题学习单元的设计反映了八年级学生的学习经验和学习内容;

单元目标基于信息科技、地理、数学和物理课程标准的学习要求进行界定;

单元活动融合多学科的学习内容,按照应用信息科技解决问题的一般过程进行设计,将跨学科概念以支架的方式渗透到学习过程中,以任务群的方式明确学生需要达成的学习结果;

单元评价中给出了学生主题学习作品集的要求和评价量表,让学生明白他们的最终学习结果是什么和达到什么程度。
单元主题活动资源提供了学生在探究过程中可能需要的数字设备和网络环境;在该活动过程中,学生既可以感受应用信息科技学科领域方法解决问题的过程、也可体验跨学科主题学习的意义,提升数字素养与技能。

1751203005202.png

三、作品主要学习目标:

一、项目概述:探秘万物互联的数字气象世界

以物联网技术为核心搭建在线气象监测系统,引导学生通过实操理解 “万物互联” 的本质 —— 让传感器、设备与数据平台实现实时对话。从校园气象观测切入,构建 “感知 - 传输 - 分析 - 应用” 的完整物联网闭环。

二、核心实践模块

搭建智能感知网络

  • 认识物联网传感器家族:气压传感器、风速风向传感器如同气象站的 “五官”,实时捕捉环境数据(如教室温度、操场风速)。
  • 动手组网:将各类传感器接入物联网平台,像搭积木一样构建简易物联系统,让物理世界的气象信息 “跑” 进数字平台。

数据的云端旅程

数据可视化实战:在平台接收传感器实时数据,用折线图动态绘制温湿度、风速变化曲线,让抽象数据变成直观的 “气象心电图”。

解码数据处理全流程

  • 拆解数据处理四步曲:
    • 采集:传感器定时 “抓拍” 气象瞬间;
    • 分析:计算温湿度、气压、风速的平均值,判断天气趋势;
    • 可视化:通过折线图解读校园气温与降雨量的周期性规律(如夏季午后高温峰值、梅雨季湿度波动)。

三、教学目标延伸

通过气象站项目,学生不仅掌握物联网技术的基础应用,更能理解 “数据驱动决策” 的逻辑 —— 例如根据历史气温数据优化校园空调使用方案,或通过风速数据设计更科学的户外体育活动安排。让科技实践与生活场景深度结合,感受物联网改变世界的力量。

四、作品硬件介绍:

主控器为行空板M10 https://www.dfrobot.com.cn/goods-3404.html

扩展版为行空板M10扩展板组合(含电机IO扩展板、金手指扩展板、800mAh电池扩展板)   https://www.dfrobot.com.cn/goods-4127.html

 

行空板productImage

传感器:

RS485风速变送器 https://www.dfrobot.com.cn/goods-3195.html

RS485风向变送器 https://www.dfrobot.com.cn/goods-3196.html

Gravity: RS485转UART 有源隔离型 信号转换模块 https://www.dfrobot.com.cn/goods-3283.html

Gravity: I2C转串口模块 https://www.dfrobot.com.cn/goods-2668.html

productImageproductImageproductImageproductImage

Gravity: BMP388气压温度传感器  https://www.dfrobot.com.cn/goods-1392.html

Gravity: GNSS北斗定位模块 https://www.dfrobot.com.cn/goods-3652.html

productImageproductImage

硬件实物连线

c77c5db4514dbebef01c45bcdbe26fa.jpg

五、万物互联原理:

在这个局域网里,第一块行空板可是个 “全能选手”,它既要当服务器,存储和处理数据,又要作为智能终端,连接风速风向这些传感器,收集和执行指令。第二块行空板则化身为移动终端,加入到局域网这个大家庭,和第一块行空板实现数据 “对话”。最后,我们用 USB 线把充当服务器的行空板和电脑连起来,这样就能轻松访问服务器数据库,查看和分析气象站收集到的数据啦!

两块行空板,左边的行空板连接传感器作为便携式气象站发送端,右边为接收端,分别连接同一热点。

df5f1c3a4bac931546c361b18371a52.jpg
1751206753235.png
微信图片_20250629222017.jpg

六,程序截图

1、发射端程序

1751206983448.png

由于本项目显示的数据较多,所以需要很多的变量。

1751207088249.png
1751207125767.png

设计UI界面(发射端和接收端几乎一致,可以利用书包的功能做好发射端程序,塞到书包,接收端直接拖出来用,接收端不显示天气预报情况)。

1751207241518.png

这里要注意MQTT初始化IP地址的填写,发射端和接收端是一样的,我用的是发射端的IP地址。

连接风速模块和风向模块要注意检查串口。

1751207361727.png

循环之内的程序都是不断更新的

1751207445171.png

通过上下两个按钮,选择所在地的三个县城的天气预报情况,我的学校在黑龙江省齐齐哈尔市拜泉县三道镇,东临海伦市,南接明水县,西北是拜泉县。

2、接收端程序

1751207576457.png

和发射端一样,需要设置许多个变量。

1751207623960.png
1751207656542.png

接收端UI界面的设计,与发射端相比,不同的是,接收端没有设计天气预报情况。

1751207713752.png

接收端MQTT设计与发射端一致

1751207758395.png

接收端数据进行变化

代码
发射端:
#  -*- coding: UTF-8 -*-

# MindPlus
# Python
import sys
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-pinpong_windspeed-thirdex")
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-pinpong_wind_direction-thirdex")
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-gravitygnss-thirdex")
import siot
import math
import requests
from unihiker import GUI
from pinpong.board import Board
from pinpong.board import Board,Pin
from pinpong.extension.unihiker import *
from pinpong.libs.dfrobot_bmp388 import BMP388
from pinpong.libs.rs485windspeed_rs485touart_uarttoi2c import IICSerialWindSpeed
from pinpong.libs.rs485winddirection_rs485touart_uarttoi2c import IICSerialWindDirection
import sys
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-gravitygnss-thirdex")
from DFRobot_GNSS import *

# 事件回调函数
def button_click1():
    global XuHao
    global city
    global ChengShiMing
    if (XuHao <= 1):
        XuHao = 3
    else:
        XuHao = (XuHao - 1)
    ChengShiMing = (city[XuHao])
    city_x.config(text=ChengShiMing)
def button_click2():
    global XuHao
    global city
    global ChengShiMing
    if (XuHao >= 3):
        XuHao = 1
    else:
        XuHao = (XuHao + 1)
    ChengShiMing = (city[XuHao])
    city_x.config(text=ChengShiMing)


Board().begin()
u_gui=GUI()
siot.init(client_id="6698767767625207",server="192.168.1.33",port=1883,user="siot",password="dfrobot")
siot.connect()
siot.loop()
# 设置变量
city = {1: "拜泉",2:"明水",3:"海伦"}
XuHao = 1
global WenDuShuJu
WenDuShuJu = 0
global QiYaShuJu
QiYaShuJu = 0
global FengSuShuJu
FengSuShuJu = 0
global JingDu
JingDu = ""
global WeiDu
WeiDu = ""
global FengXiangShuJu
FengXiangShuJu = ""
# 显示标题
title=u_gui.draw_text(text="便携式气象站系统",x=60,y=0,font_size=12, color="#0000FF")
# 显示天气预报
kuang=u_gui.draw_rect(x=20,y=25,w=200,h=30,width=2,color="#000000")
shang=u_gui.add_button(text="↑",x=40,y=25,w=30,h=30,onclick=button_click1)
xia=u_gui.add_button(text="↓",x=170,y=25,w=30,h=30,onclick=button_click2)
city_x=u_gui.draw_text(text=(city[XuHao]),x=100,y=25,font_size=15, color="#0000FF")
city_wea=u_gui.draw_text(text="",x=10,y=70,font_size=12, color="#FF0000")
city_wea.config(w=200)
ChengShiMing = (city[XuHao])
url = (str("http://v1.yiketianqi.com/free/day?appid=63499934&appsecret=GVXi6Nh8&unescape=1&city=") + str(ChengShiMing))
response = requests.get(url)
data = response.json()
# 显示温度数据
u_gui.draw_round_rect(x=20,y=110,w=95,h=65,r=5,width=1,color="#0000FF")
shidu_pic=u_gui.draw_image(image="温度.png",x=37,y=120)
shidu_pic.config(w=20)
u_gui.draw_text(text="温度",x=62,y=117,font_size=13, color="#FF6600")
temp_value=u_gui.draw_digit(text=WenDuShuJu,x=42,y=147,font_size=16, color="#000000")
u_gui.draw_text(text="℃",x=75,y=142,font_size=14, color="#000000")
# 显示气压数据
u_gui.draw_round_rect(x=125,y=110,w=95,h=65,r=5,width=1,color="#0000FF")
qiya_pic=u_gui.draw_image(image="气压.png",x=142,y=120)
qiya_pic.config(w=20)
u_gui.draw_text(text="气压",x=168,y=117,font_size=13, color="#FF6600")
qiya_value=u_gui.draw_digit(text=QiYaShuJu,x=127,y=147,font_size=13, color="#000000")
u_gui.draw_text(text="百帕",x=184,y=142,font_size=12, color="#000000")
# 显示风速数据
u_gui.draw_round_rect(x=20,y=185,w=95,h=65,r=5,width=1,color="#0000FF")
fengsu_pic=u_gui.draw_image(image="风速.png",x=37,y=195)
fengsu_pic.config(w=20)
u_gui.draw_text(text="风速",x=62,y=192,font_size=13, color="#FF6600")
speed_value=u_gui.draw_digit(text=FengSuShuJu,x=40,y=222,font_size=16, color="#000000")
u_gui.draw_text(text="级",x=75,y=217,font_size=14, color="#000000")
# 显示风向数据
u_gui.draw_round_rect(x=125,y=185,w=95,h=65,r=5,width=1,color="#0000FF")
fengxiang_pic=u_gui.draw_image(image="风向.png",x=142,y=195)
fengxiang_pic.config(w=20)
u_gui.draw_text(text="风向",x=168,y=192,font_size=13, color="#FF6600")
wind_direction=u_gui.draw_text(text=FengXiangShuJu,x=140,y=220,font_size=13, color="#000000")
# 显示经度
u_gui.draw_round_rect(x=20,y=270,w=95,h=40,r=5,width=1,color="#0000FF")
u_gui.draw_text(text="经度",x=25,y=280,font_size=10, color="#FF6600")
jingdu_value=u_gui.draw_text(text=JingDu,x=50,y=285,font_size=8, color="#FF0000")
# 显示纬度
u_gui.draw_round_rect(x=125,y=270,w=95,h=40,r=5,width=1,color="#0000FF")
u_gui.draw_text(text="纬度",x=130,y=280,font_size=10, color="#FF6600")
weidu_value=u_gui.draw_text(text=WeiDu,x=160,y=285,font_size=8, color="#FF0000")
# MQTT初始化
siot.getsubscribe(topic="siot/温度数据")
siot.getsubscribe(topic="siot/气压数据")
siot.getsubscribe(topic="siot/风速数据")
siot.getsubscribe(topic="siot/风向数据")
siot.getsubscribe(topic="siot/经度数据")
siot.getsubscribe(topic="siot/纬度数据")
# 硬件初始化
gnss = DFRobot_GNSS_I2C (bus=0, addr=0x20)
while (gnss.begin() == False):
    print("Sensor initialize failed!!")
    time.sleep(1)
gnss.enable_power()
gnss.set_gnss(GPS_BeiDou_GLONASS)
gnss.rgb_on()
gnss_utc = struct_utc_tim()
gnss_lat_lon = struct_lat_lon()

bmp = BMP388()
ws = IICSerialWindSpeed(IICSerialWindSpeed.SUBUART_CHANNEL_1,IA0=1,IA1=1)
ws.modify_address(0, 2)
wd = IICSerialWindDirection(IICSerialWindDirection.SUBUART_CHANNEL_2,IA0=1,IA1=1)
wd.modify_address(wd.V2, 0, 2)
while True:
    # 检测温度
    WenDuShuJu = (math.ceil(bmp.temp_C()))
    temp_value.config(text=WenDuShuJu)
    siot.publish(topic="siot/温度数据", data=WenDuShuJu)
    # 检测气压
    QiYaShuJu = round((bmp.pressure_pa() / 100),1)
    qiya_value.config(text=QiYaShuJu)
    siot.publish(topic="siot/气压数据", data=QiYaShuJu)
    # 检测风速
    FengSuShuJu = (math.ceil(ws.read_wind_speed()))
    speed_value.config(text=FengSuShuJu)
    siot.publish(topic="siot/风速数据", data=FengSuShuJu)
    # 检测风向
    FengXiangShuJu = wd.read_wind_direction()
    wind_direction.config(text=FengXiangShuJu)
    siot.publish(topic="siot/风向数据", data=FengXiangShuJu)
    # 检测经纬度
    gnss_utc = gnss.get_date()
    gnss_utc = gnss.get_utc()
    gnss_lat_lon = gnss.get_lat()
    gnss_lat_lon = gnss.get_lon()
    gnss_alt = gnss.get_alt()
    gnss_cog = gnss.get_cog()
    gnss_sog = gnss.get_sog()
    gnss_num = gnss.get_num_sta_used()
    gnss_star = gnss.get_gnss_mode()
    JingDu = (str(gnss_lat_lon.lonitude_degree))
    WeiDu = (str(gnss_lat_lon.latitude_degree))
    if ((int(float((str(gnss_num))))) > 3):
        jingdu_value.config(text=JingDu)
        weidu_value.config(text=WeiDu)
        siot.publish(topic="siot/经度数据", data=JingDu)
        siot.publish(topic="siot/纬度数据", data=WeiDu)
    if (button_a.is_pressed()==True):
        url = (str("http://v1.yiketianqi.com/free/day?appid=63499934&appsecret=GVXi6Nh8&unescape=1&city=") + str(ChengShiMing))
        response = requests.get(url)
        data = response.json()
        BoBaoNaRong = (str(ChengShiMing) + str((str((data["date"])) + str((str((data["wea"])) + str((str((data["tem"])) + str("°C"))))))))
        print(BoBaoNaRong)
        city_wea.config(text=BoBaoNaRong)
代码
接收端
#  -*- coding: UTF-8 -*-

# MindPlus
# Python
import sys
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-pinpong_wind_direction-thirdex")
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-pinpong_windspeed-thirdex")
sys.path.append("/root/mindplus/.lib/thirdExtension/liliang-gravitygnss-thirdex")
import siot
import time
from unihiker import GUI
from pinpong.board import Board

# 事件回调函数
def on_message_callback(client, userdata, msg):
    global WeiDu
    global WenDuShuJu
    global JingDu
    global QiYaShuJu
    global FengSuShuJu
    global FengXiangShuJu
    if (msg.topic == (str("siot/温度数据"))):
        # 订阅到温度数据
        WenDuShuJu = msg.payload.decode()
        temp_value.config(text=WenDuShuJu)
    if (msg.topic == (str("siot/气压数据"))):
        # 订阅到气压数据
        QiYaShuJu = msg.payload.decode()
        qiya_value.config(text=QiYaShuJu)
    if (msg.topic == (str("siot/风向数据"))):
        # 订阅到风向数据
        FengXiangShuJu = msg.payload.decode()
        wind_direction.config(text=FengXiangShuJu)
    if (msg.topic == (str("siot/风速数据"))):
        # 订阅到风速数据
        FengSuShuJu = msg.payload.decode()
        speed_value.config(text=FengSuShuJu)
    if (msg.topic == (str("siot/经度数据"))):
        # 订阅到经度数据
        JingDu = msg.payload.decode()
        jingdu_value.config(text=JingDu)
    if (msg.topic == (str("siot/纬度数据"))):
        # 订阅到纬度数据
        WeiDu = msg.payload.decode()
        weidu_value.config(text=WeiDu)


u_gui=GUI()
Board().begin()
siot.init(client_id="9710446376212183",server="192.168.1.33",port=1883,user="siot",password="dfrobot")
siot.set_callback(on_message_callback)
siot.connect()
siot.loop()
global QiYaShuJu
QiYaShuJu = 0
global FengSuShuJu
FengSuShuJu = 0
global JingDu
JingDu = ""
global WeiDu
WeiDu = ""
global FengXiangShuJu
FengXiangShuJu = ""
global WenDuShuJu
WenDuShuJu = 0
# 显示标题
title=u_gui.draw_text(text="便携式气象站系统",x=60,y=0,font_size=12, color="#0000FF")
# 显示温度数据
u_gui.draw_round_rect(x=20,y=110,w=95,h=65,r=5,width=1,color="#0000FF")
shidu_pic=u_gui.draw_image(image="温度.png",x=37,y=120)
shidu_pic.config(w=20)
u_gui.draw_text(text="温度",x=62,y=117,font_size=13, color="#FF6600")
temp_value=u_gui.draw_digit(text="1234",x=42,y=147,font_size=16, color="#000000")
u_gui.draw_text(text="℃",x=75,y=142,font_size=14, color="#000000")
# 显示气压数据
u_gui.draw_round_rect(x=125,y=110,w=95,h=65,r=5,width=1,color="#0000FF")
qiya_pic=u_gui.draw_image(image="气压.png",x=142,y=120)
qiya_pic.config(w=20)
u_gui.draw_text(text="气压",x=168,y=117,font_size=13, color="#FF6600")
qiya_value=u_gui.draw_digit(text=QiYaShuJu,x=127,y=147,font_size=13, color="#000000")
u_gui.draw_text(text="百帕",x=184,y=142,font_size=12, color="#000000")
# 显示风速数据
u_gui.draw_round_rect(x=20,y=185,w=95,h=65,r=5,width=1,color="#0000FF")
fengsu_pic=u_gui.draw_image(image="风速.png",x=37,y=195)
fengsu_pic.config(w=20)
u_gui.draw_text(text="风速",x=62,y=192,font_size=13, color="#FF6600")
speed_value=u_gui.draw_digit(text=FengSuShuJu,x=40,y=222,font_size=16, color="#000000")
u_gui.draw_text(text="级",x=75,y=217,font_size=14, color="#000000")
# 显示风向数据
u_gui.draw_round_rect(x=125,y=185,w=95,h=65,r=5,width=1,color="#0000FF")
fengxiang_pic=u_gui.draw_image(image="风向.png",x=142,y=195)
fengxiang_pic.config(w=20)
u_gui.draw_text(text="风向",x=168,y=192,font_size=13, color="#FF6600")
wind_direction=u_gui.draw_text(text=FengXiangShuJu,x=140,y=220,font_size=13, color="#000000")
# 显示经度
u_gui.draw_round_rect(x=20,y=270,w=95,h=40,r=5,width=1,color="#0000FF")
u_gui.draw_text(text="经度",x=25,y=280,font_size=10, color="#FF6600")
jingdu_value=u_gui.draw_text(text=JingDu,x=50,y=285,font_size=8, color="#FF0000")
# 显示纬度
u_gui.draw_round_rect(x=125,y=270,w=95,h=40,r=5,width=1,color="#0000FF")
u_gui.draw_text(text="纬度",x=130,y=280,font_size=10, color="#FF6600")
weidu_value=u_gui.draw_text(text=WeiDu,x=160,y=285,font_size=8, color="#FF0000")
# MQTT初始化
siot.getsubscribe(topic="siot/温度数据")
siot.getsubscribe(topic="siot/气压数据")
siot.getsubscribe(topic="siot/风速数据")
siot.getsubscribe(topic="siot/风向数据")
siot.getsubscribe(topic="siot/经度数据")
siot.getsubscribe(topic="siot/纬度数据")
while True:
    time.sleep(1)

附件

作品反思:

自己也不知道这个作品算不算自己的原创,因为里边包含了我从创客社区、论坛和造物记学到的知识,我根据自身的教学经验,设计了这个作品。由于正值期末,只能在家里赶作业,也没有时间设计外壳,打算下学期开展一期校园气象站的跨学科课程,就拿这个作品为例,相信会很吸引孩子们的。时间有限,精力不足,没有详细的介绍作品的设计,天气预报的API制作。在这里,可以向大家推荐我参考和学习的帖子和文章。

https://mc.dfrobot.com.cn/thread-314188-1-1.html[公告]【新课标】信息科技跨学科案例-8年级 校园气象站系统

https://mc.dfrobot.com.cn/thread-314913-1-1.html[M10教程]【行空板图形化Python入门教程】第15课:天气助手

评论

user-avatar