C#+ WPF 实现蓝牙转WIFI计步上位机
前言
一个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、计步显示
利用三轴加速度提供的数据处理步数。需打开左下角计步控制按钮。
打开后弹出提示:
本计步算法仅支持手臂摆动的峰峰值计步,若有更好的算法请分享,万分感谢!!!
计步程序如下
/** valueNum - 存放三轴数据(x,y,z)的个数
* tempValue - 用于存放计算阈值的波峰波谷差值的数组(在这个方法里存放值数组长度为5)
* isDirectionUp - 是否上升的标志位
* continueUpCount - 持续上升的次数
* continueUpFormerCount - 上一点的持续上升的次数,为了记录波峰的上升次数
* lastStatus - 上一点的状态,上升还是下降
* peakOfWave - 波峰值
* valleyOfWave - 波谷值
* timeOfThisPeak - 此次波峰的时间
* timeOfLastPeak - 上次波峰的时间
* timeOfNow - 当前的时间
* gravityOld - 上次传感器的值
* initialValue - 动态阈值需要动态的数据,这个值用于这些动态数据的阈值,这个值是由大量数据得来的
* ThreadValue - 初始阈值,这个值是由大量数据得来的
* minValue - 初始最小值 计算出来的xyz数值乘重力加速度(9.8),此为手机拿在手里(不摆臂)(由自己多次测试得出的值)
* maxValue - 初始最大值 自己设定的最大值(我们定位2)乘重力加速度(9.8),此为手机拿在手里(不摆臂)(由自己多次测试得出的值)
* g - 重力加速度(9.8)
* thisSteps 步数*/ private int valueNum = 5;//private double[] tempValue; private List<double> tempValue = new List<double>();private Boolean isDirectionUp = false;private int continueUpCount = 0;private int continueUpFormerCount = 0;private Boolean lastStatus = false;private double peakOfWave = 0;private double valleyOfWave = 0;private double timeOfThisPeak = 0;private double timeOfLastPeak = 0;private double timeOfNow = 0;private double gravityOld = 0;private double initialValue = 1.7;private double ThreadValue = 2.0;private double minValue = 11;private double maxValue = 19.6;private double g = 9.8;private double thisSteps = 0;//当前步数 private double StepsCopy = 0;//步数复制 /// <summary> ///监测新的步数 如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步///符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中/// </summary> /// <param name="_values">加速传感器三轴的平均值</param> public void detectorNewStep(double_values)
{if (gravityOld == 0)
{
gravityOld=_values;
}else{if(detectorPeak(_values, gravityOld))
{
timeOfLastPeak=timeOfThisPeak;
timeOfNow= Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);//时间差大于200ms,小于2s if (((timeOfNow - timeOfLastPeak) >= 200) && ((timeOfNow - timeOfLastPeak) <= 2000) && ((peakOfWave - valleyOfWave) >=ThreadValue))
{
timeOfThisPeak=timeOfNow;//增加步数 thisSteps++;//增加步数复制 StepsCopy++;
}if(((timeOfNow - timeOfLastPeak) >= 200) && ((peakOfWave - valleyOfWave) >=initialValue))
{
timeOfThisPeak=timeOfNow;double _diffWaveVal = peakOfWave -valleyOfWave;
ThreadValue=peak_Valley_Thread(_diffWaveVal);
}
}
gravityOld=_values;
}
}/// <summary> ///监测波峰///以下四个条件判断为波峰///1.目前点为下降的趋势:isDirectionUp为false///2.之前的点为上升的趋势:lastStatus为true///3.到波峰为止,持续上升大于等于2次///4.波峰值大于minValue,小于maxValue///记录波谷值///1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值///2.所以要记录每次的波谷值,为了和下次的波峰作对比/// </summary> /// <param name="_newValue"></param> /// <param name="_oldValue"></param> /// <returns></returns> public Boolean detectorPeak(double _newValue, double_oldValue)
{
lastStatus=isDirectionUp;if (_newValue >=_oldValue)
{
isDirectionUp= true;
continueUpCount++;
}else{
continueUpFormerCount=continueUpCount;
continueUpCount= 0;
isDirectionUp= false;
}if (!isDirectionUp && lastStatus && (continueUpFormerCount >= 2 && (_oldValue >= minValue && _oldValue <maxValue)))
{//满足上面波峰的四个条件,此时为波峰状态 peakOfWave =_oldValue;return true;
}else if (!lastStatus &&isDirectionUp)
{//满足波谷条件,此时为波谷状态 valleyOfWave =_oldValue;return false;
}else{return false;
}
}/// <summary> ///阈值的计算///1.通过波峰波谷的差值计算阈值///2.记录4个值,存入tempValue[] 数组中///3.在将数组传入函数averageValue中计算阈值/// </summary> /// <param name="_value"></param> /// <returns></returns> public double peak_Valley_Thread(double_value)
{double _tempThread =ThreadValue;
List<double> _tempValue = new List<double>(tempValue);if (tempValue.Count <valueNum)
{
tempValue.Add(_value);
}else{//tempValue数组长度=valueNum=5 _tempThread =averageValue(tempValue);
_tempValue.RemoveAt(0);
_tempValue.Add(_value);
tempValue=_tempValue;
}return_tempThread;
}/// <summary> ///梯度化阈值///1.计算数组的均值///2.通过均值将阈值梯度化在一个范围里///这些数据是通过大量的统计得到的/// </summary> /// <param name="_value"></param> /// <returns></returns> public double averageValue(List<double>_value)
{if (_value.Count != 0)
{double _ave = 0;foreach (double i in_value)
_ave+=i;
_ave= _ave /_value.Count;if(_ave >= 8)
{
_ave= 4.3;
}else if (_ave >= 7 && _ave < 8)
{
_ave= 3.3;
}else if (_ave >= 4 && _ave < 7)
{
_ave= 2.3;
}else if (_ave >= 3 && _ave < 4)
{
_ave= 2.0;
}else{
_ave= 1.7;
}return_ave;
}else{return 1.7;
}
}
计步效果如下所示:
开启步数控制按钮后总步数累加,进度条进度为50步,每到达50步距离弹出提示框,计步结束也弹提示框通知。
5、倾力UI按钮设计
设计了一组拟物化按钮,目前无任何功能,有需要的小伙伴自行更改设计功能。
项目地址
Gitee:
https://gitee.com/tytokongjian/StepCountingUpperPC
总结
以上仅展示了蓝牙转WIFI计步上位机的部分功能。更多实用特性和详细信息,请大家访问项目地址。
希望通过本文能为上位机机开发方面提供有价值的参考。欢迎在评论区留言交流,分享您的宝贵经验和建议。
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号
[DotNet技术匠]
社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!