C#+ WPF 实现蓝牙转WIFI计步上位机

打印 上一主题 下一主题

主题 843|帖子 843|积分 2531

前言

一个WIFI上位机,吸收底层MPU6050数据,途中转蓝牙从机透传,到蓝牙主机直连WIFI,PC端UDP通信,实现三轴加速度数据传送和计步功能。
项目介绍

本项目基于.NET平台,使用WPF开发了一个应用程序,用于实现MPU6050传感器数据从蓝牙模块传输到主机,并通过WiFi以UDP协议吸收这些数据并进行可视化展示。
详细而言,MPU6050作为从设备通过蓝牙毗连到主控设备(蓝牙主机),再由主控设备经由WiFi网络将数据以UDP包的形式发送至服务器或客户端进行处置惩罚和图形化显示。

项目运行情况

1、开发平台
项目基于.NET Framework,接纳 WPF 开发用户界面。
2、集成开发情况
Visual Studio 2019,确保已安装 C# 开发工作负载以支持项目开发与运行。
3、启动项目
获取源代码后,通过打开 BluetoothPC.sln 解决方案文件即可。确保所有依赖项精确设置后,直接运行解决方案,应用程序应能正常启动。
4、用户界面特色
应用程序配备了一个直观且美观的用户界面,图标计划精心,提供优秀的用户体验和视觉享受。

项目计划流程

1、计划框架
前台XAML的UI计划不过多介绍,主要看计划需求,逃不开模板、触发器、动画、样式之类的技术。
后台C#在UI主线程下开了三个子线程:
1、UDP数据监听吸收线程。
2、三轴数据UI更新线程。
3、计步和进度条数据更新线程。
因没有碰到多个线程访问同一个UI控件或写同一个UI控件,所以没用到锁,但内部加了异步延迟,让UI更新顺滑一些。
2、服务器毗连计划
UDP端IP地址和端口号需正常且有效,加了错误弹窗,若出现下图请重新输入:


3、三轴加速度显示
有硬件:成功毗连上之后需配合底层硬件,这里是吸收UDP发过来的3轴加速度值。
无硬件:假如没有硬件也行,自行找个网络调试助手,开个UDP服务,本机毗连就行,发送的数据需包含以下格式:
任意字符(:1.23938 mG)任意字符。
表明:
发送过来的数据必须包含在 :xxxx mG 内,冒号和mG不能少,可任意多组,每组代表一轴数据。

4、计步显示
利用三轴加速度提供的数据处置惩罚步数。需打开左下角计步控制按钮。
打开后弹出提示:


本计步算法仅支持手臂摆动的峰峰值计步,若有更好的算法请分享,万分感谢!!!
计步程序如下
  1. /*
  2. * valueNum - 存放三轴数据(x,y,z)的个数
  3. * tempValue - 用于存放计算阈值的波峰波谷差值的数组(在这个方法里存放值数组长度为5)
  4. * isDirectionUp - 是否上升的标志位
  5. * continueUpCount - 持续上升的次数
  6. * continueUpFormerCount - 上一点的持续上升的次数,为了记录波峰的上升次数
  7. * lastStatus - 上一点的状态,上升还是下降
  8. * peakOfWave - 波峰值
  9. * valleyOfWave - 波谷值
  10. * timeOfThisPeak - 此次波峰的时间
  11. * timeOfLastPeak - 上次波峰的时间
  12. * timeOfNow - 当前的时间
  13. * gravityOld - 上次传感器的值
  14. * initialValue - 动态阈值需要动态的数据,这个值用于这些动态数据的阈值,这个值是由大量数据得来的
  15. * ThreadValue - 初始阈值,这个值是由大量数据得来的
  16. * minValue - 初始最小值 计算出来的xyz数值乘重力加速度(9.8),此为手机拿在手里(不摆臂)(由自己多次测试得出的值)
  17. * maxValue - 初始最大值 自己设定的最大值(我们定位2)乘重力加速度(9.8),此为手机拿在手里(不摆臂)(由自己多次测试得出的值)
  18. * g - 重力加速度(9.8)
  19. * thisSteps 步数
  20. */
  21. private int valueNum = 5;
  22. //private double[] tempValue;
  23. private List<double> tempValue = new List<double>();
  24. private Boolean isDirectionUp = false;
  25. private int continueUpCount = 0;
  26. private int continueUpFormerCount = 0;
  27. private Boolean lastStatus = false;
  28. private double peakOfWave = 0;
  29. private double valleyOfWave = 0;
  30. private double timeOfThisPeak = 0;
  31. private double timeOfLastPeak = 0;
  32. private double timeOfNow = 0;
  33. private double gravityOld = 0;
  34. private double initialValue = 1.7;
  35. private double ThreadValue = 2.0;
  36. private double minValue = 11;
  37. private double maxValue = 19.6;
  38. private double g = 9.8;
  39. private double thisSteps = 0;   
  40. //当前步数
  41. private double StepsCopy = 0;   
  42. //步数复制
  43. /// <summary>
  44. /// 监测新的步数 如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
  45. /// 符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
  46. /// </summary>
  47. /// <param name="_values">加速传感器三轴的平均值</param>
  48. public void detectorNewStep(double _values)
  49. {
  50.     if (gravityOld == 0)
  51.     {
  52.         gravityOld = _values;
  53.     }
  54.     else
  55.     {
  56.         if (detectorPeak(_values, gravityOld))
  57.         {
  58.             timeOfLastPeak = timeOfThisPeak;
  59.             timeOfNow = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
  60.             //时间差大于200ms,小于2s
  61.             if (((timeOfNow - timeOfLastPeak) >= 200) && ((timeOfNow - timeOfLastPeak) <= 2000) && ((peakOfWave - valleyOfWave) >= ThreadValue))
  62.             {
  63.                 timeOfThisPeak = timeOfNow;
  64.                 //增加步数
  65.                 thisSteps++;
  66.                 //增加步数复制
  67.                 StepsCopy++;
  68.             }
  69.             if(((timeOfNow - timeOfLastPeak) >= 200) && ((peakOfWave - valleyOfWave) >= initialValue))
  70.             {
  71.                 timeOfThisPeak = timeOfNow;
  72.                 double _diffWaveVal = peakOfWave - valleyOfWave;
  73.                 ThreadValue = peak_Valley_Thread(_diffWaveVal);
  74.             }
  75.         }
  76.         gravityOld = _values;
  77.     }
  78. }
  79. /// <summary>
  80. /// 监测波峰
  81. /// 以下四个条件判断为波峰
  82. /// 1.目前点为下降的趋势:isDirectionUp为false
  83. /// 2.之前的点为上升的趋势:lastStatus为true
  84. /// 3.到波峰为止,持续上升大于等于2次
  85. /// 4.波峰值大于minValue,小于maxValue
  86. /// 记录波谷值
  87. /// 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
  88. /// 2.所以要记录每次的波谷值,为了和下次的波峰作对比
  89. /// </summary>
  90. /// <param name="_newValue"></param>
  91. /// <param name="_oldValue"></param>
  92. /// <returns></returns>
  93. public Boolean detectorPeak(double _newValue, double _oldValue)
  94. {
  95.     lastStatus = isDirectionUp;
  96.     if (_newValue >= _oldValue)
  97.     {
  98.         isDirectionUp = true;
  99.         continueUpCount++;
  100.     }
  101.     else
  102.     {
  103.         continueUpFormerCount = continueUpCount;
  104.         continueUpCount = 0;
  105.         isDirectionUp = false;
  106.     }
  107.     if (!isDirectionUp && lastStatus && (continueUpFormerCount >= 2 && (_oldValue >= minValue && _oldValue < maxValue)))
  108.     {
  109.         //满足上面波峰的四个条件,此时为波峰状态
  110.         peakOfWave = _oldValue;
  111.         return true;
  112.     }
  113.     else if (!lastStatus && isDirectionUp)
  114.     {
  115.         //满足波谷条件,此时为波谷状态
  116.         valleyOfWave = _oldValue;
  117.         return false;
  118.     }
  119.     else
  120.     {
  121.         return false;
  122.     }
  123. }
  124. /// <summary>
  125. /// 阈值的计算
  126. /// 1.通过波峰波谷的差值计算阈值
  127. /// 2.记录4个值,存入tempValue[] 数组中
  128. /// 3.在将数组传入函数averageValue中计算阈值
  129. /// </summary>
  130. /// <param name="_value"></param>
  131. /// <returns></returns>
  132. public double peak_Valley_Thread(double _value)
  133. {
  134.     double _tempThread = ThreadValue;
  135.     List<double> _tempValue = new List<double>(tempValue);
  136.     if (tempValue.Count < valueNum)
  137.     {
  138.         tempValue.Add(_value);
  139.     }
  140.     else
  141.     {
  142.         //tempValue数组长度=valueNum=5
  143.         _tempThread = averageValue(tempValue);
  144.         _tempValue.RemoveAt(0);
  145.         _tempValue.Add(_value);
  146.         tempValue = _tempValue;
  147.     }
  148.     return _tempThread;
  149. }
  150. /// <summary>
  151. /// 梯度化阈值
  152. /// 1.计算数组的均值
  153. /// 2.通过均值将阈值梯度化在一个范围里
  154. /// 这些数据是通过大量的统计得到的
  155. /// </summary>
  156. /// <param name="_value"></param>
  157. /// <returns></returns>
  158. public double averageValue(List<double> _value)
  159. {
  160.     if (_value.Count != 0)
  161.     {
  162.         double _ave = 0;
  163.         foreach (double i in _value)
  164.             _ave += i;
  165.         _ave = _ave / _value.Count;
  166.         if(_ave >= 8)
  167.         {
  168.             _ave = 4.3;
  169.         }
  170.         else if (_ave >= 7 && _ave < 8)
  171.         {
  172.             _ave = 3.3;
  173.         }
  174.         else if (_ave >= 4 && _ave < 7)
  175.         {
  176.             _ave = 2.3;
  177.         }
  178.         else if (_ave >= 3 && _ave < 4)
  179.         {
  180.             _ave = 2.0;
  181.         }
  182.         else
  183.         {
  184.             _ave = 1.7;
  185.         }
  186.         return _ave;
  187.     }
  188.     else
  189.     {
  190.         return 1.7;
  191.     }
  192. }
复制代码
计步效果如下所示:

开启步数控制按钮后总步数累加,进度条进度为50步,每到达50步距离弹出提示框,计步竣事也弹提示框通知。
5、倾力UI按钮计划
计划了一组拟物化按钮,目前无任何功能,有须要的小同伴自行更改计划功能。

项目地址

Gitee:https://gitee.com/tytokongjian/StepCountingUpperPC
总结

以上仅展示了蓝牙转WIFI计步上位机的部分功能。更多实用特性和详细信息,请大家访问项目地址。
希望通过本文能为上位机机开发方面提供有价值的参考。欢迎在评论区留言交流,分享您的宝贵经验和建议。
最后

假如你以为这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。假如有任何疑问或须要进一步的帮助,欢迎随时留言。
也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同发展!优秀是一种习惯,欢迎大家留言学习!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表