let assign = function (target, ...varArgs) { if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } if (!varArgs || varArgs.length <= 0) { return target; } // 深度合并对象 function deepAssign(obj1, obj2) { for (let key in obj2) { obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ? deepAssign(obj1[key], obj2[key]) : obj1[key] = obj2[key]; } return obj1; } varArgs.forEach(val => { target = deepAssign(target, val); }); return target; }; function Event() { this.events = {}; } Event.prototype.addEventListener = function (type, listener) { this.events[type] = this.events[type] || []; this.events[type].push(listener); }; Event.prototype.trigger = function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var type = args[0]; var params = args.slice(1); if (!!this.events[type]) { // console.log("type:",type); this.events[type].forEach(function (listener) { try { listener.apply(null, params); } catch (e) { console.error(e); } }); } }; var EquipmentAction = function EquipmentAction() { let opts = { //合力计算 oldResultantDifference: 0, resultantDifference: 0, bCalResultant: false, //最大的差值 resultantMaxDifference: 0, //最大的加速度 resultantMaxX: 0, resultantMaxZ: 0, resultantMaxY: 0, resultantMaxAddCount: 0, resultAddDifferenceCount: 0, xA: 0, oldxA: 0, zA: 0, oldzA: 0, yA: 0, oldyA: 0, //初始化 initX: false, initZ: false, initY: false, mass: 5, //是否限制回弹,true 是限制回弹,false 是快速打击 bLimitRebound: true } this.opts = opts; let runOpts = { ValueNum: 4, tempValue: [], //用于存放计算阈值的波峰波谷差值 tempCount: 0, //是否上升的标志位 isDirectionUp: false, //持续上升次数 continueUpCount: 0, //上一点的持续上升的次数,为了记录波峰的上升次数 continueUpFormerCount: 0, //上一点的状态,上升还是下降 lastStatus: false, //波峰值 peakOfWave: 0, //波谷值 valleyOfWave: 0, //此次波峰的时间 timeOfThisPeak: 0, //上次波峰的时间 timeOfLastPeak: 0, //当前的时间 timeOfNow: 0, //当前传感器的值 gravityNew: 0, //上次传感器的值 gravityOld: 0, //上传传感器的陀螺仪 gyroOld: 0, //动态阈值需要动态的数据,这个值用于这些动态数据的阈值 InitialValue: 1.3, //初始阈值 ThreadValue: 2.0, //波峰波谷时间差 TimeInterval: 250, //跳高 jumpStepCount: 0, jumpTimeOfLastStep: 0, jumpTimeOfThisStep: 0, jumpAverageTimeOfEveryStep: 0, //跑步 stepCount: 0, timeOfLastStep: 0, timeOfThisStep: 0, averageTimeOfEveryStep: 0, currentState: "idle" } this.runOpts = runOpts; let gyroOpts = { ValueNum: 4, tempValue: [], //用于存放计算阈值的波峰波谷差值 tempCount: 0, //是否上升的标志位 isDirectionUp: false, //持续上升次数 continueUpCount: 0, //上一点的持续上升的次数,为了记录波峰的上升次数 continueUpFormerCount: 0, //上一点的状态,上升还是下降 lastStatus: false, //波峰值 peakOfWave: 0, //波谷值 valleyOfWave: 0, //此次波峰的时间 timeOfThisPeak: 0, //上次波峰的时间 timeOfLastPeak: 0, //当前的时间 timeOfNow: 0, //当前传感器的值 gravityNew: 0, //上次传感器的值 gravityOld: 0, //动态阈值需要动态的数据,这个值用于这些动态数据的阈值 InitialValue: 1.3, //初始阈值 ThreadValue: 200.0, //波峰波谷时间差 TimeInterval: 250, bJump: false, } this.gyroOpts = gyroOpts; this.event = new Event(); // console.log("hit instanl:",this.opts); } EquipmentAction.prototype.addEventListener = function (type, listener) { this.event.addEventListener(type, listener); }; /** * 更新两轴数据 */ EquipmentAction.prototype.updateAcc = function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // this.opts = assign({}, this.opts, data); let bLimitRebound = data.bLimitRebound && this.opts.bLimitRebound; //使用两个轴的数据,其实就是不计算重力轴的加速度 this.opts.xA = data.xA; this.opts.zA = data.zA; // console.log(bLimitRebound,data.bLimitRebound,this.opts.bLimitRebound); //这里防止第一次触发调用 if (!this.opts.initX && this.opts.oldxA === 0) { this.opts.oldxA = data.xA; this.opts.initX = true; console.log("初始化oldxa"); } if (!this.opts.initZ && this.opts.oldzA === 0) { this.opts.oldzA = data.zA; this.opts.initZ = true; console.log("初始化oldza"); } let _differenceX = this.opts.xA - this.opts.oldxA; let _differenceZ = this.opts.zA - this.opts.oldzA; this.opts.resultantDifference = Math.abs(_differenceX) + Math.abs(_differenceZ); if (this.opts.oldResultantDifference != this.opts.resultantDifference && 0 !== this.opts.resultantDifference) { //5 默认值是12 let _limitresultDifference = 12; //如果是回弹限制时候,判断值等于5 if (bLimitRebound) _limitresultDifference = 5; if (this.opts.resultantDifference > _limitresultDifference) { if (!this.opts.bCalResultant) { //假如进入了一个计算周期 this.opts.bCalResultant = true; } } if (this.opts.bCalResultant) { if (this.opts.resultantMaxX <= this.opts.xA) this.opts.resultantMaxX = this.opts.xA; if (this.opts.resultantMaxZ <= this.opts.zA) this.opts.resultantMaxZ = this.opts.zA; if (this.opts.resultantMaxDifference <= this.opts.resultantDifference) { this.opts.resultantMaxDifference = this.opts.resultantDifference; this.opts.resultantMaxAddCount = 0; } else { this.opts.resultantMaxAddCount++; //小于最大值的个数判断,超过限制,说明波动下滑 // > 4 if (this.opts.resultantMaxAddCount >= 4) { //这里区分两个版本,bLimitRebound:true一个是限制回弹版,bLimitRebound:false一个是快速打击版本 if (bLimitRebound) { if (this.opts.resultantDifference <= 3) { this.opts.resultAddDifferenceCount++; // 当波动值小于3 次数到达5次,判断达到一个平稳状态 if (this.opts.resultAddDifferenceCount >= 5) { let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ); this.opts.bCalResultant = false; this.opts.resultantMaxAddCount = 0; this.opts.resultAddDifferenceCount = 0; //成功判断打击直拳 todo return this.event.trigger('resultantHit', { type: "hit", acc: _resultantMaxAcc, power: Math.ceil(_resultantMaxAcc * this.opts.mass), mass: this.opts.mass }); this.opts.oldResultantDifference = 0; this.opts.resultantDifference = 0; this.opts.resultantMaxDifference = 0; this.opts.resultantMaxX = 0; this.opts.resultantMaxZ = 0; // this.opts.oldxA = 0; // this.opts.oldzA = 0; } } else { this.opts.resultAddDifferenceCount = 0; } } else { let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ); this.opts.bCalResultant = false; this.opts.resultantMaxAddCount = 0; this.opts.resultAddDifferenceCount = 0; //成功判断打击直拳 todo return this.event.trigger('resultantHit', { type: "hit", acc: _resultantMaxAcc, power: Math.ceil(_resultantMaxAcc * this.opts.mass), mass: this.opts.mass }); this.opts.oldResultantDifference = 0; this.opts.resultantDifference = 0; this.opts.resultantMaxDifference = 0; this.opts.resultantMaxX = 0; this.opts.resultantMaxZ = 0; // this.opts.oldxA = 0; // this.opts.oldzA = 0; } } } } this.opts.oldResultantDifference = this.opts.resultantDifference; } this.opts.oldxA = this.opts.xA; this.opts.oldzA = this.opts.zA; }; /** * 更新三轴数据 */ EquipmentAction.prototype.updateTriaxialAcc = function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // this.opts = assign({}, this.opts, data); let bLimitRebound = data.bLimitRebound && this.opts.bLimitRebound; //使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值 this.opts.xA = data.xA; this.opts.zA = data.zA; this.opts.yA = data.yA; // console.log(bLimitRebound,data.bLimitRebound,this.opts.bLimitRebound); //这里防止第一次触发调用 if (!this.opts.initX && this.opts.oldxA === 0) { this.opts.oldxA = data.xA; this.opts.initX = true; console.log("初始化oldxa"); } if (!this.opts.initZ && this.opts.oldzA === 0) { this.opts.oldzA = data.zA; this.opts.initZ = true; console.log("初始化oldza"); } if (!this.opts.initY && this.opts.oldyA === 0) { this.opts.oldyA = data.yA; this.opts.initY = true; console.log("初始化oldyA"); } let _differenceX = this.opts.xA - this.opts.oldxA; let _differenceZ = this.opts.zA - this.opts.oldzA; let _differenceY = this.opts.yA - this.opts.oldyA; // let gravityNew = Math.sqrt(xA * xA + yA * yA + zA * zA); // this.opts.resultantDifference = Math.abs(_differenceX) + Math.abs(_differenceZ) + Math.abs(_differenceY); this.opts.resultantDifference = Math.sqrt(_differenceX * _differenceX + _differenceZ * _differenceZ + _differenceY * _differenceY); if (this.opts.oldResultantDifference != this.opts.resultantDifference && 0 !== this.opts.resultantDifference) { //5 默认值是12 let _limitresultDifference = 12; //如果是回弹限制时候,判断值等于5 if (bLimitRebound) _limitresultDifference = 5; if (this.opts.resultantDifference > _limitresultDifference) { if (!this.opts.bCalResultant) { //假如进入了一个计算周期 this.opts.bCalResultant = true; } } if (this.opts.bCalResultant) { if (this.opts.resultantMaxDifference <= this.opts.resultantDifference) { this.opts.resultantMaxDifference = this.opts.resultantDifference; this.opts.resultantMaxAddCount = 0; } else { this.opts.resultantMaxAddCount++; //小于最大值的个数判断,超过限制,说明波动下滑 // > 4 if (this.opts.resultantMaxAddCount >= 4) { //这里区分两个版本,bLimitRebound:true一个是限制回弹版,bLimitRebound:false一个是快速打击版本 if (bLimitRebound) { if (this.opts.resultantDifference <= 3) { this.opts.resultAddDifferenceCount++; // 当波动值小于3 次数到达5次,判断达到一个平稳状态 if (this.opts.resultAddDifferenceCount >= 5) { // let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ) + Math.abs(this.opts.resultantMaxY); // console.log("this.opts.resultantMaxDifference:",this.opts.resultantMaxDifference); this.opts.bCalResultant = false; this.opts.resultantMaxAddCount = 0; this.opts.resultAddDifferenceCount = 0; //成功判断打击直拳 todo return this.event.trigger('resultantHit', { type: "hit", acc: this.opts.resultantMaxDifference, power: Math.ceil(this.opts.resultantMaxDifference * this.opts.mass), mass: this.opts.mass }); this.opts.oldResultantDifference = 0; this.opts.resultantDifference = 0; this.opts.resultantMaxDifference = 0; this.opts.resultantMaxX = 0; this.opts.resultantMaxZ = 0; this.opts.resultantMaxY = 0; } } else { this.opts.resultAddDifferenceCount = 0; } } else { this.opts.bCalResultant = false; this.opts.resultantMaxAddCount = 0; this.opts.resultAddDifferenceCount = 0; //成功判断打击直拳 todo return this.event.trigger('resultantHit', { type: "hit", acc: this.opts.resultantMaxDifference, power: Math.ceil(this.opts.resultantMaxDifference * this.opts.mass), mass: this.opts.mass }); this.opts.oldResultantDifference = 0; this.opts.resultantDifference = 0; this.opts.resultantMaxDifference = 0; this.opts.resultantMaxX = 0; this.opts.resultantMaxZ = 0; this.opts.resultantMaxY = 0; } } } } this.opts.oldResultantDifference = this.opts.resultantDifference; } this.opts.oldxA = this.opts.xA; this.opts.oldzA = this.opts.zA; this.opts.oldyA = this.opts.yA; }; EquipmentAction.prototype.updateJumpAndRun = function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; //使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值 //********加速计******** let { ax, ay, az } = data.acc; ax = ax * 9.80665; ay = ay * 9.80665; az = az * 9.80665; let gravityNew = Math.sqrt(ax * ax + ay * ay + az * az); let { gx, gy, gz } = data.gyro; let gyroNew = Math.sqrt(gx * gx + gy * gy + gz * gz); this.detectorNewStep(gravityNew, gyroNew); }; /* * 检测步子,并开始计步 * 1.传入数据 * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步 * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中 * */ EquipmentAction.prototype.detectorNewStep = function (values, gyroValue) { if (this.gyroOpts.gravityOld == 0) { this.gyroOpts.gravityOld = gyroValue; } else { if (this.gyroDetectorPeak(gyroValue, this.gyroOpts.gravityOld)) { let step1 = this.gyroOpts.peakOfWave - this.gyroOpts.valleyOfWave; // if(step>10) // console.log("Gyro:", step); if (step1 > this.gyroOpts.ThreadValue) { this.gyroOpts.timeOfThisPeak = this.gyroOpts.timeOfNow; this.gyroOpts.bJump = true; } } } if (this.runOpts.gravityOld == 0) { this.runOpts.gravityOld = values; } else { if (this.detectorPeak(values, this.runOpts.gravityOld)) { this.runOpts.timeOfLastPeak = this.runOpts.timeOfThisPeak; this.runOpts.timeOfNow = new Date().getTime(); let step2 = this.runOpts.peakOfWave - this.runOpts.valleyOfWave; if (this.runOpts.timeOfNow - this.runOpts.timeOfLastPeak >= this.runOpts.TimeInterval && step2 > this.runOpts.ThreadValue) { this.runOpts.timeOfThisPeak = this.runOpts.timeOfNow; this.countRunStep(); } // if (this.runOpts.timeOfNow - this.runOpts.timeOfLastPeak >= this.runOpts.TimeInterval // && (this.runOpts.peakOfWave - this.runOpts.valleyOfWave >= this.runOpts.InitialValue)) { // this.runOpts.timeOfThisPeak = this.runOpts.timeOfNow; // this.runOpts.ThreadValue = this.peakValleyThread(this.runOpts.peakOfWave - this.runOpts.valleyOfWave); // } } } this.runOpts.gravityOld = values; this.gyroOpts.gravityOld = gyroValue; } EquipmentAction.prototype.countRunStep = function () { this.runOpts.timeOfLastStep = this.runOpts.timeOfThisStep; this.runOpts.timeOfThisStep = new Date().getTime(); let diffValue = this.runOpts.timeOfThisStep - this.runOpts.timeOfLastStep; if (diffValue <= 2000) { if (this.gyroOpts.bJump) { let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave; this.event.trigger('resultant', { type: "jump", acc: step }); this.resetJumpValue(); // this.resSomeValue(); } // else // { this.runOpts.averageTimeOfEveryStep += diffValue; this.runOpts.stepCount++; // if (this.runOpts.stepCount == 2) { this.runOpts.averageTimeOfEveryStep = this.runOpts.averageTimeOfEveryStep / 2; // this.runOpts.currentState = "runing"; let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave; this.resSomeValue(); this.event.trigger('resultant', { type: "runing", acc: step }); } // } } else { //超时,说明没有运动了 this.resSomeValue(); console.log("超时", "averageTimeOfEveryStep: " + this.runOpts.averageTimeOfEveryStep); if (this.gyroOpts.bJump) { //判断是否跳 let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave; this.event.trigger('resultant', { type: "jump", acc: step }); this.resetJumpValue(); } } } EquipmentAction.prototype.resSomeValue = function () { this.runOpts.stepCount = 0; this.runOpts.averageTimeOfEveryStep = 0; } EquipmentAction.prototype.resetJumpValue = function () { // this.runOpts.jumpStepCount = 0; // this.runOpts.jumpAverageTimeOfEveryStep = 0; this.gyroOpts.bJump = false; } /* * 检测波峰 * 以下四个条件判断为波峰: * 1.目前点为下降的趋势:isDirectionUp为false * 2.之前的点为上升的趋势:lastStatus为true * 3.到波峰为止,持续上升大于等于2次 * 4.波峰值大于20 * 记录波谷值 * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值 * 2.所以要记录每次的波谷值,为了和下次的波峰做对比 * */ EquipmentAction.prototype.detectorPeak = function (newValue, oldValue) { this.runOpts.lastStatus = this.runOpts.isDirectionUp; if (newValue >= oldValue) { this.runOpts.isDirectionUp = true; this.runOpts.continueUpCount++; } else { this.runOpts.continueUpFormerCount = this.runOpts.continueUpCount; this.runOpts.continueUpCount = 0; this.runOpts.isDirectionUp = false; } //this.runOpts.continueUpFormerCount >= 2 || oldValue >= 20 if (!this.runOpts.isDirectionUp && this.runOpts.lastStatus && (this.runOpts.continueUpFormerCount >= 2)) { this.runOpts.peakOfWave = oldValue; return true; } else if (!this.runOpts.lastStatus && this.runOpts.isDirectionUp) { this.runOpts.valleyOfWave = oldValue; return false; } else { return false; } } /* * 检测波峰 * 以下四个条件判断为波峰: * 1.目前点为下降的趋势:isDirectionUp为false * 2.之前的点为上升的趋势:lastStatus为true * 3.到波峰为止,持续上升大于等于2次 * 4.波峰值大于20 * 记录波谷值 * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值 * 2.所以要记录每次的波谷值,为了和下次的波峰做对比 * */ EquipmentAction.prototype.gyroDetectorPeak = function (newValue, oldValue) { this.gyroOpts.lastStatus = this.gyroOpts.isDirectionUp; if (newValue >= oldValue) { this.gyroOpts.isDirectionUp = true; this.gyroOpts.continueUpCount++; } else { this.gyroOpts.continueUpFormerCount = this.gyroOpts.continueUpCount; this.gyroOpts.continueUpCount = 0; this.gyroOpts.isDirectionUp = false; } //this.runOpts.continueUpFormerCount >= 2 || oldValue >= 20 if (!this.gyroOpts.isDirectionUp && this.gyroOpts.lastStatus && (this.gyroOpts.continueUpFormerCount >= 2)) { this.gyroOpts.peakOfWave = oldValue; return true; } else if (!this.gyroOpts.lastStatus && this.gyroOpts.isDirectionUp) { this.gyroOpts.valleyOfWave = oldValue; return false; } else { return false; } } /* * 阈值的计算 * 1.通过波峰波谷的差值计算阈值 * 2.记录4个值,存入tempValue[]数组中 * 3.在将数组传入函数averageValue中计算阈值 * */ EquipmentAction.prototype.peakValleyThread = function (value) { let tempThread = this.runOpts.ThreadValue; if (this.runOpts.tempCount < this.runOpts.ValueNum) { this.runOpts.tempValue[this.runOpts.tempCount] = value; this.runOpts.tempCount++; } else { tempThread = this.averageValue(this.runOpts.tempValue, this.runOpts.ValueNum); for (let i = 1; i < this.runOpts.ValueNum; i++) { this.runOpts.tempValue[i - 1] = this.runOpts.tempValue[i]; } this.runOpts.tempValue[this.runOpts.ValueNum - 1] = value; } return tempThread; } /* * 梯度化阈值 * 1.计算数组的均值 * 2.通过均值将阈值梯度化在一个范围里 * */ EquipmentAction.prototype.averageValue = function (value, n) { let ave = 0; for (let i = 0; i < n; i++) { ave += value[i]; } ave = ave / this.runOpts.ValueNum; // console.log("ave:", ave); 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.3; } return ave; } if (typeof module === "object" && typeof module.exports === "object") { module.exports = EquipmentAction; //export default EquipmentAction;//建议使用nodejs的module导出方式,如报错请使用export方式导出 }