Newhor

  • 2024-11-27
  • 回复了主题帖: 【2024 DigiKey 创意大赛】自行车智能骑行助手

    wangerxian 发表于 2024-11-27 09:02 原来如此,这样确实也能检测胎压,不过在骑行的过程压力会变化吧 分为了两个阶段,初始未骑行的状态的测量值转换为胎压,骑行中的值转换为体重,用了一些算法对进行骑行时的数据进行滤波处理

  • 2024-11-26
  • 回复了主题帖: 【2024 DigiKey 创意大赛】自行车智能骑行助手

    wangerxian 发表于 2024-11-26 18:47 可能传感器是夹在内胎和外胎之间 先将轮胎气放光,然后夹在钢圈和内胎之间,然后再充气固定的  

  • 2024-11-25
  • 发表了主题帖: 【2024 DigiKey 创意大赛】自行车智能骑行助手

    本帖最后由 Newhor 于 2024-11-27 09:38 编辑 自行车智能骑行助手 作者:newhor   一、作品简介   简介         自行车智能骑行助手的想法是填补骑行配件功能的空缺,为户外骑行爱好者提供一个集胎压测量、体重监测分析及环境感知预警于一体的综合智能解决方案 市面上现有的骑行配件中,很少有监测骑行者长途骑行下的体重变化,胎压预警以及环境感知预警等功能。本作品主要特点如下: ①在骑行前,安装在自行车轮胎中的压力传感器采集的压力数据,可以监测轮胎的初始压力值,并通过ESP-NOW无线通信将数据传送到主控MCU,再通过前期的数据标定确定的函数关系,MCU将压力数据转换为胎压后,显示在屏幕上。当检测到胎压低于预设的安全范围(例如25PSI)时,智能助手会立即通过显示器提示骑行者进行胎压补充,确保骑行安全。具体实现包括:压力传感器安装在轮胎钢圈与内胎之间,测量初始压力值;ESP-NOW模块负责将传感器数据无线传输到主控MCU;主控MCU处理接收到的数据,并通过显示器显示给骑行者。   ②在长时间骑行时,系统通过采集安装在轮胎内的压力传感器的压力值,通过前期的标定,将其转化为体重值。结合骑行时间和BME680传感器提供的环境温度数据,系统通过算法计算一段时间内体重的变化量,如果体重变化量超过预设阈值,会触发警报,通过显示屏提醒用户,同时提供休息和补水建议。   ③通过拓展的BME680环境传感器,给骑行者提供户外骑行时的空气质量预警和高温预警。一旦发现空气质量下降或温度过高,智能助手将通过显示屏及时提醒骑行者采取相应措施,如减少运动强度或寻找遮阴处休息,确保骑行者的健康和安全。   ④通过车把端的MCU采集并记录BME680传感器在一段时间内的气压和湿度数据,MCU对这些数据进行分析,当检测到气压持续降低且空气湿度升高超过一定阈值时,提供下雨预警,通过显示器告警骑行者,建议提前返回或寻找避雨场所,确保骑行安全。   ⑤可记录骑行过程中的体重、胎压、环境变化数据保存在本地(后续添加手机端无线接收功能),并提供长期趋势分析,帮助骑行者更好地了解自身状况和改善骑行计划。 此外,该还系统具有强大的可拓展性,以后可以集成更多好玩的功能进来。   主要特点: 胎压监测 实时监测体重变化 智能骑行建议 恶劣天气预警 可存储运动数据,分析长期数据 硬件模功能块化设计,功能易扩展 可太阳能充电 开源   照片 (1)车把数据接收显示端        (2)轮胎数据采集发送端             二、系统框图 硬件说明   主要物料 控制器:ESP32-C6,ESP32-S2MINI 加速度传感器:4554、MMA8452 湿度空气传感器:BME680 显示屏幕:1.8寸TFT 充电管理芯片:TP4054 薄膜式压力传感器 锂电池、太阳能板   硬件框图 主要分为车轮压力数据采集端、以及车把数据接收显示端,采用模块集成方式、方便更换与拓展。         2.软件说明       软件分为4个部分: MCU数据处理 ESPNOW数据传输 传感器数据采样控制 液晶显示   三、各部分功能说明 硬件功能 (1)轮胎端:主要完成胎压数据采集、ESPnow数据发送等功能   轮胎端主控使用ESP32-S2MINI,这是一款乐鑫一款入门级开发板,搭载Xtensa®32位LX7单核处理器,工作频率高达240MHz。可深度休眠,利用低功耗协处理器监测外设的状态变化或某些模拟量多的阈值,可通过外部中断唤醒,常用于可穿戴电子设备、智能家居等场景常用于物联网设备开发。在该作品中,利用其ADC功能,采集安装于轮胎内壁的薄膜式压力传感器的电压值,并通过ESPnow无线功能,实时将数据上传到车把端的MCU进行处理。 加速度传感器采用了基础型号MMA8452,加速度传感器的中断输出引脚,连接到轮胎端ESP32MINI上可支持休眠唤醒的IO口,并在采样程序中配置了休唤醒中断。当自行车静止一段时间后,ESP32MINI由于未检测到加速度传感器的运动中断,会进入深度休眠降低功耗,当检测到轮胎震动时,加速度传感器会立即产生运动中断唤醒MCU,开始采集压力数据,实现了轮胎端采样系统的低功耗。     压力传感器采用薄膜式,方便安装于轮胎与钢圈之间,当轮胎由于胎压或骑行者体重产生形变时,薄膜式压力传感器受到压力产生相应的形变,其电阻值产生相应变化,MCU通过电阻分压电路的方式进行ADC采样,将压力值转换为电压值。   供电部分,配备了电池,并基于TP4054芯片设计了可多路供电的防反充电电路,通过添加多个二极管防止反充,实现开发板的USB接口以及太阳能板双充电模式。       (2)车把端:主要完成数据接收,处理、以及数据显示等功能   车把端主控使用大赛提供的ESP32-C6开发板,是一款高性能、低功耗的单芯片解决方案。多达 22 个 GPIO 引脚,支持 SPI、I2C、UART 等多种通信协议,具有 Wi-Fi 6 和 蓝牙低能耗(Bluetooth LE 5.2) 的支持,主要面向现代无线通信需求。该作品采用该模块作为主控接收端MCU,能满足ESPNOW无线功能高频的数据接收和处理需求,并同时实现了对多个传感器的数据采集处理,以及显示。 显示器使用ST7735驱动TFT屏,支持全彩显示、内容方向可调整,数据显示量够大,且观感更好。 加速度传感器模块使用的是大赛提供的4554,ICM-20948 是一款高性能的9轴运动传感器,具有高精度与低噪声等特点,在该作品中,该模块用于判断自行车实时的骑行状态,是加减速还是匀速,帮助MCU处理数据,消除加减速带来的轮胎形变时产生的误差数据。 环境传感器使用的是大赛提供的BME680模块,具有环境参数丰富,精度较高等特点。在该作品中,主要用于采样环境参数,包括温湿度、空气质量、大气压等。其中温度数据,用于辅助长时间骑行时体重变化量供相应的休息和补水建议;通过分析湿度和大气压数据下雨前的变化趋势,提前预测降雨的可能性,并通过屏幕向骑行者发出提醒;空气质量数据,实时转换为空气质量IAQ,给户外骑者相应的户外骑行建议。 供电电路与轮胎端一致,采用电池供电,并支持USB与太阳能板双充电。 2.软件功能     (1)数据标定以及转换部分 在胎压数据标定时,由于传感器的精度以及受到安装位置的影响,会出现相同胎压下前后轮的压力传感器初始压力不一致的现象,故前后轮的压力数据分开进行标定。压力传感器安装于车轮内部后,通过带压力显示的打气筒给轮胎补充到多组不同的胎压值,得到对应胎压下的传感器压力数值,作为空载状态下,不同胎压与采集电压的数据组合,通过数据拟合得到相应的函数关系后,实现通过空载状态下电压计算出当前胎压数值的功能。 在体重数据标定时,通过记录多个不同体重骑行者,骑行时与空载的压力差值,与相应体重进行数据组合,然后进行数据拟合,得到电压差与骑行者体重函数关系。     (2)数据滤波部分           骑行时压力传感器由于轮胎转动到不同的位置、路面颠簸、急加减速等因素,会产生部分误差数据。采用滑动平均法,对一段时间窗口内的数据进行平均,从而减少噪声或波动,使数据更加平滑。   四、作品源码   自行车智能骑行助手——作品源码-嵌入式开发相关资料下载-EEWORLD下载中心     系统的硬件部分软件使用 micropython 进行开发,采用异步多任务形式。部分源码如下:       文件:task_TFTshow.py import asyncio from machine import Pin, SoftSPI from time import sleep_ms from global_var import * from cfg import * async def TFTshow(): while True: if gv.int_flag == 1: # pass lcd.clear(0) lcd.rotate(180) lcd.drawText('系统初始化中'+str(gv.int_cnt*10)+'%',0,50,font,0x0f0) lcd.drawText('请在10S内推动自',0,70,font,0xff0) lcd.drawText('行车采集初始数据',0,90,font,0xff0) lcd.show() elif gv.str_flag == 1 or 2 or 3: lcd.clear(0) lcd.rotate(180) lcd.drawText('温度:'+str(round(gv.tmp,1))+'°',0,0,font,0x0f0) lcd.drawText('湿度:'+str(round(gv.hum,1))+'%',0,20,font,0xff0) lcd.drawText('气压:'+str(round(gv.pre,1))+'Pa',0,40,font,0x00f) lcd.drawText('IAQ:'+str(gv.IAQ)+gv.iaq_leve,0,60,font,0xff0) lcd.show() await asyncio.sleep(2) if gv.weight_int !=0: lcd.clear(0) lcd.rotate(180) lcd.drawText('初始胎压psi:',0,0,font,0x00f) lcd.drawText('前:'+str(gv.P1_int)+'后:'+str(gv.P2_int),0,20,font,0x00f) lcd.drawText('初始体重:'+str(gv.weight_int)+'kg',0,40,font,0x0f0) lcd.drawText('实时体重:'+str(gv.weight)+'kg',0,60,font,0x0f0) # lcd.drawText('体重差值:'+str(gv.weight_int-gv.weight)+'kg',0,80,font,0x00f) lcd.drawText('运动时长:'+str(round(gv.SportTime/60+0.7,1))+'min',0,100,font,0x00f) lcd.show() await asyncio.sleep(2) gv.SportTime+=2 gv.SportTime+=2.1 if gv.end_flag ==1:#运动结束 lcd.clear(0) lcd.rotate(180) lcd.drawText('运动已结束',0,0,font,0x0f0) lcd.drawText('该次运动时长为',0,50,font,0xff0) lcd.drawText(str(round(gv.SportTime/60,1))+'min',0,70,font,0xff0) lcd.drawText('该次运动减重;',0,90,font,0xff0) lcd.drawText(str(gv.weight_int-gv.weightmin)+'kg',0,110,font,0xff0) lcd.show() import machine machine.reset() await asyncio.sleep(0.1) # asyncio.run(TFTshow())     文件:task_ESPnow.py import network import aioespnow import asyncio import neopixel import binascii,time from machine import Pin from neopixel import NeoPixel from time import localtime from global_var import * from cfg import * np = neopixel.NeoPixel(Pin(8), 1) # WLAN接口必须处于活动状态才能 send()/recv() sta = network.WLAN(network.STA_IF) # 或 network.AP_IF sta.active(True) sta.disconnect() # 对于 ESP8266 e = aioespnow.AIOESPNow() e.active(True) peer = b'\xAA\xBB\xCC\xDD\xEE\xFF' # 配对设备wifi接口的MAC地址 e.add_peer(peer) # 发送前必须 add_peer() # e.send(peer, '123') def Pcvt1(x): if x>=0 and x<0.76: return 35 if x>=0.76 and x<0.92: return 25 if x>=0.92 and x<1.0: return 30 if x>=1.0 and x<1.08: return 35 if x>=1.08 and x<1.3: return 40 if x>=1.3 and x<1.4: return 45 if x>=1.4: return 50 def Pcvt2(x): if x>=0 and x<1.12: return 20 if x>=1.12 and x<1.19: return 25 if x>=1.19 and x<1.24: return 30 if x>=1.24 and x<1.26: return 35 if x>=1.26 and x<1.28: return 40 if x>=1.28 and x<1.32: return 45 if x>=1.32: return 50 def P_Vdata_int(r):# 初始电压平均 global v1,v2,m,n print('接收的r[4:9]字节数据为:',r[4:9],type(r[4:9])) if r[2] == 49: gv.V1 = float(r[4:9].decode('utf-8')) print('转换后的整数数据为V1:',gv.V1) v1 = gv.V1+v1 n=n+1 gv.Vint1 = round(v1/n,3) print('gv.Vint1',gv.Vint1 ) elif r[2] == 50: gv.V2 = float(r[4:9].decode('utf-8')) print('转换后的整数数据为V2:',gv.V2) v2 = gv.V2+v2 m=m+1 gv.Vint2 = round(v2/m,3) print('gv.Vint2',gv.Vint2) def P_Vdata(x):#取峰值 global r gv.st_cnt+=1 if gv.st_cnt<=x: if r[2] == 49: gv.V1 = float(r[4:9].decode('utf-8')) elif r[2] == 50: gv.V2 = float(r[4:9].decode('utf-8')) if gv.V1 > gv.V1max: gv.V1max = gv.V1 if gv.V2 > gv.V2max: gv.V2max = gv.V2 else: gv.st_cnt = 0 gv.V = gv.V1+gv.V2-gv.Vint1-gv.Vint2 print('========gv.V:',gv.V) gv.weight = WGTcvt(gv.V) if gv.weight<gv.weightmin: gv.weightmin = gv.weight def WGTcvt(y): if y>0.1: t = 57+y*12 elif y< 0.1 and y >0.05: t = 57+y*21 elif y <0.05 and y>0.01: t = 57+y*31 elif y <0.01: t = 57+y*61 print('^^^^^^^^^t',t) return t async def e_recv(): global r while True: if e.any(): host, msg = e.recv() if len(msg)>=5 and len(msg)<=15: if msg[:2] == b'cc': print('msg',msg) np[0] = (0, 30, 0) np.write() gv.int_cnt +=1 print('gv.int_cnt',gv.int_cnt) if gv.int_cnt <= 10:#初始化时间10S #gv.int_flag = 1 P_Vdata_int(msg) print('gv.int_flag :',gv.int_flag) elif gv.int_cnt>10 and gv.str_flag ==0: gv.int_flag = 0 gv.str_flag = 1 print('gv.str_flag:',gv.str_flag) else: pass if gv.str_flag == 1:#初始化结束,胎压转换 gv.P1_int = Pcvt1(gv.Vint1) print('gv.P1_int',gv.P1_int) gv.P2_int = Pcvt2(gv.Vint2) print('gv.P2_int',gv.P2_int) gv.str_flag = 2 print('gv.str_flag :',gv.str_flag) if gv.str_flag == 2:#开始测量初始体重 print('---------------gv.str_flag :',gv.str_flag) gv.waitcnt+=1 if gv.waitcnt>=100: r = msg P_Vdata(10)#取50次数据的峰值 if gv.weight>0 and gv.st_cnt ==0: gv.weight_int = gv.weight print('gv.weight_int',gv.weight_int) gv.weight = 0 gv.str_flag = 3 if gv.str_flag == 3:#开始测量运动后体重 print('```````````gv.str_flag:',gv.str_flag) r = msg P_Vdata(20)#每100次数据更新一次体重 r = localtime() s = '{:04}-{:02}-{:02} {:02}:{:02}:{:02} > {}'.format(r[0], r[1], r[2], r[3], r[4], r[5], str(msg)) f = open('称重数据1.txt', "a", encoding="UTF-8") f.write( s+'\n') f.close() await asyncio.sleep(0.05) np[0] = (0, 0, 0) np.write() else: print('msg head error') else: print(' msg len error') else: print('等待数据,请在5秒内启动车辆') gv.endcnt+=1 if gv.endcnt>=100:#(5秒内未收到数据,运动结束) gv.endcnt = 0 gv.end_flag = 1 await asyncio.sleep(0.05) # asyncio.run(e_recv())   五、作品功能演示视频 自行车智能骑行助手——得捷大赛作品演示视频_哔哩哔哩_bilibili [localvideo]7cc8994b5fdfb34a822f81dc96acf77b[/localvideo]   六、项目总结     参加这次活动之前,刚好买了一辆自行车,加入了骑行者的队伍,然后计划购买一些配件来改装车辆,和同事讨论时,想到胎压测量以及骑行时的体重监测等场景,在市面上没有找到类似功能的产品,所以想尝试做一下这个功能的作品,看看是否能够实现预期的效果。     此次作品将最初想法能大致实现了,可以完成测量胎压和体重等功能,但由于各方面的限制,数据精度上但是还有很多不足,例如传感器精度不足以及线性度不够、安装位置无法保证受力均衡、轮胎的自然转动带来的数据波动,都会影响最后得到的数据精度。由于时间关系,还有运动数据上传到手机功能暂未实现,这个后续再添加。     通过参加本次活动,收获还是不小的,真真切切的感受到了从一个想法到一个作品做好的难度,需要考虑的东西太多了,做到一半才发现很多东西与预想的差别很大,可能写程序、画板子还是其中最容易的环节,例如此次作品中,一个合适的传感器的选择和安装固定的方式,在前期就花了很多时间。     最后,感谢得捷和EEworld,组织了这次活动,让大家的想法可以有个很好的机会来实现,并且能学习到很多其他人的有趣想法。     【2024 DigiKey 创意大赛】物料开箱帖 - DigiKey得捷技术专区 - 电子工程世界-论坛 【2024 DigiKey 创意大赛】自行车智能骑行助手 - DigiKey得捷技术专区 - 电子工程世界-论坛   https://gitee.com/newhor/zhinengqixing.git  

  • 2024-11-24
  • 上传了资料: 自行车智能骑行助手——作品源码

  • 2024-11-05
  • 加入了学习《【2024 DigiKey 创意大赛】AI全功能环境监测站作品功能演示视频》,观看 【2024 DigiKey 创意大赛】AI全功能环境监测站作品功能演示视频

  • 2024-08-11
  • 发表了主题帖: 【2024 DigiKey 创意大赛】物料开箱帖

    本帖最后由 Newhor 于 2024-8-11 11:38 编辑   非常荣幸能入选这次2024 DigiKey 创意大赛“大赛,这次我想做的是一个山地车胎压测量以及称重系统,本次我选择的物料是一块ESP32-C6开发板、BME680传感器和4554加速度传感器。接下来先来看一下物料   包装很严实   一个esp32 c6的开发板,作为主控MCU,感觉包装盒还不错   BME680用来采集温度,用来做胎压的算法的温度校准,它的VOC、湿度、气压这几个检测功能也可以为户外骑行条件提供一些参考,功能很齐全     一个4554用来做运动状态检测    

最近访客

< 1/1 >

统计信息

已有9人来访过

  • 芯积分:129
  • 好友:1
  • 主题:6
  • 回复:24

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言