博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第六十四篇、OC_计步器
阅读量:6477 次
发布时间:2019-06-23

本文共 11779 字,大约阅读时间需要 39 分钟。

计步器的实现方式主要有那么两种

1.通过直接调用系统的健康数据,基于HealthKit框架的,但是貌似是一小时更新一次数据。如果要实时获取步数,这种方式并不是最佳。

2.基于CoreMotion框架,顾名思义就是加速计/加速度传感器

  》最早出现在iOS设备上的传感器之一

  》加速计用于检测设备在X、Y、Z轴上的加速度 (哪个方向有力的作用)

  》加速计可以用于检测设备的摇晃,经典应用场景(例如摇一摇、计步器等)

源码:

#import 
#import
@interface StepManager : NSObject@property (nonatomic) NSInteger step; // 运动步数(总计)+ (StepManager *)sharedManager;//开始计步- (void)startWithStep;//得到计步所消耗的卡路里//+ (NSInteger)getStepCalorie;////得到所走的路程(单位:米)//+ (CGFloat)getStepDistance;////得到运动所用的时间//+ (NSInteger)getStepTime;@end

 

#import "StepManager.h"#import "StepModel.h"#import 
// 计步器开始计步时间(秒)#define ACCELERO_START_TIME 2// 计步器开始计步步数(步)#define ACCELERO_START_STEP 100// 数据库存储步数采集间隔(步)#define DB_STEP_INTERVAL 1@interface StepManager (){ NSMutableArray *arrAll; // 加速度传感器采集的原始数组 int record_no_save; int record_no; NSDate *lastDate;}@property (nonatomic) NSInteger startStep; // 计步器开始步数@property (nonatomic, retain) NSMutableArray *arrSteps; // 步数数组@property (nonatomic, retain) NSMutableArray *arrStepsSave; // 数据库纪录步数数组@property (nonatomic) CGFloat gpsDistance; // GPS轨迹的移动距离(总计)@property (nonatomic) CGFloat agoGpsDistance; // GPS轨迹的移动距离(之前)@property (nonatomic) CGFloat agoActionDistance; // 实际运动的移动距离(之前)@property (nonatomic, retain) NSString *actionId; // 运动识别ID@property (nonatomic) CGFloat distance; // 运动里程(总计)@property (nonatomic) NSInteger calorie; // 消耗卡路里(总计)@property (nonatomic) NSInteger second; // 运动用时(总计)@end@implementation StepManagerstatic StepManager *sharedManager;static CMMotionManager *motionManager;+ (StepManager *)sharedManager{ @synchronized (self) { if (!sharedManager) { sharedManager = [[StepManager alloc]init]; motionManager = [[CMMotionManager alloc]init]; } } return sharedManager;}//开始计步- (void)startWithStep{ if (!motionManager.isAccelerometerAvailable) { NSLog(@"加速度传感器不可用"); return; }else { motionManager.accelerometerUpdateInterval = 1.0/40; } [self startAccelerometer];}- (void)startAccelerometer{ /* @try 。。。@catch 。。。 * @try 后面跟或许会出现异常的程序,代码块 * @catch 当@try抛出异常时 系统会进行异常捕捉 具体可以了解下 NSException 异常类 @catch 在这里处理 程序所抛出的异常 */ @try { //如果不支持陀螺仪,需要用加速传感器来采集数据 if (!motionManager.isAccelerometerActive) {
// isAccelerometerAvailable方法用来查看加速度器的状态:是否Active(启动)。 // 加速度传感器采集的原始数组 if (arrAll == nil) { arrAll = [[NSMutableArray alloc] init]; } else { [arrAll removeAllObjects]; } /* 1.push方式 这种方式,是实时获取到Accelerometer的数据,并且用相应的队列来显示。即主动获取加速计的数据。 */ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error){ if (!motionManager.isAccelerometerActive) { return; } //三个方向加速度值 double x = accelerometerData.acceleration.x; double y = accelerometerData.acceleration.y; double z = accelerometerData.acceleration.z; //g是一个double值 ,根据它的大小来判断是否计为1步. double g = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2)) - 1; //将信息保存在步数模型中 StepModel *stepsAll = [[StepModel alloc] init]; stepsAll.date = [NSDate date]; //日期 NSDateFormatter *df = [[NSDateFormatter alloc] init] ; df.dateFormat = @"yyyy-MM-dd HH:mm:ss"; NSString *strYmd = [df stringFromDate:stepsAll.date]; df = nil; stepsAll.record_time =strYmd; stepsAll.g = g; // 加速度传感器采集的原始数组 [arrAll addObject:stepsAll]; // 每采集10条,大约1.2秒的数据时,进行分析 if (arrAll.count == 10) { // 步数缓存数组 NSMutableArray *arrBuffer = [[NSMutableArray alloc] init]; arrBuffer = [arrAll copy]; [arrAll removeAllObjects]; // 踩点数组 NSMutableArray *arrCaiDian = [[NSMutableArray alloc] init]; //遍历步数缓存数组 for (int i = 1; i < arrBuffer.count - 2; i++) { //如果数组个数大于3,继续,否则跳出循环,用连续的三个点,要判断其振幅是否一样,如果一样,然并卵 if (![arrBuffer objectAtIndex:i-1] || ![arrBuffer objectAtIndex:i] || ![arrBuffer objectAtIndex:i+1]) { continue; } StepModel *bufferPrevious = (StepModel *)[arrBuffer objectAtIndex:i-1]; StepModel *bufferCurrent = (StepModel *)[arrBuffer objectAtIndex:i]; StepModel *bufferNext = (StepModel *)[arrBuffer objectAtIndex:i+1]; //控制震动幅度,,,,,,根据震动幅度让其加入踩点数组, if (bufferCurrent.g < -0.12 && bufferCurrent.g < bufferPrevious.g && bufferCurrent.g < bufferNext.g) { [arrCaiDian addObject:bufferCurrent]; } } //如果没有步数数组,初始化 if (nil == self.arrSteps) { self.arrSteps = [[NSMutableArray alloc] init]; self.arrStepsSave = [[NSMutableArray alloc] init]; } // 踩点过滤 for (int j = 0; j < arrCaiDian.count; j++) { StepModel *caidianCurrent = (StepModel *)[arrCaiDian objectAtIndex:j]; //如果之前的步数为0,则重新开始记录 if (self.arrSteps.count == 0) { //上次记录的时间 lastDate = caidianCurrent.date; // 重新开始时,纪录No初始化 record_no = 1; record_no_save = 1; // 运动识别号 NSTimeInterval interval = [caidianCurrent.date timeIntervalSince1970]; NSNumber *numInter = [[NSNumber alloc] initWithDouble:interval*1000]; long long llInter = numInter.longLongValue; //运动识别id self.actionId = [NSString stringWithFormat:@"%lld",llInter]; self.distance = 0.00f; self.second = 0; self.calorie = 0; self.step = 0; self.gpsDistance = 0.00f; self.agoGpsDistance = 0.00f; self.agoActionDistance = 0.00f; caidianCurrent.record_no = record_no; caidianCurrent.step = (int)self.step; [self.arrSteps addObject:caidianCurrent]; [self.arrStepsSave addObject:caidianCurrent]; } else { int intervalCaidian = [caidianCurrent.date timeIntervalSinceDate:lastDate] * 1000; // 步行最大每秒2.5步,跑步最大每秒3.5步,超过此范围,数据有可能丢失 int min = 259; if (intervalCaidian >= min) { if (motionManager.isAccelerometerActive) { //存一下时间 lastDate = caidianCurrent.date; if (intervalCaidian >= ACCELERO_START_TIME * 1000) {
// 计步器开始计步时间(秒) self.startStep = 0; } if (self.startStep < ACCELERO_START_STEP) {
//计步器开始计步步数 (步) self.startStep ++; break; } else if (self.startStep == ACCELERO_START_STEP) { self.startStep ++; // 计步器开始步数 // 运动步数(总计) self.step = self.step + self.startStep; } else { self.step ++; } //步数在这里 NSLog(@"步数%ld",self.step); int intervalMillSecond = [caidianCurrent.date timeIntervalSinceDate:[[self.arrSteps lastObject] date]] * 1000; if (intervalMillSecond >= 1000) { record_no++; caidianCurrent.record_no = record_no; caidianCurrent.step = (int)self.step; [self.arrSteps addObject:caidianCurrent]; } // 每隔100步保存一条数据(将来插入DB用) StepModel *arrStepsSaveVHSSteps = (StepModel *)[self.arrStepsSave lastObject]; int intervalStep = caidianCurrent.step - arrStepsSaveVHSSteps.step; // DB_STEP_INTERVAL 数据库存储步数采集间隔(步) 100步 if (self.arrStepsSave.count == 1 || intervalStep >= DB_STEP_INTERVAL) { //保存次数 record_no_save++; caidianCurrent.record_no = record_no_save; [self.arrStepsSave addObject:caidianCurrent]; NSLog(@"---***%ld",self.step); // 备份当前运动数据至文件中,以备APP异常退出时数据也不会丢失 // [self bkRunningData]; } } } // 运动提醒检查 // [self checkActionAlarm]; } } } }]; } }@catch (NSException * e) { NSLog(@"Exception: %@", e); return; }}////得到计步所消耗的卡路里//+ (NSInteger)getStepCalorie//{// 在这里原谅我并没有对其实现。本以为卡路里和步数的换算单位,一个公式就可以了。不查不知道,一查吓一跳原来还和其他众多因素有关:走路的快慢,步子的大小,体重的大小等等有关。。。笔者已吓尿,还是找算法大牛吧。//}//////得到所走的路程(单位:米)//+ (CGFloat)getStepDistance//{// //}//////得到运动所用的时间//+ (NSInteger)getStepTime//{// //}

 

外部使用方式:

#import "ViewController.h"#import "StepManager.h"@interface ViewController (){    NSTimer *_timer;    UILabel *lable;}@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];      [[StepManager sharedManager] startWithStep];      lable =[[ UILabel alloc]initWithFrame:CGRectMake(100, 300, 300, 40)];    [self.view addSubview:lable];    _timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(getStepNumber) userInfo:nil repeats:YES];    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];}- (void)getStepNumber{    lable.text = [NSString stringWithFormat:@"我走了  %ld步",[StepManager sharedManager].step];}

 

当然还有特别注意,应用程序在后台也要做采集动作:

- (void)applicationDidEnterBackground:(UIApplication *)application {    //播放一段无声音乐,使其可以一直在后台进行计步  此方法为第三方 若要详细了解,请下载demo自行研究    [[MMPDeepSleepPreventer sharedSingleton] startPreventSleep];}

 

转载于:https://www.cnblogs.com/HJQ2016/p/5971854.html

你可能感兴趣的文章
installshield12如何改变默认安装目录
查看>>
少用数字来作为参数标识含义
查看>>
ScrollView中嵌套ListView
查看>>
JAVA虚拟机05--面试必问之JVM原理
查看>>
Algs4-2.3.1如何切分数组
查看>>
观察者模式
查看>>
在properties.xml中定义变量,在application.xml中取值问题
查看>>
js 数组
查看>>
Linux scp命令详解
查看>>
struct和typedef struct
查看>>
cell reuse & disposebag
查看>>
【故障处理】ORA-12545: Connect failed because target host or object does not exist
查看>>
云时代,程序员将面临的分化
查看>>
js判断移动端是否安装某款app的多种方法
查看>>
学习angularjs的内置API函数
查看>>
4、输出名称 Exported names
查看>>
paste工具
查看>>
Pre-echo(预回声),瞬态信号检测与TNS
查看>>
【转载】如何发送和接收 Windows Phone 的 Raw 通知
查看>>
poj2378
查看>>