2013-03-26 2 views
2

휴대 전화의 가속도를 40ms마다 (25Hz에서) 기록하는 앱을 작성 중입니다. 이 프레임 속도는 평균으로 유지 될 수 있지만 때로는 시간 프레임 사이에서 5 분의 1 ~ 50 분의 1 초의 지연이 발생합니다. 나는 이것이 왜 일어나는지 궁금합니다. 여기가속도계 로거 : 프레임 간의 가끔 지연 발생

당신은 당신이 그들이 자주 발생하는 것을 볼 수있는 지연의 그래프를 가지고 :

  • 을 :

    여기

    occasional long delays between accelerometer measurements

    내가 (나쁜 될 수있는) 일을하고 무엇을 액티비티는 가속도계 로거 클래스 (싱글 톤, 순수 자바, 안드로이드 클래스 확장 없음)를 가리 킵니다.

  • 가속도계 로거 싱글 톤은 백그라운드에서 계속 로그인합니다.
  • 가속도계 로거는 모든 로그를 sqlite db에 직접 저장합니다.
  • 나는 백그라운드에서 GPS 데이터도 기록하고있다.
  • DAO (데이터 액세스 개체)는 모든 로그를 LinkedBlockingQueue에 할당하고 별도의 스레드에 저장합니다. 여기

내가 문제가 될 것 같아요 내용은 다음과 같습니다

  • 어쩌면 내가 더 라이프 사이클 메소드를 구현하거나, 아니면 우선 순위를 설정합니다 (accererometer 로거 이익 우선 순위 있도록, 특정 안드로이드 클래스를 확장해야 어딘가에).
  • System.currentTimeMills() 대신 event.timestamp을 사용할 수 있습니다. (좀 센서는 서로 다른 시간대를 가지고, 내가 System.currentTimeMillis()를 사용하는 이유 먹으 렴하지만, 필요한 경우 I 스위치 것,이 일을하지 않으려는 것입니다.)

당신이 나 제안 어떤 경험이 있나요 어디에 문제가 수 아마 거짓말?

@SuppressLint("NewApi") 
public class AccelerometerLogger implements SensorEventListener { 

    private static AccelerometerLogger singleton = new AccelerometerLogger(); 

    private LoggerDao loggerDao; 

    private SensorManager sensorManager; 

    private Sensor accelerometer; 

    private double acceleorometerRate = 25; // Hz 

    int accelerometerDelayMicroseconds = (int) (Math.round(((1/this.acceleorometerRate)*1000000.0))); 

    private AccelerometerLogger() 
    { 
     this.loggerDao = LoggerDao.getInstance(); 
    } 

    public static AccelerometerLogger getInstance() 
    { 
     return singleton; 
    } 

    public void start(Context context) 
    { 
     this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 
     this.accelerometer = this.sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 

     int accelerometerMinDelay = this.accelerometer.getMinDelay(); 

     //Log.d("lggr-r", "desired delay: "+this.accelerometerDelayMicroseconds+" microseconds"); 
     //Log.d("lggr-r", "provided min delay: "+accelerometerMinDelay+" microseconds"); 

     if(accelerometerMinDelay < this.accelerometerDelayMicroseconds) 
     { 
      this.sensorManager.registerListener(this, this.accelerometer, this.accelerometerDelayMicroseconds); 
      //Log.d("lggr-r", "listener registered for desired rate: "+this.acceleorometerRate+"Hz (delay of "+this.accelerometerDelayMicroseconds+" microseconds)."); 
     } 
     else if(accelerometerMinDelay==0) 
     {   
      this.sensorManager.registerListener(this, this.accelerometer, SensorManager.SENSOR_DELAY_FASTEST); 
      // Log.d("lggr-r", "listener registered for streaming api. only changes will be notified (interrupt)."); 
     } 
     else 
     { 
      int providedRate = (int) Math.round(1/(accelerometerMinDelay/1000000.0)); 
      this.sensorManager.registerListener(this, this.accelerometer, SensorManager.SENSOR_DELAY_FASTEST); 
      // Log.d("lggr-r", "can't read at the desired rate ("+this.acceleorometerRate+"Hz), app will read at "+providedRate+"Hz instead (delay of "+accelerometerMinDelay+" microseconds)."); 
     } 
    } 

    public void stop() 
    { 
     this.sensorManager.unregisterListener(this); 
    } 

    @Override 
    public void onAccuracyChanged(Sensor sensor, int accuracy) 
    { 
     // String name = sensor.getName(); 
     // Log.d("lggr", "the accurracy of "+name+" changed to "+accuracy+"."); 
    } 

    @Override 
    public void onSensorChanged(SensorEvent event) 
    { 
     // lazy load loggerDao (TODO: fix all of those) 
     if(this.loggerDao == null) 
     { 
      this.loggerDao = LoggerDao.getInstance(); 
     } 


     String values = ""; 
     for(float value : event.values) values += value+","; 
     values = values.substring(0,values.length()-2); 

     // long timestamp = System.currentTimeMillis(); 
     // Log.d("lggr", "acc = {time:"+timestamp+", data: ["+values+"]}"); 

     AccelerometerSample accelerometerSample = new AccelerometerSample(); 
     accelerometerSample.setTimestamp(System.currentTimeMillis()); 
     accelerometerSample.setValues(event.values); 

     this.loggerDao.save(accelerometerSample); 
    } 

} 

은 분명히 문제가 단지 삼성 갤럭시 SIII 미니에 발생합니다

여기 내 코드입니다. 필자는 삼성 갤럭시 SII (맞춤 ROM)로 테스트했으며 지연 시간은 항상 0.04 초 (0.005 ~ 0.12 초)였습니다.

삼성 갤럭시 SIII 미니에서 이러한 현상이 발생하는 이유는 무엇입니까?

업데이트 : event.timestamp 크게 지연을 개선 사용할 목적의

벤 Voigts 대답. 아직도, 나는 때때로 더 긴 지연을 경험하고있다. 내가 그들을 어떻게 더 향상시킬 수 있는지 아십니까?

enter image description here

+0

센서 관리자 코드 – nayab

+0

을 게시 할 수 있습니까? 방금 추가했습니다. – ndrizza

+0

로깅 때문일 수 있습니다. 스레드에 데이터를 기록하십시오. –

답변

4

당신은 절대적으로 event.timestamp를 사용한다. 현지 시간을 원한다면 첫 번째 이벤트에서 event.timestampSystem.currentTimeMills() 사이의 조정 계수를 계산하고 후속 샘플에 동일한 조정을 적용하십시오.

샘플에 연결된 하드웨어 제공 시간 소인의 전체 요점은 스레드 스케줄링 지연으로 엉망이되지 않는다는 것입니다.

+0

지연이 훨씬 짧아졌습니다. 그들은 위의 예 에서처럼 여전히 스파이크를 보이고 있으며 0.18 초 (0.04 초)에 이르기까지 여전히 규칙적인 큰 지연이 있지만 모자는 이미 훨씬 더 좋습니다. 이 문제를 어떻게 개선 할 수 있을지 알고 있습니까? – ndrizza

+0

@ndrizza : 하드웨어에는 아마도 소프트웨어가 수집하기 위해 기다리는 동안 제한된 수의 샘플을 저장할 수있는 FIFO 버퍼가있을 것입니다. 일반적으로 FIFO가 거의 찼을 때 인터럽트를 처리하고 샘플을 시스템 메모리의 더 큰 버퍼로 옮기는 것은 드라이버의 임무입니다. 다중 초 건너 뛰기가 표시되면 드라이버 버퍼가 처리 할 수있는 것 이상일 수 있으므로 스레드의 우선 순위를 높이면 버퍼 오버플로가 발생하기 전에 샘플을 읽을 수 있습니다. –

+0

특정 장치 또는 ROM에서 문제가 악화 되었기 때문에 하드웨어 FIFO가 작거나 드라이버가 데이터를 버퍼링하지 못하거나 두 가지 모두 일 수 있습니다. 성능이 좋지 않은 장치에서 다른 ROM을 시험해보고 문제가 하드웨어인지 소프트웨어인지 확인하십시오 (물론 다른 ROM이 반드시 다른 드라이버 버전을 사용하지는 않습니다). –

0

Ben Voigt가 말했듯이 센서 측정을위한 정확한 타임 스탬프를 얻으려면 event.timestamp를 사용해야합니다. 여기에 자신을 사용하고 나를 위해 일한 코드 샘플이 있습니다.

@Override 
public void onSensorChanged(SensorEvent event) { 
    if (sampleCounter == 0) { 
     long miliTime = System.currentTimeMillis(); 

     long nanoTime = event.timestamp; 

     timeDiff = miliTime - nanoTime/1000000; 
     log.info("Synchornizing sensor clock. Current time= " + miliTime 
       + ", difference between clocks = " + timeDiff); 
    } 

    float x = event.values[0]; 
    float y = event.values[1]; 
    float z = event.values[2]; 
    long ts = event.timestamp/1000000 + timeDiff; 

    //Do your stuff 

    sampleCounter++; 
} 
관련 문제