comparison Discovery/Src/motion.c @ 387:0dbb74be972f

Merged in Ideenmodellierer/ostc4/MotionDetection (pull request #34) MotionDetection
author heinrichsweikamp <bitbucket@heinrichsweikamp.com>
date Sun, 24 Nov 2019 15:46:58 +0000
parents 0cd862e501f6
children e3237f580ae9
comparison
equal deleted inserted replaced
358:c6a084d1433f 387:0dbb74be972f
1 /*
2 * motion.c
3 *
4 * Created on: 20.05.2019
5 * Author: Thorsten Sonntag
6 */
7
8 #include <stdint.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include "motion.h"
13 #include "data_central.h"
14 #include "t7.h"
15 #include "t3.h"
16 #include "settings.h"
17
18 #define STABLE_STATE_COUNT 2 /* number of count to declare a state as stable (at the moment based on 100ms) */
19 #define STABLE_STATE_TIMEOUT 5 /* Detection shall be aborted if a movement state is stable for more than 500ms */
20
21 #define SECTOR_WINDOW 80.0 /* Pitch window which is used for custom view projection */
22 #define SECTOR_WINDOW_MAX 120.0 /* Pitch window which will be greater than the divers field of view */
23 #define SECTOR_HYSTERY 2 /* Additional offset to avoid fast changing displays */
24 #define SECTOR_BORDER 400.0 /* Define a value which is out of limit to avoid not wanted key events */
25 #define SECTOR_FILTER 10 /* Define speed for calculated angle to follow real value */
26
27 #define SECTOR_MAX 24 /* maximum number of sectors */
28 #define SECTOR_SCROLL 7 /* number of sectors used for scroll detection */
29
30 detectionState_t detectionState = DETECT_NOTHING;
31 SSector sectorDetection;
32
33
34 uint8_t GetSectorForPitch(float pitch)
35 {
36 static uint8_t lastsector = 0;
37 float newPitch;
38 uint8_t sector = 0;
39
40 newPitch = pitch + sectorDetection.offset + sectorDetection.center; /* do not use negative values and consider offset to center position */
41 if (newPitch < 0.0) /* clip value */
42 {
43 newPitch = 0.0;
44 }
45 if (newPitch > sectorDetection.window) /* clip value */
46 {
47 newPitch = sectorDetection.window;
48 }
49
50 /* switch to other sector? */
51 if((newPitch > sectorDetection.upperborder) || (newPitch <= sectorDetection.lowerborder))
52 {
53 sector = (uint16_t) newPitch / sectorDetection.size;
54 sectorDetection.lowerborder = sector * sectorDetection.size - SECTOR_HYSTERY;
55 sectorDetection.upperborder = (sector + 1) * sectorDetection.size + SECTOR_HYSTERY;
56 lastsector = sector;
57 }
58
59 return lastsector;
60 }
61
62 void DefinePitchSectors(float centerPitch,uint8_t numOfSectors)
63 {
64 if(numOfSectors == CUSTOMER_DEFINED_VIEWS)
65 {
66 if(settingsGetPointer()->design == 3) /* Big font view ? */
67 {
68 sectorDetection.count = t3_GetEnabled_customviews();
69 }
70 else
71 {
72 sectorDetection.count = t7_GetEnabled_customviews();
73 }
74 if(sectorDetection.count > 7)
75 {
76 sectorDetection.count = 7; /* more views are hard to manually control */
77 }
78 }
79 else
80 if(numOfSectors != CUSTOMER_KEEP_LAST_SECTORS)
81 {
82 sectorDetection.count = numOfSectors;
83 }
84
85 if(sectorDetection.count == SECTOR_MAX)
86 {
87 sectorDetection.window = SECTOR_WINDOW_MAX;
88 }
89 else
90 {
91 sectorDetection.window = SECTOR_WINDOW;
92 }
93
94 sectorDetection.offset = (centerPitch - (sectorDetection.window / 2)) * -1.0;
95 sectorDetection.size = sectorDetection.window / sectorDetection.count;
96 sectorDetection.center = 0;
97
98 /* reset border values */
99 sectorDetection.lowerborder = SECTOR_BORDER;
100 sectorDetection.upperborder = SECTOR_BORDER * -1.0;
101 /* get the current sector */
102 sectorDetection.current = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
103 sectorDetection.target = sectorDetection.current;
104 /* do a small adjustment to center pitch to make sure the actual pitch is in the center of the current sector */
105 sectorDetection.center = (sectorDetection.upperborder) - ((sectorDetection.size + 2 *SECTOR_HYSTERY) / 2.0) - (centerPitch + sectorDetection.offset);
106
107 }
108
109 void InitMotionDetection(void)
110 {
111 sectorDetection.target = 0;
112 sectorDetection.current = 0;
113 sectorDetection.size = 0;
114 sectorDetection.count = 0;
115
116 switch(settingsGetPointer()->MotionDetection)
117 {
118 case MOTION_DETECT_SECTOR: DefinePitchSectors(0,CUSTOMER_DEFINED_VIEWS);
119 break;
120 case MOTION_DETECT_MOVE: DefinePitchSectors(0,SECTOR_MAX);
121 break;
122 case MOTION_DETECT_SCROLL: DefinePitchSectors(0,SECTOR_SCROLL);
123 break;
124 default:
125 break;
126 }
127
128 }
129
130 /* Map the current pitch value to a sector and create button event in case the sector is left */
131 detectionState_t detectSectorButtonEvent(float curPitch)
132 {
133 static uint8_t lastTargetSector = 0;
134 uint8_t newTargetSector;
135 uint8_t PitchEvent = DETECT_NOTHING;
136
137 /* only change sector if reading is stable */
138 newTargetSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
139 if(lastTargetSector == newTargetSector)
140 {
141 sectorDetection.target = newTargetSector;
142 }
143 lastTargetSector = newTargetSector;
144 if(sectorDetection.target != sectorDetection.current)
145 {
146 if(sectorDetection.target > sectorDetection.current)
147 {
148 sectorDetection.current++;
149 PitchEvent = DETECT_POS_PITCH;
150 }
151 else
152 {
153 sectorDetection.current--;
154 PitchEvent = DETECT_NEG_PITCH;
155 }
156 }
157 return PitchEvent;
158 }
159
160 /* Check if pitch is not in center position and trigger a button action if needed */
161 detectionState_t detectScrollButtonEvent(float curPitch)
162 {
163 static uint8_t delayscroll = 0; /* slow down the number of scroll events */
164
165 uint8_t PitchEvent = DETECT_NOTHING;
166 uint8_t newSector;
167
168 if(delayscroll == 0)
169 {
170 newSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
171 /* for scroll detection the motion windoe is split into 6 sectors => set event accoring to the sector number*/
172 switch(newSector)
173 {
174 case 0:
175 case 1: PitchEvent = DETECT_POS_PITCH;
176 break;
177 case 5:
178 case 6: PitchEvent = DETECT_NEG_PITCH;
179 break;
180 default:
181 break;
182 }
183 if(PitchEvent != DETECT_NOTHING)
184 {
185 delayscroll = 5;
186 }
187 }
188 else
189 {
190 delayscroll--;
191 }
192 return PitchEvent;
193 }
194
195
196 /* Detect if user is generating an pitch including return to starting position */
197 /* This is done by feeding the past movements value per value into a state machine */
198 detectionState_t detectPitch(float currentPitch)
199 {
200 static uint8_t lastSector = 0;
201 static uint8_t startSector = 0;
202 static uint8_t stableCnt = 0;
203
204 uint8_t curSector;
205
206 if((detectionState == DETECT_NEG_PITCH) || (detectionState == DETECT_POS_PITCH)) /* discard last detection */
207 {
208 detectionState = DETECT_NOTHING;
209 }
210
211 curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
212
213 /* feed value into state machine */
214 switch (detectionState)
215 {
216 case DETECT_NOTHING: if(curSector != lastSector) /* detect a stable condition before evaluating for the next move */
217 {
218 stableCnt=0;
219 }
220
221 if(stableCnt > STABLE_STATE_COUNT)
222 {
223 detectionState = DETECT_START;
224 stableCnt = 0;
225 startSector = lastSector;
226 }
227 break;
228 case DETECT_START: if(curSector != lastSector)
229 {
230 if(abs(curSector - startSector) > 1)
231 {
232 if(curSector > lastSector)
233 {
234 detectionState = DETECT_POS_MOVE;
235 }
236 else
237 {
238 detectionState = DETECT_NEG_MOVE;
239 }
240 stableCnt = 0;
241 startSector = lastSector;
242 }
243 }
244 break;
245 case DETECT_NEG_MOVE:
246 case DETECT_POS_MOVE: if(curSector == lastSector) /* Moved to a max? */
247 {
248 if(abs(startSector - curSector) > 2)
249 {
250 detectionState++;
251 stableCnt = 0;
252 }
253 if(stableCnt > 2)
254 {
255 detectionState = DETECT_NOTHING;
256 stableCnt = 0;
257 }
258 }
259 break;
260 case DETECT_MAXIMA:
261 case DETECT_MINIMA: if(curSector != lastSector) /* reset timeout detection */
262 {
263 detectionState++;
264 stableCnt = 0;
265 }
266 break;
267 case DETECT_RISEBACK:
268 case DETECT_FALLBACK:
269 if(curSector == lastSector) /* check if we are back at start position at end of movement */
270 {
271 if(abs(startSector - curSector) <= 1)
272 {
273 if(stableCnt > 2)
274 {
275 detectionState++;
276 stableCnt = 0;
277 }
278 }
279 }
280 break;
281 default:
282 detectionState = DETECT_NOTHING;
283 break;
284 }
285 if(detectionState != DETECT_START)
286 {
287 stableCnt++;
288 }
289 lastSector = curSector;
290 if(stableCnt > STABLE_STATE_TIMEOUT)
291 {
292 detectionState = DETECT_NOTHING;
293 stableCnt = 0;
294 }
295
296 return detectionState;
297 }