MsgSynchronizer
Lorsque les caméras renvoient des données, elles ne le font pas de façon groupée. Ainsi, si l'on récupère sur une caméra la vidéo et les résultats d'un réseau de neurones appliqué à la vidéo, on ne recevra probablement pas en même temps la frame actuelle avec les résultats correspondant. Il faut donc implémenter une solution pour regrouper les informations liées entres elles du côté du programme qui les reçoit.
Pour aider à synchroniser les informations, les caméras OAK-D transmettent avec presque toutes les données un numéro de séquence. Ce numéro est unique à chaque passe du pipeline de la caméra, par exemple à chaque nouvelle image de la caméra, et toutes les informations qui en découleront posséderont elles aussi ce même numéro de séquence. On peut donc classer les informations reçues par leur numéro de séquence pour les synchroniser.
Cependant, toutes les données envoyées par la caméra ne possèdent pas de numéro de séquence : c'est le cas des messages provenant de l'IMU de la caméra, qui envoie ses informations de façon totalement indépendante. On se base donc sur une autre donnée pour synchroniser ses messages : un timestamp aussi fournit en parallèle du numéro de séquence, correspondant à l'uptime de la caméra au moment de la capture de l'information.
En utilisant ces deux données, on peut réaliser un système de synchronisation des données récoltées depuis la caméra.
Opérations disponibles
Afin d'être le plus flexible possible, un certain nombre d'opérations sont disponibles sur le MsgSynchronizer.
Tout d'abord, l'ajout d'un nouveau message provenant de la caméra se fait via une méthode add et en indiquant le type de message. En fonction du type de message à ajouter, le synchroniseur va le traiter différemment, et va essayer de le synchroniser avec d'autres messages déjà existants dans la file interne, ou de l'ajouter à part si il n'est pas synchronisable avec les autres messages déjà présents.
En interne, l'objet fonctionne avec une file de Message, dans lesquels on regroupe les différents paquets provenant de la caméra en fonction du numéro de séquence et du timestamp, et en les traitant pour ne récupérer que les informations souhaitées. Cette file à été implémentée à la main pour permettre plus de flexibilité sur les actions réalisées dessus. L'implémentation n'est donc pas optimale, mais est suffisamment rapide pour recevoir en temps réel les données des caméras.
Ensuite, on veut récupérer depuis la file les données synchronisées. Pour cela, on va "filtrer la file" selon les données dont on a besoin. On vérifie d'abord que la file possède au moins un message qui possède au moins une des données (resp. toutes les données) dont on a besoin avec la méthode has_any (resp. has_all). Puis, on peut récupérer le message le plus vieux avec au moins une des données (resp. toutes les données) dont on a besoin avec la méthode next_with_any (resp. next_with_all). De même, on peut récupérer le message le plus récent selon nos critères avec les méthodes last_with_any et last_with_all.
Pour la vérification de la présence des données, on peut soit vérifier qu'un message possède toutes les données nécessaires, soit qu'un message possède au moins une partie des données souhaitées.
De même pour la récupération des données, on peut récupérer le prochain message ou le message le plus récent possédant tout ou une partie des données souhaitées.
Lorsqu'un message est récupéré, tous les messages plus anciens (c.a.d de numéro de séquence plus petit) sont supprimés de la file, il faut donc faire attention à la façon dont on récupère les données (traiter toutes les données récupérées vs. ne traiter que les données les plus récentes).
Enfin, on peut aussi récupérer directement les dernières données reçues de chaque types de données, ainsi que la fréquence à laquelle on reçoit ces données.
Attention : les dernières données récupérées ne sont pas synchronisées entre elles, il s'agit simplement de la dernière donnée du type qui a été reçu par le système.
Fonctionnement en temps réel
Lorsque l'on veut récupérer et traiter des données en temps réel, on veut souvent récupérer les dernières données disponibles dans la file. Si toutes ces données sont tout le temps présentes ensemble, on peut simplement filtrer par message possédant toutes les données souhaitées. Cependant, si toutes les données souhaitées ne sont pas tout le temps présentes ensembles, ou que l'on ne souhaite pas forcément les traiter ensemble, il arrive assez fréquemment qu'une donnée arrive plus tard qu'une autre dans la file, même si elles possèdent le même numéro de séquence. Mais si l'on récupère simplement le dernier message possédant au moins une des données souhaitées, il va arriver une situation où l'on va recevoir des données pour lesquelles d'autres données ayant le même numéro de séquence ont déjà été récupérées et traitées par le reste du système. Pour éviter des incohérences sur la chronologie des données récupérées, les données provenant du "passé" (c'est-à-dire qui correspondent à des messages dont le numéro de séquence à déjà été traité) sont automatiquement rejetées.

Pour résoudre ce problème, on introduit artificiellement une latence dans la file de messages. Par défaut, cette latence est de 2 messages, et n'est utilisé que lors de la vérification de la présence d'un message avec les données souhaitées. Ainsi, par défaut les 2 derniers messages de la file seront ignorés de la vérification, ce qui va laisser le temps aux paquets d'arriver avant que les messages ne puissent être considérés comme récupérables.