diff --git a/dfall_ws/src/dfall_pkg/launch/qualisys_datastream_MWE.launch b/dfall_ws/src/dfall_pkg/launch/qualisys_datastream_MWE.launch
new file mode 100755
index 0000000000000000000000000000000000000000..39cd587978702571e12e5194217c5d6d0dd2dea2
--- /dev/null
+++ b/dfall_ws/src/dfall_pkg/launch/qualisys_datastream_MWE.launch
@@ -0,0 +1,32 @@
+<launch>
+
+	<!-- INPUT ARGUMENT OF THE AGENT's ID -->
+	<arg name="agentID" default="$(optenv DFALL_DEFAULT_AGENT_ID)" />
+
+	<!-- INPUT ARGUMENT OF THE COORDINATOR's ID -->
+	<arg name="coordID" default="$(optenv DFALL_DEFAULT_COORD_ID)" />
+
+	<!-- INPUT ARGUMENT FOR LAUNCHING A GUI OR NOT -->
+	<arg name="withGUI" default="true" />
+
+	<!-- Example of how to use the value in agentID -->
+	<!-- <param name="param" value="$(arg agentID)"/> -->
+
+	<!-- Example of how to specify the agentID from command line -->
+	<!-- roslaunch dfall_pkg agentID:=1 -->
+
+	<group ns="$(eval 'agent' + str(agentID).zfill(3))">
+
+		<!-- QUALISYS DATA PUBLISHER -->
+		<node
+			pkg    = "dfall_pkg"
+			name   = "QualisysDataPublisherMWE"
+			output = "screen"
+			type   = "QualisysDataPublisherMWE.py"
+			>
+			<rosparam command="load" file="$(find dfall_pkg)/param/QualisysConfig.yaml" />
+		</node>
+
+	</group>
+
+</launch>
diff --git a/dfall_ws/src/dfall_pkg/param/QualisysConfig.yaml b/dfall_ws/src/dfall_pkg/param/QualisysConfig.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7d1b1d38d2f3e4fc04ad1d22509733c36f83c986
--- /dev/null
+++ b/dfall_ws/src/dfall_pkg/param/QualisysConfig.yaml
@@ -0,0 +1 @@
+qtm_host_ip_address: "10.42.0.15"
\ No newline at end of file
diff --git a/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisher.py b/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisher.py
new file mode 100755
index 0000000000000000000000000000000000000000..cee7ce819acc2ca2bb836750de3b40ec0278e73c
--- /dev/null
+++ b/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisher.py
@@ -0,0 +1,435 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# OPTIONS: #!/usr/bin/env python
+# OR:      #!/usr/bin/python3
+# OR:      #!/usr/bin/python3.5
+
+# WHERE THE KEY INSTALLATIONS TO USE python3 ARE:
+# >> sudo apt-get install python3-pip python3-yaml
+# >> pip3 install rospkg catkin_pkg --user
+
+# INSTALL THE LATEST VERSION OF QTM
+# >> pip3 install qtm --user
+#
+# OR
+#
+# For ubuntu 16.04, it is necessary to install an older version of QTM
+# because of compatibility with Python 3.5.2 versus >3.5.3, the commit
+# key from the GitHub repository is:
+# qualisys_python_sdk-327bf90e2829e02c40d3d85ed11e6e4d2d25f8a8
+#
+# Once downloaded, this can be installed from the local files using:
+# pip3 install -e /path/to/folder/containing/setup.py
+#
+# Install also the requirements
+# Note: that you may need to remove "black==18.6b4" from the list
+# in the "requirements.txt" file pip3 throws an error
+# >> pip3 install -r /path/to/requirements.txt
+
+#    Copyright (C) 2019, ETH Zurich, D-ITET, Paul Beuchat
+#
+#    This file is part of D-FaLL-System.
+#    
+#    D-FaLL-System is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#    
+#    D-FaLL-System is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#    
+#    You should have received a copy of the GNU General Public License
+#    along with D-FaLL-System.  If not, see <http://www.gnu.org/licenses/>.
+#    
+#
+#    ----------------------------------------------------------------------------------
+#    DDDD        FFFFF        L     L           SSSS  Y   Y   SSSS  TTTTT  EEEEE  M   M
+#    D   D       F      aaa   L     L          S       Y Y   S        T    E      MM MM
+#    D   D  ---  FFFF  a   a  L     L     ---   SSS     Y     SSS     T    EEE    M M M
+#    D   D       F     a  aa  L     L              S    Y        S    T    E      M   M
+#    DDDD        F      aa a  LLLL  LLLL       SSSS     Y    SSSS     T    EEEEE  M   M
+#
+#
+#    DESCRIPTION:
+#    The publisher for the Qualisys motion capture data
+#
+#    ----------------------------------------------------------------------------------
+
+
+
+# Import ros and the D-FaLL package
+import roslib; roslib.load_manifest('dfall_pkg')
+import rospy
+
+# Import the standard message types
+from std_msgs.msg import Int32
+from std_msgs.msg import Float32
+from std_msgs.msg import String
+
+# Import the D-FaLL message types
+from dfall_pkg.msg import ViconData
+from dfall_pkg.msg import CrazyflieData
+from dfall_pkg.msg import UnlabeledMarker
+
+# General import
+import time
+import math
+
+# Not sure if any of these are required
+#import logging
+#import datetime
+#from enum import Enum
+#import sys
+#import struct
+
+# ROS imports
+#import rosbag
+from rospkg import RosPack
+
+# Import the library for asynchronous I/O
+import asyncio
+
+# Import the library for parsing XML trees
+import xml.etree.ElementTree as ET
+
+# Import the Qualisys Track Manager (QTM) Library
+import qtm
+
+
+
+
+
+# DEFINE CONSTANTS
+
+# Conversion between radians and degrees
+RAD_TO_DEG = 57.296
+DEG_TO_RAD = 0.01745329
+
+# Path to the file with "fake" data for testing QTM
+#QTM_FILE = pkg_resources.resource_filename("qtm", "data/Demo.qtm")
+QTM_FILE = "none"
+
+
+# OPEN THE ROS BAG FOR WRITING
+#rp = RosPack()
+#record_file = rp.get_path('dfall_pkg') + '/LoggingOnboard.bag'
+#rospy.loginfo('afdsasdfasdfsadfasdfasdfasdfasdfasdfasdf')
+#rospy.loginfo(record_file)
+#bag = rosbag.Bag(record_file, 'w')
+
+
+
+
+
+class QualisysQtmClient:
+    """
+       Qualisys Data Publisher that connects to the
+       Qualisys Track Manager (QTM) server, receives
+       the 6DOF data, and publishs it for other nodes
+       to use.
+    """
+    def __init__(self):
+
+        # QTM CONNECTION STATUS AND OBJECT
+        self.qtm_ip = "10.42.00.15:801"
+        self._qtm_status = "empty"
+        self._qtm_connection = None
+
+        self._body_to_index_dictionary = None
+        self._list_of_body_names = None
+
+        self._qualisys_data_publisher = rospy.Publisher(node_name + '/ViconData', ViconData, queue_size=1)
+
+
+        # WAIT FOR A SHORT TIME BEFORE PROCEEDING WITH INITIALISATION
+        time.sleep(0.1)
+
+        # Initialize the CrazyFlie and add callbacks
+        self._init_qtm_client()
+
+
+
+
+
+    # INITIALISE THE QTM CLIENT OBJECT
+    def _init_qtm_client(self):
+        # Get the "qtm_host_ip_address" parameter that is the IP address
+        self.qtm_ip = rospy.get_param("~qtm_host_ip_address")
+
+
+    # CONNECT TO THE QTM SERVER
+    async def connect_to_qtm(self):
+        # Inform the user
+        print("[QUALISYS DATA PUBLISHER] now attempting to connect to QTM at IP address ", self.qtm_ip )
+
+        # Connect to QTM
+        self._qtm_connection = await qtm.connect( self.qtm_ip )
+
+        # Inform the user is the QTM connection failed
+        if self._qtm_connection is None:
+            print("[QUALISYS DATA PUBLISHER] connection is NONE for IP address = " , self.qtm_ip )
+            return
+
+        # Take control of qtm, context manager will automatically release control after scope end
+        async with qtm.TakeControl(self._qtm_connection, "password"):
+
+            # Specify whether to:
+            # True  = get real-time QTM
+            # False = get data from file
+            get_realtime_data = True
+
+            if get_realtime_data:
+                
+                # Get the current connection state to the QTM server
+                current_connection_state = await self._qtm_connection.get_state()
+
+                # Inform the user of the current connection state
+                print( "[QUALISYS DATA PUBLISHER] QTM connection State = " , current_connection_state )
+
+                # If not currently connected to the QTM serever...
+                if (current_connection_state != qtm.QRTEvent.EventConnected):
+                    # ... then start new connection to the QTM server
+                    await self._qtm_connection.new()
+
+            else:
+                # Load qtm file
+                await self._qtm_connection.load(QTM_FILE)
+
+                # start rtfromfile
+                await self._qtm_connection.start(rtfromfile=True)
+
+        # Get 6dof settings from QTM
+        parameters_6d_as_xml_string = await self._qtm_connection.get_parameters(parameters=["6d"])
+
+        # Convert the XML string to a index of the 6DOF bodies available from QTM
+        # This should be a dictionary that has the name of the object, and its index,
+        # for example: {'CF01',0 , 'CF02',1}
+        self._body_to_index_dictionary = self.create_body_index(parameters_6d_as_xml_string)
+
+        self._list_of_body_names = self.create_list_of_body_names(parameters_6d_as_xml_string)
+
+        print("[QUALISYS DATA PUBLISHER] Index of 6DOF bodies available from QTM: " , self._body_to_index_dictionary )
+
+
+
+
+
+    # START STREAMING FRAMES RECIEVED FROM QTM
+    async def start_streaming(self):
+        # Inform the user
+        print("[QUALISYS DATA PUBLISHER] Now starting to stream 6DOF data" )
+        # Start streaming frames:
+        # > with position and rotation matrix
+        #await connection.stream_frames(components=["6d"], on_packet=on_6d_packet)
+        # > with position and euler angles
+        # Take control of qtm, context manager will automatically release control after scope end
+        await self._qtm_connection.stream_frames(frames="allframes",components=["6deuler"], on_packet=self.on_6deuler_packet)
+
+        # Options for .stream_frames:
+        # frames=| allframes | frequency:n | frequencydivisor:n |
+        # where n should be the desired value
+
+
+
+
+    # STOP STREAMING FRAMES RECIEVED FROM QTM
+    async def stop_streaming(self):
+        # Stop streaming
+        await self._qtm_connection.stream_frames_stop()
+
+
+
+
+
+    def on_6deuler_packet(self,packet):
+
+        # DEBUGGING: Print the frame number
+        #print("[DEBUGGING] Framenumber: {}".format(packet.framenumber))
+
+        # GET THE DATA FROM THE PACKET
+        #info, bodies = packet.get_6d()
+        info, bodies  = packet.get_6d_euler()
+
+        # DEBUGGING: Print the body count and position of an object
+        # print("[DEBUGGING] Body count = ", info.body_count )
+        # if info.body_count > 0:
+        #     position, rotation = bodies[0]
+        #     print( "position.x = " , position[0] )
+
+        if info.body_count > 0:
+
+            # Initilise a "ViconData" struct
+            # > This is defined in the "ViconData.msg" file
+            viconData = ViconData()
+
+            # Initalise a counter for the bodies
+            current_body_index = 0
+
+            # Iterate through the bodies
+            for body in bodies:
+                
+                # Get the position and rotation data of the body
+                position, rotation = body
+
+                # DEBUGGING: to check the naming of rotation angles
+                #print( "rotation = ", rotation )
+
+                # Initialise a "ViconData" struct
+                # > This is defined in the "CrazyflieData.msg" file
+                this_crazyflie_data = CrazyflieData();
+
+                # Add the name of this object
+                if current_body_index < len(self._list_of_body_names):
+                    this_crazyflie_data.crazyflieName = self._list_of_body_names[current_body_index]
+                else:
+                    this_crazyflie_data.crazyflieName = ''
+
+                # Check for "nan" as an indication of occulsion
+                if math.isnan(position.x):
+                    # Fill in the occlusion flag
+                    this_crazyflie_data.occluded = True
+                else:
+                    # Fill in the occlusion flag
+                    this_crazyflie_data.occluded = False
+
+                    # Fill in the position data
+                    this_crazyflie_data.x = position.x * 0.001
+                    this_crazyflie_data.y = position.y * 0.001
+                    this_crazyflie_data.z = position.z * 0.001
+
+                    # Fill in the position data
+                    this_crazyflie_data.roll  = rotation.a3 * DEG_TO_RAD
+                    this_crazyflie_data.pitch = rotation.a2 * DEG_TO_RAD
+                    this_crazyflie_data.yaw   = rotation.a1 * DEG_TO_RAD
+
+                # DEBUGGIN: print out the crazyflie data
+                #print(this_crazyflie_data)
+
+                # Add the data for this body to the ViconData struct
+                viconData.crazyflies.append(this_crazyflie_data)
+
+                # Increment the indexing
+                current_body_index = current_body_index + 1
+
+
+            # PUBLISH THE VICON DATA
+            self._qualisys_data_publisher.publish(viconData)
+
+            # DEBUGGIN:
+            #print(viconData)
+
+
+
+
+
+    # EXTRACT THE INDEX DICTIONARY FROM 6DOF SETTING XML
+    def create_body_index(self, xml_string):
+        # Parse the element tree of the XML string
+        xml = ET.fromstring(xml_string)
+
+        # Initliase the "body_to_index" return variable
+        body_to_index = {}
+        # Iterate through the approriate elements of the XML element tree
+        for index, body in enumerate(xml.findall("*/Body/Name")):
+            # Add the name of this body and its index
+            body_to_index[body.text.strip()] = index
+
+        # Return the "body_to_index" variable
+        return body_to_index
+
+
+
+
+
+    # EXTRACT THE INDEX DICTIONARY FROM 6DOF SETTING XML
+    def create_list_of_body_names(self, xml_string):
+        # Parse the element tree of the XML string
+        xml = ET.fromstring(xml_string)
+
+        # Initliase the "list_of_names" return variable
+        list_of_names = list()
+        # Iterate through the approriate elements of the XML element tree
+        for index, body in enumerate(xml.findall("*/Body/Name")):
+            # Add the name of this body to the list
+            list_of_names.append(body.text.strip())
+
+        # Return the "list_of_names" variable
+        return list_of_names
+
+
+
+
+
+# THIS INITIALISES THE ROS NODE
+if __name__ == '__main__':
+
+    # STARTING THE ROS-NODE
+    global node_name
+    node_name = "ViconDataPublisher"
+    rospy.init_node(node_name, anonymous=True)
+
+    # GET THE NAMESPACE OF THIS NODE
+    global ros_namespace
+    ros_namespace = rospy.get_namespace()
+    
+    # PUBLISHER FOR THE MOTION CAPTURE DATA
+    #global qualisys_data_publisher
+    #qualisys_data_publisher = rospy.Publisher(node_name + '/ViconData', ViconData, queue_size=1)
+
+    # IP ADDRESS OF THE HOST "QUALISYS COMPUTER"
+    # > This is specified in the "QualisysConfig.yaml" file
+    # > That yaml file is added to this node during launch
+    # > The "Qualisys Computer" runs the "QTM" software that
+    #   is the heart of the Qualisys Motion Capture system
+    number_of_fails = 0
+    while not rospy.has_param("~qtm_host_ip_address"):
+        number_of_fails = number_of_fails + 1 
+        if number_of_fails > 9:
+            print("[QUALISYS DATA PUBLISHER] ERROR, qtm_host_ip_address parameter not found.")
+            number_of_fails = 0;
+        time.sleep(0.05)
+
+    #global qtm_ip
+    qtm_ip = rospy.get_param("~qtm_host_ip_address")
+
+    print("[QUALISYS DATA PUBLISHER] qtm_host_ip_address parameter = " , qtm_ip )
+    
+    # INFORM THE USER
+    #rospy.loginfo("[QUALISYS DATA PUBLISHER] Now attempting to connection to QTM server at IP address: %s", qtm_ip)
+    
+
+    # Initialise a "CrazyRadioClient" type variable that handles
+    # all communication over the CrazyRadio
+    global qtm_client
+    qtm_client = QualisysQtmClient()
+
+    # Connect to the QTM server
+    asyncio.get_event_loop().run_until_complete( qtm_client.connect_to_qtm() )
+
+
+
+    #asyncio.get_event_loop().run_until_complete( qtm_client.start_streaming() )
+
+    # Start streaming the data
+    asyncio.ensure_future( qtm_client.start_streaming() )
+    asyncio.get_event_loop().run_forever()
+    
+    # PAUSE FOR A SECOND AND THEN SPIN
+    time.sleep(1.0)
+    print("[QUALISYS DATA PUBLISHER] Node READY :-)")
+    rospy.spin()
+
+    # DISCONNECT FROM THE QTM SERVER
+    #print("[QUALISYS DATA PUBLISHER] Disconnecting from QTM server")
+    #qtm_client.stop_streaming()
+    
+    # Wait for diconnection to complete
+    #time.sleep(1.0)
+    #print("[QUALISYS DATA PUBLISHER] Disconnected from QTM server")
+
+    # CLOSE THE LOGGING "BAG"
+    #bag.close()
+    #rospy.loginfo("[QUALISYS DATA PUBLISHER] ROS logging bag is closed")
\ No newline at end of file
diff --git a/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisherMWE.py b/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisherMWE.py
new file mode 100755
index 0000000000000000000000000000000000000000..8775db9607eb4d3085e598a45837435b6ca76663
--- /dev/null
+++ b/dfall_ws/src/dfall_pkg/src/qualisys/QualisysDataPublisherMWE.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+#    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat
+#
+#    This file is part of D-FaLL-System.
+#    
+#    D-FaLL-System is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#    
+#    D-FaLL-System is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#    
+#    You should have received a copy of the GNU General Public License
+#    along with D-FaLL-System.  If not, see <http://www.gnu.org/licenses/>.
+#    
+#
+#    ----------------------------------------------------------------------------------
+#    DDDD        FFFFF        L     L           SSSS  Y   Y   SSSS  TTTTT  EEEEE  M   M
+#    D   D       F      aaa   L     L          S       Y Y   S        T    E      MM MM
+#    D   D  ---  FFFF  a   a  L     L     ---   SSS     Y     SSS     T    EEE    M M M
+#    D   D       F     a  aa  L     L              S    Y        S    T    E      M   M
+#    DDDD        F      aa a  LLLL  LLLL       SSSS     Y    SSSS     T    EEEEE  M   M
+#
+#
+#    DESCRIPTION:
+#    The publisher for the Qualisys motion capture data
+#
+#    ----------------------------------------------------------------------------------
+
+
+
+
+import roslib;
+import rospy
+
+
+#import rosbag
+from rospkg import RosPack
+
+
+
+# Import the library for asynchronous I/O
+import asyncio
+
+# Import the Qualisys Track Manager (QTM) Library
+import qtm
+
+
+def on_packet(packet):
+    """ Callback function that is called everytime a data packet arrives from QTM """
+    print("Framenumber: {}".format(packet.framenumber))
+    #header, markers = packet.get_3d_markers()
+    #print("Component info: {}".format(header))
+    #for marker in markers:
+    #    print("\t", marker)
+
+
+async def setup():
+    """ Main function """
+    connection = await qtm.connect("10.42.0.15")
+
+    if connection is None:
+        print("[QUALISYS DATA PUBLISHER] connection is NONE")
+        return
+
+    async with qtm.TakeControl(connection, "password"):
+        await connection.stream_frames(frames="frequencydivisor:50",components=["3d"], on_packet=on_packet)
+
+        # Wait asynchronously 5 seconds
+        await asyncio.sleep(2)
+
+        # Stop streaming
+        await self._qtm_connection.stream_frames_stop()
+
+
+if __name__ == "__main__":
+	# Starting the ROS-node
+    global node_name
+    node_name = "QualisysDataPublisherMWE"
+    rospy.init_node(node_name, anonymous=True)
+
+    # Get the namespace of this node
+    global ros_namespace
+    ros_namespace = rospy.get_namespace()
+
+    asyncio.ensure_future(setup())
+    asyncio.get_event_loop().run_forever()
+
+    # PAUSE FOR A SECOND AND THEN SPIN
+    time.sleep(1.0)
+    print("[QUALISYS DATA PUBLISHER] Node READY :-)")
+    rospy.spin()