2015-05-09 13 views
8

Sto riscontrando discrepanze significative tra le pose dal callback onPoseAvailable() e Tango.getPoseAtTime(). Ho scritto un programma di test in cui nel onPoseAvailable() ho registrato la posa consegnata e ho utilizzato getPoseAtTime() per richiedere la posa utilizzando il timestamp da 2 richiamate in precedenza. KEY_BOOLEAN_SMOOTH_POSE è configurato false. Ecco il codice che lo fa (la variabile timestamps_ membro è un LinkedList<Double>):Discrepanze Project Tango onPoseAvailable() e getPoseAtTime()

@Override 
public void onPoseAvailable(TangoPoseData poseData) { 
    if (poseData != null && poseData.statusCode == TangoPoseData.POSE_VALID) { 
     Log.v("bug", 
     String.format("onPoseAvailable t: %f, base: %d, target %d, p: (%f, %f, %f)", 
      poseData.timestamp, 
      poseData.baseFrame, 
      poseData.targetFrame, 
      poseData.translation[0], poseData.translation[1], poseData.translation[2])); 
     timestamps_.add(poseData.timestamp); 
     if (timestamps_.size() > 3) 
     timestamps_.remove(); 
    } 

    if (timestamps_.isEmpty()) 
     return; 

    TangoCoordinateFramePair framePair = new TangoCoordinateFramePair(
     TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE, 
     TangoPoseData.COORDINATE_FRAME_DEVICE); 
    poseData = tango_.getPoseAtTime(timestamps_.getFirst(), framePair); 
    if (poseData != null && poseData.statusCode == TangoPoseData.POSE_VALID) { 
     Log.v("bug", 
     String.format("getPoseAtTime t: %f, base: %d, target %d, p: (%f, %f, %f)", 
      poseData.timestamp, 
      poseData.baseFrame, 
      poseData.targetFrame, 
      poseData.translation[0], poseData.translation[1], poseData.translation[2])); 
    } 
} 

Ecco un estratto da un registro effettivo (ho deinterleaved le chiamate registrate per chiarezza):

onPoseAvailable t: 2732.762486, base: 2, target 4, p: (0.280245, 0.412468, 0.562201) 
onPoseAvailable t: 2732.802553, base: 2, target 4, p: (0.296951, 0.420919, 0.599938) 
onPoseAvailable t: 2732.852638, base: 2, target 4, p: (0.317444, 0.429809, 0.646445) 
onPoseAvailable t: 2732.882689, base: 2, target 4, p: (0.330845, 0.434106, 0.676810) 
onPoseAvailable t: 2732.932774, base: 2, target 4, p: (0.350995, 0.439777, 0.723639) 
onPoseAvailable t: 2732.962825, base: 2, target 4, p: (0.363319, 0.442731, 0.754508) 
onPoseAvailable t: 2732.992875, base: 2, target 4, p: (0.373911, 0.445289, 0.784786) 
onPoseAvailable t: 2733.032943, base: 2, target 4, p: (0.387709, 0.448182, 0.822682) 
onPoseAvailable t: 2733.062994, base: 2, target 4, p: (0.398502, 0.450481, 0.852662) 
onPoseAvailable t: 2733.073011, base: 2, target 4, p: (0.401869, 0.451084, 0.862530) 
onPoseAvailable t: 2733.103062, base: 2, target 4, p: (0.411136, 0.452486, 0.890441) 

getPoseAtTime t: 2732.712401, base: 2, target 4, p: (0.269301, 0.410911, 0.549182) 
getPoseAtTime t: 2732.732435, base: 2, target 4, p: (0.277217, 0.415130, 0.567040) 
getPoseAtTime t: 2732.762486, base: 2, target 4, p: (0.288928, 0.421914, 0.595162) 
getPoseAtTime t: 2732.802553, base: 2, target 4, p: (0.305241, 0.429648, 0.632158) 
getPoseAtTime t: 2732.852638, base: 2, target 4, p: (0.324359, 0.437655, 0.680300) 
getPoseAtTime t: 2732.882689, base: 2, target 4, p: (0.332997, 0.442538, 0.712727) 
getPoseAtTime t: 2732.932774, base: 2, target 4, p: (0.353665, 0.447269, 0.759725) 
getPoseAtTime t: 2732.962825, base: 2, target 4, p: (0.369174, 0.451645, 0.790263) 
getPoseAtTime t: 2732.992875, base: 2, target 4, p: (0.382584, 0.454754, 0.819555) 
getPoseAtTime t: 2733.032943, base: 2, target 4, p: (0.396857, 0.456922, 0.856626) 
getPoseAtTime t: 2733.062994, base: 2, target 4, p: (0.409672, 0.460060, 0.888748) 

Dai un'occhiata all'ultimo dato getPoseAtTime(), con timestamp 2733.062994. Si noti che i suoi valori di posizione non corrispondono alla posa da onPoseAvailable con lo stesso timestamp. Qualcosa non è giusto qui.

Ho preso in considerazione il fatto che una posizione di posa spline non avrebbe necessariamente bisogno di passare attraverso i punti di controllo, ma non penso che sia una spiegazione accettabile. Prima di tutto non ha molto senso avere un'API che fornisca valori diversi per la stessa misura. Ma in più i numeri reali non sostengono quella congettura.

Controllare il valore di getPoseAtTime() Y, 0,460060. Questo è al di fuori dell'intervallo Y di tutti i valori di onPoseAvailable() Y, sia prima che dopo (sull'intero registro di fatto). Nessun modello di interpolazione ragionevole può produrre questo valore.

Immagino che la domanda sia: cosa sta succedendo qui? Le pose sono incoerenti quindi almeno una di esse è sbagliata (se non entrambe). La mia ipotesi sarebbe che il onPoseAvailable() è più probabile che sia corretto.

Qui è un grafico della posizione Y in funzione del tempo dei due posa metodi (rilascio Nash) con il fermo tablet nel dock:

enter image description here

La linea blu è la onPoseAvailable() callback e la linea rossa è il polling getPoseAtTime(). Questi risultati sono piuttosto strani. Se le pose dovessero essere diverse, mi aspetto che il valore di polling sia più agevole perché potrebbe essere filtrato utilizzando i contributi dei campioni prima e dopo il tempo di polling, mentre il valore di callback non sarà filtrato o filtrato usando solo campioni. Ma questo non è ciò che vediamo - il valore del sondaggio appare molto più rumoroso.

Ecco un grafico simile catturato mentre spostavo il tablet su e giù. Il valore del polling ha ancora più alte frequenze e i due segnali non seguono particolarmente da vicino.

enter image description here

+0

C'è qualcosa di nuovo da aggiungere? – bashbug

risposta

4

Grazie rhashimoto per la segnalazione!

EDIT

devo modificare il mio post precedente. Ho affermato di avere una deriva maggiore durante l'utilizzo di GetPoseAtTime anziché la posa del callback OnPoseAvailable.

È proprio il contrario. Ottengo risultati molto migliori con GetPoseAtTime.

Ho fatto una scansione ruotando di 360 ° sulla mia sedia. Ho iniziato e mi sono fermato alla mia scrivania come puoi vedere nella foto.

inizio e la fine del ciclo di scansione (clic su di esso per una maggiore risoluzione) start and end of the scanning cycle

Le nuvole di punti di cui sopra uso pone GetPoseAtTime e le nuvole di punti al di sotto utilizzo pongono dal callback OnPoseAvailable. Entrambi catturati allo stesso tempo. La deriva con GetPoseAtTime è marginale, ma con il callback OnPoseAvailable davvero enorme.

Quello che ho scoperto finora è che GetPoseAtTime utilizza un grafico di posa e corregge le pose se viene rilevata una chiusura del ciclo see this article. Ho provato se i risultati miglioravano, se accedo immediatamente alla posa con una nuvola di punti disponibile o solo alla fine mentre sto unendo tutte le nuvole di punti.

E infatti il ​​risultato è decisamente migliore. Così la mia esperienza finora è:

OnPoseAvailabe callback < GetPoseAtTime subito con una nuvola di punti disponibili < GetPoseAtTime al termine della scansione