/// <summary>
        /// Adds the given label to the <see cref="RotationQueues"/> dictionary if it is not present.
        /// </summary>
        /// <param name="label">The label to be added.</param>
        protected virtual void UpdateRotationDictionaries(string label)
        {
            lock (RotationLocks)
            {
                if (ContainsRotation(label))
                {
                    return;
                }

                RotationLocks.Add(label, new object());
                RotationQueues.Add(label, new Queue <UdpRotation>());
            }
        }
        /// <summary>
        /// Returns the Quaternion representing the rotation of the given label. Can be redefined in children classes to change the smoothing logic. Current smoothing logic is as follows:<para><example> <see cref="GenericDeviceController.Smoothing"/> ? <see cref="Smoother.Average(Queue{Quaternion})"/> : queue.LastOrDefault()</example></para>
        /// </summary>
        /// <param name="label">The label to get the rotation.</param>
        /// <returns>A Quaternion representing the rotation of the given label.</returns>
        public virtual Quaternion GetRotation(string label)
        {
            if (RotationLocks.ContainsKey(label) == false)
            {
                return(Quaternion.identity);
            }

            var @lock = RotationLocks[label];
            var queue = RotationQueues[label];

            lock (@lock)
            {
                return(Controller.Smoothing ? Smoother.Average(queue) : queue.Count == 0 ? Quaternion.identity : queue.Last().Rotation);
            }
        }
        /// <summary>
        /// Removes all data from the dictionaries that are older than <see cref="GenericDeviceController.TimeToLive"/>
        /// </summary>
        private void CleanDictionaries()
        {
            //sleeps in the beggining to give time for the software to stabilize
            //Thread.Sleep(2000);

            while (true)
            {
                //Debug.Log("Cleaning Dictionary");
                var keysToKill = new List <string>();

                //Debug.Log("TimeToLive" + Controller.TimeToLive);

                #region floats

                foreach (var floatQueueEntry in FloatQueues)
                {
                    if (floatQueueEntry.Key.Contains("max_"))
                    {
                        continue;
                    }

                    lock (FloatLocks[floatQueueEntry.Key])
                    {
                        while (floatQueueEntry.Value.Count != 0 && (DateTime.Now - floatQueueEntry.Value.Peek().LastTimeUpdated).TotalSeconds >= Controller.TimeToLive)
                        {
                            floatQueueEntry.Value.Dequeue();
                        }

                        if (floatQueueEntry.Value.Count == 0)
                        {
                            keysToKill.Add(floatQueueEntry.Key);
                        }
                    }
                }

                foreach (var key in keysToKill)
                {
                    FloatQueues.Remove(key);
                    FloatLocks.Remove(key);
                }

                //Debug.Log("Float count: " + FloatQueues.Count);

                #endregion floats

                keysToKill.Clear();

                #region positions

                foreach (var positionQueueEntry in PositionQueues)
                {
                    lock (PositionLocks[positionQueueEntry.Key])
                    {
                        while (positionQueueEntry.Value.Count != 0 && (DateTime.Now - positionQueueEntry.Value.Peek().LastTimeUpdated).TotalSeconds >= Controller.TimeToLive)
                        {
                            positionQueueEntry.Value.Dequeue();
                        }

                        if (positionQueueEntry.Value.Count == 0)
                        {
                            keysToKill.Add(positionQueueEntry.Key);
                        }
                    }
                }

                foreach (var key in keysToKill)
                {
                    PositionQueues.Remove(key);
                    PositionLocks.Remove(key);
                }
                //Debug.Log("Position count: " + PositionQueues.Count);

                #endregion positions

                keysToKill.Clear();

                #region rotations

                foreach (var rotationsQueueEntry in RotationQueues)
                {
                    lock (RotationLocks[rotationsQueueEntry.Key])
                    {
                        while (rotationsQueueEntry.Value.Count != 0 && (DateTime.Now - rotationsQueueEntry.Value.Peek().LastTimeUpdated).TotalSeconds >= Controller.TimeToLive)
                        {
                            rotationsQueueEntry.Value.Dequeue();
                        }

                        if (rotationsQueueEntry.Value.Count == 0)
                        {
                            keysToKill.Add(rotationsQueueEntry.Key);
                        }
                    }
                }

                foreach (var key in keysToKill)
                {
                    RotationQueues.Remove(key);
                    RotationLocks.Remove(key);
                }
                //Debug.Log("Rotation count: " + RotationQueues.Count);

                #endregion rotations

                keysToKill.Clear();

                #region samples

                foreach (var sampleQueueEntry in SampleList)
                {
                    lock (SampleLocks[sampleQueueEntry.Key])
                    {
                        if ((DateTime.Now - sampleQueueEntry.Value.LastTimeUpdated).TotalSeconds >= Controller.TimeToLive)
                        {
                            keysToKill.Add(sampleQueueEntry.Key);
                        }
                    }
                }

                foreach (var key in keysToKill)
                {
                    SampleList.Remove(key);
                    SampleLocks.Remove(key);
                }
                //Debug.Log("Samples count: " + SampleList.Count);

                #endregion samples

                keysToKill.Clear();

                #region booleans

                foreach (var booleanQueueEntry in BooleanProperties)
                {
                    lock (BooleanLocks[booleanQueueEntry.Key])
                    {
                        if ((DateTime.Now - booleanQueueEntry.Value.LastTimeUpdated).TotalSeconds >= Controller.TimeToLive)
                        {
                            keysToKill.Add(booleanQueueEntry.Key);
                        }
                    }
                }

                foreach (var key in keysToKill)
                {
                    BooleanProperties.Remove(key);
                    BooleanLocks.Remove(key);
                }
                //Debug.Log("Boolean count: " + BooleanProperties.Count);

                #endregion booleans

                //Debug.Log("cleaning dictionaries");

                Thread.Sleep(50);
            }
        }