How to detect the Shake gesture?

Hi,

Does anyone know how to detect the shake gesture in ofxiPhone?

Cheers
rS

shake the device look at accelerometer in log find max and min vals for x and y. then count how many times those values are hit. something like.

if(accelX < -2 && accelX >2 && accelY < -2 && accelY >2){count++;}else{count=0;}

if(count==4){//shake;}

Thanks dust! I will try that out later

Cheers
rS

hi

i don t really understand why you are doing &&s

i would do ||s

like

  
if(accelX < -2 || accelX >2 && accelY < -2 || accelY >2){  
count++;  
}  
else{  
count=0;  
}  
  
if(count==4){  
//shake;  
}   

and 2 is a little bit hard to reach
i mean , i was a little bit scared to drop my ipod

i set to 1.6
it fits for me ;

here is what i did
it is not reacting really like a shake , but it s running

here we are

.h

  
#pragma once  
  
#include "ofMain.h"  
#include "ofxiPhone.h"  
#include "ofxiPhoneExtras.h"  
  
class testApp : public ofxiPhoneApp {  
	  
public:  
	void setup();  
	void update();  
	void draw();  
	void exit();  
	  
	void touchDown(ofTouchEventArgs &touch);  
	void touchMoved(ofTouchEventArgs &touch);  
	void touchUp(ofTouchEventArgs &touch);  
	void touchDoubleTap(ofTouchEventArgs &touch);  
  
	void lostFocus();  
	void gotFocus();  
	void gotMemoryWarning();  
	void deviceOrientationChanged(int newOrientation);  
	  
	int shake,inccount;  
	float accx,accy,treshold;  
};  
  
  
   

and the testapp.mm

  
  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){	  
	// register touch events  
	ofRegisterTouchEvents(this);  
	  
	// initialize the accelerometer  
	ofxAccelerometer.setup();  
	  
	//iPhoneAlerts will be sent to this.  
	ofxiPhoneAlerts.addListener(this);  
	  
	//If you want a landscape oreintation   
	//iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);  
	  
	ofBackground(127,127,127);  
	  
	treshold=1.6;  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
  
	  
	  
	accx=ofxAccelerometer.getForce().x;  
	accy=ofxAccelerometer.getForce().y;  
	  
	if(accx<-treshold || accx>treshold || accy<-treshold || accy>treshold){  
		inccount++;  
	}  
	else {  
		inccount=0;  
	}  
  
	if (inccount==4) {  
		shake++;  
	}  
	if (shake>1) {  
		shake=0;  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofPushStyle();  
	if (shake==0) {  
		ofSetColor(255, 255, 255);  
	}  
	else {  
		ofSetColor(0, 0, 0);  
	}  
	ofDrawBitmapString("shake:"+ ofToString(shake, 0), 10, 10);  
	ofDrawBitmapString("inccount:"+ ofToString(inccount, 0), 10, 20);  
	ofDrawBitmapString("accx:"+ ofToString(accx, 3), 10, 30);  
	ofDrawBitmapString("accy:"+ ofToString(accy, 3), 10, 40);  
	ofPopStyle();  
	  
	if (shake==0) {  
		ofBackground(0, 0, 0);  
	}  
	else {  
		ofBackground(255, 255, 255);  
	}  
  
  
}  
  
//--------------------------------------------------------------  
void testApp::exit(){}  
void testApp::touchDown(ofTouchEventArgs &touch){}  
void testApp::touchMoved(ofTouchEventArgs &touch){}  
void testApp::touchUp(ofTouchEventArgs &touch){}  
void testApp::touchDoubleTap(ofTouchEventArgs &touch){}  
void testApp::lostFocus(){}  
void testApp::gotFocus(){}  
void testApp::gotMemoryWarning(){}  
void testApp::deviceOrientationChanged(int newOrientation){}  

i m still working on it , it doesn t feel right

i ll upload the result

ok here is my final code (you can download it to simplify things)

i haded a timing to reset the variables

important variables are mapped to the touch screen


code preview

#include “testApp.h”

//--------------------------------------------------------------
void testApp::setup(){
// register touch events
ofRegisterTouchEvents(this);

// initialize the accelerometer
ofxAccelerometer.setup();

//iPhoneAlerts will be sent to this.
ofxiPhoneAlerts.addListener(this);

//If you want a landscape oreintation
//iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

ofBackground(127,127,127);

treshold=1.6;

testcount=0;

font.loadFont(“b.ttf”,75);
fontB.loadFont(“b.ttf”,30);

//----------------
//paste your testcount value average here;
yourtestcount=8; // acctually it s going to trigger for yourtestcount-1 (see comments in update)
//
//----------------

timeofgesture=450; // self explainatory
}

//--------------------------------------------------------------
void testApp::update(){

accx=ofxAccelerometer.getForce().x;
accy=ofxAccelerometer.getForce().y;

if(accx<-treshold || accx>treshold && accy<-treshold || accy>treshold){
inccount++;
testcount++;
}

if (inccount>yourtestcount) {
inccount=0;
}

if (inccount==1) { // here i have to admit : i cheated
startshake = ofGetElapsedTimeMillis(); // i wanted to get the moment you start shaking
inccount++; //
} //so take care you re going to trigger for yourtestcount -1

if ((ofGetElapsedTimeMillis() - startshake) > timeofgesture) {
inccount=0;
}

if (inccount==yourtestcount) {
shake++;
}

if (shake==0) {
if (inccount>=yourtestcount) {
inccount=0;
}
}

if (shake==1) {
if (inccount>=yourtestcount) {
inccount=0;
}
}

if (shake>1) {
shake=0;
inccount=0;
}

}

//--------------------------------------------------------------
void testApp::draw(){
ofPushStyle();
ofSetColor(25, 25, 25);
fontB.drawString(“shake me”,10,(ofGetScreenHeight()-ofGetScreenHeight()/6));
fontB.drawString(“touch me”,10,(ofGetScreenHeight()-ofGetScreenHeight()/6)+33);
ofPopStyle();

ofPushStyle();
if (shake==0) {
ofSetColor(255, 255, 255);
}
else {
ofSetColor(0, 0, 0);
}
// how to setup:
ofDrawBitmapString(“setup: shake your gesture \nand notice your testcount average value \nyou can reset by double tap”, 5,10 );
int i=15;
ofDrawBitmapString(“shake:”+ ofToString(shake, 0), 10, 40+i);
ofDrawBitmapString(“inccount:”+ ofToString(inccount, 0), 10, 50+i);
ofDrawBitmapString(“accx:”+ ofToString(accx, 3), 10, 60+i);
ofDrawBitmapString(“accy:”+ ofToString(accy, 3), 10, 70+i);
ofDrawBitmapString(“the inccount for trig shake(+1):”+ofToString(yourtestcount, 0), 10, 80+i);
ofDrawBitmapString(“time of your gesture(ms):”+ofToString(timeofgesture, 0), 10, 90+i);

ofDrawBitmapString(“testcount:” ,10, 130);
font.drawString(ofToString(testcount, 0),(ofGetScreenWidth()/2)-130,(ofGetScreenHeight()/2));
ofPushMatrix();
ofTranslate(touchPos.x, touchPos.y, 0);
ofNoFill();
ofRect(-10, -10, 20, 20);
ofDrawBitmapString(“time(ms):”+ofToString(timeofgesture, 0), 25, 0);
ofDrawBitmapString(“inccount(+1):”+ofToString(yourtestcount, 0), 0, 25);
ofPopMatrix();
ofPopStyle();

if (shake==0) {
ofBackground(0, 0, 0);
}
else {
ofBackground(255, 255, 255);
}

}

//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){
touchPos.set(touch.x,touch.y);
timeofgesture = ((touchPos.x/ofGetScreenWidth())*1500)+100;
yourtestcount = ((touchPos.y/ofGetScreenHeight())*25)+1;

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){
touchPos.set(touch.x,touch.y);
timeofgesture = ((touchPos.x/ofGetScreenWidth())*1500)+100;
yourtestcount = ((touchPos.y/ofGetScreenHeight())*25)+1;

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

testcount=0;
ofBackground(255, 0, 0);
}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

file :

http://linekernel.net/shake2.zip

Thanks a lot for sharing, I will check it out a bit later

rS

ok , i ve tried this over and over ,

(first of all , some of the code is useless like :

if (shake==0) {
if (inccount>=yourtestcount) {
inccount=0;
}
}

if (shake==1) {
if (inccount>=yourtestcount) {
inccount=0;
}
}

if (shake>1) {
shake=0;
inccount=0;
}

)
(i am using shake as a int because i want to increase it to change my colors for every shake value , that is why shake is not a bool , so i also need it to go up more than 1)

does anybody have a better idea ,
the problem encountered is that the inccount variable , if i remember well , seems to be in a loop , so as long as the accelerometer value is over the trigger , the inccount variable increase ,
but i want is to just increase only once

and i ve tryed it on a project i m working on right now , and it seems that if you run at a really low frame rate , depending on your timeofgesture and yourtestcount , it is impossible to change the shake state

so basically you re stuck however hard you shake …

i m just beginning in programing , so the answer didn t revealed itself to me yet

i was thinking maybe _it would be much easier to try to get the shake gesture from the orientation sequence _

what do you think about it

like

  
bool shake=false;  
  
if (orientation == 4){  
if (orientation == 5){  
if (orientation == 3){  
if (orientation == 5){  
if (orientation == 4){  
if (orientation == 5){  
if (orientation == 3){  
!shake;  
}}}}}}}  

(haven t tried yet)
(or you could use a int shake; if … shake++;)

maybe without the 3 times the orientations == 5 (it looks like a tricky one to get wile shaking)

btw
int portrait mode (home button near you)

orientation
5 = flat
3 = resting on the left side
4 = resting on the left side
2 = on the head (home button up and lock button down)
1 = facing you (home button down ,and lock button up)

and the secret one
(that is soooooo cool to make secret mode in your app)
i am so going to use that

6 = screen facing down

my bad
i realized that it s never going to work

because orientation cannot be == to 3 and 4 at the same time

so it would look more liek something like this

  
bool shake=fasle;  
int a=0;  
int b=0;  
  
if (orientation == 4){  
a=1;}  
if (orientation == 3){  
b=1;}  
if (a==b&&b==1){  
!shake;                            //or   shake=true;  
a=0;  
b=0;  
}  
  

tell me what you think

:slight_smile:

cheers

i understand the mistake i made

i am not supposed to increase variables depending on if the accelerometer value is over the triggers ,
i am supposed to change their state

then make a condition

i ll rewrite all this later …

  
  
if (accelerometer value x > trigger x)  
a = 1;  
if (accelerometer value -x > trigger -x && a==1)  
a =2;  
if (accelerometer value x > trigger x && a==2)  
a =3;  
if (accelerometer value -x > trigger -x && a==3)  
a =4;  
  
if (a == 4)  
shake++;  
a=0;  
  
  

ok here is the final working code

in the header

  
float sTreshold;  
float accx,accy;  
int trig;  
int startshake;  
int shake;  
int shakemaxnumber ;  
int timeofgesture;  

in the setup

  
sTreshold = 1.6;  
trig=0;  
shake=0;  
shakemaxnumber = 1;  
timeofgesture = 500;  
  

in the update

  
  
  
	accx=ofxAccelerometer.getForce().x;  
	accy=ofxAccelerometer.getForce().y;  
	  
	if(accx<-sTreshold && trig ==0){  
		trig = 1;  
		startshake = ofGetElapsedTimeMillis();  
	}  
	if(accx>sTreshold && trig == 1){  
		trig=2;  
	}  
	if(accx<-sTreshold && trig == 2){  
		trig=3;  
	}  
	if(accx>sTreshold && trig == 3){  
		trig=4;  
	}  
	if (trig==4) {  
		shake++;  
		trig=0;  
	}  
	if ((ofGetElapsedTimeMillis() - startshake) > timeofgesture) {  
		trig=0;  
	}  
	  
	  
	if (shake>shakemaxnumber) {  
		shake=0;  
	}  

it is working as a charm

please don t care about all the other experiments , this one is perfect
play around with it to get the feeling that fits to your app

i hope everybody can enjoy it

cheers

1 Like

Just taking LineKernel’s code (thank you!) and adding the y axis:

  
int testApp::DetectShake()  
{  
	static int trig = 0;  
	static int startshake = 0;  
	static int shake = 0;  
	  
	static int y_trig = 0;  
	static int y_startshake = 0;  
	  
	const int timeofgesture	= 500;  
	const float f_threshold	= 1.5;  
	float f_x,f_y;  
	  
	// detect x shake  
	f_x=ofxAccelerometer.getForce().x;  
	  
	// back  
	if(f_x < -f_threshold && trig == 0){  
		trig = 1;  
		startshake = ofGetElapsedTimeMillis();  
	}  
	// forth  
	if(f_x > f_threshold && trig == 1){  
		trig=2;  
	}  
	  
	// back   
	if(f_x < -f_threshold && trig == 2){  
		trig=3;  
	}  
	  
	// forth  
	if(f_x > f_threshold && trig == 3){  
		shake++;  
		trig=0;  
	}  
	if ((ofGetElapsedTimeMillis() - startshake) > timeofgesture) {  
		trig=0;  
	}  
	  
	// detect y shake  
	if(!shake){  
		f_y=ofxAccelerometer.getForce().y;   
  
		// back  
		if(f_y < -f_threshold && y_trig == 0){  
			y_trig = 1;  
			y_startshake = ofGetElapsedTimeMillis();  
		}  
		// forth  
		if(f_y > f_threshold && y_trig == 1){  
			y_trig=2;  
		}  
		  
		// back   
		if(f_y < -f_threshold && y_trig == 2){  
			y_trig=3;  
		}  
		  
		// forth  
		if(f_y > f_threshold && y_trig == 3){  
			shake++;  
			y_trig=0;  
		}  
		if ((ofGetElapsedTimeMillis() - y_startshake) > timeofgesture) {  
			y_trig=0;  
		}  
	}//if !x shake, test y shake  
	  
	int shaken = shake;  
		  
	shake = 0;  
	  
	return(shaken);  
}//end detect shake  
  

2 Likes