1 package edu.ucla.iBeaconNav;
3 import java.util.LinkedList;
4 import java.util.Queue;
6 import android.app.Notification;
7 import android.app.Activity;
8 import android.app.Service;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.hardware.Sensor;
12 import android.hardware.SensorEvent;
13 import android.hardware.SensorEventListener;
14 import android.hardware.SensorManager;
15 import android.os.Handler;
16 import android.os.IBinder;
17 import android.os.Message;
18 import android.os.SystemClock;
19 import android.widget.EditText;
20 import edu.ucla.iBeaconNav.R;
22 public class Sensors implements SensorEventListener
27 private SensorManager sensorManager;
28 private Sensor accSensor;
29 private Sensor grvSensor;
30 private Sensor magSensor;
31 private Sensor gyrSensor;
33 private boolean active;
34 private long lastTime_ms = 0;
35 private float snsInterval_ms = 0;
36 private long lastTime_ns = 0;
37 private long snsInterval_ns = 0;
41 private float[] accValues = new float[3];
42 private float[] magValues = new float[3];
43 private float[] gyrValues = new float[3];
44 private float[] rotationMatrix_R = new float[9];
45 private float[] rtMatrixStable_R = new float[9];
46 private float[] rotationMatrix_I = new float[9];
47 private float[] orientValues_rd = new float[3];
48 private float[] orientValues = new float[3];
49 private float[] accWorldCoord = {0,0,0};
50 private float[] gyrWorldCoord = {0,0,0};
53 /* Auxiliary Variables for Sensor Processing */
55 private final int cycle = 32;
57 private LinkedList<Float> accBuffers = new LinkedList<Float>();
58 private LinkedList<Float> magBuffers = new LinkedList<Float>();
59 private LinkedList<Float> gyrBuffers = new LinkedList<Float>();
60 private LinkedList<Float> orientBuffers = new LinkedList<Float>();
61 private LinkedList<Float> rtMtrxBuffers = new LinkedList<Float>();
62 private float[] data = new float[4];
63 private float[] accSum = {0,0,0};
64 private float[] accAvg = {0,0,0};
65 private float[] magSum = {0,0,0};
66 private float[] gyrSum = {0,0,0};
67 private float[] gyrOffset = {0,0,0};
68 private float[] orientSum = {0,0,0};
69 private float[] rtMtrxSum = {0,0,0,
72 private float[] accBuffer = {0,0,0};
73 private float[] magBuffer = {0,0,0};
74 private float[] orientBuffer= {0,0,0};
76 private int accCnt = 0;
77 private int magCnt = 0;
78 private int gyrCnt = 0;
79 private int orientCnt = 0;
80 private int rtMtrxCnt = 0;
82 private boolean ifGyrOffset = false;
83 private boolean ifGrvOffset = false;
84 private boolean ifStable = false;
86 private final float EPSILON = (float)0.01;
88 private float accValueTotal = 0;
89 private float calculatedGravity = SensorManager.GRAVITY_EARTH;
90 private float gravityRef = 0;
91 private float gyroscopeRef = 0;
92 private boolean ifSetGrvRef = false;
94 /* Position Related Stuff */
95 //private float startPosX = 0;
96 //private float startPos = 0;
97 private float currentPosX = 0;
98 private float currentPosY = 0;
99 // rotate around gravity direction, positive when counterclock-wise, initially align with user's first step
100 private float currentHeading = 0;
101 private float headingOffset = 0;
102 private float stepLength = (float)0.5; // in m
103 private int stepCount = 0;
104 private boolean stepStart = false;
107 /* Integrated positions */
108 private Vect position = new Vect();
109 private Quat rotation = new Quat();
112 private long time1hz = 0;
113 private Vect gyr1hz = new Vect();
116 public Sensors(Task task)
118 Util.debug("Sensors: constructor");
120 this.sensorManager = (SensorManager)task.getSystemService(Context.SENSOR_SERVICE);
123 this.accSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
124 this.grvSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
125 this.magSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
126 this.gyrSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
129 public void connect() {
130 // Connect sensor listeners
131 sensorManager.registerListener(this, accSensor, SensorManager.SENSOR_DELAY_FASTEST);
132 sensorManager.registerListener(this, grvSensor, SensorManager.SENSOR_DELAY_FASTEST);
133 sensorManager.registerListener(this, magSensor, SensorManager.SENSOR_DELAY_FASTEST);
134 sensorManager.registerListener(this, gyrSensor, SensorManager.SENSOR_DELAY_FASTEST);
137 public void disconnect() {
138 // Remove sensor listeners
139 sensorManager.unregisterListener(this, accSensor);
140 sensorManager.unregisterListener(this, grvSensor);
141 sensorManager.unregisterListener(this, magSensor);
142 sensorManager.unregisterListener(this, gyrSensor);
145 public void reset_heading() {
146 Util.debug("Sensors: handle - reset heading");
147 this.rotation = new Quat();
149 displayData(CMD.Data.HEADING);
152 public void reset_distance() {
153 Util.debug("Sensors: handle - reset distance");
156 displayData(CMD.Data.POSITION);
159 /* Sensor Event Listener functions */
161 public void onAccuracyChanged(Sensor sensor, int accuracy) {
162 Util.debug("Sensors: onAccuracyChanged");
166 public void onSensorChanged(SensorEvent event) {
167 switch(event.sensor.getType()){
168 case Sensor.TYPE_ACCELEROMETER:
170 System.arraycopy(event.values, 0, accValues, 0, 3);
171 //accCnt = everyAveragedBuffer(accBuffer, accValues, 3, accCnt, cycle, CMD.Data.ACC);
172 forwardAveragedBuffer(accBuffers, accSum, accAvg, accValues, 3, accCnt, cycle, CMD.Data.ACC);
173 toWorldCoordinates(accWorldCoord, accValues, rotationMatrix_R, accCnt, CMD.Data.WRDACC);
174 accValueTotal = accWorldCoord[2];
175 if (ifSetGrvRef && !ifGrvOffset && Math.abs((accValueTotal-gravityRef)/gravityRef)<0.05){
176 rtMatrixStable_R = rotationMatrix_R;
177 calculatedGravity = accValueTotal;
181 else if(!ifSetGrvRef && accCnt>400){
183 gravityRef = accValueTotal;
187 case Sensor.TYPE_MAGNETIC_FIELD:
189 System.arraycopy(event.values, 0, magValues, 0, 3);
190 //magCnt = everyAveragedBuffer(magBuffer, magValues, 3, magCnt, cycle, CMD.Data.MAG);
191 forwardAveragedBuffer(magBuffers, magSum, null, magValues, 3, magCnt, cycle, CMD.Data.MAG);
192 updateOrientation(); // This maybe useless
194 case Sensor.TYPE_GYROSCOPE:
196 float gyrTemp[] = new float[3];
197 long currentTime_ns = event.timestamp;
198 snsInterval_ns = currentTime_ns-lastTime_ns;
199 lastTime_ns = currentTime_ns;
201 int chkIntCnt = 8; //check Interval Count
202 if (gyrCnt%chkIntCnt==0){
203 //long currentTime_ms = SystemClock.elapsedRealtime();
204 //snsInterval_ms = (float)(currentTime_ms-lastTime_ms)/chkIntCnt;
206 ifStable = isStable(accBuffers, 3, cycle/2) && isStable(gyrBuffers, 3, cycle/2);
211 //lastTime_ms = SystemClock.elapsedRealtime();
212 //Util.debug("Interal in ms: "+Float.toString(snsInterval_ms));
215 System.arraycopy(event.values, 0, gyrValues, 0, 3);
216 System.arraycopy(gyrValues, 0, gyrTemp, 0, 3);
217 forwardAveragedBuffer(gyrBuffers, gyrSum, null, gyrValues, 3, gyrCnt, 2*cycle, CMD.Data.GYR);
218 System.arraycopy(gyrTemp, 0, gyrValues, 0, 3);
219 if (!ifGyrOffset && ifGrvOffset){
220 //Util.debug("[GYR1] Reset "+Float.toString(gyrValues[2]));
221 gyrOffset[0] = gyrValues[0]; //x
222 gyrOffset[1] = gyrValues[1]; //y
223 gyrOffset[2] = gyrValues[2]; //z
226 depleteOffset(gyrValues, gyrOffset, 3);
227 //cycleFloatArray(gyrValues, 3);
228 toWorldCoordinates(gyrWorldCoord, gyrValues, rtMatrixStable_R, gyrCnt, CMD.Data.WRDGYR);
230 float gyrZ = gyrWorldCoord[2];
231 //if (!ifStable && ifGyrOffset && Math.abs(gyrZ)>0.05){
233 //currentHeading+=gyrZ*snsInterval_ms/1000*180/Math.PI;
234 currentHeading += gyrZ*snsInterval_ns/1000000000*180/Math.PI;
236 displayData(CMD.Data.HEADING);
239 // Integrate rotations
240 Vect rpy = new Vect(event.values[1], event.values[0], -event.values[2]);
241 rpy.mul((double)snsInterval_ns/1E9);
242 Quat rot = new Quat(rpy.x, rpy.y, rpy.z);
243 this.rotation.mul(rot);
244 displayData(CMD.Data.ROTATION);
246 // Calculate 1 second gryo data
247 this.gyr1hz.add(rpy);
248 if (currentTime_ns > time1hz+1E9) {
249 displayData(CMD.Data.GYR1HZ);
250 this.gyr1hz.set(0, 0, 0);
251 time1hz = currentTime_ns;
261 /* Private helper functions */
262 private void cycleFloatArray(float[] array, int length){
263 float temp = array[length-1];
264 for(int i=1; i<length; i++){
265 array[i] = array[i-1];
270 private void depleteOffset(float[] values, float[] offset, int len){
271 for(int i=0; i<len; i++){
272 values[i]-=offset[i];
276 private boolean isStable(LinkedList<Float> buffer, int length, int cycle){
277 int len = buffer.size();
278 float[] avrg = new float[length];
279 float[] devSum = new float[length];
281 for(int i=0; i<length; i++){
283 for (int j=0; j<cycle; j++){
284 avrg[length-1-i]+=buffer.get(len-1-j*length-i);
286 avrg[length-1-i]/=cycle;
288 for (int i=0; i<length; i++){
290 for(int j=0; j<cycle; j++){
291 devSum[length-1-i]+=(float) Math.pow(buffer.get(len-1-j*length-i)-avrg[length-1-i],2);
293 devSum[length-1-i] = (float) Math.sqrt(devSum[length-1-i]/cycle);
296 for (int i=0; i<length; i++){
301 //Util.debug("[DEV] unStable");
302 displayData(CMD.Data.STABLE);
305 //Util.debug("[DEV] Stable");
306 displayData(CMD.Data.STABLE);
311 private void processSensorInfo(){
312 displayData(CMD.Data.STPCNT);
313 float epsl = (float)0.6;
317 if(accValueTotal-calculatedGravity>epsl){
320 currentPosX += stepLength*Math.sin(currentHeading);
321 currentPosY += stepLength*Math.cos(currentHeading);
322 displayData(CMD.Data.POSITION);
327 if (calculatedGravity-accValueTotal>epsl ){
333 private void updateOrientation(){
334 if (accValues == null || magValues == null){
337 float R[] = new float[9];
338 float I[] = new float[9];
340 success = SensorManager.getRotationMatrix(R, I, accValues, magValues);
344 rotationMatrix_R = R;
345 rotationMatrix_I = I;
346 SensorManager.getOrientation(rotationMatrix_R, orientValues_rd);
349 orientValues[0] = (float) (orientValues_rd[0]*180/Math.PI);
350 orientValues[1] = (float) (orientValues_rd[1]*180/Math.PI);
351 orientValues[2] = (float) (orientValues_rd[2]*180/Math.PI);
353 //orientCnt=everyAveragedBuffer(orientBuffer, orientValues, 3, orientCnt, 2*cycle, CMD.Data.ORIENT);
354 forwardAveragedBuffer(rtMtrxBuffers,rtMtrxSum, null, rotationMatrix_R, 9, rtMtrxCnt, 2*cycle, null);
355 forwardAveragedBuffer(orientBuffers,orientSum, null, orientValues, 3, orientCnt, 2*cycle, CMD.Data.ORIENT);
356 //displayData(CMD.Data.ORIENT);
359 private void toWorldCoordinates(float[] worldCoord, float[] values, float[] rotationMatrix, int cnt, CMD.Data cmd){
360 float result[] = new float[3];
361 result = new Matrix(rotationMatrix).multipleV(values);
362 worldCoord[0] = result[0];
363 worldCoord[1] = result[1];
364 worldCoord[2] = result[2];
370 private void displayData(CMD.Data dataType){
371 //Util.debug("Sensors: displayData");
372 float data[] = new float[4];
373 data[0] = dataType.ordinal();
376 data[1] = accValues[0];
377 data[2] = accValues[1];
378 data[3] = accValues[2];
381 data[1] = magValues[0];
382 data[2] = magValues[1];
383 data[3] = magValues[2];
386 data[1] = orientValues[0];
387 data[2] = orientValues[1];
388 data[3] = orientValues[2];
391 data[1] = accWorldCoord[0];
392 data[2] = accWorldCoord[1];
393 data[3] = accWorldCoord[2];
397 data[2] = calculatedGravity;
400 data[1] = currentPosX;
401 data[2] = currentPosY;
404 Vect rpy = new Vect();
405 this.rotation.get(rpy);
406 data[1] = (float)(rpy.x * (180/Math.PI));
407 data[2] = (float)(rpy.y * (180/Math.PI));
408 data[3] = (float)(rpy.z * (180/Math.PI));
411 data[1] = gyrValues[0];
412 data[2] = gyrValues[1];
413 data[3] = gyrValues[2];
416 data[1] = (float)(gyr1hz.x * (180/Math.PI) * 60 * 60);
417 data[2] = (float)(gyr1hz.y * (180/Math.PI) * 60 * 60);
418 data[3] = (float)(gyr1hz.z * (180/Math.PI) * 60 * 60);
421 data[1] = currentHeading;
424 data[1] = gyrWorldCoord[0];
427 data[1] = ifStable?1:0;
430 Util.debug("Bad Data Sending Command!");
434 this.task.tellMain(CMD.Response.SHOWDATA, data);
437 private int everyAveragedBuffer(float[] buffer, float[] values, int length, int cnt, int cycle, CMD.Data cmd){
438 for(int i=0; i<length; i++){
439 buffer[i]+=values[i];
443 for(int i=0; i<length; i++){
444 values[i] = buffer[i]/cycle;
452 private void forwardAveragedBuffer(LinkedList<Float> buffer, float[] sum, float[] avg,
453 float[] values, int length, int cnt, int cycle, CMD.Data cmd){
454 if (buffer==null||buffer.size()<cycle*length){
455 for(int i=0; i<length; i++){
456 buffer.addLast(values[i]);
458 values[i] = sum[i]/buffer.size();
462 float[] discarded = new float[length];
463 for(int i=0; i<length; i++){
464 discarded[i]= buffer.removeFirst();
465 buffer.addLast(values[i]);
466 sum[i]-=discarded[i];
468 values[i]=sum[i]/cycle;
472 for(int i=0; i<length; i++){
476 if (cnt%32==0 && cmd != null){
481 private void printMatrix(String s, Matrix m){
482 Util.debug("Sensor: ["+s+"] "+m.mValue[0]+" "+m.mValue[1]+" "+m.mValue[2]);
483 Util.debug("Sensor: " +m.mValue[3]+" "+m.mValue[4]+" "+m.mValue[5]);
484 Util.debug("Sensor: " +m.mValue[6]+" "+m.mValue[7]+" "+m.mValue[8]);
487 private void printVector(String s, float[] v){
488 Util.debug("Sensor: ["+s+"] "+v[0]+" "+v[1]+" "+v[2]);