mousealgorithm.c

来自「陀螺仪程序」· C语言 代码 · 共 411 行

C
411
字号
/**************************************************************************************
;* Copyright 2007 InvenSense, Inc. All rights reserved.
;* GyroMouse v. 1.1
;**************************************************************************************/
// MouseAlgorithm.cpp : Mouse update function
//

#include "driftcompensation.h"

//Thresholds
#define DEAD_ZONE 1536
#define NO_MOTION 3
#define ENTER_STOP_MODE 50
#define EXIT_STOP_MODE 10
#define SPEED_0 28000
#define SPEED_1 24000
#define SPEED_2 20000
#define SPEED_3 16000
#define SPEED_4 12000
#define SPEED_5 8000

//Variables

//Pointer speed mode variables
unsigned char mode=0;
unsigned char lastMode=0;

//Raw gyro data
unsigned short gyroYRaw=0;
unsigned short gyroZRaw=0;
unsigned short tempRaw =0;

//Buffered raw gyro data for median filter
//Used for filtering out button clicks
unsigned short gyroYRaw1=0;
unsigned short gyroZRaw1=0;
unsigned short gyroYRaw2=0;
unsigned short gyroZRaw2=0;
unsigned short gyroYRaw3=0;
unsigned short gyroZRaw3=0;

//Temporary storage for computing "speed" metric
signed long gyroTempY = 0;
signed long gyroTempZ = 0;

//Bias calculation variables
signed long gyroZBiasAv = 0;
signed long gyroYBiasAv = 0;
signed long tempBiasAv = 0;
unsigned short gyroZMin=0;
unsigned short gyroZMax=0;
unsigned short gyroYMin=0;
unsigned short gyroYMax=0;
signed long gyroYBias = 2048;
signed long gyroZBias = 2048;
signed long tempBias = 2048;
unsigned short motionTemp;
unsigned short biasCounter = 0;
unsigned char motionDetected = 0;

//Variables for detecting "STOP" mode
unsigned char lastSignY = 0;
unsigned char lastSignZ = 0;
unsigned char signYCount = 0;
unsigned char signZCount = 0;
unsigned char signY = 0;
unsigned char signZ = 0;

//Processed gyro data
signed long gyroY = 0;
signed long gyroZ = 0;
signed long temp = 0;

//Integrated gyro data
signed long gyroYInt = 0;
signed long gyroZInt = 0;

//Button information
//Used for freezing gyro data temporarily when button is pressed or released
unsigned char lastButton = 48;
unsigned char buttonCounter = 0;

//Initial Calibration
unsigned char calibrated = 0;


void updateMouse(unsigned short *tempData, unsigned short *gyroYData, unsigned short *gyroZData, signed short *pixelYShift, signed short *pixelZShift, unsigned char *button){

	//Compute median filter to filter out button clicks
	gyroYRaw3 = gyroYRaw2;
	gyroZRaw3 = gyroZRaw2;

	gyroYRaw2 = gyroYRaw1;
	gyroZRaw2 = gyroZRaw1;

	gyroYRaw = *gyroYData;
	gyroZRaw = *gyroZData;
	tempRaw = *tempData;

	gyroYRaw1 = gyroYRaw;
	gyroZRaw1 = gyroZRaw;

	if (gyroYRaw3>gyroYRaw2) {
		if (gyroYRaw2>gyroYRaw) {
			gyroYRaw=gyroYRaw2;
		} else if (gyroYRaw3<gyroYRaw) {
			gyroYRaw=gyroYRaw3;
		}
	} else {
		if (gyroYRaw2<gyroYRaw) {
			gyroYRaw=gyroYRaw2;
		} else if (gyroYRaw3>gyroYRaw) {
			gyroYRaw=gyroYRaw3;
		}
	}

	if (gyroZRaw3>gyroZRaw2) {
		if (gyroZRaw2>gyroZRaw) {
			gyroZRaw=gyroZRaw2;
		} else if (gyroZRaw3<gyroZRaw) {
			gyroZRaw=gyroZRaw3;
		}
	} else {
		if (gyroZRaw2<gyroZRaw) {
			gyroZRaw=gyroZRaw2;
		} else if (gyroZRaw3>gyroZRaw) {
			gyroZRaw=gyroZRaw3;
		}
	}

	//Bias Calibration
	gyroYBiasAv+=(signed long)gyroYRaw;
	tempBiasAv+=(signed long)tempRaw;

	if (gyroYRaw<gyroYMin) {
		gyroYMin = gyroYRaw;
	}
	if (gyroYRaw>gyroYMax) {
		gyroYMax = gyroYRaw;
	}

	gyroZBiasAv+=(signed long)gyroZRaw;
	if (gyroZRaw<gyroZMin) {
		gyroZMin = gyroZRaw;
	}
	if (gyroZRaw>gyroZMax) {
		gyroZMax = gyroZRaw;
	}

	biasCounter+=1;
	if (biasCounter>511) {
		biasCounter = 0;
	}
	if (biasCounter==0) {
		
		#ifdef DEBUG_INFO
		printf("RESETTING BIAS\n");
		#endif

		mode = 8;
		gyroYBias = gyroYBiasAv>>1;
		gyroZBias = gyroZBiasAv>>1;
		tempBias = tempBiasAv>>1;
		calibrated = 1;

		gyroYBiasAv = 0;
		gyroZBiasAv = 0;
		tempBiasAv = 0;
		
		gyroYMin = gyroYRaw;
		gyroYMax = gyroYRaw;
		gyroZMin = gyroZRaw;
		gyroZMax = gyroZRaw;		
		gyroYInt = 0;
		gyroZInt = 0;
	} 
	
	motionDetected = 0;

	motionTemp = gyroYMax-gyroYMin;
	if (motionTemp<0) {
		motionTemp = -motionTemp;
	}
	if (motionTemp>NO_MOTION) {
		motionDetected = 1;
	}
	motionTemp = gyroZMax-gyroZMin;
	if (motionTemp<0) {
		motionTemp = -motionTemp;
	}
	if (motionTemp>NO_MOTION) {
		motionDetected = 1;
	}
	if (motionDetected) { 
		mode=6;
		biasCounter = 0;
		gyroYBiasAv = 0;
		gyroZBiasAv = 0;
		tempBiasAv = 0;
		gyroYMin = gyroYRaw;
		gyroYMax = gyroYRaw;
		gyroZMin = gyroZRaw;		
		gyroZMax = gyroZRaw;		
	}
	
	gyroY = (((signed long)gyroYRaw)<<8)-gyroYBias;
	gyroZ = (((signed long)gyroZRaw)<<8)-gyroZBias;
	if (calibrated==0) {
		gyroY = 0;
		gyroZ = 0;
	}
	temp = (((signed long)tempRaw)<<8)-tempBias;
	
	//Drift Compensation
	driftComp(&gyroY, &gyroZ, &temp, &mode);

	#ifdef TEMP_DEBUG_INFO
	printf("%*d %*d %*d\n", 10, gyroY>>8, 10, gyroZ>>8, 10, temp>>8);
	#endif
	
	//Dead zone
	if (((gyroY<(DEAD_ZONE)) && (gyroY>(-DEAD_ZONE))) && (mode>5)) {
		gyroY=0;
	}
	if (((gyroZ<(DEAD_ZONE)) && (gyroZ>(-DEAD_ZONE))) && (mode>5)) {
		gyroZ=0;
	}

	//Unless mode is OFF (on the desk), start in mode 6
	if (mode!=8) {mode = 6;}

    //Determine if pointer should be in "STOP" mode
    signY = 0;
    signZ = 0;       
	if (gyroY>0) {
        signY = 1;
	}
	if (gyroZ>0) {
        signZ = 1;
	}
	if (signY==lastSignY) {
        signYCount+=1;
		if (signYCount==255) {
			signYCount-=1;
		}
	} else {
        signYCount = 0;
	}
	if (signZ==lastSignZ) {
        signZCount+=1;
		if (signZCount==255) {
			signZCount-=1;
		}
	} else {
        signZCount = 0;
	}
    lastSignY = signY;
    lastSignZ = signZ;

	if (mode!=8) {//Unless mode is "OFF" (on the desk)...
		if ((signYCount<ENTER_STOP_MODE) && (signZCount<ENTER_STOP_MODE)) {//If sign changes are happening
			//at a high frequency, enter stop mode
			mode = 7;
		}
		if ((gyroTempY>SPEED_5) || (gyroTempZ>SPEED_5)) {// Test for "MEDIUM" mode
			if (lastMode==7) {//Not allowed if coming straight from "stop mode"
				mode=6;
			} else {
				mode=5;
			}
		}
		if ((signYCount>EXIT_STOP_MODE) || (signZCount>EXIT_STOP_MODE)) {// || (lastMode!=7)) {
			gyroTempY = gyroY;
			gyroTempZ = gyroZ;
			if (gyroTempY<0) {gyroTempY=-gyroTempY;}
			if (gyroTempZ<0) {gyroTempZ=-gyroTempZ;}
			if ((gyroTempY>SPEED_0) || (gyroTempZ>SPEED_0)) {
				mode=0;
			} else if ((gyroTempY>SPEED_1) || (gyroTempZ>SPEED_1)) {
				mode=1;
			} else if ((gyroTempY>SPEED_2) || (gyroTempZ>SPEED_2)) {
				mode=2;
			} else if ((gyroTempY>SPEED_3) || (gyroTempZ>SPEED_3)) {
				mode=3;
			} else if ((gyroTempY>SPEED_4) || (gyroTempZ>SPEED_4)) {
				mode=4;
			} 
		}
		lastMode = mode;
	}

	if (mode==0) {

		#ifdef DEBUG_INFO
		printf("SPEED 0\n");
		#endif

        gyroY=gyroY-(gyroY>>2);
        gyroZ=gyroZ-(gyroZ>>2);
	}
	if (mode==1) {

		#ifdef DEBUG_INFO
		printf("SPEED 1\n");
		#endif

        gyroY=gyroY-(gyroY>>2)-(gyroY>>3);
        gyroZ=gyroZ-(gyroZ>>2)-(gyroZ>>3);
	}
	if (mode==2) {

		#ifdef DEBUG_INFO
		printf("SPEED 2\n");
		#endif

        gyroY=(gyroY>>1);
        gyroZ=(gyroZ>>1);
	}
	if (mode==3) {

		#ifdef DEBUG_INFO
		printf("SPEED 3\n");
		#endif

        gyroY=(gyroY>>1)-(gyroY>>3);
        gyroZ=(gyroZ>>1)-(gyroZ>>3);
	}
	if (mode==4) {

		#ifdef DEBUG_INFO
		printf("SPEED 4\n");
		#endif

        gyroY=(gyroY>>1)-(gyroY>>2);
        gyroZ=(gyroZ>>1)-(gyroZ>>2);
	}
	if (mode==5) {

		#ifdef DEBUG_INFO
		printf("SPEED 5\n");
		#endif

        gyroY=(gyroY>>2);
        gyroZ=(gyroZ>>2);
	}
	if (mode==6) {

		#ifdef DEBUG_INFO
		printf("SPEED 6\n");
		#endif

        gyroY=gyroY>>3;
        gyroZ=gyroZ>>3;
	}
	//"STOP MODE", when gyro pointer is staying within a small area
	if (mode==7) {

		#ifdef DEBUG_INFO
		printf("STOP\n");
		#endif

		gyroY=gyroY>>5;
		gyroZ=gyroZ>>5;
		if (gyroY>25) {gyroY=25;}
		if (gyroY<-25) {gyroY=-25;}
		if (gyroZ>25) {gyroZ=25;}
		if (gyroZ<-25) {gyroZ=-25;}
	}
	//"OFF" Mode, when the gyro is on a desk, and only sensor noise is detected
	if (mode==8) {

		#ifdef DEBUG_INFO
		printf("OFF\n");
		#endif

		gyroY=0;	
		gyroZ=0;
	}
	//When button is detected, temporarily freeze the gyro data
	if (buttonCounter<25) {

		#ifdef DEBUG_INFO
		printf("CLICK DETECTED\n");
		#endif

		buttonCounter+=1;
		gyroY = 0;
		gyroZ = 0;		
	}
	if ((*button!=lastButton)){
		buttonCounter=0;
	}
	lastButton = *button;

	//Integrate the gyro data
	gyroYInt += gyroY;
	gyroZInt -= gyroZ;

	//Round to the nearest pixel, and adjust the gyro integral
	*pixelYShift = (signed short)(gyroYInt>>10);
	*pixelZShift = (signed short)(gyroZInt>>10);
	gyroYInt-=(((signed long)*pixelYShift)<<10);
	gyroZInt-=(((signed long)*pixelZShift)<<10);
	if (calibrated==0) {
		*pixelYShift = 0;
		*pixelZShift = 0;
	}	
	
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?