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

#决赛#学霸助手 简单

头像 dlzxlsx 2023.08.10 241 2

* 项目介绍:

 

Rome wasn't built in a day.学霸并不是天生的,他们通过养成良好学习习惯,不断努力和坚持,逐步取得优异成绩。因此,家长让孩子从小够养成良好的学习习惯,那么他们也有可能在学业上获得突出的表现,走上学霸的道路。

 

良好的学习习惯的核心是按时学习,合理规划时间,集中注意力,以及坚持不懈的学习态度。我们可以用技术手段您帮助孩子养成良好的学习习惯,成就他的学霸之梦。

 

作品组成:一个智能书桌和一张大屏幕组成。其中智能书桌包括:摄像头、光线传感器、智能阅读架(内置光线传感器)、空气质量传感器、智能笔(内置三轴地磁传感器)、SCI采集模块、行空板、智能坐椅(含一个轻触开关)。

IMG_20230805_084653.jpg

座位内的轻触开关,四周四个缓冲弹簧。

IMG_20230805_092700.jpg

坐垫内部的轻触开关与坐位木板存在一个间隙,人坐下时,正好让开关闭合。

IMG_20230810_163910.jpg

笔杆上安装一个三轴传感器,用于判断笔的状态。

IMG_20230810_163929.jpg

阅读支架面板上有一个光线传感器,当孩子把书本放置在书架上,光线传感器被遮挡,输出的数值变化大。支架顶端有一个摄像头,用于记录孩子的学习实况。该摄像头只有当孩子坐下时才工作,孩子离开座位10秒时,摄像头停止工作。这样能保护孩子的隐私。

IMG_20230810_164023.jpg
IMG_20230810_164333.jpg

上图是阅读支架的后视图与侧视图。空气质量传感器、温湿度传感器、SCI采集模块安装在后部,环境光线传感器与环境噪音传感器用行空板载的。行空板屏幕上显示的是孩子是否在学习或是在休息中。

image.png

 

作品功能:该设置能实现监测孩子的学习环境与学习状态,统计孩子的学习时间,显示孩子的学习画面。在书房内,孩子一坐到椅子上,椅子上的传感器(开关)触发系统进入工作状态:开启摄像头、监测环境光线、噪音、温度、湿度、空气质量的值,把这些信息显示在客厅的大屏上。如果上述环境因素值没有适宜的范围内,家长要帮助孩子调节到适宜学习的范围内:调节书房的灯光、空调,关闭音乐,其他家庭成员保持安静。孩子写作业的笔杆上有一个三轴传感器,能记录笔的位置,估算出孩子书写的时长;阅读支架上的光线传感器根据光线的变化(在阅读时,孩子把书本放置在阅读支架上,光线传感器被书本遮盖,数值产生变化。)大屏幕上除了显示这些数据外,还能实时显示孩子学习时的画面。屏幕上显示孩子的学习(阅读与书写)时长。如果达到预定的学习时长,屏幕上出现鼓励性的图标,否则出现“还要加油”的图片。大屏幕的中下部显示孩子一天的学习计划。所有的这些设计有助于养成学霸应具备的学习习惯。

 

 

* 制作过程:

1. 制作椅子触发开关(P21,常高)。用四个弹力合适的缓冲弹簧与两片木板组成,如果没有人坐下,开关输出低电平,学霸助手休眠;当有人坐下,片木板的间隔变小,开关被按下,输出低电平,学霸助手启动。

 

2. 安装在书桌上、阅读支架、笔杆上的各种传感器把数据通过采集器传送给行空板,行空板把这些数据与学习的图像通过物联网传送到大屏幕上。

 

3. 收集笔平放在桌子上与书写两种姿态行空板上集成的三轴传感器xyz轴方向的加速度数据(从中提取一组数据如下表),笔(行空板)从平躺到直立时,x与z轴的加速度值变化很大。我用x轴的数据判定,如果x轴的加速度大于0.5时,笔处于书写姿态。

 

image.png

4. 在制作笔的姿态判定时,最初使得行空板自带的三轴加速度传感器,但实际使用时要把三轴加速度传感器固定在笔杆上,由于行空板体积太大,不方便固定在笔杆上。希望购置一个单独的加速度传感器。在查阅sci采集器支持的三轴传感器模块中,只有BMM150 三轴地磁传感器:

image.png

经过多次实验与精心设置场景,在本项目中,通过判断Z方向的数值可以推断出笔的姿态,进而推断使用者是否在用笔书写。

image.png

5. 用同样的思路实现阅读时长的获取。

image.png

 

6. 孩子短暂(本例中为了演示方便,时间设为10秒)起身离开椅子,不影响系统的工作,只记录离开时长;如果离开椅子时间大于10秒,则表示该时段的学习结束,系统停止工作。

image.png

7. 设计大屏幕的画面布局。

 

8. 大屏幕上显示休息与学习两种状态的图片,代码如下:

 

在运行代码前,要把0.jpg和1.jpg两个图片文件通过下图的步骤传到行空板的“/root/xueba/目录”

 

设置siot相应的话题:

image.png

大屏幕面板的设置:

 image.png

运行代码的效果如下:

 image.png

9. 学习的实时画面,也要先设置话题“siot/学习画面”和大屏幕上放置“网络图片”组件,订阅这个话题,再编写下面的代码:

 image.png

10. 用mind+1.8为每个传感器编写代码,逐个调试;

每日学习计划:

6:00~6:30 朗读并背诵I have  a dream      6:30~7:10 听写CNN 10      7:10~7:30 早餐      7:30~8:30  临习米芾尺牍《至知府大夫尺牍》      8:30~9:30 学习B站宋浩的偏导数第一课      9:30~10:00 coffe break      10:00~11:00 跟粒子姐姐学mind+python编程      11:00~12:00上浦育innolab继续autobilling项目      12:00~12:30午餐      12:30~13:30午休      13:30~14:30 练习古琴《广陵散》      14:30~15:30陶艺课      15:30~16:00 coffe break      16:00~17:00 1000米游泳练习      17:00~17:30 晚餐      17:30~19:30 英语社团辩论活动      19:30~20:30 街舞课      

20:30~21:00 营养点心      21:00~22:00 阅读与日记      22:00~22:40 家庭分享      22:40~23:00 睡前准备      23:00 休息

11.用到了大量的变量,如下 :

image.png

遇到的问题及解决方案:

1. 可视化大屏幕的“网络图片”既能显示摄像头的视频,也能显示图片。在该项目中有一个“学习状态”话题,用于显示书房里孩子是在学习还是在休息。我用两张图片表示这两个状态,起初我把这两张图片放在电脑中,利用cv2与base64模块希望把这两张图显示在大屏幕中,但程序运行时提示无法打开目标文件,root/mindplus/cach下不存在这个文件。后把这两个文件传到行空板的root/xueba目录下,并在cv2读取图片文件中标题图片文件的绝对路径。运行程序,能显示两张图片。

image.png

2. 在可视化屏幕布局设计时,发现“单行”文字的字体太小,字体、字号不能调整。“多行”文件组件不能人工分段,所有文字连成一大段,不美观。

image.png

3. Siot v2只能在局域网内使用,局限性较大,实用性不足;

期望下一个版本能对上述问题进行改进。

 

* 作品演示:

1. 使用者入座即启动系统。椅子上有一个触发开关;当有人坐下,开关被按下,学霸助手启动。行空板上从“休息”画面切换为“加油”,书房外的可视化大屏启动。

2. 实时监测书房的环境质量。书房的光线、噪音、温度、湿度、氧气值显示在客厅的大屏上。家长根据上述数据把孩子的学习环境调整到最适宜学习。

3. 笔杆上与阅读支架上传感器能判断孩子是否在书写或阅读,并记录相应的时长,发送到大屏幕上显示。

4. 大屏幕实时显示孩子学习的画面

5. 大屏幕上显示每天详细的和学习任务与安排,起到提示的作用。

6. 屏幕上显示孩子在书房里学习的时长,包括阅读时长、书写时长、离开座位的时长。

7. 自动奖励。如果孩子达到预定的学习时长,屏幕上出现鼓励性的图标,礼物盒自动开启,送给孩子一个礼物做鼓励。

(详细演示见下面的视频)

 

* 总结:

该作品实现了设计的目标,能实时获得并记录孩子在家中学习的情况。未来,可在现在作品功能的基础上进行改进升级,主要有以下方面:

1.笔上安装的三轴传感器改用蓝牙传输数据,方便孩子书写。

2.桌面上安装脉搏、体温、皮肤导电等传感器,用于获取孩子的情绪数据,分配孩子在学习中的情绪状态;

3.屏幕有触屏功能,设计一些选择按键,记录孩子每天每件学习/活动任务的完成情况,每天结束后,产生一个统计表,显示每个工作完成的进度。

4.有远程访问功能。家长出门在外也能通过物联网平台观看孩子的学习/活动情况。

 

* 资源:

image.png
image.png
image.png
image.png
image.png

材料清单

  • 行空板 X1 链接
  • Gravity: SCI采集模块 X1 链接
  • Gravity:BMM150三轴地磁传感器 X1 链接
  • Gravity: ENS160 空气质量传感器 X1 链接
  • Gravity: SHT31-F数字温湿度传感器 X1 链接
  • Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) Gravity: I2C VEML7700 环境光传感器 (0~120Klx) X1 链接
  • micro:bit掌控I/O扩展板 X1 链接
  • 普通USB摄像头 X1
代码
#  -*- coding: UTF-8 -*-

# MindPlus
# Python
import base64
from io import BytesIO
from PIL import Image
from pinpong.libs.dfrobot_ens160 import Ens160
from pinpong.libs.dfrobot_sht31 import SHT31
from pinpong.extension.unihiker import *
from pinpong.board import Board,Pin
from dfrobot_rp2040_sci import *
from pinpong.board import Board
from unihiker import Audio
from unihiker import GUI
import math
import siot
import time
import cv2


Board().begin()
siot.init(client_id="7626107718319322",server="192.168.31.128",port=1883,user="siot",password="dfrobot")
u_gui=GUI()
u_audio = Audio()
siot.connect()
siot.loop()
p_p21_in=Pin(Pin.P21, Pin.IN)
SCI1 = DFRobot_RP2040_SCI_IIC(addr=0x21)
while SCI1.begin() != 0:
    print("Initialization Sensor Universal Adapter Board failed.")
    time.sleep(1)
print("Initialization Sensor Universal Adapter Board done.")
p_ens160 = Ens160(0x52)
p_sht31 = SHT31(0x45)
ZuoWeiKaiGuan = False
BiGanZiTai = False
ShuXieShiChang = 0
ShuXieKaiShi = 0
YueDuKaiShi = 0
YueDuShiChang = 0
YueDuQiZhuangTai = False
YouXiaoShiChang = 0
XueXiShiChang = 0
XueXiZhuangTai = False
XueXiKaiShi = 0
ZheCiDeLiKaiShiChang = 0
KaiShiLiKai = 0
LiKaiShiChang = 0
XueXiJiHua = (str("6:00~6:30 朗读并背诵I have  a dream      6:30~7:10 听写CNN 10      7:10~7:30 早餐      7:30~8:30  临习米芾尺牍《至知府大夫尺牍》      8:30~9:30 学习B站宋浩的偏导数第一课      9:30~10:00 coffe break      10:00~11:00 跟粒子姐姐学mind+python编程      11:00~12:00上浦育innolab继续autobilling项目      12:00~12:30午餐      12:30~13:30午休      13:30~14:30 练习古琴《广陵散》      14:30~15:30陶艺课      15:30~16:00 coffe break      16:00~17:00 1000米游泳练习      17:00~17:30 晚餐      17:30~19:30 英语社团辩论活动      19:30~20:30 街舞课       20:30~21:00 营养点心      21:00~22:00 阅读与日记      22:00~22:40 家庭分享      22:40~23:00 睡前准备      23:00 休息 "))
ShiDu = 78
QiWen = 26
ZaoYin = 18
GuangZhao = 85
YangQi = 95

def frame2base64(frame):
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    img = Image.fromarray(frame) #将每一帧转为Image
    output_buffer = BytesIO() #创建一个BytesIO
    img.save(output_buffer, format='JPEG') #写入output_buffer
    byte_data = output_buffer.getvalue() #在内存中读取
    base64_data = base64.b64encode(byte_data) #转为BASE64
    return base64_data #转码成功 返回base64编码

def base642base64(frame):
    data=str('data:image/png;base64,')
    base64data = str(frame2base64(frame))
    framedata = base64data[2:(len(base64data)-1)]
    base642base64_data = data + str(framedata)
    return base642base64_data
siot.getsubscribe(topic="siot/学习状态")
siot.getsubscribe(topic="siot/学习画面")
img2 = cv2.imread("/root/xueba/bizhi.png", cv2.IMREAD_UNCHANGED)
siot.publish(topic="siot/学习画面", data=base642base64(img2))
vd = cv2.VideoCapture()
vd.open(0)
while not (vd.isOpened()):
    print("摄像头初始化..")
print("摄像头初始化成功")
txt=u_gui.draw_text(text="休息....",x=70,y=220,font_size=20, color="#0000FF")
bq=u_gui.draw_emoji(emoji="Smile",x=0,y=0,duration=0.2)
img0 = cv2.imread("/root/xueba/0.jpg", cv2.IMREAD_UNCHANGED)
siot.publish(topic="siot/学习状态", data=base642base64(img0))
while not ((not (p_p21_in.read_digital()==True))):
    pass
KaiShiLiKai = time.time()
XueXiZhuangTai = True
txt.config(text="加油!")
bq.config(emoji="Think")
siot.publish_save(topic="siot/学习计划", data=XueXiJiHua)
img1 = cv2.imread("/root/xueba/1.jpg", cv2.IMREAD_UNCHANGED)
siot.publish(topic="siot/学习状态", data=base642base64(img1))
siot.publish_save(topic="siot/正在做什么", data="学霸准备中...")
time.sleep(1)
while not ((XueXiZhuangTai == False)):
    if vd.grab():
        ret, grab = vd.read()
        siot.publish(topic="siot/学习画面", data=base642base64(grab))
    ShiDu = p_sht31.humidity()
    QiWen = p_sht31.temp_c()
    ZaoYin = u_audio.sound_level()
    GuangZhao = light.read()
    YangQi = p_ens160.get_aqi()
    siot.publish_save(topic="siot/书房湿度", data=ShiDu)
    siot.publish_save(topic="siot/书房温度", data=QiWen)
    siot.publish_save(topic="siot/书房噪音", data=ZaoYin)
    siot.publish_save(topic="siot/书房光线", data=GuangZhao)
    siot.publish_save(topic="siot/空气质量指数", data=YangQi)
    # 这两个如果的功能是获取书写时间,用x轴的加速度是否<0.5做为判定是否处于书写状态。
    if (((int(float(SCI1.get_value1(SCI1.eALL,"Mag_Z")))) > 0) and (BiGanZiTai == True)):
        siot.publish_save(topic="siot/正在做什么", data="停止书写")
        BiGanZiTai = False
        ShuXieShiChang = (ShuXieShiChang + (time.time() - ShuXieKaiShi))
    if (((int(float(SCI1.get_value1(SCI1.eALL,"Mag_Z")))) < 0) and (BiGanZiTai == False)):
        siot.publish_save(topic="siot/正在做什么", data="正在书写")
        BiGanZiTai = True
        ShuXieKaiShi = time.time()
    # 这两个如果的功能是获取阅读时间,用光线传感器的值做为判定是否处于阅读状态。
    if (((int(float(SCI1.get_value1(SCI1.eALL,"Light")))) < 40) and (YueDuQiZhuangTai == False)):
        siot.publish_save(topic="siot/正在做什么", data="正在阅读")
        YueDuKaiShi = time.time()
        YueDuQiZhuangTai = True
    if (((int(float(SCI1.get_value1(SCI1.eALL,"Light")))) >= 40) and (YueDuQiZhuangTai == True)):
        siot.publish_save(topic="siot/正在做什么", data="停止阅读")
        YueDuShiChang = (YueDuShiChang + (time.time() - YueDuKaiShi))
        YueDuQiZhuangTai = False
    # 开关一松开,人离开,开始持续计算离开的时长。
    if ((p_p21_in.read_digital()==True) == True):
        if (ZuoWeiKaiGuan == True):
            ZuoWeiKaiGuan = False
            siot.publish_save(topic="siot/正在做什么", data="离开椅子")
            KaiShiLiKai = time.time()
            XueXiShiChang = (XueXiShiChang + (time.time() - XueXiKaiShi))
        ZheCiDeLiKaiShiChang = (time.time() - KaiShiLiKai)
        if (ZheCiDeLiKaiShiChang > 10):
            XueXiZhuangTai = False
    else:
        # 开关刚按下,开始学习,学习时间开始计时。
        # 结算离开的时长。
        if (ZuoWeiKaiGuan == False):
            LiKaiShiChang = (LiKaiShiChang + (time.time() - KaiShiLiKai))
            siot.publish_save(topic="siot/正在做什么", data="回到座位")
            XueXiKaiShi = time.time()
            ZuoWeiKaiGuan = True
siot.publish_save(topic="siot/学习时长", data=(str((int(ShuXieShiChang))) + str((str(",") + str((str((int(YueDuShiChang))) + str((str(",") + str((int(LiKaiShiChang)))))))))))
if ((ShuXieShiChang + YueDuShiChang) < 100):
    img2 = cv2.imread("/root/xueba/bizhi.png", cv2.IMREAD_UNCHANGED)
    siot.publish(topic="siot/学习画面", data=base642base64(img2))
else:
    img2 = cv2.imread("/root/xueba/bizhi.png", cv2.IMREAD_UNCHANGED)
    siot.publish(topic="siot/学习画面", data=base642base64(img2))
txt.config(text="休息...")
bq.config(emoji="Sleep")
img0 = cv2.imread("/root/xueba/0.jpg", cv2.IMREAD_UNCHANGED)
siot.publish(topic="siot/学习状态", data=base642base64(img0))

评论

user-avatar
  • 少东

    少东2023.09.04

    “学霸”说,我真的会谢。哈哈哈哈哈(好奇学霸用户的感受)

    0
    • hacker_

      hacker_2023.08.14

      666

      0