Mercurial > public > ostc4
comparison Discovery/Src/motion.c @ 381:695434a6dcf6 MotionDetection
Simplified pitch detection state machine:
Considering a pitch to last 1 to 2 seconds only around 5 to 10 iterations are used. As result the used counters had limits of 1 or 2 => not really needed
author | ideenmodellierer |
---|---|
date | Thu, 10 Oct 2019 22:11:59 +0200 |
parents | 834e087505ec |
children | 49a02dea8ae3 |
comparison
equal
deleted
inserted
replaced
380:a7331e4a9ca6 | 381:695434a6dcf6 |
---|---|
14 #include "t7.h" | 14 #include "t7.h" |
15 #include "settings.h" | 15 #include "settings.h" |
16 | 16 |
17 #define STABLE_STATE_COUNT 2 /* number of count to declare a state as stable (at the moment based on 100ms) */ | 17 #define STABLE_STATE_COUNT 2 /* number of count to declare a state as stable (at the moment based on 100ms) */ |
18 #define STABLE_STATE_TIMEOUT 5 /* Detection shall be aborted if a movement state is stable for more than 500ms */ | 18 #define STABLE_STATE_TIMEOUT 5 /* Detection shall be aborted if a movement state is stable for more than 500ms */ |
19 #define MOVE_DELTA_SPEED 4 /* Delta speed needed to identify a valid movement */ | |
20 #define PITCH_DELTA_COUNT 10 /* Delta count needed to identify a valid minima / maxima */ | |
21 #define PITCH_DELTA_END 10 /* Delta allowed between start and end position */ | |
22 | |
23 | 19 |
24 #define SECTOR_WINDOW 80.0 /* Pitch window which is used for custom view projection */ | 20 #define SECTOR_WINDOW 80.0 /* Pitch window which is used for custom view projection */ |
21 #define SECTOR_WINDOW_MAX 120.0 /* Pitch window which will be greater than the divers field of view */ | |
25 #define SECTOR_HYSTERY 3 /* Additional offset to avoid fast changing displays */ | 22 #define SECTOR_HYSTERY 3 /* Additional offset to avoid fast changing displays */ |
26 #define SECTOR_BORDER 400.0 /* Define a value which is out of limit to avoid not wanted key events */ | 23 #define SECTOR_BORDER 400.0 /* Define a value which is out of limit to avoid not wanted key events */ |
27 #define SECTOR_FILTER 10 /* Define speed for calculated angle to follow real value */ | 24 #define SECTOR_FILTER 10 /* Define speed for calculated angle to follow real value */ |
28 | 25 |
29 #define SECTOR_MAX 19 /* maximum number of sectors */ | 26 #define SECTOR_MAX 30 /* maximum number of sectors */ |
30 #define SECTOR_SCROLL 7 /* number of sectors used for scroll detection */ | 27 #define SECTOR_SCROLL 7 /* number of sectors used for scroll detection */ |
31 | 28 |
32 detectionState_t detectionState = DETECT_NOTHING; | 29 static detectionState_t detectionState = DETECT_NOTHING; |
33 | 30 |
34 uint8_t curSector; | 31 uint8_t curSector; |
35 static uint8_t targetSector; | 32 static uint8_t targetSector; |
36 static uint8_t sectorSize; | 33 static float sectorSize; |
34 static float sectorwindow; | |
37 static uint8_t sectorCount; | 35 static uint8_t sectorCount; |
38 | 36 |
39 SSector PitchSector[SECTOR_MAX]; /* max number of enabled custom views */ | 37 static float sector_upperborder; |
38 static float sector_lowerborder; | |
40 | 39 |
41 | 40 |
42 uint8_t GetSectorForPitch(float pitch) | 41 uint8_t GetSectorForPitch(float pitch) |
43 { | 42 { |
44 static float lastPitch = 1000; | 43 static uint8_t lastsector = 0xFF; |
45 float newPitch; | 44 float newPitch; |
46 uint8_t index; | |
47 uint8_t sector = 0; | 45 uint8_t sector = 0; |
48 | 46 |
49 if(lastPitch == 1000) /* init at first call */ | 47 |
50 { | 48 newPitch = pitch + (sectorwindow / 2.0); /* do not use negativ values */ |
51 lastPitch = pitch; | 49 if (newPitch < 0.0) /* clip value */ |
52 } | 50 { |
53 | 51 newPitch = 0.0; |
54 newPitch = lastPitch + (pitch / SECTOR_FILTER); | 52 } |
55 | 53 if (newPitch > sectorwindow) /* clip value */ |
56 for(index = 1; index < sectorCount; index++) | 54 { |
57 { | 55 newPitch = sectorwindow; |
58 if((pitch < PitchSector[index].upperlimit) && (pitch > PitchSector[index].lowerlimit )) | 56 } |
59 { | 57 |
60 sector = index; | 58 if(lastsector == 0xFF) /* First call of function => make sure a new sector is set */ |
61 break; | 59 { |
62 } | 60 sector_lowerborder = SECTOR_BORDER; |
63 } | 61 sector_upperborder = SECTOR_BORDER * -1.0; |
64 lastPitch = newPitch; | 62 |
65 return sector; | 63 } |
64 | |
65 /* switch to other sector? */ | |
66 if((newPitch > sector_upperborder) || (newPitch <= sector_lowerborder)) | |
67 { | |
68 sector = (uint16_t) newPitch / sectorSize; | |
69 sector_lowerborder = sector * sectorSize - SECTOR_HYSTERY; | |
70 sector_upperborder = (sector + 1) * sectorSize + SECTOR_HYSTERY; | |
71 lastsector = sector; | |
72 } | |
73 | |
74 return lastsector; | |
66 } | 75 } |
67 | 76 |
68 void DefinePitchSectors(float centerPitch,uint8_t numOfSectors) | 77 void DefinePitchSectors(float centerPitch,uint8_t numOfSectors) |
69 { | 78 { |
70 uint8_t index; | |
71 | |
72 if(numOfSectors == CUSTOMER_DEFINED_VIEWS) | 79 if(numOfSectors == CUSTOMER_DEFINED_VIEWS) |
73 { | 80 { |
74 sectorCount = t7_GetEnabled_customviews(); | 81 sectorCount = t7_GetEnabled_customviews(); |
75 if(sectorCount > 7) | 82 if(sectorCount > 7) |
76 { | 83 { |
80 else | 87 else |
81 if(numOfSectors != CUSTOMER_KEEP_LAST_SECTORS) | 88 if(numOfSectors != CUSTOMER_KEEP_LAST_SECTORS) |
82 { | 89 { |
83 sectorCount = numOfSectors; | 90 sectorCount = numOfSectors; |
84 } | 91 } |
85 sectorSize = SECTOR_WINDOW / sectorCount; | 92 |
86 | 93 if(sectorCount == SECTOR_MAX) |
87 PitchSector[0].upperlimit = centerPitch + (SECTOR_WINDOW / 2); | 94 { |
88 PitchSector[0].lowerlimit = PitchSector[0].upperlimit - sectorSize - SECTOR_HYSTERY; | 95 sectorwindow = SECTOR_WINDOW_MAX; |
89 | 96 } |
90 for(index = 1; index < sectorCount; index++) | 97 else |
91 { | 98 { |
92 PitchSector[index].upperlimit = PitchSector[0].upperlimit - index * sectorSize + SECTOR_HYSTERY; | 99 sectorwindow = SECTOR_WINDOW; |
93 PitchSector[index].lowerlimit = PitchSector[0].upperlimit - (index + 1) * sectorSize - SECTOR_HYSTERY; | 100 } |
94 } | 101 |
95 | 102 sectorSize = sectorwindow / sectorCount; |
96 PitchSector[0].upperlimit = SECTOR_BORDER; | |
97 PitchSector[index - 1].lowerlimit = SECTOR_BORDER * -1.0; | |
98 | 103 |
99 /* get the current sector */ | 104 /* get the current sector */ |
100 curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); | 105 curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); |
101 targetSector = curSector; | 106 targetSector = curSector; |
102 } | 107 } |
133 newTargetSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); | 138 newTargetSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); |
134 if(lastTargetSector == newTargetSector) | 139 if(lastTargetSector == newTargetSector) |
135 { | 140 { |
136 targetSector = newTargetSector; | 141 targetSector = newTargetSector; |
137 } | 142 } |
138 lastTargetSector = newTargetSector; | 143 lastTargetSector = newTargetSector; |
139 if(targetSector != curSector) | 144 if(targetSector != curSector) |
140 { | 145 { |
141 if(targetSector > curSector) | 146 if(targetSector > curSector) |
142 { | 147 { |
143 curSector++; | 148 curSector++; |
203 detectionState = DETECT_NOTHING; | 208 detectionState = DETECT_NOTHING; |
204 } | 209 } |
205 | 210 |
206 curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); | 211 curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); |
207 | 212 |
208 sectorhist[sectorindex++] = curSector; | |
209 if(sectorindex == 20) sectorindex=0; | |
210 | |
211 /* feed value into state machine */ | 213 /* feed value into state machine */ |
212 switch (detectionState) | 214 switch (detectionState) |
213 { | 215 { |
214 case DETECT_NOTHING: if(curSector == lastSector) /* detect a stable condition before evaluating for the next move */ | 216 case DETECT_NOTHING: if(curSector != lastSector) /* detect a stable condition before evaluating for the next move */ |
215 { | |
216 stableCnt++; | |
217 } | |
218 else | |
219 { | 217 { |
220 stableCnt=0; | 218 stableCnt=0; |
221 } | 219 } |
222 | 220 |
223 if(stableCnt > STABLE_STATE_COUNT) | 221 if(stableCnt > STABLE_STATE_COUNT) |
240 detectionState = DETECT_NEG_MOVE; | 238 detectionState = DETECT_NEG_MOVE; |
241 } | 239 } |
242 stableCnt = 0; | 240 stableCnt = 0; |
243 startSector = lastSector; | 241 startSector = lastSector; |
244 } | 242 } |
245 else | |
246 { | |
247 stableCnt++; /* reset start sector in case of slow movement */ | |
248 } | |
249 } | 243 } |
250 break; | 244 break; |
251 case DETECT_NEG_MOVE: | 245 case DETECT_NEG_MOVE: |
252 case DETECT_POS_MOVE: if(curSector != lastSector) /* still moving? */ | 246 case DETECT_POS_MOVE: if(curSector == lastSector) /* Moved to a max? */ |
253 { | |
254 stableCnt++; | |
255 } | |
256 else | |
257 { | 247 { |
258 if(abs(startSector - curSector) > 2) | 248 if(abs(startSector - curSector) > 2) |
259 { | 249 { |
260 detectionState++; | 250 detectionState++; |
261 stableCnt = 0; | 251 stableCnt = 0; |
262 } | 252 } |
263 else | 253 if(stableCnt > 2) |
264 { | 254 { |
265 stableCnt++; /* maybe on the boundary of a sector => handle as stable */ | 255 detectionState = DETECT_NOTHING; |
266 } | |
267 } | |
268 break; | |
269 case DETECT_MINIMA: | |
270 case DETECT_MAXIMA: /* stay at maximum for short time to add a pattern for user interaction */ | |
271 if(curSector == lastSector) | |
272 { | |
273 stableCnt++; | |
274 } | |
275 else | |
276 { | |
277 if(stableCnt > 0) /* restart movement after a short break? */ | |
278 { | |
279 detectionState++; | |
280 stableCnt = 0; | 256 stableCnt = 0; |
281 } | 257 } |
282 else | 258 } |
283 { | 259 break; |
284 stableCnt++; /* maybe on the boundary of a sector => handle as stable */ | 260 case DETECT_MAXIMA: |
285 } | 261 case DETECT_MINIMA: if(curSector != lastSector) /* reset timeout detection */ |
262 { | |
263 detectionState++; | |
264 stableCnt = 0; | |
286 } | 265 } |
287 break; | 266 break; |
288 case DETECT_RISEBACK: | 267 case DETECT_RISEBACK: |
289 case DETECT_FALLBACK: if(curSector == lastSector) /* check if we are back at start position at end of movement */ | 268 case DETECT_FALLBACK: |
290 { | 269 if(curSector == lastSector) /* check if we are back at start position at end of movement */ |
291 if(abs(startSector - curSector) <= 1) //(curSector == startSector) | 270 { |
292 { | 271 if(abs(startSector - curSector) <= 1) |
293 detectionState++; | 272 { |
294 stableCnt = 0; | 273 if(stableCnt > 2) |
295 } | 274 { |
296 else | 275 detectionState++; |
297 { | 276 stableCnt = 0; |
298 stableCnt++; /* maybe on the boundary of a sector => handle as stable */ | 277 } |
299 } | 278 } |
300 } | 279 } |
301 else | 280 break; |
302 { | |
303 stableCnt++; | |
304 } | |
305 break; | |
306 default: | 281 default: |
307 detectionState = DETECT_NOTHING; | 282 detectionState = DETECT_NOTHING; |
308 break; | 283 break; |
309 | 284 } |
285 if(detectionState != DETECT_START) | |
286 { | |
287 stableCnt++; | |
310 } | 288 } |
311 lastSector = curSector; | 289 lastSector = curSector; |
312 if(stableCnt > STABLE_STATE_TIMEOUT) | 290 if(stableCnt > STABLE_STATE_TIMEOUT) |
313 { | 291 { |
314 detectionState = DETECT_NOTHING; | 292 detectionState = DETECT_NOTHING; |