-
-
Notifications
You must be signed in to change notification settings - Fork 984
/
Copy pathMotionController.cpp
165 lines (137 loc) · 5.09 KB
/
MotionController.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "components/motion/MotionController.h"
#include <task.h>
#include "utility/Math.h"
using namespace Pinetime::Controllers;
namespace {
constexpr inline int32_t Clamp(int32_t val, int32_t min, int32_t max) {
return val < min ? min : (val > max ? max : val);
}
// only returns meaningful values if inputs are acceleration due to gravity
int16_t DegreesRolled(int16_t y, int16_t z, int16_t prevY, int16_t prevZ) {
int16_t prevYAngle = Pinetime::Utility::Asin(Clamp(prevY * 32, -32767, 32767));
int16_t yAngle = Pinetime::Utility::Asin(Clamp(y * 32, -32767, 32767));
if (z < 0 && prevZ < 0) {
return yAngle - prevYAngle;
}
if (prevZ < 0) {
if (y < 0) {
return -prevYAngle - yAngle - 180;
}
return -prevYAngle - yAngle + 180;
}
if (z < 0) {
if (y < 0) {
return prevYAngle + yAngle + 180;
}
return prevYAngle + yAngle - 180;
}
return prevYAngle - yAngle;
}
}
void MotionController::AdvanceDay() {
--nbSteps; // Higher index = further in the past
NbStepsRef(Days::Today) = 0;
if (service != nullptr) {
service->OnNewStepCountValue(NbSteps(Days::Today));
}
}
void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) {
uint32_t& oldSteps = NbStepsRef(Days::Today);
if (oldSteps != nbSteps && service != nullptr) {
service->OnNewStepCountValue(nbSteps);
}
if (service != nullptr && (xHistory[0] != x || yHistory[0] != y || zHistory[0] != z)) {
service->OnNewMotionValues(x, y, z);
}
lastTime = time;
time = xTaskGetTickCount();
xHistory++;
xHistory[0] = x;
yHistory++;
yHistory[0] = y;
zHistory++;
zHistory[0] = z;
stats = GetAccelStats();
int32_t deltaSteps = nbSteps - oldSteps;
if (deltaSteps > 0) {
currentTripSteps += deltaSteps;
}
oldSteps = nbSteps;
}
MotionController::AccelStats MotionController::GetAccelStats() const {
AccelStats stats;
for (uint8_t i = 0; i < AccelStats::numHistory; i++) {
stats.xMean += xHistory[histSize - i];
stats.yMean += yHistory[histSize - i];
stats.zMean += zHistory[histSize - i];
stats.prevXMean += xHistory[1 + i];
stats.prevYMean += yHistory[1 + i];
stats.prevZMean += zHistory[1 + i];
}
stats.xMean /= AccelStats::numHistory;
stats.yMean /= AccelStats::numHistory;
stats.zMean /= AccelStats::numHistory;
stats.prevXMean /= AccelStats::numHistory;
stats.prevYMean /= AccelStats::numHistory;
stats.prevZMean /= AccelStats::numHistory;
for (uint8_t i = 0; i < AccelStats::numHistory; i++) {
stats.xVariance += (xHistory[histSize - i] - stats.xMean) * (xHistory[histSize - i] - stats.xMean);
stats.yVariance += (yHistory[histSize - i] - stats.yMean) * (yHistory[histSize - i] - stats.yMean);
stats.zVariance += (zHistory[histSize - i] - stats.zMean) * (zHistory[histSize - i] - stats.zMean);
}
stats.xVariance /= AccelStats::numHistory;
stats.yVariance /= AccelStats::numHistory;
stats.zVariance /= AccelStats::numHistory;
return stats;
}
bool MotionController::ShouldRaiseWake() const {
constexpr uint32_t varianceThresh = 56 * 56;
constexpr int16_t xThresh = 384;
constexpr int16_t yThresh = -64;
constexpr int16_t rollDegreesThresh = -45;
if (std::abs(stats.xMean) > xThresh) {
return false;
}
// if the variance is below the threshold, the accelerometer values can be considered to be from acceleration due to gravity
if (stats.yVariance > varianceThresh || (stats.yMean < -724 && stats.zVariance > varianceThresh) || stats.yMean > yThresh) {
return false;
}
return DegreesRolled(stats.yMean, stats.zMean, stats.prevYMean, stats.prevZMean) < rollDegreesThresh;
}
bool MotionController::ShouldShakeWake(uint16_t thresh) {
/* Currently Polling at 10hz, If this ever goes faster scalar and EMA might need adjusting */
int32_t speed = std::abs(zHistory[0] - zHistory[histSize - 1] + (yHistory[0] - yHistory[histSize - 1]) / 2 +
(xHistory[0] - xHistory[histSize - 1]) / 4) *
100 / (time - lastTime);
// (.2 * speed) + ((1 - .2) * accumulatedSpeed);
accumulatedSpeed = speed / 5 + accumulatedSpeed * 4 / 5;
return accumulatedSpeed > thresh;
}
bool MotionController::ShouldLowerSleep() const {
if ((stats.xMean > 887 && DegreesRolled(stats.xMean, stats.zMean, stats.prevXMean, stats.prevZMean) > 30) ||
(stats.xMean < -887 && DegreesRolled(stats.xMean, stats.zMean, stats.prevXMean, stats.prevZMean) < -30)) {
return true;
}
if (stats.yMean < 724 || DegreesRolled(stats.yMean, stats.zMean, stats.prevYMean, stats.prevZMean) < 30) {
return false;
}
for (uint8_t i = AccelStats::numHistory + 1; i < yHistory.Size(); i++) {
if (yHistory[i] < 265) {
return false;
}
}
return true;
}
void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) {
switch (types) {
case Drivers::Bma421::DeviceTypes::BMA421:
this->deviceType = DeviceTypes::BMA421;
break;
case Drivers::Bma421::DeviceTypes::BMA425:
this->deviceType = DeviceTypes::BMA425;
break;
default:
this->deviceType = DeviceTypes::Unknown;
break;
}
}