Mercurial > public > ostc4
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Discovery/Src/motion.c Sun Nov 24 15:46:58 2019 +0000 @@ -0,0 +1,297 @@ +/* + * motion.c + * + * Created on: 20.05.2019 + * Author: Thorsten Sonntag + */ + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include "motion.h" +#include "data_central.h" +#include "t7.h" +#include "t3.h" +#include "settings.h" + +#define STABLE_STATE_COUNT 2 /* number of count to declare a state as stable (at the moment based on 100ms) */ +#define STABLE_STATE_TIMEOUT 5 /* Detection shall be aborted if a movement state is stable for more than 500ms */ + +#define SECTOR_WINDOW 80.0 /* Pitch window which is used for custom view projection */ +#define SECTOR_WINDOW_MAX 120.0 /* Pitch window which will be greater than the divers field of view */ +#define SECTOR_HYSTERY 2 /* Additional offset to avoid fast changing displays */ +#define SECTOR_BORDER 400.0 /* Define a value which is out of limit to avoid not wanted key events */ +#define SECTOR_FILTER 10 /* Define speed for calculated angle to follow real value */ + +#define SECTOR_MAX 24 /* maximum number of sectors */ +#define SECTOR_SCROLL 7 /* number of sectors used for scroll detection */ + +detectionState_t detectionState = DETECT_NOTHING; +SSector sectorDetection; + + +uint8_t GetSectorForPitch(float pitch) +{ + static uint8_t lastsector = 0; + float newPitch; + uint8_t sector = 0; + + newPitch = pitch + sectorDetection.offset + sectorDetection.center; /* do not use negative values and consider offset to center position */ + if (newPitch < 0.0) /* clip value */ + { + newPitch = 0.0; + } + if (newPitch > sectorDetection.window) /* clip value */ + { + newPitch = sectorDetection.window; + } + + /* switch to other sector? */ + if((newPitch > sectorDetection.upperborder) || (newPitch <= sectorDetection.lowerborder)) + { + sector = (uint16_t) newPitch / sectorDetection.size; + sectorDetection.lowerborder = sector * sectorDetection.size - SECTOR_HYSTERY; + sectorDetection.upperborder = (sector + 1) * sectorDetection.size + SECTOR_HYSTERY; + lastsector = sector; + } + + return lastsector; +} + +void DefinePitchSectors(float centerPitch,uint8_t numOfSectors) +{ + if(numOfSectors == CUSTOMER_DEFINED_VIEWS) + { + if(settingsGetPointer()->design == 3) /* Big font view ? */ + { + sectorDetection.count = t3_GetEnabled_customviews(); + } + else + { + sectorDetection.count = t7_GetEnabled_customviews(); + } + if(sectorDetection.count > 7) + { + sectorDetection.count = 7; /* more views are hard to manually control */ + } + } + else + if(numOfSectors != CUSTOMER_KEEP_LAST_SECTORS) + { + sectorDetection.count = numOfSectors; + } + + if(sectorDetection.count == SECTOR_MAX) + { + sectorDetection.window = SECTOR_WINDOW_MAX; + } + else + { + sectorDetection.window = SECTOR_WINDOW; + } + + sectorDetection.offset = (centerPitch - (sectorDetection.window / 2)) * -1.0; + sectorDetection.size = sectorDetection.window / sectorDetection.count; + sectorDetection.center = 0; + +/* reset border values */ + sectorDetection.lowerborder = SECTOR_BORDER; + sectorDetection.upperborder = SECTOR_BORDER * -1.0; +/* get the current sector */ + sectorDetection.current = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); + sectorDetection.target = sectorDetection.current; +/* do a small adjustment to center pitch to make sure the actual pitch is in the center of the current sector */ + sectorDetection.center = (sectorDetection.upperborder) - ((sectorDetection.size + 2 *SECTOR_HYSTERY) / 2.0) - (centerPitch + sectorDetection.offset); + +} + +void InitMotionDetection(void) +{ + sectorDetection.target = 0; + sectorDetection.current = 0; + sectorDetection.size = 0; + sectorDetection.count = 0; + + switch(settingsGetPointer()->MotionDetection) + { + case MOTION_DETECT_SECTOR: DefinePitchSectors(0,CUSTOMER_DEFINED_VIEWS); + break; + case MOTION_DETECT_MOVE: DefinePitchSectors(0,SECTOR_MAX); + break; + case MOTION_DETECT_SCROLL: DefinePitchSectors(0,SECTOR_SCROLL); + break; + default: + break; + } + +} + +/* Map the current pitch value to a sector and create button event in case the sector is left */ +detectionState_t detectSectorButtonEvent(float curPitch) +{ + static uint8_t lastTargetSector = 0; + uint8_t newTargetSector; + uint8_t PitchEvent = DETECT_NOTHING; + +/* only change sector if reading is stable */ + newTargetSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); + if(lastTargetSector == newTargetSector) + { + sectorDetection.target = newTargetSector; + } + lastTargetSector = newTargetSector; + if(sectorDetection.target != sectorDetection.current) + { + if(sectorDetection.target > sectorDetection.current) + { + sectorDetection.current++; + PitchEvent = DETECT_POS_PITCH; + } + else + { + sectorDetection.current--; + PitchEvent = DETECT_NEG_PITCH; + } + } + return PitchEvent; +} + +/* Check if pitch is not in center position and trigger a button action if needed */ +detectionState_t detectScrollButtonEvent(float curPitch) +{ + static uint8_t delayscroll = 0; /* slow down the number of scroll events */ + + uint8_t PitchEvent = DETECT_NOTHING; + uint8_t newSector; + + if(delayscroll == 0) + { + newSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); + /* for scroll detection the motion windoe is split into 6 sectors => set event accoring to the sector number*/ + switch(newSector) + { + case 0: + case 1: PitchEvent = DETECT_POS_PITCH; + break; + case 5: + case 6: PitchEvent = DETECT_NEG_PITCH; + break; + default: + break; + } + if(PitchEvent != DETECT_NOTHING) + { + delayscroll = 5; + } + } + else + { + delayscroll--; + } + return PitchEvent; +} + + +/* Detect if user is generating an pitch including return to starting position */ +/* This is done by feeding the past movements value per value into a state machine */ +detectionState_t detectPitch(float currentPitch) +{ + static uint8_t lastSector = 0; + static uint8_t startSector = 0; + static uint8_t stableCnt = 0; + + uint8_t curSector; + + if((detectionState == DETECT_NEG_PITCH) || (detectionState == DETECT_POS_PITCH)) /* discard last detection */ + { + detectionState = DETECT_NOTHING; + } + + curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch); + + /* feed value into state machine */ + switch (detectionState) + { + case DETECT_NOTHING: if(curSector != lastSector) /* detect a stable condition before evaluating for the next move */ + { + stableCnt=0; + } + + if(stableCnt > STABLE_STATE_COUNT) + { + detectionState = DETECT_START; + stableCnt = 0; + startSector = lastSector; + } + break; + case DETECT_START: if(curSector != lastSector) + { + if(abs(curSector - startSector) > 1) + { + if(curSector > lastSector) + { + detectionState = DETECT_POS_MOVE; + } + else + { + detectionState = DETECT_NEG_MOVE; + } + stableCnt = 0; + startSector = lastSector; + } + } + break; + case DETECT_NEG_MOVE: + case DETECT_POS_MOVE: if(curSector == lastSector) /* Moved to a max? */ + { + if(abs(startSector - curSector) > 2) + { + detectionState++; + stableCnt = 0; + } + if(stableCnt > 2) + { + detectionState = DETECT_NOTHING; + stableCnt = 0; + } + } + break; + case DETECT_MAXIMA: + case DETECT_MINIMA: if(curSector != lastSector) /* reset timeout detection */ + { + detectionState++; + stableCnt = 0; + } + break; + case DETECT_RISEBACK: + case DETECT_FALLBACK: + if(curSector == lastSector) /* check if we are back at start position at end of movement */ + { + if(abs(startSector - curSector) <= 1) + { + if(stableCnt > 2) + { + detectionState++; + stableCnt = 0; + } + } + } + break; + default: + detectionState = DETECT_NOTHING; + break; + } + if(detectionState != DETECT_START) + { + stableCnt++; + } + lastSector = curSector; + if(stableCnt > STABLE_STATE_TIMEOUT) + { + detectionState = DETECT_NOTHING; + stableCnt = 0; + } + + return detectionState; +}