From cd00d37b5c0cf6194b6b2c78d777ade6a5c417a1 Mon Sep 17 00:00:00 2001
From: bav6096 <benedikt.deike@informatik.uni-hamburg.de>
Date: Thu, 23 Dec 2021 06:04:53 +0100
Subject: [PATCH] more refactoring

---
 CMakeLists.txt                                |   2 +-
 launch/visualiser.launch                      |  35 ++++--
 ...ild_still_ensemble.py => build_emotion.py} |  13 +-
 scripts/write.py                              |   2 +-
 src/visualising/communication/arduino.py      |  51 +++++---
 .../communication/channel/connection.py       |  39 +++---
 .../communication/channel/message.py          |  83 ------------
 .../channel/message/__init__.py}              |   0
 .../communication/channel/message/message.py  |   9 ++
 .../channel/message/msg_frame.py              |  37 ++++++
 .../channel/message/msg_instr.py              |  58 +++++++++
 .../communication/channel/message/response.py |  50 ++++++++
 .../communication/illustration/animation.py   |  40 ++++--
 .../illustration/color/__init__.py            |   0
 .../communication/illustration/color/color.py |  29 +++++
 .../communication/illustration/color/rgb.py   |  47 +++++++
 .../communication/illustration/ensemble.py    |  24 +++-
 .../communication/illustration/frame.py       |  50 ++++----
 .../communication/illustration/pixel.py       |  24 ++--
 .../expression/{artificial.py => abstract.py} |   2 +-
 src/visualising/expression/emotion.py         | 106 +++++++++++++---
 src/visualising/expression/expression.py      |  14 +++
 .../expression/library/{ => alphabet}/A.txt   |   0
 .../expression/library/{ => alphabet}/B.txt   |   0
 .../expression/library/{ => alphabet}/C.txt   |   0
 .../expression/library/{ => alphabet}/D.txt   |   0
 .../expression/library/{ => alphabet}/E.txt   |   0
 .../expression/library/{ => alphabet}/G.txt   |   0
 .../expression/library/{ => alphabet}/H.txt   |   0
 .../expression/library/{ => alphabet}/I.txt   |   0
 .../expression/library/{ => alphabet}/J.txt   |   0
 .../expression/library/{ => alphabet}/L.txt   |   0
 .../expression/library/alphabet/M.txt         |   2 +
 .../expression/library/alphabet/N.txt         |   2 +
 .../expression/library/{ => alphabet}/O.txt   |   0
 .../expression/library/alphabet/R.txt         |   2 +
 .../expression/library/alphabet/S.txt         |   2 +
 .../expression/library/alphabet/T.txt         |   2 +
 .../expression/library/alphabet/__init__.py   |   0
 .../expression/library/emotion/__init__.py    |   0
 .../library/emotion/expression_angry.txt      |   2 +
 .../{ => emotion}/expression_clean.txt        |   0
 .../library/emotion/expression_happy.txt      |   2 +
 .../library/emotion/expression_ok.txt         |   2 +
 .../expression/library/expression_angry.txt   |   2 -
 .../expression/library/expression_happy.txt   |   2 -
 src/visualising/expression/library/test.txt   |   2 +
 src/visualising/expression/tool.py            | 118 +++++-------------
 src/visualising/monitoring/watchdog.py        |   1 +
 src/visualising/visualiser.py                 |   6 +-
 50 files changed, 568 insertions(+), 294 deletions(-)
 rename scripts/{build_still_ensemble.py => build_emotion.py} (72%)
 delete mode 100755 src/visualising/communication/channel/message.py
 rename src/visualising/{expression/library/expression_ok.txt => communication/channel/message/__init__.py} (100%)
 create mode 100755 src/visualising/communication/channel/message/message.py
 create mode 100644 src/visualising/communication/channel/message/msg_frame.py
 create mode 100644 src/visualising/communication/channel/message/msg_instr.py
 create mode 100644 src/visualising/communication/channel/message/response.py
 create mode 100644 src/visualising/communication/illustration/color/__init__.py
 create mode 100644 src/visualising/communication/illustration/color/color.py
 create mode 100644 src/visualising/communication/illustration/color/rgb.py
 rename src/visualising/expression/{artificial.py => abstract.py} (95%)
 create mode 100644 src/visualising/expression/expression.py
 rename src/visualising/expression/library/{ => alphabet}/A.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/B.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/C.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/D.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/E.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/G.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/H.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/I.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/J.txt (100%)
 rename src/visualising/expression/library/{ => alphabet}/L.txt (100%)
 create mode 100644 src/visualising/expression/library/alphabet/M.txt
 create mode 100644 src/visualising/expression/library/alphabet/N.txt
 rename src/visualising/expression/library/{ => alphabet}/O.txt (100%)
 create mode 100644 src/visualising/expression/library/alphabet/R.txt
 create mode 100644 src/visualising/expression/library/alphabet/S.txt
 create mode 100644 src/visualising/expression/library/alphabet/T.txt
 create mode 100644 src/visualising/expression/library/alphabet/__init__.py
 create mode 100644 src/visualising/expression/library/emotion/__init__.py
 create mode 100644 src/visualising/expression/library/emotion/expression_angry.txt
 rename src/visualising/expression/library/{ => emotion}/expression_clean.txt (100%)
 create mode 100644 src/visualising/expression/library/emotion/expression_happy.txt
 create mode 100644 src/visualising/expression/library/emotion/expression_ok.txt
 delete mode 100644 src/visualising/expression/library/expression_angry.txt
 delete mode 100644 src/visualising/expression/library/expression_happy.txt
 create mode 100644 src/visualising/expression/library/test.txt

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9d3016..d486f68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -162,7 +162,7 @@ catkin_install_python(PROGRAMS
    nodes/visualiser
    scripts/play_animation.py
    scripts/reset_display.py
-   scripts/build_still_ensemble.py
+   scripts/build_emotion.py
    scripts/build_state_cycle.py
    scripts/write.py
    DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
diff --git a/launch/visualiser.launch b/launch/visualiser.launch
index eed1fb9..d0e9d06 100644
--- a/launch/visualiser.launch
+++ b/launch/visualiser.launch
@@ -1,22 +1,39 @@
 <launch>
     <node pkg="visualising" type="visualiser" name="visualiser">
-        <param name="/wdg_freq" value="2.0" type="double" />
-        <param name="/vis_freq" value="2.0" type="double" />
+        <!-- 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="/arduino_port" value="/ttyUSB0" type="str" />
+        <param name="/arduino_port" value="/dev/ttyUSB0" type="str" />
         <param name="/arduino_baud" value="57600" type="int" />
 
         <!-- set visualisation strategy -->
+        <!-- 1: emotion  -->
+        <!-- 2: abstract -->
         <param name="/visualisation_strategy" value="1" type="int" />
 
-        <!-- example of how to set an aggregation strategy for a metric -->
+        <!-- example of how to set an aggregation strategy for a metric                                 -->
+        <!-- strategy 1 :                     Take the highest error level of any metric in a domain.   -->
+        <!-- strategy 2 :                     Take the lowest error level of any metric in a domain.    -->
+        <!-- strategy 0 | default strategy :  Take the average error level of every metric in a domain. -->
         <rosparam param="aggregation_strategy_metrics">
-            example_1: 10
-            example_2: 10
-            test_domain_1: 0
-            test_domain_2: 0
+            <!-- metric name: metric aggregation strategy -->
+
+            example_1: 0 <!-- default -->
+            example_2: 0 <!-- default -->
+            test_domain_1: 0 <!-- default -->
+            test_domain_2: 0 <!-- default -->
+            test_domain_3: 0 <!-- default -->
         </rosparam>
         <!-- set the aggregation strategy for domains -->
-        <param name="aggregation_strategy_domains" value="0" type="int" />
+        <!-- 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" />
     </node>
 </launch>
diff --git a/scripts/build_still_ensemble.py b/scripts/build_emotion.py
similarity index 72%
rename from scripts/build_still_ensemble.py
rename to scripts/build_emotion.py
index 620282a..9c9ead4 100755
--- a/scripts/build_still_ensemble.py
+++ b/scripts/build_emotion.py
@@ -3,8 +3,10 @@
 import argparse
 
 from visualising.expression.tool import Tool
+from visualising.expression.emotion import Emotion
 from visualising.communication.arduino import Arduino
 from visualising.communication.channel.connection import Connection
+from visualising.communication.illustration.color.rgb import RGB
 
 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")
@@ -18,11 +20,16 @@ baud = args["baud"]
 file = args["file"]
 time = args["time"]
 
-color = [10, 10, 10]
+# 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)
+ensembles = Tool.create_ensembles(file, "emotion")
 
-arduino.stream_animation(Tool.build_still_ensemble_parallel(ensembles[0], time, color))
+arduino.stream_animation(Emotion.build_emotion_parallel(ensembles[0], time, color))
 
diff --git a/scripts/write.py b/scripts/write.py
index ec35159..447c9b8 100755
--- a/scripts/write.py
+++ b/scripts/write.py
@@ -19,6 +19,6 @@ time = args["time"]
 
 arduino = Arduino(Connection(port, baud))
 
-animation = Tool.write("HALLO")
+animation = Tool.write("HALLONORMAN")
 
 arduino.stream_animation(Animation(animation, time, 1))
diff --git a/src/visualising/communication/arduino.py b/src/visualising/communication/arduino.py
index 0bfaf9b..c79a4d3 100755
--- a/src/visualising/communication/arduino.py
+++ b/src/visualising/communication/arduino.py
@@ -2,55 +2,70 @@
 
 import time
 
-from visualising.communication.channel.connection import FrameMsg
-from visualising.communication.channel.connection import InstrMsg
-from visualising.communication.channel.connection import ArduinoMsg
+from visualising.communication.channel.connection import Connection
+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
 
 
 class Arduino:
     def __init__(self, connection):
-        self.connection = connection
+        self._connection = connection
+
+    @property
+    def connection(self):
+        return self._connection
+
+    @connection.setter
+    def connection(self, connection):
+        if not isinstance(connection, Connection):
+            raise TypeError("The parameter connection must be an object of the Connection class!")
+        self._connection = connection
 
     # Creates instruction message and sends it to the Arduino,
     # to play a loaded animation.
     def start_playback(self):
-        self.connection.confirm_msg(InstrMsg('B'), [ArduinoMsg(b'\x1f')], 5)
+        self._connection.confirm_msg(MsgInstr('B'), [Response(b'\x1f')], 5)
 
     # Creates instruction message and sends it to the Arduino,
     # to pause a playing animation.
     def pause_playback(self):
-        self.connection.confirm_msg(InstrMsg('C'), [ArduinoMsg(b'\x5f')], 5)
+        self._connection.confirm_msg(MsgInstr('C'), [Response(b'\x5f')], 5)
 
     # Creates instruction message and sends it to the Arduino,
     # to resume playback of a loaded animation.
     def resume_playback(self):
-        self.connection.confirm_msg(InstrMsg('D'), [ArduinoMsg(b'\x6f')], 5)
+        self._connection.confirm_msg(MsgInstr('D'), [Response(b'\x6f')], 5)
 
     # Creates instruction message and sends it to the Arduino,
     # to clear the NeoPixel rings.
     def reset_display(self):
-        self.connection.confirm_msg(InstrMsg('E'), [ArduinoMsg(b'\x7f')], 5)
+        self._connection.confirm_msg(MsgInstr('E'), [Response(b'\x7f')], 5)
 
     # Creates one instruction messages and multiple frame messages to load an animation
     # onto the Arduino.
     def load_animation(self, animation):
-        if len(animation.ensembles) > 16:
-            raise ValueError("Animation has to many ensembles!")
+        if not isinstance(animation, Animation) or len(animation.ensembles) > 16:
+            raise ValueError("The animation parameter must be an object of the Animation class, which may contain a "
+                             "maximum of 16 ensembles!")
 
-        self.connection.confirm_msg(InstrMsg('A', animation), [ArduinoMsg(b'\x0f')], 5)
+        self._connection.confirm_msg(MsgInstr('A', animation), [Response(b'\x0f')], 5)
 
         for ensemble in animation.ensembles:
             l_frame = ensemble.l_frame
             r_frame = ensemble.r_frame
 
-            self.connection.confirm_msg(FrameMsg(l_frame), [ArduinoMsg(b'\x2f'), ArduinoMsg(b'\x3f')], 10)
-            self.connection.confirm_msg(FrameMsg(r_frame), [ArduinoMsg(b'\x2f'), ArduinoMsg(b'\x3f')], 10)
+            self._connection.confirm_msg(MsgFrame(l_frame), [Response(b'\x2f'), Response(b'\x3f')], 10)
+            self._connection.confirm_msg(MsgFrame(r_frame), [Response(b'\x2f'), Response(b'\x3f')], 10)
 
     # First, an animation is loaded onto the Arduino. The playback of this
     # 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()
 
@@ -59,7 +74,7 @@ class Arduino:
         # Current time in seconds.
         curr_time = time.time()
 
-        while not ArduinoMsg(b'\x4f').compare(self.connection.receive_msg()):
+        while not Response(b'\x4f').compare(self._connection.receive_msg()):
             # Wait 10 times the estimated animation playback time for a response.
             if time.time() > curr_time + playback_time * 10:
                 raise ArduinoException("Successful playback of animation can't be confirmed!")
@@ -69,11 +84,9 @@ 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 consecutively animations to the Arduino.
-    def stream_multiple_animations(self, animation_list):
-        for animation in animation_list:
-            self.stream_animation(animation)
diff --git a/src/visualising/communication/channel/connection.py b/src/visualising/communication/channel/connection.py
index 0f76509..c6fb34c 100755
--- a/src/visualising/communication/channel/connection.py
+++ b/src/visualising/communication/channel/connection.py
@@ -3,9 +3,10 @@
 import time
 import serial
 
-from visualising.communication.channel.message import FrameMsg
-from visualising.communication.channel.message import InstrMsg
-from visualising.communication.channel.message import ArduinoMsg
+from visualising.communication.channel.message.message import Message
+from visualising.communication.channel.message.response import Response
+from visualising.communication.channel.message.msg_frame import MsgFrame
+from visualising.communication.channel.message.msg_instr import MsgInstr
 
 
 class ArduinoException(Exception):
@@ -26,7 +27,10 @@ class Connection:
 
     # Send a message to the Arduino.
     def send_msg(self, msg):
-        for byte in msg.content:
+        if not isinstance(msg, Message):
+            raise TypeError("The parameter msg must be an object of the Message class!")
+
+        for byte in msg.export_message():
             self.connection.write(byte)
 
         self.connection.reset_output_buffer()  # Clear serial output buffer.
@@ -36,35 +40,40 @@ class Connection:
         try:
             # Since the timeout is set to one second, there is a waiting period of
             # exactly one second to read a byte from the serial buffer. If no byte
-            # is read in this one second period, an exception is thrown.
+            # is read in this time period, an exception is thrown.
             byte = self.connection.read(1)
         except SerialException:  # Arduino has not responded in time.
             byte = b'\xff'
 
         self.connection.reset_input_buffer()  # Clear serial input buffer.
 
-        return ArduinoMsg(byte)
+        return Response(byte)
 
     # Send a message and confirm that the response is as expected.
     # If the response is not as expected, try again as often as
     # specified. In case any response wasn't even once one of the
     # expected responses raise an exception.
-    def confirm_msg(self, msg, responses, resends):
+    def confirm_msg(self, msg, expectations, resends):
+        if not isinstance(msg, Message):
+            raise TypeError("The parameter msg must be an object of the Message class!")
+        if not isinstance(expectations, list) or not all(isinstance(expectation, Response) for expectation in
+                                                         expectations):
+            raise TypeError("The parameter responses must be a list of objects of the Response class!")
+        if not isinstance(resends, int) or not resends > 0:
+            raise ValueError("The parameter resends must be an integer greater 0!")
+
         def evaluate():
             bool = resends > 0
-            for exp_resp in responses:
-                bool = bool and not resp.compare(exp_resp)
+            for expectation in expectations:
+                bool = bool and not response.compare(expectation)
             return bool
 
-        if not resends > 0:
-            raise ValueError("Number of resends must be greater than zero!")
-
         while True:
             self.send_msg(msg)
-            resp = self.receive_msg()
+            response = self.receive_msg()
             if not evaluate():
                 break
-            resends -= 1
+            resends = resends - 1
 
         if not resends > 0:
-            raise ArduinoException(resp.desc)
+            raise ArduinoException(response.desc)
diff --git a/src/visualising/communication/channel/message.py b/src/visualising/communication/channel/message.py
deleted file mode 100755
index 5150bef..0000000
--- a/src/visualising/communication/channel/message.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-
-class FrameMsg:
-    # Creates a 50-bit frame message. The first and last bit are intended for authentication
-    # as a frame message. The remaining 48 bits store exactly one frame.
-    def __init__(self, frame):
-        self.content = [bytes('{', 'ascii')]
-
-        for pixel in frame.pixels:
-            r = pixel.r
-            g = pixel.g
-            b = pixel.b
-
-            self.content.append(r.to_bytes(1, byteorder='big'))
-            self.content.append(g.to_bytes(1, byteorder='big'))
-            self.content.append(b.to_bytes(1, byteorder='big'))
-
-        self.content.append(bytes('}', 'ascii'))
-
-
-class InstrMsg:
-    # Creates a 50-bit instruction message. Since only 7 bits at most are required for the
-    # actual message, most of the message consists only of zeros. The first and last bit
-    # are intended for authentication as an instruction message.
-    def __init__(self, instr, animation=None):
-        self.content = [bytes('[', 'ascii'), bytes(instr, 'ascii')]
-
-        if animation is not None:
-            num_frames = len(animation.ensembles) * 2
-            self.content.append(num_frames.to_bytes(1, byteorder='big'))
-
-            ensemble_time_bytes = animation.ensemble_time.to_bytes(4, byteorder='big')
-            self.content.append((ensemble_time_bytes[0]).to_bytes(1, byteorder='big'))
-            self.content.append((ensemble_time_bytes[1]).to_bytes(1, byteorder='big'))
-            self.content.append((ensemble_time_bytes[2]).to_bytes(1, byteorder='big'))
-            self.content.append((ensemble_time_bytes[3]).to_bytes(1, byteorder='big'))
-
-            self.content.append(animation.num_iter.to_bytes(1, byteorder='big'))
-
-            for _ in range(41):
-                self.content.append((0).to_bytes(1, byteorder='big'))
-        else:
-            for _ in range(47):
-                self.content.append((0).to_bytes(1, byteorder='big'))
-
-        self.content.append(bytes(']', 'ascii'))
-
-
-class ArduinoMsg:
-    # 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.content = byte
-
-        translation = {
-            240: "Animation has to many frame ensembles!",  # 0xF0
-            241: "No entities is loaded!",  # 0xF1
-            242: "Instruction was not recognized!",  # 0xF2
-            243: "No entities message expected!",  # 0xF3
-            244: "Message has wrong format!",  # 0xF4
-            245: "Animation is playing!",  # 0xF5
-            246: "Animation has no iteration!",  # 0xF6
-            247: "Unequal number of frames_library for the left and right NeoPixel ring!",  # 0xF7
-            248: "Animation has no frame ensemble!",  # 0xF8
-            255: "Timeout!",  # 0xFF
-            0: "No response!",  # 0x00
-            15: "Waiting for frames_library to be send!",  # 0x0F
-            31: "Animation playback has been started!",  # 0x1F
-            47: "Frame successfully received!",  # 0x2F
-            63: "Last frame successfully received!",  # 0x3F
-            79: "Animation successfully played!",  # 0x4F
-            95: "Animation playback has been paused!",  # 0x5F
-            111: "Animation playback has been resumed!",  # 0x6F
-            127: "Displays have been cleared!",  # 0x7F
-        }
-
-        try:
-            self.desc = translation[int.from_bytes(byte, byteorder='big')]
-        except KeyError:
-            self.desc = "Unknown response!"
-
-    def compare(self, msg):
-        return bytes(self.content) == bytes(msg.content)
diff --git a/src/visualising/expression/library/expression_ok.txt b/src/visualising/communication/channel/message/__init__.py
similarity index 100%
rename from src/visualising/expression/library/expression_ok.txt
rename to src/visualising/communication/channel/message/__init__.py
diff --git a/src/visualising/communication/channel/message/message.py b/src/visualising/communication/channel/message/message.py
new file mode 100755
index 0000000..06617b8
--- /dev/null
+++ b/src/visualising/communication/channel/message/message.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+from abc import ABC, abstractmethod
+
+
+class Message(ABC):
+    @abstractmethod
+    def export_message(self):
+        pass
diff --git a/src/visualising/communication/channel/message/msg_frame.py b/src/visualising/communication/channel/message/msg_frame.py
new file mode 100644
index 0000000..6403697
--- /dev/null
+++ b/src/visualising/communication/channel/message/msg_frame.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+from visualising.communication.channel.message.message import Message
+from visualising.communication.illustration.frame import Frame
+
+
+class MsgFrame(Message):
+    def __init__(self, frame):
+        self._frame = frame
+
+    @property
+    def frame(self):
+        return self._frame
+
+    @frame.setter
+    def frame(self, frame):
+        if not isinstance(frame, Frame):
+            raise TypeError("The parameter frame must be an object of the Frame class!")
+        self._frame = frame
+
+    # Creates a 50-bit frame message. The first and last bit are intended for authentication
+    # as a frame message. The remaining 48 bits store exactly one frame.
+    def export_message(self):
+        message = [bytes('{', 'ascii')]
+
+        for pixel in self._frame.pixels:
+            r = pixel.color.r
+            g = pixel.color.g
+            b = pixel.color.b
+
+            message.append(r.to_bytes(1, byteorder='big'))
+            message.append(g.to_bytes(1, byteorder='big'))
+            message.append(b.to_bytes(1, byteorder='big'))
+
+        message.append(bytes('}', 'ascii'))
+
+        return message
diff --git a/src/visualising/communication/channel/message/msg_instr.py b/src/visualising/communication/channel/message/msg_instr.py
new file mode 100644
index 0000000..9b927ed
--- /dev/null
+++ b/src/visualising/communication/channel/message/msg_instr.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+from visualising.communication.channel.message.message import Message
+from visualising.communication.illustration.animation import Animation
+
+
+class MsgInstr(Message):
+    def __init__(self, instr, animation=None):
+        self._instr = instr
+        self._animation = animation
+
+    @property
+    def instr(self):
+        return self._instr
+
+    @instr.setter
+    def instr(self, instr):
+        if instr != "A" and instr != "B" and instr != "C" and instr != "D" and instr != "E":
+            raise ValueError("Unknown instruction!")
+        self._instr = instr
+
+    @property
+    def animation(self):
+        return self._animation
+
+    @animation.setter
+    def animation(self, animation):
+        if not isinstance(animation, Animation):
+            raise TypeError("The parameter animation must be an object of the Animation class!")
+        self._animation = animation
+
+    # Creates a 50-bit instruction message. Since only 7 bits at most are required for the
+    # actual message, most of the message consists only of zeros. The first and last bit
+    # are intended for authentication as an instruction message.
+    def export_message(self):
+        message = [bytes('[', 'ascii'), bytes(self._instr, 'ascii')]
+
+        if self._animation is not None:
+            num_frames = len(self._animation.ensembles) * 2
+            message.append(num_frames.to_bytes(1, byteorder='big'))
+
+            ensemble_time_bytes = self._animation.ensemble_time.to_bytes(4, byteorder='big')
+            message.append((ensemble_time_bytes[0]).to_bytes(1, byteorder='big'))
+            message.append((ensemble_time_bytes[1]).to_bytes(1, byteorder='big'))
+            message.append((ensemble_time_bytes[2]).to_bytes(1, byteorder='big'))
+            message.append((ensemble_time_bytes[3]).to_bytes(1, byteorder='big'))
+
+            message.append(self._animation.num_iter.to_bytes(1, byteorder='big'))
+
+            for _ in range(41):
+                message.append((0).to_bytes(1, byteorder='big'))
+        else:
+            for _ in range(47):
+                message.append((0).to_bytes(1, byteorder='big'))
+
+        message.append(bytes(']', 'ascii'))
+
+        return message
diff --git a/src/visualising/communication/channel/message/response.py b/src/visualising/communication/channel/message/response.py
new file mode 100644
index 0000000..30c439a
--- /dev/null
+++ b/src/visualising/communication/channel/message/response.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+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
+
+    @property
+    def byte(self):
+        return self._byte
+
+    @byte.setter
+    def byte(self, byte):
+        if not isinstance(byte, bytes):
+            raise TypeError("The parameter byte must be an object of the byte class!")
+        self._byte = byte
+
+    def translate(self):
+        translation = {
+            240: "Animation has to many frame ensembles!",  # 0xF0
+            241: "No entities is loaded!",  # 0xF1
+            242: "Instruction was not recognized!",  # 0xF2
+            243: "No entities message expected!",  # 0xF3
+            244: "Message has wrong format!",  # 0xF4
+            245: "Animation is playing!",  # 0xF5
+            246: "Animation has no iteration!",  # 0xF6
+            247: "Unequal number of frames_library for the left and right NeoPixel ring!",  # 0xF7
+            248: "Animation has no frame ensemble!",  # 0xF8
+            255: "Timeout!",  # 0xFF
+            0: "No response!",  # 0x00
+            15: "Waiting for frames_library to be send!",  # 0x0F
+            31: "Animation playback has been started!",  # 0x1F
+            47: "Frame successfully received!",  # 0x2F
+            63: "Last frame successfully received!",  # 0x3F
+            79: "Animation successfully played!",  # 0x4F
+            95: "Animation playback has been paused!",  # 0x5F
+            111: "Animation playback has been resumed!",  # 0x6F
+            127: "Displays have been cleared!",  # 0x7F
+        }
+
+        try:
+            return translation[int.from_bytes(self._byte, byteorder='big')]
+        except KeyError:
+            return "Unknown response!"
+
+    def compare(self, response):
+        if not isinstance(response, Response):
+            raise TypeError("The parameter response must be an object of the Response class!")
+        return bytes(self._byte) == bytes(response.byte)
diff --git a/src/visualising/communication/illustration/animation.py b/src/visualising/communication/illustration/animation.py
index f6d4ed5..e622d90 100755
--- a/src/visualising/communication/illustration/animation.py
+++ b/src/visualising/communication/illustration/animation.py
@@ -5,19 +5,37 @@ from visualising.communication.illustration.ensemble import Ensemble
 
 class Animation:
     def __init__(self, ensembles, ensemble_time=0, num_iter=1):
-        self.ensembles = ensembles
+        self._ensembles = ensembles
+        self._ensemble_time = ensemble_time
+        self._num_iter = num_iter
 
-        if ensemble_time < 0:
-            raise ValueError("Ensemble time must be positive!")
-        if ensemble_time > 4294967295:
-            raise ValueError("Ensemble time is to high!")
+    @property
+    def ensembles(self):
+        return self._ensembles
 
+    @ensembles.setter
+    def ensembles(self, ensembles):
+        if not isinstance(ensembles, Ensemble):
+            raise TypeError("The parameter ensembles must be an object of the Ensemble class!")
+        self._ensembles = ensembles
+
+    @property
+    def ensemble_time(self):
+        return self._ensemble_time
+
+    @ensemble_time.setter
+    def ensemble_time(self, ensemble_time):
+        if not isinstance(ensemble_time, int) or not 0 <= ensemble_time <= 4294967295:
+            raise ValueError("The parameter ensemble_time  must be an integer between 0 an 4294967295!")
         # The ensemble time is given in milliseconds.
-        self.ensemble_time = ensemble_time
+        self._ensemble_time = ensemble_time
 
-        if num_iter > 255:
-            raise ValueError("Animation has to many iterations!")
-        if num_iter <= 0:
-            raise ValueError("Animation must have at least one iteration!")
+    @property
+    def num_iter(self):
+        return self._num_iter
 
-        self.num_iter = num_iter
+    @num_iter.setter
+    def num_iter(self, num_iter):
+        if not isinstance(num_iter, int) or not 1 <= num_iter <= 255:
+            raise ValueError("The parameter num_iter must be an integer between 1 an 255!")
+        self._num_iter = num_iter
diff --git a/src/visualising/communication/illustration/color/__init__.py b/src/visualising/communication/illustration/color/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/visualising/communication/illustration/color/color.py b/src/visualising/communication/illustration/color/color.py
new file mode 100644
index 0000000..de6edd4
--- /dev/null
+++ b/src/visualising/communication/illustration/color/color.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from abc import ABC, abstractmethod
+
+
+class Color(ABC):
+    @property
+    @abstractmethod
+    def r(self):
+        pass
+
+    @property
+    @abstractmethod
+    def g(self):
+        pass
+
+    @property
+    @abstractmethod
+    def b(self):
+        pass
+
+    @property
+    @abstractmethod
+    def illuminated(self):
+        pass
+
+    @abstractmethod
+    def export_color(self):
+        pass
diff --git a/src/visualising/communication/illustration/color/rgb.py b/src/visualising/communication/illustration/color/rgb.py
new file mode 100644
index 0000000..c874cd1
--- /dev/null
+++ b/src/visualising/communication/illustration/color/rgb.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+from visualising.communication.illustration.color.color import Color
+
+
+class RGB(Color):
+    def __init__(self, r, g, b):
+        self._r = r
+        self._g = g
+        self._b = b
+
+    @property
+    def r(self):
+        return self._r
+
+    @r.setter
+    def r(self, r):
+        if not isinstance(r, int) or not 0 <= r <= 255:
+            raise ValueError("The parameter r must be an integer between 0 and 255!")
+        self._r = r
+
+    @property
+    def g(self):
+        return self._g
+
+    @g.setter
+    def g(self, g):
+        if not isinstance(g, int) or not 0 <= g <= 255:
+            raise ValueError("The parameter g must be an integer between 0 and 255!")
+        self._g = g
+
+    @property
+    def b(self):
+        return self._b
+
+    @b.setter
+    def b(self, b):
+        if not isinstance(b, int) or not 0 <= b <= 255:
+            raise ValueError("The parameter b must be an integer between 0 and 255!")
+        self._b = b
+
+    @property
+    def illuminated(self):
+        return self._r + self._g + self._b != 0
+
+    def export_color(self):
+        return [self._r, self._g, self._b]
\ No newline at end of file
diff --git a/src/visualising/communication/illustration/ensemble.py b/src/visualising/communication/illustration/ensemble.py
index 6a6ca87..3e17571 100644
--- a/src/visualising/communication/illustration/ensemble.py
+++ b/src/visualising/communication/illustration/ensemble.py
@@ -5,5 +5,25 @@ from visualising.communication.illustration.frame import Frame
 
 class Ensemble:
     def __init__(self, l_frame, r_frame):
-        self.l_frame = l_frame
-        self.r_frame = r_frame
+        self._l_frame = l_frame
+        self._r_frame = r_frame
+
+    @property
+    def l_frame(self):
+        return self._l_frame
+
+    @l_frame.setter
+    def l_frame(self, l_frame):
+        if not isinstance(l_frame, Frame):
+            raise TypeError("The parameter left must be an object of the Frame class!")
+        self._l_frame = l_frame
+
+    @property
+    def r_frame(self):
+        return self._r_frame
+
+    @r_frame.setter
+    def r_frame(self, r_frame):
+        if not isinstance(r_frame, Frame):
+            raise TypeError("The parameter right must be an object of the Frame class!")
+        self._r_frame = r_frame
diff --git a/src/visualising/communication/illustration/frame.py b/src/visualising/communication/illustration/frame.py
index 16f36f1..bab4750 100644
--- a/src/visualising/communication/illustration/frame.py
+++ b/src/visualising/communication/illustration/frame.py
@@ -1,33 +1,31 @@
 #!/usr/bin/env python
 
 from visualising.communication.illustration.pixel import Pixel
+from visualising.communication.illustration.color.color import Color
 
 
 class Frame:
     def __init__(self, pixels):
-        if len(pixels) != 16:
-            raise ValueError("Frames must have exactly 16 pixels!")
-
-        self.pixels = pixels
-
-    def is_colored(self, pixel):
-        if not 0 <= pixel <= 15:
-            raise ValueError("Pixel index must be an integer between 0 and 15!")
-
-        return self.pixels[pixel].r + self.pixels[pixel].g + self.pixels[pixel].b != 0
-
-    def adjust_brightness(self, pixel, factor):
-        if not 0 <= pixel <= 15:
-            raise ValueError("Pixel index must be an integer between 0 and 15!")
-
-        r = min(max(self.frame[pixel].r * factor, 0), 255)
-        g = min(max(self.frame[pixel].g * factor, 0), 255)
-        b = min(max(self.frame[pixel].b * factor, 0), 255)
-
-        self.pixels[pixel] = Pixel(r, g, b)
-
-    def adjust_color(self, pixel, r, g, b):
-        if not 0 <= pixel <= 15:
-            raise ValueError("Pixel index must be an integer between 0 and 15!")
-
-        self.pixels[pixel] = Pixel(r, g, b)
+        self._pixels = pixels
+
+    @property
+    def pixels(self):
+        return self._pixels
+
+    @pixels.setter
+    def pixels(self, pixels):
+        if not isinstance(pixels, list) or not all(isinstance(pixel, Pixel) for pixel in pixels) or len(pixels) != 16:
+            raise ValueError("The parameter pixels must be a list of exactly 16 objects of the Pixel class!")
+        self._pixels = pixels
+
+    def illuminated(self, index):
+        if not isinstance(index, int) or not 0 <= index <= 15:
+            raise ValueError("The parameter index must be an integer between 0 and 15!")
+        return self._pixels[index].color.illuminated
+
+    def replace_pixel(self, index, pixel):
+        if not isinstance(index, int) or not 0 <= index <= 15:
+            raise ValueError("The parameter index must be an integer between 0 and 15!")
+        if not isinstance(pixel, Pixel):
+            raise TypeError("The parameter pixel must be an object of the Pixel class!")
+        self._pixels[index] = pixel
diff --git a/src/visualising/communication/illustration/pixel.py b/src/visualising/communication/illustration/pixel.py
index 8bf68ce..2e2c975 100644
--- a/src/visualising/communication/illustration/pixel.py
+++ b/src/visualising/communication/illustration/pixel.py
@@ -1,13 +1,19 @@
 #!/usr/bin/env python
 
+from visualising.communication.illustration.color.color import Color
+
+
 class Pixel:
-    def __init__(self, r, g, b):
-        if r < 0 or g < 0 or b < 0:
-            raise ValueError("All pixel color values must be positive!")
-        if r > 255 or g > 255 or b > 255:
-            raise ValueError("All pixel color values must be smaller than 256!")
-
-        self.r = int(r)
-        self.g = int(g)
-        self.b = int(b)
+    def __init__(self, color):
+        self._color = color
+
+    @property
+    def color(self):
+        return self._color
+
+    @color.setter
+    def color(self, color):
+        if not isinstance(color, Color):
+            raise TypeError("The parameter color must be an object of the Color class!")
+        self._color = color
 
diff --git a/src/visualising/expression/artificial.py b/src/visualising/expression/abstract.py
similarity index 95%
rename from src/visualising/expression/artificial.py
rename to src/visualising/expression/abstract.py
index bc73772..a352fa1 100644
--- a/src/visualising/expression/artificial.py
+++ b/src/visualising/expression/abstract.py
@@ -4,7 +4,7 @@ import numpy as np
 
 from visualising.expression.tool import Tool
 
-class State:
+class Abstract:
     def __init__(self, arduino):
         self.arduino = arduino
         self.playback_start = 0
diff --git a/src/visualising/expression/emotion.py b/src/visualising/expression/emotion.py
index bb37410..b514670 100644
--- a/src/visualising/expression/emotion.py
+++ b/src/visualising/expression/emotion.py
@@ -1,37 +1,105 @@
 import time
 
+from visualising.communication.arduino import Arduino
+from visualising.communication.illustration.animation import Animation
+from visualising.communication.illustration.color.rgb import RGB
+from visualising.expression.expression import Expression
 from visualising.expression.tool import Tool
 
 
-class Emotion:
+class Emotion(Expression):
     def __init__(self, arduino):
-        self.arduino = arduino
+        self._arduino = arduino
         self.playback_start = 0
+        self.refresh = 5
 
-    def react(self, state):
-        if time().time - playback_start > 5:
+        self.happy = "expression_happy.txt"
+        self.ok = "expression_ok.txt"
+        self.angry = "expression_angry.txt"
+
+    @property
+    def arduino(self):
+        return self._arduino
 
-            color = Tool.state_to_color(state[0], [25, 25, 25], [25, 0, 0])
+    @arduino.setter
+    def arduino(self, arduino):
+        if not isinstance(arduino, Arduino):
+            raise TypeError("The parameter arduino must be an object of the Arduino class!")
+        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:
-                self.happy(color)
+                self.visualise(self.angry, color)
             else:
                 if state[0] > 0.3:
-                    self.ok(color)
+                    self.visualise(self.ok, color)
                 else:
-                    self.angry(color)
+                    self.visualise(self.happy, color)
 
-    def happy(self, color):
-        ensembles = Tool.create_ensembles("expression_happy.txt")
-        self.arduino.stream_animation(Tool.build_still_ensemble_parallel(ensembles[0], 50, color))
+    def visualise(self, filepath, color):
+        ensembles = Tool.create_ensembles(filepath, "emotion")
+        self.arduino.stream_animation(Emotion.build_emotion_parallel(ensembles[0], 50, color))
         self.playback_start = time.time()
 
-    def ok(self, color):
-        ensembles = Tool.create_ensembles("expression_ok.txt")
-        self.arduino.stream_animation(Tool.build_still_ensemble_parallel(ensembles[0], 50, color))
-        self.playback_start = time.time()
+    @staticmethod
+    def build_emotion(blueprint, time, color):
+        ensembles = []
+        for i in range(32):
+            ensemble = Tool.create_empty_ensemble()
+            for j in range(i + 1):
+                if j < 16:
+                    illuminated = blueprint.l_frame.illuminated(j)
+                else:
+                    illuminated = bluepring.r_frame.illuminated(j % 16)
+
+                if illuminated or j == i:
+                    ensemble = Tool.set_pixel_color(ensemble, j, color)
+
+            ensembles.append(ensemble)
+
+        ensemble = Tool.create_empty_ensemble()
+        for k in range(32):
+            if k < 16:
+                illuminated = blueprint.l_frame.illuminated(k)
+            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)
+
+    @staticmethod
+    def build_emotion_parallel(blueprint, time, color):
+        ensembles = []
+        for i in range(16):
+            ensemble = Tool.create_empty_ensemble()
+            for j in range(i + 1):
+                if blueprint.l_frame.illuminated(j):
+                    ensemble = Tool.set_pixel_color(ensemble, j, color)
+                if blueprint.r_frame.illuminated(j):
+                    ensemble = Tool.set_pixel_color(ensemble, 16 + j, color)
+                if j == i:
+                    ensemble = Tool.set_pixel_color(ensemble, j, color)
+                    ensemble = Tool.set_pixel_color(ensemble, 16 + j, color)
+
+            ensembles.append(ensemble)
+
+        ensemble = Tool.create_empty_ensemble()
+        for k in range(32):
+            if k < 16:
+                illuminated = blueprint.l_frame.illuminated(k)
+            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)
 
-    def angry(self, color):
-        ensembles = Tool.create_ensembles("expression_angry.txt")
-        self.arduino.stream_animation(Tool.build_still_ensemble_parallel(ensembles[0], 50, color))
-        self.playback_start = time.time()
diff --git a/src/visualising/expression/expression.py b/src/visualising/expression/expression.py
new file mode 100644
index 0000000..2aa033f
--- /dev/null
+++ b/src/visualising/expression/expression.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+from abc import ABC, abstractmethod
+
+
+class Expression(ABC):
+    @property
+    @abstractmethod
+    def arduino(self):
+        pass
+
+    @abstractmethod
+    def react(self, state):
+        pass
diff --git a/src/visualising/expression/library/A.txt b/src/visualising/expression/library/alphabet/A.txt
similarity index 100%
rename from src/visualising/expression/library/A.txt
rename to src/visualising/expression/library/alphabet/A.txt
diff --git a/src/visualising/expression/library/B.txt b/src/visualising/expression/library/alphabet/B.txt
similarity index 100%
rename from src/visualising/expression/library/B.txt
rename to src/visualising/expression/library/alphabet/B.txt
diff --git a/src/visualising/expression/library/C.txt b/src/visualising/expression/library/alphabet/C.txt
similarity index 100%
rename from src/visualising/expression/library/C.txt
rename to src/visualising/expression/library/alphabet/C.txt
diff --git a/src/visualising/expression/library/D.txt b/src/visualising/expression/library/alphabet/D.txt
similarity index 100%
rename from src/visualising/expression/library/D.txt
rename to src/visualising/expression/library/alphabet/D.txt
diff --git a/src/visualising/expression/library/E.txt b/src/visualising/expression/library/alphabet/E.txt
similarity index 100%
rename from src/visualising/expression/library/E.txt
rename to src/visualising/expression/library/alphabet/E.txt
diff --git a/src/visualising/expression/library/G.txt b/src/visualising/expression/library/alphabet/G.txt
similarity index 100%
rename from src/visualising/expression/library/G.txt
rename to src/visualising/expression/library/alphabet/G.txt
diff --git a/src/visualising/expression/library/H.txt b/src/visualising/expression/library/alphabet/H.txt
similarity index 100%
rename from src/visualising/expression/library/H.txt
rename to src/visualising/expression/library/alphabet/H.txt
diff --git a/src/visualising/expression/library/I.txt b/src/visualising/expression/library/alphabet/I.txt
similarity index 100%
rename from src/visualising/expression/library/I.txt
rename to src/visualising/expression/library/alphabet/I.txt
diff --git a/src/visualising/expression/library/J.txt b/src/visualising/expression/library/alphabet/J.txt
similarity index 100%
rename from src/visualising/expression/library/J.txt
rename to src/visualising/expression/library/alphabet/J.txt
diff --git a/src/visualising/expression/library/L.txt b/src/visualising/expression/library/alphabet/L.txt
similarity index 100%
rename from src/visualising/expression/library/L.txt
rename to src/visualising/expression/library/alphabet/L.txt
diff --git a/src/visualising/expression/library/alphabet/M.txt b/src/visualising/expression/library/alphabet/M.txt
new file mode 100644
index 0000000..614e924
--- /dev/null
+++ b/src/visualising/expression/library/alphabet/M.txt
@@ -0,0 +1,2 @@
+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,0,0,0,0,0,0,0,0,0,0,0,0,0
+0,0,0,0,0,0,10,0,0,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0
\ No newline at end of file
diff --git a/src/visualising/expression/library/alphabet/N.txt b/src/visualising/expression/library/alphabet/N.txt
new file mode 100644
index 0000000..c222d6c
--- /dev/null
+++ b/src/visualising/expression/library/alphabet/N.txt
@@ -0,0 +1,2 @@
+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,0,0,0,0,0,0,0,0,0,0,0,0,0
+0,0,0,0,0,0,10,0,0,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,10,0,0,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0
\ No newline at end of file
diff --git a/src/visualising/expression/library/O.txt b/src/visualising/expression/library/alphabet/O.txt
similarity index 100%
rename from src/visualising/expression/library/O.txt
rename to src/visualising/expression/library/alphabet/O.txt
diff --git a/src/visualising/expression/library/alphabet/R.txt b/src/visualising/expression/library/alphabet/R.txt
new file mode 100644
index 0000000..6d8ccd6
--- /dev/null
+++ b/src/visualising/expression/library/alphabet/R.txt
@@ -0,0 +1,2 @@
+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,0,0,0,0,0,0,0,0,0,0,0,0,0
+10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,10,0,0,10,10,10,10,10,10
\ No newline at end of file
diff --git a/src/visualising/expression/library/alphabet/S.txt b/src/visualising/expression/library/alphabet/S.txt
new file mode 100644
index 0000000..22ce48b
--- /dev/null
+++ b/src/visualising/expression/library/alphabet/S.txt
@@ -0,0 +1,2 @@
+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,0,0,0,0,0,0,0,0,0,0,0,0,0
+10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,10,10,10,10,10,10,10,10,10
\ No newline at end of file
diff --git a/src/visualising/expression/library/alphabet/T.txt b/src/visualising/expression/library/alphabet/T.txt
new file mode 100644
index 0000000..79be5a6
--- /dev/null
+++ b/src/visualising/expression/library/alphabet/T.txt
@@ -0,0 +1,2 @@
+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,0,0,0,0,0,0,0,0,0,0,0,0,0
+10,0,0,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,10,10,10
\ No newline at end of file
diff --git a/src/visualising/expression/library/alphabet/__init__.py b/src/visualising/expression/library/alphabet/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/visualising/expression/library/emotion/__init__.py b/src/visualising/expression/library/emotion/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/visualising/expression/library/emotion/expression_angry.txt b/src/visualising/expression/library/emotion/expression_angry.txt
new file mode 100644
index 0000000..48e2b7f
--- /dev/null
+++ b/src/visualising/expression/library/emotion/expression_angry.txt
@@ -0,0 +1,2 @@
+50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0
+50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,0,0,0,0,0,0,0,0
\ No newline at end of file
diff --git a/src/visualising/expression/library/expression_clean.txt b/src/visualising/expression/library/emotion/expression_clean.txt
similarity index 100%
rename from src/visualising/expression/library/expression_clean.txt
rename to src/visualising/expression/library/emotion/expression_clean.txt
diff --git a/src/visualising/expression/library/emotion/expression_happy.txt b/src/visualising/expression/library/emotion/expression_happy.txt
new file mode 100644
index 0000000..213cbe6
--- /dev/null
+++ b/src/visualising/expression/library/emotion/expression_happy.txt
@@ -0,0 +1,2 @@
+50,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50
+50,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50
diff --git a/src/visualising/expression/library/emotion/expression_ok.txt b/src/visualising/expression/library/emotion/expression_ok.txt
new file mode 100644
index 0000000..a989e0d
--- /dev/null
+++ b/src/visualising/expression/library/emotion/expression_ok.txt
@@ -0,0 +1,2 @@
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
diff --git a/src/visualising/expression/library/expression_angry.txt b/src/visualising/expression/library/expression_angry.txt
deleted file mode 100644
index bfb8ee5..0000000
--- a/src/visualising/expression/library/expression_angry.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0
-50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0,50,50,50,50,50,50,0,0,0,0,0,0
\ No newline at end of file
diff --git a/src/visualising/expression/library/expression_happy.txt b/src/visualising/expression/library/expression_happy.txt
deleted file mode 100644
index 12b6349..0000000
--- a/src/visualising/expression/library/expression_happy.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50
-50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50
diff --git a/src/visualising/expression/library/test.txt b/src/visualising/expression/library/test.txt
new file mode 100644
index 0000000..a2d8125
--- /dev/null
+++ b/src/visualising/expression/library/test.txt
@@ -0,0 +1,2 @@
+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/tool.py b/src/visualising/expression/tool.py
index b635235..de188c9 100644
--- a/src/visualising/expression/tool.py
+++ b/src/visualising/expression/tool.py
@@ -8,7 +8,9 @@ from visualising.communication.illustration.animation import Animation
 from visualising.communication.illustration.ensemble import Ensemble
 from visualising.communication.illustration.frame import Frame
 from visualising.communication.illustration.pixel import Pixel
-from visualising.expression import library
+from visualising.communication.illustration.color.rgb import RGB
+from visualising.expression.library import alphabet
+from visualising.expression.library import emotion
 
 
 class Tool:
@@ -16,7 +18,7 @@ class Tool:
         pass
 
     @staticmethod
-    def read_raw_ensembles(filename):
+    def read_raw_ensembles(filename, directory):
         def read_raw_frame(line):
             raw_frame = []
             for value in line.split(","):
@@ -25,7 +27,12 @@ class Tool:
                 )
             return raw_frame
 
-        file = importlib.resources.open_text(library, filename)
+        if directory == "emotion":
+            file = importlib.resources.open_text(emotion, filename)
+        elif directory == "alphabet":
+            file = importlib.resources.open_text(alphabet, filename)
+        else:
+            raise ValueError("The parameter directory describes a unknown directory!")
 
         raw_ensembles = []
         while True:
@@ -45,7 +52,7 @@ class Tool:
         return raw_ensembles
 
     @staticmethod
-    def create_ensembles(filename):
+    def create_ensembles(filename, directory):
         def create_frame(raw_pixels):
             if len(raw_pixels) != 48:
                 raise ValueError("Frame must have exactly 48 values!")
@@ -58,12 +65,12 @@ class Tool:
                 g = raw_pixels[i + 1]
                 b = raw_pixels[i + 2]
 
-                pixels.append(Pixel(r, g, b))
+                pixels.append(Pixel(RGB(r, g, b)))
                 i = i + 3
 
             return Frame(pixels)
 
-        raw_ensembles = Tool.read_raw_ensembles(filename)
+        raw_ensembles = Tool.read_raw_ensembles(filename, directory)
 
         ensembles = []
         for raw_ensemble in raw_ensembles:
@@ -78,8 +85,8 @@ class Tool:
         return ensembles
 
     @staticmethod
-    def create_animation(filename, ensemble_time, iterations):
-        ensembles = Tool.create_ensembles(filename)
+    def create_animation(filename, directory, ensemble_time, iterations):
+        ensembles = Tool.create_ensembles(filename, directory)
         return Animation(ensembles, ensemble_time, iterations)
 
     @staticmethod
@@ -87,105 +94,40 @@ class Tool:
         l_pixels = []
         r_pixels = []
         for _ in range(16):
-            l_pixels.append(Pixel(0, 0, 0))
-            r_pixels.append(Pixel(0, 0, 0))
+            l_pixels.append(Pixel(RGB(0, 0, 0)))
+            r_pixels.append(Pixel(RGB(0, 0, 0)))
 
         return Ensemble(Frame(l_pixels), Frame(r_pixels))
 
     @staticmethod
-    def set_pixel_color(ensemble, pixel, r, g, b):
-        if not 0 <= pixel <= 31:
-            raise ValueError("Pixel index must be an integer between 0 and 31!")
+    def set_pixel_color(ensemble, index, color):
+        if not isinstance(index, int) or not 0 <= index <= 31:
+            raise ValueError("The parameter index must be an integer between 0 and 31!")
 
-        if pixel < 16:
-            ensemble.l_frame.adjust_color(pixel, r, g, b)
+        if index < 16:
+            ensemble.l_frame.replace_pixel(index, Pixel(color))
         else:
-            pixel = pixel - 16
-            ensemble.r_frame.adjust_color(pixel, r, g, b)
+            index = index - 16
+            ensemble.r_frame.replace_pixel(index, Pixel(color))
 
         return ensemble
 
     @staticmethod
     def state_to_color(state, start_color, end_color):
         if not 0 <= state <= 1:
-            raise ValueError("State must be a value between 0 and 1!")
-
-        return (1 - state) * np.array(start_color) + state * np.array(end_color)
-
-    @staticmethod
-    def build_still_ensemble(still_ensemble, ensemble_time, color):
-        r = color[0]
-        g = color[1]
-        b = color[2]
-
-        ensembles = []
-        for i in range(32):
-            ensemble = Tool.create_empty_ensemble()
-            for j in range(i + 1):
-                if j < 16:
-                    is_colored = still_ensemble.l_frame.is_colored(j)
-                else:
-                    is_colored = still_ensemble.r_frame.is_colored(j % 16)
-
-                if is_colored or j == i:
-                    ensemble = Tool.set_pixel_color(ensemble, j, r, g, b)
-
-            ensembles.append(ensemble)
-
-        ensemble = Tool.create_empty_ensemble()
-        for k in range(32):
-            if k < 16:
-                is_colored = still_ensemble.l_frame.is_colored(k)
-            else:
-                is_colored = still_ensemble.r_frame.is_colored(k % 16)
-
-            if is_colored:
-                ensemble = Tool.set_pixel_color(ensemble, k, r, g, b)
-
-        ensembles.append(ensemble)
-
-        return Animation(ensembles, ensemble_time, 1)
-
-    @staticmethod
-    def build_still_ensemble_parallel(still_ensemble, ensemble_time, color):
-        r = color[0]
-        g = color[1]
-        b = color[2]
-
-        ensembles = []
-        for i in range(16):
-            ensemble = Tool.create_empty_ensemble()
-            for j in range(i + 1):
-                if still_ensemble.l_frame.is_colored(j):
-                    ensemble = Tool.set_pixel_color(ensemble, j, r, g, b)
-                if still_ensemble.r_frame.is_colored(j):
-                    ensemble = Tool.set_pixel_color(ensemble, 16 + j, r, g, b)
-                if j == i:
-                    ensemble = Tool.set_pixel_color(ensemble, j, r, g, b)
-                    ensemble = Tool.set_pixel_color(ensemble, 16 + j, r, g, b)
-
-            ensembles.append(ensemble)
-
-        ensemble = Tool.create_empty_ensemble()
-        for k in range(32):
-            if k < 16:
-                is_colored = still_ensemble.l_frame.is_colored(k)
-            else:
-                is_colored = still_ensemble.r_frame.is_colored(k % 16)
-
-            if is_colored:
-                ensemble = Tool.set_pixel_color(ensemble, k, r, g, b)
+            raise ValueError("The parameter state must be a floating point number between 0 and 1!")
 
-        ensembles.append(ensemble)
+        color = (1 - state) * np.array(start_color.export_color()) + state * np.array(end_color.export_color())
+        color = color.tolist()
 
-        return Animation(ensembles, ensemble_time, 1)
+        return RGB(int(color[0]), int(color[1]), int(color[2]))
 
     @staticmethod
     def build_state_cycle(state_vector):
         ensemble = Tool.create_empty_ensemble()
         pixel = 0
         for state in state_vector:
-            color = Tool.state_to_color(state,  [0, 50, 0], [50, 0, 0])
+            color = Tool.state_to_color(state, [0, 50, 0], [50, 0, 0])
             ensemble = Tool.set_pixel_color(ensemble, pixel, color[0], color[1], color[2])
             pixel = pixel + 1
 
@@ -219,7 +161,7 @@ class Tool:
 
         ensembles.append(Tool.create_empty_ensemble())
 
-        return Animation(ensembles, 500, 1)
+        return Animation(ensembles, 1000, 1)
 
     @staticmethod
     def write(text):
diff --git a/src/visualising/monitoring/watchdog.py b/src/visualising/monitoring/watchdog.py
index 0b9428d..2c1eb8c 100755
--- a/src/visualising/monitoring/watchdog.py
+++ b/src/visualising/monitoring/watchdog.py
@@ -59,6 +59,7 @@ class Watchdog:
     def update_condition(self, event):
         self.aggregate_metrics()
         self.aggregate_domains()
+        rospy.logwarn(self.aggregated_domains)
 
     # TODO: Add more modes!
     def aggregate_metrics(self):
diff --git a/src/visualising/visualiser.py b/src/visualising/visualiser.py
index fcffc42..f1db8e6 100644
--- a/src/visualising/visualiser.py
+++ b/src/visualising/visualiser.py
@@ -3,7 +3,7 @@
 import rospy
 
 from visualising.monitoring.watchdog import Watchdog
-from visualising.expression.expression import Emotion
+from visualising.expression.emotion import Emotion
 from visualising.communication.arduino import Arduino
 from visualising.communication.channel.connection import Connection
 
@@ -14,11 +14,11 @@ class Visualiser:
         baud = rospy.get_param("/visualiser/arduino_baud")
         freq = rospy.get_param("/visualiser/vis_freq")
 
-        self.arduino = Arduino(Connection(port, baud))
+        arduino = Arduino(Connection(port, baud))
         self.watchdog = Watchdog()
 
         if rospy.get_param("/visualiser/visualisation_strategy") == 1:
-            self.expression = Emotion(self.arduino)
+            self.expression = Emotion(arduino)
         else:
             self.expression = None
 
-- 
GitLab