diff --git a/launch/visualiser.launch b/launch/visualiser.launch
index d0e9d06ed6f1fb2dfa77190f7fb8f09a4b5c490e..98234399c28a4e49e54c71a0b4308d933ebf24c7 100644
--- a/launch/visualiser.launch
+++ b/launch/visualiser.launch
@@ -1,13 +1,6 @@
 <launch>
     <node pkg="visualising" type="visualiser" name="visualiser">
-        <!-- frequency at which the watchdog aggregates metrics and domains -->
-        <param name="/wdg_freq" value="0.2" type="double" />
-        <!--
-             frequency at which the visualisation of the robot state is updated,
-             must be lesser than 0.2 and only is relevant for the emotion
-             visualisation
-        -->
-        <param name="/vis_freq" value="0.2" type="double" />
+        <param name="/vis_freq" value="0.1" type="double" />
 
         <param name="/arduino_port" value="/dev/ttyUSB0" type="str" />
         <param name="/arduino_baud" value="57600" type="int" />
@@ -15,7 +8,7 @@
         <!-- set visualisation strategy -->
         <!-- 1: emotion  -->
         <!-- 2: abstract -->
-        <param name="/visualisation_strategy" value="1" type="int" />
+        <param name="/visualisation_strategy" value="2" type="int" />
 
         <!-- example of how to set an aggregation strategy for a metric                                 -->
         <!-- strategy 1 :                     Take the highest error level of any metric in a domain.   -->
@@ -34,6 +27,6 @@
         <!-- strategy 1 :                    Take the highest error level of any domain.   -->
         <!-- strategy 2 :                    Take the lowes error level of any domain.     -->
         <!-- strategy 0 | default strategy : Take the average error level of every domain. -->
-        <param name="aggregation_strategy_domains" value="2" type="int" />
+        <param name="aggregation_strategy_domains" value="0" type="int" />
     </node>
 </launch>
diff --git a/scripts/abstract.py b/scripts/abstract.py
index 550b6f4f4108b5b1bdf2edbfd6f3c9bf5fd6804b..0675836a59763e5b30a34d64a6e20f774700e0f4 100755
--- a/scripts/abstract.py
+++ b/scripts/abstract.py
@@ -1,14 +1,11 @@
 #!/usr/bin/env python
 
 import argparse
-import time
 
-
-from visualising.expression.tool import Tool
-from visualising.expression.abstract import Abstract
+from visualising.communication.animation.animation import Animation
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.illustration.animation import Animation
-from visualising.communication.channel.connection import Connection
+from visualising.expression.abstract import Abstract
 
 parser = argparse.ArgumentParser(description="script to play an animation")
 parser.add_argument("-p", "--port", help="port to which the Arduino is connected", type=str, default="/dev/ttyUSB0")
@@ -20,17 +17,13 @@ port = args["port"]
 baud = args["baud"]
 delay = args["time"]
 
-color = [10, 10, 10]
-
 arduino = Arduino(Connection(port, baud))
 
-states = [0, 1.0, 0.10, 0.15, 0.20, 0.85, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65,
-          0.70, 0.75, 0.80, 0.25, 0.90, 0.05, 0.95]
-text = ["A", "CPU", "A", "A", "A", "ARM", "A", "A", "A", "A", "A", "A", "A", "A",
+name = ["A", "CPU", "A", "A", "A", "ARM", "A", "A", "A", "A", "A", "A", "A", "A",
         "A", "A", "A", "A", "RAM", "A", "CAMERA"]
-ensemble = Abstract.cycle(states)
 
-time.sleep(10)
+error = [0, 1.0, 0.10, 0.15, 0.20, 0.85, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65,
+         0.70, 0.75, 0.80, 0.25, 0.90, 0.05, 0.95]
 
-arduino.stream_animations(Abstract.highlight(ensemble, states, text, 4))
-# arduino.stream_animation(Animation([ensemble], 50, 2))
+ensemble = Abstract.cycle(error)
+arduino.stream_animations(Abstract.highlight(ensemble, name, error, 4))
diff --git a/scripts/emotion.py b/scripts/emotion.py
index 9c9ead4df7616ff2b7b2f3e76df8e3245f0407cd..384ddcdb329a954259685140365d9083bfe4c797 100755
--- a/scripts/emotion.py
+++ b/scripts/emotion.py
@@ -2,16 +2,17 @@
 
 import argparse
 
-from visualising.expression.tool import Tool
-from visualising.expression.emotion import Emotion
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.animation import Animation
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.channel.connection import Connection
-from visualising.communication.illustration.color.rgb import RGB
+from visualising.expression.library.raw import Raw
+from visualising.expression.emotion import Emotion
 
 parser = argparse.ArgumentParser(description="script to play an animation")
 parser.add_argument("-p", "--port", help="port to which the Arduino is connected", type=str, default="/dev/ttyUSB0")
 parser.add_argument("-b", "--baud", help="baud rate of the connection", type=int, default=57600)
-parser.add_argument("-f", "--file", help="file in the library directory to be played", type=str, required=True)
+parser.add_argument("-f", "--file", help="emotion to be played", type=str, required=True)
 parser.add_argument("-t", "--time", help="time between ensembles", type=int, default=100)
 args = vars(parser.parse_args())
 
@@ -20,16 +21,10 @@ baud = args["baud"]
 file = args["file"]
 time = args["time"]
 
-# 50, 10, 10
-
 color = RGB(10, 0, 0)
-print(color.r)
-print(color.g)
-print(color.b)
 
 arduino = Arduino(Connection(port, baud))
-
-ensembles = Tool.create_ensembles(file, "emotion")
-
-arduino.stream_animation(Emotion.build_emotion_parallel(ensembles[0], time, color))
+ensembles = Raw.to_ensemble_list(file, "emotion")
+animation = Animation(Emotion.build_parallel(ensembles[0], color), time, 1)
+arduino.stream_animation(animation)
 
diff --git a/scripts/play_animation.py b/scripts/play_animation.py
index fffbd223678ec980152aec71bff2963e03fca51d..99921bfe6d243bcd51878b8ff5df607d0d769205 100755
--- a/scripts/play_animation.py
+++ b/scripts/play_animation.py
@@ -2,25 +2,26 @@
 
 import argparse
 
-from visualising.expression.tool import Tool
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.channel.connection import Connection
+from visualising.expression.library.raw import Raw
 
 parser = argparse.ArgumentParser(description="script to play an animation")
 parser.add_argument("-p", "--port", help="port to which the Arduino is connected", type=str, default="/dev/ttyUSB0")
 parser.add_argument("-b", "--baud", help="baud rate of the connection", type=int, default=57600)
-parser.add_argument("-f", "--file", help="file in the library directory to be played", type=str, required=True)
+parser.add_argument("-f", "--file", help="file to be played", type=str, required=True)
+parser.add_argument("-d", "--dict", help="folder containing the file to be played", type=str, required=True)
 parser.add_argument("-t", "--time", help="time between ensembles", type=int, default=100)
-parser.add_argument("-i", "--iterations", help="number of iterations", type=int, default=1)
+parser.add_argument("-i", "--iter", help="number of iterations", type=int, default=1)
 args = vars(parser.parse_args())
 
 port = args["port"]
 baud = args["baud"]
 file = args["file"]
+dict = args["dict"]
 time = args["time"]
-iter = args["iterations"]
+iter = args["iter"]
 
 arduino = Arduino(Connection(port, baud))
-animation = Tool.create_animation(file, "alphabet", time, iter)
-
+animation = Raw.to_animation(file, dict, time, iter)
 arduino.stream_animation(animation)
diff --git a/scripts/reset_display.py b/scripts/reset_display.py
index c2e86e237fa39462e4f7735910a14820088ae32e..10f318528cce1811825eaa51f7fe6a982afe4356 100755
--- a/scripts/reset_display.py
+++ b/scripts/reset_display.py
@@ -2,8 +2,8 @@
 
 import argparse
 
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.channel.connection import Connection
 
 parser = argparse.ArgumentParser(description="script to reset the NeoPixel rings")
 parser.add_argument("-p", "--port", help="port to which the Arduino is connected", type=str, default="/dev/ttyUSB0")
@@ -14,5 +14,4 @@ port = args["port"]
 baud = args["baud"]
 
 arduino = Arduino(Connection(port, baud))
-
 arduino.reset_display()
diff --git a/scripts/write.py b/scripts/write.py
index 447c9b80e64f92da9d69d0d88ef6eb2f4475b85f..ceb0f9c1dc248dc815676988274e64493e0391f9 100755
--- a/scripts/write.py
+++ b/scripts/write.py
@@ -2,23 +2,25 @@
 
 import argparse
 
-from visualising.expression.tool import Tool
+from visualising.communication.animation.animation import Animation
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.illustration.animation import Animation
-from visualising.communication.channel.connection import Connection
+from visualising.expression.abstract import Abstract
 
 parser = argparse.ArgumentParser(description="script to play an animation")
 parser.add_argument("-p", "--port", help="port to which the Arduino is connected", type=str, default="/dev/ttyUSB0")
 parser.add_argument("-b", "--baud", help="baud rate of the connection", type=int, default=57600)
-parser.add_argument("-t", "--time", help="time between ensembles", type=int, default=100)
+parser.add_argument("-t", "--time", help="time between ensembles", type=int, default=1000)
+parser.add_argument("-w", "--word", help="word to be displayed", type=str, required=True)
+parser.add_argument("-r", "--ring", help="ring that is supposed to represent the word", type=str, default="r")
 args = vars(parser.parse_args())
 
 port = args["port"]
 baud = args["baud"]
 time = args["time"]
+word = args["word"]
+ring = args["ring"]
 
 arduino = Arduino(Connection(port, baud))
-
-animation = Tool.write("HALLONORMAN")
-
+animation = Abstract.write(word, ring)
 arduino.stream_animation(Animation(animation, time, 1))
diff --git a/src/visualising/communication/animation/animation.py b/src/visualising/communication/animation/animation.py
index 3ebf2809a2c279f8f5fe6b9236a07bde67b041fd..21712aaf5d4867ef30d082bcbaa11ebd7059247f 100755
--- a/src/visualising/communication/animation/animation.py
+++ b/src/visualising/communication/animation/animation.py
@@ -1,8 +1,9 @@
 #!/usr/bin/env python
 
+
 class Animation:
     # The ensemble time is given in milliseconds.
-    def __init__(self, ensembles, ensemble_time=0, num_iter=1):
+    def __init__(self, ensembles, ensemble_time, num_iter):
         self.ensembles = ensembles
         self._ensemble_time = ensemble_time
         self._num_iter = num_iter
diff --git a/src/visualising/communication/animation/color/rgb.py b/src/visualising/communication/animation/color/rgb.py
index 08cab69f159900e3bbb0759374c467d0e578772f..bf8a6d0bb8e55109cb98d0316185aa084430e4a6 100644
--- a/src/visualising/communication/animation/color/rgb.py
+++ b/src/visualising/communication/animation/color/rgb.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from visualising.communication.illustration.color.color import Color
+from visualising.communication.animation.color.color import Color
 
 
 class RGB(Color):
diff --git a/src/visualising/communication/animation/ensemble.py b/src/visualising/communication/animation/ensemble.py
index 96b41ce71f7d240e09810687bab307e9dc51fd89..f924cf15aead9f442e21d55543f530e44606c596 100644
--- a/src/visualising/communication/animation/ensemble.py
+++ b/src/visualising/communication/animation/ensemble.py
@@ -1,11 +1,8 @@
 #!/usr/bin/env python
 
-import re
-import importlib.resources
-
-from visualising.illustration.animation.color.rgb import RGB
-from visualising.illustration.animation.pixel import Pixel
-from visualising.illustration.animation.frame import Frame
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.pixel import Pixel
+from visualising.communication.animation.frame import Frame
 
 
 class Ensemble:
@@ -13,6 +10,14 @@ class Ensemble:
         self.l_frame = l_frame
         self.r_frame = r_frame
 
+    def color(self, index):
+        if not 0 <= index <= 31:
+            raise ValueError("The parameter index must be an integer between 0 and 31!")
+        if index < 16:
+            return self.l_frame.color(index)
+        else:
+            return self.r_frame.color(index - 16)
+
     def illuminated(self, index):
         if not 0 <= index <= 31:
             raise ValueError("The parameter index must be an integer between 0 and 31!")
diff --git a/src/visualising/communication/animation/frame.py b/src/visualising/communication/animation/frame.py
index 1c5fe2560257a2b968e1fa618376623f07c720ed..67dbae809ad29fe4b23f63f446d744a3c2dee874 100644
--- a/src/visualising/communication/animation/frame.py
+++ b/src/visualising/communication/animation/frame.py
@@ -14,6 +14,11 @@ class Frame:
             raise ValueError("The parameter pixels must be a list of exactly 16 objects of the Pixel class!")
         self._pixels = pixels
 
+    def color(self, index):
+        if not 0 <= index <= 15:
+            raise ValueError("The parameter index must be an integer between 0 and 15!")
+        return self.pixels[index].color
+
     def illuminated(self, index):
         if not 0 <= index <= 15:
             raise ValueError("The parameter index must be an integer between 0 and 15!")
diff --git a/src/visualising/communication/arduino.py b/src/visualising/communication/arduino.py
index 735b3244892e0c2fcb8439e387929cd806d9757d..bbc95d1ad2d9e7fc4cca9c6c0ba7fe72c2ac7403 100755
--- a/src/visualising/communication/arduino.py
+++ b/src/visualising/communication/arduino.py
@@ -2,10 +2,10 @@
 
 import time
 
-from visualising.communication.channel.message.msg_frame import MsgFrame
-from visualising.communication.channel.message.msg_instr import MsgInstr
-from visualising.communication.channel.message.response import Response
-from visualising.communication.illustration.animation import Animation
+from visualising.communication.animation.animation import Animation
+from visualising.communication.message.msg_frame import MsgFrame
+from visualising.communication.message.msg_instr import MsgInstr
+from visualising.communication.message.response import Response
 
 
 class Arduino:
@@ -52,9 +52,6 @@ class Arduino:
     # animation is then started. In addition, it is checked whether the
     # animation was played successfully.
     def play_animation(self, animation):
-        if not isinstance(animation, Animation):
-            raise TypeError("The parameter animation must be an object of the Animation class!")
-
         self.load_animation(animation)
         self.start_playback()
 
@@ -73,14 +70,13 @@ class Arduino:
     # the received ensemble and then confirms the playback, whereupon a new
     # ensemble is sent.
     def stream_animation(self, animation):
-        if not isinstance(animation, Animation):
-            raise TypeError("The parameter animation must be an object of the Animation class!")
-
         for _ in range(animation.num_iter):
             for ensemble in animation.ensembles:
                 self.play_animation(Animation([ensemble], animation.ensemble_time, 1))
 
-    # Streams multiple animations in succession to the Arduino.
+    # Streams multiple animations in succession to the Arduino. This functionality
+    # makes it possible to send individual ensembles as animations and thus to play
+    # back individual ensembles with individual ensemble time.
     def stream_animations(self, animations):
         for animation in animations:
             self.stream_animation(animation)
diff --git a/src/visualising/communication/channel/connection.py b/src/visualising/communication/connection.py
similarity index 91%
rename from src/visualising/communication/channel/connection.py
rename to src/visualising/communication/connection.py
index 332fda5bc3c90084edc841f6c9d7aa0ec3dc5303..d6cf1cc22545259cca5b00bd0304686cdd884d66 100755
--- a/src/visualising/communication/channel/connection.py
+++ b/src/visualising/communication/connection.py
@@ -3,7 +3,7 @@
 import time
 import serial
 
-from visualising.communication.channel.message.response import Response
+from visualising.communication.message.response import Response
 
 
 class ArduinoException(Exception):
@@ -55,10 +55,10 @@ class Connection:
             raise ValueError("The parameter resends must be an integer greater 0!")
 
         def evaluate():
-            bool = resends > 0
+            boolean = resends > 0
             for expectation in expectations:
-                bool = bool and not response.compare(expectation)
-            return bool
+                boolean = boolean and not response.compare(expectation)
+            return boolean
 
         while True:
             self.send_msg(msg)
diff --git a/src/visualising/communication/channel/__init__.py b/src/visualising/communication/message/__init__.py
similarity index 100%
rename from src/visualising/communication/channel/__init__.py
rename to src/visualising/communication/message/__init__.py
diff --git a/src/visualising/communication/channel/message/message.py b/src/visualising/communication/message/message.py
similarity index 100%
rename from src/visualising/communication/channel/message/message.py
rename to src/visualising/communication/message/message.py
diff --git a/src/visualising/communication/channel/message/msg_frame.py b/src/visualising/communication/message/msg_frame.py
similarity index 91%
rename from src/visualising/communication/channel/message/msg_frame.py
rename to src/visualising/communication/message/msg_frame.py
index 0a0ebe3fa86ecdfe8f6397236201677124388bcf..f3b2865bceea9605cd8dc7c7d97839262d5b03cb 100644
--- a/src/visualising/communication/channel/message/msg_frame.py
+++ b/src/visualising/communication/message/msg_frame.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from visualising.communication.channel.message.message import Message
+from visualising.communication.message.message import Message
 
 
 class MsgFrame(Message):
diff --git a/src/visualising/communication/channel/message/msg_instr.py b/src/visualising/communication/message/msg_instr.py
similarity index 96%
rename from src/visualising/communication/channel/message/msg_instr.py
rename to src/visualising/communication/message/msg_instr.py
index 14b0a1f2301f4447cc6254d2d46159a464190b9a..6d43b2d2edb4059093a095cb5eaa09fcacfd401a 100644
--- a/src/visualising/communication/channel/message/msg_instr.py
+++ b/src/visualising/communication/message/msg_instr.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from visualising.communication.channel.message.message import Message
+from visualising.communication.message.message import Message
 
 
 class MsgInstr(Message):
diff --git a/src/visualising/communication/channel/message/response.py b/src/visualising/communication/message/response.py
similarity index 89%
rename from src/visualising/communication/channel/message/response.py
rename to src/visualising/communication/message/response.py
index 78aaeb9310195b262137bb681db73ff1e253832a..53e11dadeec918946ca03e1bfed3e1253f025fca 100644
--- a/src/visualising/communication/channel/message/response.py
+++ b/src/visualising/communication/message/response.py
@@ -4,7 +4,16 @@ class Response:
     # Generates an Arduino message, which is composed of a message byte from the Arduino
     # and a translation of the message byte.
     def __init__(self, byte):
-        self.byte = byte
+        self._byte = byte
+        self.desc = self.translate()
+
+    @property
+    def byte(self):
+        return self._byte
+
+    @byte.setter
+    def byte(self, byte):
+        self._byte = byte
 
     def translate(self):
         translation = {
diff --git a/src/visualising/expression/abstract.py b/src/visualising/expression/abstract.py
index 9aa6fb28f8e8656670caa1f23e7498cc2e6ea962..773c0d683e3468126183735bdf453c1db85c96e9 100644
--- a/src/visualising/expression/abstract.py
+++ b/src/visualising/expression/abstract.py
@@ -1,95 +1,112 @@
+#!/usr/bin/env python
+
 import time
 import rospy
 import numpy as np
 
-from visualising.expression.tool import Tool
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.pixel import Pixel
+from visualising.communication.animation.ensemble import Ensemble
+from visualising.communication.animation.animation import Animation
+from visualising.expression.library.raw import Raw
 from visualising.expression.expression import Expression
-from visualising.communication.illustration.animation import Animation
-from visualising.communication.illustration.color.rgb import RGB
+from visualising.expression.tool import Tool
 
 
 class Abstract(Expression):
     def __init__(self, arduino):
-        self.arduino = arduino
-        self.playback_start = 0
+        self._arduino = arduino
+        self.displayed = True
+
+    @property
+    def arduino(self):
+        return self._arduino
+
+    @arduino.setter
+    def arduino(self, arduino):
+        self._arduino = arduino
 
-    def react(self, state):
-        if len(state[1]) > 32:
-            rospy.logwarn("Only displaying the first 32 metric aggregations!")
-            state = state[:32]
+    def react(self, condition):
+        if self.displayed:
+            self.displayed = False
+
+            animations = Abstract.highlight(Abstract.cycle(condition.error()), condition.name(), condition.error(), 5)
+
+            self.arduino.stream_animations(animations)
+            self.displayed = True
 
     @staticmethod
-    def cycle(state_vector):
-        ensemble = Tool.create_empty_ensemble()
+    def cycle(error_vector):
+        empty = Ensemble.empty()
         index = 0
-        for state in state_vector:
-            color = Tool.state_to_color(state, RGB(0, 50, 0), RGB(50, 0, 0))
-            ensemble = Tool.set_pixel_color(ensemble, index, color)
+        for error_value in error_vector:
+            color = Tool.value_to_color(error_value, RGB(0, 50, 0), RGB(50, 0, 0))
+            empty.replace_pixel(index, Pixel(color))
             index = index + 1
+        return empty
 
-        return ensemble
+    @staticmethod
+    def write(text, ring, index=None, color=None):
+        if not text.isalpha():
+            raise ValueError("The parameter text must be a string that only contains alphabetic characters!")
+
+        text = text.upper()
+
+        ensembles = []
+        for char in text:
+            if ring == "l":
+                filename = "l_" + char + ".txt"
+            elif ring == "r":
+                filename = "r_" + char + ".txt"
+            else:
+                raise ValueError("The parameter ring must be a character that is either l or r!")
+
+            letter_ensemble = Raw.to_ensemble_list(filename, "alphabet")
+            if index is not None:
+                letter_ensemble[0].replace_pixel(index, Pixel(color))
+            ensembles = ensembles + letter_ensemble
+            if index is not None:
+                empty = Ensemble.empty()
+                empty.replace_pixel(index, Pixel(color))
+                ensembles.append(empty)
+            else:
+                ensembles.append(Ensemble.empty())
+        return ensembles
 
     @staticmethod
-    def highlight(cycle, states, text, number):
-        number = min(len(states), number)
-        highlight = sorted(zip(states, range(len(states))), reverse=True)[:number]
+    def highlight(generated_cycle, name_vector, error_vector, number):
+        number = min(len(name_vector), number)
+        zipped = sorted(zip(error_vector, range(len(error_vector))), reverse=True)[:number]
 
-        cycle_animation = Animation([cycle], 5000, 1)
+        cycle_animation = Animation([generated_cycle], 5000, 1)
 
         animations = [cycle_animation]
+        for tuple in zipped:
+            highlighted_ring = ""
+            highlighted_color = None
+            highlighted_index = None
 
-        for tuple in highlight:
+            empty = Ensemble.empty()
             ensembles = []
-            highlight = Tool.create_empty_ensemble()
-            ring = ""
-            highlight_pixel = None
-            color = None
             for i in range(32):
                 if tuple[1] != i:
-                    highlight = Tool.set_pixel_color(highlight, i, RGB(0, 0, 0))
+                    empty.replace_pixel(i, Pixel(RGB(0, 0, 0)))
                 else:
-                    highlight_pixel = i
+                    highlighted_index = i
                     if i < 16:
-                        ring = "l"
-                        color = cycle.l_frame.pixels[i].color
+                        highlighted_ring = "l"
                     else:
-                        ring = "r"
-                        color = cycle.r_frame.pixels[i % 16].color
+                        highlighted_ring = "r"
 
-                    highlight = Tool.set_pixel_color(highlight, i, color)
+                    highlighted_color = generated_cycle.color(i)
+                    empty.replace_pixel(i, Pixel(highlighted_color))
 
-            ensembles.append(highlight)
-            ensembles = ensembles + Abstract.write(text[highlight_pixel], ring, highlight_pixel, color)
+            ensembles.append(empty)
+            ensembles = ensembles + Abstract.write(name_vector[highlighted_index], highlighted_ring, highlighted_index,
+                                                   highlighted_color)
             animations.append(Animation(ensembles, 1000, 1))
             animations.append(cycle_animation)
 
-        animations.append(Animation([Tool.create_empty_ensemble()], 1000, 1))
+        animations.append(Animation([Ensemble.empty()], 1000, 1))
 
         return animations
-
-    @staticmethod
-    def write(text, ring, highlight=None, color=None):
-        if not isinstance(text, str) or not text.isalpha():
-            raise ValueError("The parameter text must be a string that only contains alphabetic characters!")
-
-        text = text.upper()
-
-        ensembles = []
-        for char in text:
-            if ring == "l":
-                file = "l_" + char + ".txt"
-            elif ring == "r":
-                file = "r_" + char + ".txt"
-            else:
-                raise ValueError("The parameter index must be a string that is either l or r!")
-
-            letter = Tool.create_ensembles(file, "alphabet")
-            if highlight is not None:
-                letter = [Tool.set_pixel_color(letter[0], highlight, color)]
-            ensembles = ensembles + letter
-            if highlight is not None:
-                ensembles.append(Tool.set_pixel_color(Tool.create_empty_ensemble(), highlight, color))
-            else:
-                ensembles.append(Tool.create_empty_ensemble())
-
-        return ensembles
diff --git a/src/visualising/expression/emotion.py b/src/visualising/expression/emotion.py
index 079df3722a56797c6fc52571155b67668108c295..96275acbce67120913dc27d4ac8d45e8f5fe38b6 100644
--- a/src/visualising/expression/emotion.py
+++ b/src/visualising/expression/emotion.py
@@ -1,78 +1,90 @@
+#!/usr/bin/env python
+
 import time
 
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.pixel import Pixel
+from visualising.communication.animation.ensemble import Ensemble
+from visualising.communication.animation.animation import Animation
 from visualising.expression.library.raw import Raw
-from visualising.communication.illustration.ensemble import Ensemble
-from visualising.communication.illustration.color.rgb import RGB
 from visualising.expression.expression import Expression
 from visualising.expression.tool import Tool
 
 
 class Emotion(Expression):
     def __init__(self, arduino):
-        self.arduino = arduino
-        self.playback_start = 0
-        self.refresh = 5
+        self._arduino = arduino
+        self.displayed = True
+
+        self.happy = "emotion_happy.txt"
+        self.ok = "emotion_ok.txt"
+        self.angry = "emotion_angry.txt"
+
+    @property
+    def arduino(self):
+        return self._arduino
 
-        self.happy = "expression_happy.txt"
-        self.ok = "expression_ok.txt"
-        self.angry = "expression_angry.txt"
+    @arduino.setter
+    def arduino(self, arduino):
+        self._arduino = arduino
 
-    def react(self, state):
-        if time.time() - self.playback_start > self.refresh:
-            color = Tool.state_to_color(state[0], RGB(25, 25, 25), RGB(25, 0, 0))
-            if state[0] > 0.7:
+    def react(self, condition):
+        aggregated_domains = condition.aggregated_domains
+        if self.displayed:
+            self.displayed = False
+            color = Tool.value_to_color(aggregated_domains, RGB(25, 25, 25), RGB(25, 0, 0))
+            if aggregated_domains > 0.7:
                 self.visualise(self.angry, color)
             else:
-                if state[0] > 0.3:
+                if aggregated_domains > 0.3:
                     self.visualise(self.ok, color)
                 else:
                     self.visualise(self.happy, color)
 
     def visualise(self, filepath, color):
         still = Raw.to_ensemble_list(filepath, "emotion")
-        buildup = Tool.build_emotion(still[0], color)
+        buildup = Emotion.build_parallel(Tool.color_ensemble(still[0], color), color)
         animation = Animation(buildup, 50, 1)
+
         self.arduino.stream_animation(animation)
-        self.playback_start = time.time()
+        self.displayed = True
 
+    # The function is given an ensemble. Then an animation is generated that builds
+    # up the given ensemble.
     @staticmethod
-    def build_emotion(still, color):
+    def build(still, color):
         ensembles = []
         for i in range(32 + 1):
             empty = Ensemble.empty()
-            for j in range(i + 1):
-                if still.illuminated(j) or (j == i and i != 32):
-                    empty.replace_pixel(j, Pixel(color))
-            ensembles.append(empty)
+            if i < 32:
+                for j in range(i + 1):
+                    if still.illuminated(j) or j == i:
+                        empty.replace_pixel(j, Pixel(color))
+                ensembles.append(empty)
+            else:
+                ensembles.append(still)
+        ensembles.append(still)
         return ensembles
 
+    # The function is given an ensemble. Then an animation is generated that builds
+    # up the given ensemble. The generated animation builds up the given ensemble
+    # on both NeoPixel rings in parallel.
     @staticmethod
-    def build_emotion_parallel(still, color):
+    def build_parallel(still, color):
         ensembles = []
         for i in range(16 + 1):
             empty = Ensemble.empty()
-            for j in range(i + 1):
-                if still.l_frame.illuminated(j):
-                    empty.replace_pixel(j, Pixel(color))
-                if still.r_frame.illuminated(j):
-                    empty.replace_pixel(j, Pixel(color))
-                if j == i:
-                    empty.replace_pixel(j, Pixel(color))
-                    empty.replace_pixel(16 + j, Pixel(color))
-
-            ensembles.append(ensemble)
-
-        ensemble = Tool.create_empty_ensemble()
-        for k in range(32):
-            if k < 16:
-                illuminated = blueprint.l_frame.illuminated(k)
+            if i < 16:
+                for j in range(i + 1):
+                    if still.illuminated(j):
+                        empty.replace_pixel(j, Pixel(color))
+                    if still.illuminated(j + 16):
+                        empty.replace_pixel(j + 16, Pixel(color))
+                    if j == i:
+                        empty.replace_pixel(j, Pixel(color))
+                        empty.replace_pixel(j + 16, Pixel(color))
+                ensembles.append(empty)
             else:
-                illuminated = blueprint.r_frame.illuminated(k % 16)
-
-            if illuminated:
-                ensemble = Tool.set_pixel_color(ensemble, k, color)
-
-        ensembles.append(ensemble)
-
-        return Animation(ensembles, time, 1)
-
+                ensembles.append(still)
+        ensembles.append(still)
+        return ensembles
diff --git a/src/visualising/communication/channel/message/__init__.py b/src/visualising/expression/library/animation/__init__.py
similarity index 100%
rename from src/visualising/communication/channel/message/__init__.py
rename to src/visualising/expression/library/animation/__init__.py
diff --git a/src/visualising/expression/library/animation_happy.txt b/src/visualising/expression/library/animation/animation_happy.txt
similarity index 100%
rename from src/visualising/expression/library/animation_happy.txt
rename to src/visualising/expression/library/animation/animation_happy.txt
diff --git a/src/visualising/expression/library/animation_ok.txt b/src/visualising/expression/library/animation/animation_ok.txt
similarity index 100%
rename from src/visualising/expression/library/animation_ok.txt
rename to src/visualising/expression/library/animation/animation_ok.txt
diff --git a/src/visualising/expression/library/animation_sad.txt b/src/visualising/expression/library/animation/animation_sad.txt
similarity index 100%
rename from src/visualising/expression/library/animation_sad.txt
rename to src/visualising/expression/library/animation/animation_sad.txt
diff --git a/src/visualising/expression/library/expression/__init__.py b/src/visualising/expression/library/emotion/__init__.py
similarity index 100%
rename from src/visualising/expression/library/expression/__init__.py
rename to src/visualising/expression/library/emotion/__init__.py
diff --git a/src/visualising/expression/library/expression/expression_angry.txt b/src/visualising/expression/library/emotion/emotion_angry.txt
similarity index 100%
rename from src/visualising/expression/library/expression/expression_angry.txt
rename to src/visualising/expression/library/emotion/emotion_angry.txt
diff --git a/src/visualising/expression/library/expression/expression_clear.txt b/src/visualising/expression/library/emotion/emotion_clear.txt
similarity index 100%
rename from src/visualising/expression/library/expression/expression_clear.txt
rename to src/visualising/expression/library/emotion/emotion_clear.txt
diff --git a/src/visualising/expression/library/expression/expression_happy.txt b/src/visualising/expression/library/emotion/emotion_happy.txt
similarity index 100%
rename from src/visualising/expression/library/expression/expression_happy.txt
rename to src/visualising/expression/library/emotion/emotion_happy.txt
diff --git a/src/visualising/expression/library/expression/expression_ok.txt b/src/visualising/expression/library/emotion/emotion_ok.txt
similarity index 100%
rename from src/visualising/expression/library/expression/expression_ok.txt
rename to src/visualising/expression/library/emotion/emotion_ok.txt
diff --git a/src/visualising/expression/library/raw.py b/src/visualising/expression/library/raw.py
index 4cb1bcd03b532566c15fed4ced324995cfd7184d..a42c9657c113e1d087869a82080bdd544b75a8d2 100644
--- a/src/visualising/expression/library/raw.py
+++ b/src/visualising/expression/library/raw.py
@@ -3,13 +3,15 @@
 import re
 import importlib.resources
 
-from visualising.illustration.animation.color.rgb import RGB
-from visualising.illustration.animation.pixel import Pixel
-from visualising.illustration.animation.frame import Frame
-from visualising.illustration.animation.ensemble import Ensemble
-from visualising.illustration.animation.animation import Animation
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.pixel import Pixel
+from visualising.communication.animation.frame import Frame
+from visualising.communication.animation.ensemble import Ensemble
+from visualising.communication.animation.animation import Animation
 from visualising.expression.library import alphabet
-from visualising.expression.library import expression
+from visualising.expression.library import animation
+from visualising.expression.library import emotion
+from visualising.expression.library import transition
 
 
 class Raw:
@@ -19,25 +21,30 @@ class Raw:
     @staticmethod
     def to_ensemble_list(filename, directory):
         def load():
-            if directory != "expression" and directory != "alphabet":
+            if directory != "emotion" and directory != "alphabet" and directory != "animation" \
+                    and directory != "transition":
                 raise ValueError("The parameter directory describes a unknown directory!")
-            if directory == "expression":
+            if directory == "emotion":
                 return importlib.resources.open_text(emotion, filename)
             if directory == "alphabet":
                 return importlib.resources.open_text(alphabet, filename)
+            if directory == "animation":
+                return importlib.resources.open_text(animation, filename)
+            if directory == "transition":
+                return importlib.resources.open_text(transition, filename)
 
         def to_pixel_list(line):
             pixels = []
-            for (r, g, b) in line.split(","):
-                pixels.append(
-                    Pixel(
-                        RGB(
-                            int(re.search(r'\d+', r).group()),
-                            int(re.search(r'\d+', g).group()),
-                            int(re.search(r'\d+', b).group())
-                        )
-                    )
-                )
+            i, r, g, b = 0, 0, 0, 0
+            for value in line.split(","):
+                if i % 3 == 0:
+                    r = int(re.search(r'\d+', value).group())
+                if i % 3 == 1:
+                    g = int(re.search(r'\d+', value).group())
+                if i % 3 == 2:
+                    b = int(re.search(r'\d+', value).group())
+                    pixels.append(Pixel(RGB(r, g, b)))
+                i = i + 1
             return pixels
 
         file = load()
diff --git a/src/visualising/expression/library/test.txt b/src/visualising/expression/library/test.txt
deleted file mode 100644
index a2d81257e9a9404c7bea1d63cbf57ba2ad023753..0000000000000000000000000000000000000000
--- a/src/visualising/expression/library/test.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,10,0,0,10,0,0,10,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-10,0,0,10,0,0,10,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0
diff --git a/src/visualising/expression/library/transition/__init__.py b/src/visualising/expression/library/transition/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/visualising/expression/library/transition_happy_happy.txt b/src/visualising/expression/library/transition/transition_happy_happy.txt
similarity index 100%
rename from src/visualising/expression/library/transition_happy_happy.txt
rename to src/visualising/expression/library/transition/transition_happy_happy.txt
diff --git a/src/visualising/expression/tool.py b/src/visualising/expression/tool.py
index b38bad83e3b6df9f4342911b318cd9b4b3ac06ef..8e36f36d9405d1107a0508fb4bc820d9ff3b5c5c 100644
--- a/src/visualising/expression/tool.py
+++ b/src/visualising/expression/tool.py
@@ -2,7 +2,8 @@
 
 import numpy as np
 
-from visualising.communication.illustration.color.rgb import RGB
+from visualising.communication.animation.color.rgb import RGB
+from visualising.communication.animation.pixel import Pixel
 
 
 class Tool:
@@ -10,12 +11,18 @@ class Tool:
         pass
 
     @staticmethod
-    def state_to_color(state, start_color, end_color):
-        if not 0 <= state <= 1:
-            raise ValueError("The parameter state must be a floating point number between 0 and 1!")
+    def value_to_color(value, start_color, end_color):
+        if not 0 <= value <= 1:
+            raise ValueError("The parameter value must be a floating point number between 0 and 1!")
 
-        color = (1 - state) * np.array(start_color.export_color()) + state * np.array(end_color.export_color())
+        color = (1 - value) * np.array(start_color.export_color()) + value * np.array(end_color.export_color())
         color = color.tolist()
 
         return RGB(int(color[0]), int(color[1]), int(color[2]))
 
+    @staticmethod
+    def color_ensemble(ensemble, color):
+        for i in range(32):
+            if ensemble.illuminated(i):
+                ensemble.replace_pixel(i, Pixel(color))
+        return ensemble
diff --git a/src/visualising/monitoring/log/__init__.py b/src/visualising/monitoring/log/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/visualising/monitoring/log/condition.py b/src/visualising/monitoring/log/condition.py
new file mode 100644
index 0000000000000000000000000000000000000000..d715a634cc68406433540ee24e24bbc899e077c2
--- /dev/null
+++ b/src/visualising/monitoring/log/condition.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+class Condition:
+    def __init__(self, aggregated_metrics, aggregated_domains):
+        self._aggregated_metrics = aggregated_metrics
+        self.aggregated_domains = aggregated_domains
+
+    @property
+    def aggregated_metrics(self):
+        return self._aggregated_metrics
+
+    @aggregated_metrics.setter
+    def aggregated_metrics(self, aggregated_metrics):
+        if len(aggregated_metrics) > 32:
+            # Only saving the first 32 metric aggregations!
+            self._aggregated_metrics = aggregated_metrics[:32]
+        else:
+            self._aggregated_metrics = aggregated_metrics
+
+    def name(self):
+        unzipped = [[i for i, j in self._aggregated_metrics],
+                    [j for i, j in self._aggregated_metrics]]
+        return unzipped[0]
+
+    def error(self):
+        unzipped = [[i for i, j in self._aggregated_metrics],
+                    [j for i, j in self._aggregated_metrics]]
+        return unzipped[1]
diff --git a/src/visualising/monitoring/log/log.py b/src/visualising/monitoring/log/log.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f3ded4fa52309e59b3d913cf6f03f938d2fbf9f
--- /dev/null
+++ b/src/visualising/monitoring/log/log.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+from visualising.monitoring.log.condition import Condition
+
+
+class Log:
+    def __init__(self):
+        self.domains = []
+        self.aggregated_metrics = None
+        self.aggregated_domains = None
+
+    def add(self, domain):
+        self.domains.append(domain)
+
+    def exists(self, domain):
+        for x in self.domains:
+            if x.compare(domain):
+                return x
+        return None
+
+    def max_error(self):
+        max_error = 0.0
+        for domain in self.aggregated_metrics:
+            if domain[1] > max_error:
+                max_error = domain[1]
+        return max_error
+
+    def min_error(self):
+        min_error = 1.0
+        for domain in self.aggregated_metrics:
+            if domain[1] < min_error:
+                min_error = domain[1]
+        return min_error
+
+    def avg_error(self):
+        count = 0.001
+        avg_error = 0.0
+        for domain in self.aggregated_metrics:
+            count = count + 1
+            avg_error = avg_error + domain[1]
+        return avg_error / count
+
+    # TODO: Add more modes!
+    # TODO: Think about efficiency!
+    def aggregate_metrics(self, aggregation_strategy_metrics):
+        aggregated_metrics = []
+        for domain in self.domains:
+            if domain.name in aggregation_strategy_metrics and aggregation_strategy_metrics[domain.name] != 0:
+
+                # Strategy 1: Take the highest error level of any metric in a domain.
+                if aggregation_strategy_metrics[domain] == 1:
+                    aggregated_metrics.append((domain.name, domain.max_error()))
+
+                # Strategy 2: Take the lowest error level of any metric in a domain.
+                elif aggregation_strategy_metrics[domain] == 2:
+                    aggregated_metrics.append((domain.name, domain.min_error()))
+
+                else:
+                    raise ValueError("The specified method for aggregating metrics is not recognised!")
+
+            # Default strategy: Take the average error level of every metric in a domain.
+            else:
+                aggregated_metrics.append((domain.name, domain.avg_error()))
+
+        self.aggregated_metrics = aggregated_metrics
+
+    # TODO: Add more modes!
+    def aggregate_domains(self, aggregation_strategy_domains):
+        # Strategy 1: Take the highest error level of any domain.
+        if aggregation_strategy_domains == 1:
+            self.aggregated_domains = self.max_error()
+
+        # Strategy 2: Take the lowes error level of any domain.
+        elif aggregation_strategy_domains == 2:
+            self.aggregated_domains = self.min_error()
+
+        # Default strategy: Take the average error level of every domain.
+        else:
+            self.aggregated_domains = self.avg_error()
+
+    def condition(self, aggregation_strategy_metrics, aggregation_strategy_domains):
+        self.aggregate_metrics(aggregation_strategy_metrics)
+        self.aggregate_domains(aggregation_strategy_domains)
+        return Condition(self.aggregated_metrics, self.aggregated_domains)
diff --git a/src/visualising/monitoring/log/log_domain.py b/src/visualising/monitoring/log/log_domain.py
new file mode 100644
index 0000000000000000000000000000000000000000..65c36ee6d9c13bf924658d8cc836ef958d60ab06
--- /dev/null
+++ b/src/visualising/monitoring/log/log_domain.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+class Domain:
+    def __init__(self, name):
+        self.name = name
+        self.metrics = []
+
+    def compare(self, domain):
+        return self.name == domain.name
+
+    def add(self, metric):
+        self.metrics.append(metric)
+
+    def exists(self, metric):
+        for x in self.metrics:
+            if x.compare(metric):
+                return x
+        return None
+
+    def max_error(self):
+        max_error = 0.0
+        for metric in self.metrics:
+            if metric.error > max_error:
+                max_error = metric.error
+        return max_error
+
+    def min_error(self):
+        min_error = 1.0
+        for metric in self.metrics:
+            if metric.error < min_error:
+                min_error = metric.error
+        return min_error
+
+    def avg_error(self):
+        count = 0.001
+        avg_error = 0.0
+        for metric in self.metrics:
+            count = count + 1
+            avg_error = avg_error + metric.error
+        return avg_error / count
diff --git a/src/visualising/monitoring/log/log_metric.py b/src/visualising/monitoring/log/log_metric.py
new file mode 100644
index 0000000000000000000000000000000000000000..884a0fe0ecdd6ba3ad486fee7197a923b7ca6a98
--- /dev/null
+++ b/src/visualising/monitoring/log/log_metric.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+class Metric:
+    def __init__(self, origin, label, unit):
+        self.origin = origin  # Origin of the monitored metric.
+        self.label = label    # Label of the metric.
+        self.value = None     # Value of the metric.
+        self.error = None     # Error level of the metric.
+        self.unit = unit      # Unit of the metric.
+
+    def compare(self, metric):
+        return self.origin == metric.origin and self.label == metric.label
+
+    def update(self, value, error):
+        self.value = value
+        self.error = error
diff --git a/src/visualising/monitoring/watchdog.py b/src/visualising/monitoring/watchdog.py
index 2c1eb8cf6a44fe7b8fdf6e86577fff8b63c20ebf..516a5616db4581ec83a040a114b57edc3f18de8c 100755
--- a/src/visualising/monitoring/watchdog.py
+++ b/src/visualising/monitoring/watchdog.py
@@ -3,6 +3,9 @@
 import rospy
 
 from monitoring.msg import Monitoring
+from visualising.monitoring.log.log_metric import Metric
+from visualising.monitoring.log.log_domain import Domain
+from visualising.monitoring.log.log import Log
 
 
 class Watchdog:
@@ -10,134 +13,31 @@ class Watchdog:
         self.sub = rospy.Subscriber("/monitoring", Monitoring, self.update_log)
 
         # Stores the most current values of each metric.
-        self.log = {}
+        self.log = Log()
 
         # Strategies that specify how the critical level of each metric should be aggregated in a domain.
         # It is possible to specify a different aggregation strategy for every single domain.
         self.aggregation_strategy_metrics = rospy.get_param("/visualiser/aggregation_strategy_metrics")
-        # Dictionary that stores the aggregated critical levels of the metrics of a domain.
-        self.aggregated_metrics = {}
 
         # Strategy that specifies how the critical levels of all domains should be aggregated.
         self.aggregation_strategy_domains = rospy.get_param("/visualiser/aggregation_strategy_domains")
-        # Variable that stores the aggregated critical level of all domains.
-        self.aggregated_domains = None
 
-        # Frequency at which the metrics in the log are aggregated.
-        wdg_freq = rospy.get_param("/visualiser/wdg_freq", 1.0)
-
-        if not wdg_freq > 0.0:
-            rospy.logwarn(
-                "Watchdog: The frequency at which the metrics of the robot are aggregated must be greater then 0! "
-                "Using 1 as frequency!")
-            wdg_freq = 1.0
-
-        self.timer = rospy.Timer(rospy.Duration(1.0 / wdg_freq), self.update_condition)
-
-    # TODO: Think about efficiency!
     def update_log(self, monitoring):
-        origin = monitoring.origin
-        metric = monitoring.metric
+        new_metric = Metric(monitoring.origin, monitoring.metric.label, monitoring.metric.unit)
+        new_metric.update(monitoring.metric.value, monitoring.metric.error)
 
-        domain = metric.domain
-        label = metric.label
-        value = metric.value
-        unit = metric.unit
-        error = metric.error
+        new_domain = Domain(monitoring.metric.domain)
+        new_domain.add(new_metric)
 
-        if domain in self.log:
-            if origin in self.log[domain]:
-                self.log[domain][origin].update({label: {"value": value, "unit": unit, "error": error}})
-            else:
-                self.log[domain][origin] = {}
-                self.log[domain][origin][label] = {"value": value, "unit": unit, "error": error}
+        domain = self.log.exists(new_domain)
+        if domain is None:
+            self.log.add(new_domain)
         else:
-            self.log[domain] = {}
-            self.log[domain][origin] = {}
-            self.log[domain][origin][label] = {"value": value, "unit": unit, "error": error}
-
-    def update_condition(self, event):
-        self.aggregate_metrics()
-        self.aggregate_domains()
-        rospy.logwarn(self.aggregated_domains)
-
-    # TODO: Add more modes!
-    def aggregate_metrics(self):
-        for domain in self.log:
-            if domain in self.aggregation_strategy_metrics and self.aggregation_strategy_metrics[domain] != 0:
-
-                # Strategy 1: Take the highest error level of any metric in a domain.
-                if self.aggregation_strategy_metrics[domain] == 1:
-                    highest_error = 0.0
-
-                    for origin in self.log[domain]:
-                        for label in self.log[domain][origin]:
-                            local_error = self.log[domain][origin][label]["error"]
-                            if local_error > highest_error:
-                                highest_error = local_error
-
-                    self.aggregated_metrics.update({domain: highest_error})
-
-                # Strategy 2: Take the lowest error level of any metric in a domain.
-                elif self.aggregation_strategy_metrics[domain] == 2:
-                    lowest_error = 1.0
-
-                    for origin in self.log[domain]:
-                        for label in self.log[domain][origin]:
-                            local_error = self.log[domain][origin][label]["error"]
-                            if local_error < lowest_error:
-                                lowest_error = local_error
-
-                    self.aggregated_metrics.update({domain: lowest_error})
-
-                else:
-                    rospy.logwarn("Watchdog: The specified method for aggregating metrics is not recognised!")
-
-            # Default strategy: Take the average error level of every metric in a domain.
+            metric = domain.exists(new_metric)
+            if metric is None:
+                domain.add(new_metric)
             else:
-                count = 0.001
-                aggregated_error = 0.0
-
-                for origin in self.log[domain]:
-                    for label in self.log[domain][origin]:
-                        count = count + 1
-                        aggregated_error = aggregated_error + self.log[domain][origin][label]["error"]
-
-                quotient = aggregated_error / count
-                self.aggregated_metrics.update({domain: quotient})
-
-    # TODO: Add more modes!
-    def aggregate_domains(self):
-        # Strategy 1: Take the highest error level of any domain.
-        if self.aggregation_strategy_domains == 1:
-            highest_error = 0.0
-
-            for domain in self.aggregated_metrics:
-                local_error = self.aggregated_metrics[domain]
-                if local_error > highest_error:
-                    highest_error = local_error
-
-            self.aggregated_domains = highest_error
-
-        # Strategy 2: Take the lowes error level of any domain.
-        elif self.aggregation_strategy_domains == 2:
-            lowest_error = 1.0
-
-            for domain in self.aggregated_metrics:
-                local_error = self.aggregated_metrics[domain]
-                if local_error < lowest_error:
-                    lowest_error = local_error
-
-            self.aggregated_domains = lowest_error
-
-        # Default strategy: Take the average error level of every domain.
-        else:
-            count = 0.001
-            aggregated_error = 0.0
-
-            for domain in self.aggregated_metrics:
-                count = count + 1
-                aggregated_error = aggregated_error + self.aggregated_metrics[domain]
+                metric.update(monitoring.metric.value, monitoring.metric.error)
 
-            quotient = aggregated_error / count
-            self.aggregated_domains = quotient
+    def condition(self):
+        return self.log.condition(self.aggregation_strategy_metrics, self.aggregation_strategy_domains)
diff --git a/src/visualising/visualiser.py b/src/visualising/visualiser.py
index f1db8e67639c0133e0a329fbdc8ca17e53cb4a6a..47c6cf7b20939a14c3f3330d7ea22e056dcc971a 100644
--- a/src/visualising/visualiser.py
+++ b/src/visualising/visualiser.py
@@ -2,10 +2,11 @@
 
 import rospy
 
-from visualising.monitoring.watchdog import Watchdog
-from visualising.expression.emotion import Emotion
+from visualising.communication.connection import Connection
 from visualising.communication.arduino import Arduino
-from visualising.communication.channel.connection import Connection
+from visualising.expression.emotion import Emotion
+from visualising.expression.abstract import Abstract
+from visualising.monitoring.watchdog import Watchdog
 
 
 class Visualiser:
@@ -20,7 +21,7 @@ class Visualiser:
         if rospy.get_param("/visualiser/visualisation_strategy") == 1:
             self.expression = Emotion(arduino)
         else:
-            self.expression = None
+            self.expression = Abstract(arduino)
 
         if not freq > 0.0:
             rospy.logwarn(
@@ -30,6 +31,5 @@ class Visualiser:
 
         self.timer = rospy.Timer(rospy.Duration(1.0 / freq), self.visualise)
 
-    def visualise(self, event):
-        state = [self.watchdog.aggregated_domains, self.watchdog.aggregated_metrics]
-        self.expression.react(state)
+    def visualise(self, _):
+        self.expression.react(self.watchdog.condition())