diff --git a/.gitmodules b/.gitmodules
index 2b7a4fe10be4def3b75624e91852ee7add08eaa2..bcd8314d41aac94b005fc0873d3ded7008f37bd0 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
 [submodule "cmake"]
 	path = cmake
 	url = https://github.com/jrl-umi3218/jrl-cmakemodules.git
+[submodule "paho.mqtt.c"]
+	path = paho.mqtt.c
+	url = https://github.com/eclipse/paho.mqtt.c.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 761b80c22b273d3d8d4b9f45d84de54895a0b958..9104b5d0a7839dbd216391e0a7d3403bb373c5c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -139,10 +139,17 @@ target_compile_options(${PROJECT_NAME} PUBLIC -DNDEBUG -O3)
 target_compile_definitions(${PROJECT_NAME} PUBLIC CONFIG_SOLO12_YAML="${PROJECT_SOURCE_DIR}/scripts/config_solo12.yaml")
 target_compile_definitions(${PROJECT_NAME} PUBLIC WALK_PARAMETERS_YAML="${PROJECT_SOURCE_DIR}/src/walk_parameters.yaml")
 
+
+# MQTT Interface
+add_subdirectory (paho.mqtt.c)
+add_library(mqtt-interface SHARED include/qrw/mqtt-interface.hpp src/mqtt-interface.cpp)
+target_link_libraries(mqtt-interface PRIVATE paho-mqtt3c paho-mqtt3a)
+target_include_directories(mqtt-interface PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>)
+
 # Main Executable
 # add_executable(${PROJECT_NAMESPACE}-${PROJECT_NAME} src/main.cpp)
 add_executable(${PROJECT_NAMESPACE}-${PROJECT_NAME} src/control_solo12.cpp)
-target_link_libraries(${PROJECT_NAMESPACE}-${PROJECT_NAME} ${PROJECT_NAME})
+target_link_libraries(${PROJECT_NAMESPACE}-${PROJECT_NAME} ${PROJECT_NAME} mqtt-interface)
 
 # Python Bindings
 if(BUILD_PYTHON_INTERFACE)
diff --git a/include/qrw/mqtt-interface.hpp b/include/qrw/mqtt-interface.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7c23f77ece454f0dfbdf9a27876a8a689af0f508
--- /dev/null
+++ b/include/qrw/mqtt-interface.hpp
@@ -0,0 +1,34 @@
+#ifndef MQTT_INTERFACE_HPP
+#define MQTT_INTERFACE_HPP
+
+#include <mutex>
+
+
+class MqttInterface {
+ public:
+  MqttInterface();
+  void set(double current, double voltage, double energy, std::string & joystick);
+  void setStatus(std::string & status);
+  void start();
+  void stop();
+  bool getStop();
+  bool getCalibrate();
+
+ private:
+  bool run_;
+  double current_;
+  double voltage_;
+  double energy_;
+  std::string status_;
+  std::string joystick_;
+  std::mutex run_m;
+  std::mutex data_m;
+
+  bool getRun();
+  std::string getCurrent();
+  std::string getVoltage();
+  std::string getEnergy();
+  std::string getStatus();
+  std::string getJoystick();
+};
+#endif /* !MQTT_INTERFACE_HPP */
diff --git a/paho.mqtt.c b/paho.mqtt.c
new file mode 160000
index 0000000000000000000000000000000000000000..3b7ae6348bc917d42c04efa962e4868c09bbde9f
--- /dev/null
+++ b/paho.mqtt.c
@@ -0,0 +1 @@
+Subproject commit 3b7ae6348bc917d42c04efa962e4868c09bbde9f
diff --git a/src/control_solo12.cpp b/src/control_solo12.cpp
index c87af91314edda930ade1e6b6c856e8a674c6b90..8c68154cac329ea644c2ee4c9688304b4fb21f4c 100644
--- a/src/control_solo12.cpp
+++ b/src/control_solo12.cpp
@@ -6,6 +6,7 @@
 #include "qrw/Params.hpp"
 #include "qrw/Controller.hpp"
 #include "qrw/FakeRobot.hpp"
+#include "qrw/mqtt-interface.hpp"
 
 using namespace odri_control_interface;
 
@@ -83,13 +84,26 @@ int main()
     robot->joints->SetZeroCommands();
     robot->ParseSensorData();
 
+    // Initialize MQTT
+    MqttInterface mqtt_interface;
+    std::thread mqtt_thread(&MqttInterface::start, &mqtt_interface);
+    std::string mqtt_ready = "ready";
+    std::string mqtt_running = "running";
+    std::string mqtt_stopping = "stopping";
+    std::string mqtt_done = "done";
+    std::string mqtt_placeholder = "TODO";
+    mqtt_interface.setStatus(mqtt_ready);
+    mqtt_interface.set(robot->powerboard->GetCurrent(), robot->powerboard->GetVoltage(), 
+		    robot->powerboard->GetEnergy(), mqtt_placeholder);
     // Wait for Enter input before starting the control loop
     put_on_the_floor(robot, q_init, params, controller);
 
+    mqtt_interface.setStatus(mqtt_running);
     std::chrono::time_point<std::chrono::steady_clock> t_log [params.N_SIMULATION-2];
     // Main loop
     while ((!robot->IsTimeout()) && (k_loop < params.N_SIMULATION-2) && (!controller.error))
     {
+	if (mqtt_interface.getStop()) break;
         t_log[k_loop] = std::chrono::steady_clock::now();
 
         // Parse sensor data from the robot
@@ -127,6 +141,8 @@ int main()
         k_loop++;
         if (k_loop % 1000 == 0)
         {
+	    mqtt_interface.set(robot->powerboard->GetCurrent(), robot->powerboard->GetVoltage(), 
+			    robot->powerboard->GetEnergy(), mqtt_placeholder);
             std::cout << "Joints: ";
             robot->joints->PrintVector(robot->joints->GetPositions());
             std::cout << std::endl;
@@ -134,6 +150,7 @@ int main()
     }
 
     // DAMPING TO GET ON THE GROUND PROGRESSIVELY *********************
+    mqtt_interface.setStatus(mqtt_stopping);
     double t = 0.0;
     double t_max = 2.5;
     while ((!robot->IsTimeout()) && (t < t_max))
@@ -157,6 +174,8 @@ int main()
     }
     // FINAL SHUTDOWN *************************************************
 
+    mqtt_interface.setStatus(mqtt_done);
+
     // Whatever happened we send 0 torques to the motors.
     robot->joints->SetZeroCommands();
     robot->SendCommandAndWaitEndOfCycle(params.dt_wbc);
@@ -172,6 +191,8 @@ int main()
     parallel_thread.join();
     std::cout << "Parallel thread closed" << std::endl;
 
+    mqtt_interface.stop();
+    mqtt_thread.join();
     /*int duration_log [params.N_SIMULATION-2];
     for (int i = 0; i < params.N_SIMULATION-3; i++)
     {
diff --git a/src/mqtt-interface.cpp b/src/mqtt-interface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef192d9da51b2ef5b9ccf119afc9cb9ab0748fa5
--- /dev/null
+++ b/src/mqtt-interface.cpp
@@ -0,0 +1,161 @@
+#include "qrw/mqtt-interface.hpp"
+
+#include <iostream>
+#include <thread>
+#include <cstring>
+
+#include "MQTTClient.h"
+
+#define ADDRESS "tcp://localhost:1883"
+#define CLIENTID "Gepetto QRW MQTT Interface"
+
+bool stop_ = false;
+bool calibrate_ = false;
+std::mutex commands_m;
+
+void delivered(void * /*context*/, MQTTClient_deliveryToken /*dt*/) {}
+
+int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
+  std::string payload((char *)message->payload, message->payloadlen);
+  if (payload == "stop") {
+    std::lock_guard<std::mutex> guard(commands_m);
+    stop_ = true;
+  } else if (payload == "calibrate") {
+    std::lock_guard<std::mutex> guard(commands_m);
+    calibrate_ = true;
+  } else {
+    std::cerr << "Unknown Message on " << topicName << ": " << payload << std::endl;
+  }
+
+  MQTTClient_freeMessage(&message);
+  MQTTClient_free(topicName);
+  return 1;
+}
+
+void connlost(void *context, char *cause) {
+  std::cerr << "Connection lost" << std::endl;
+  std::cerr << "cause: " << cause << std::endl;
+}
+
+void MqttInterface::set(double current, double voltage, double energy, std::string & joystick) {
+  std::lock_guard<std::mutex> guard(data_m);
+  current_ = current;
+  voltage_ = voltage;
+  energy_ = energy;
+  joystick_ = joystick;
+}
+
+void MqttInterface::setStatus(std::string & status) {
+  std::lock_guard<std::mutex> guard(data_m);
+  status_ = status;
+}
+
+MqttInterface::MqttInterface() : run_(true), current_(0), voltage_(0), energy_(0) {}
+
+void MqttInterface::start() {
+  int rc;
+
+  MQTTClient client;
+  MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
+  MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
+  conn_opts.keepAliveInterval = 20;
+  conn_opts.cleansession = 1;
+  MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
+  if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
+    printf("Failed to connect, return code %d\n", rc);
+    exit(EXIT_FAILURE);
+  }
+  MQTTClient_subscribe(client, "/odri/commands", 0);
+  MQTTClient_deliveryToken token;
+
+  std::string current_s;
+  std::string voltage_s;
+  std::string energy_s;
+  std::string status_s;
+  std::string joystick_s;
+  const char* current_c;
+  const char* voltage_c;
+  const char* energy_c;
+  const char* status_c;
+  const char* joystick_c;
+
+  while (getRun()) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(330));
+
+    current_s = getCurrent();
+    voltage_s = getVoltage();
+    energy_s = getEnergy();
+    status_s = getStatus();
+    joystick_s = getJoystick();
+    current_c = current_s.data();
+    voltage_c = voltage_s.data();
+    energy_c = energy_s.data();
+    status_c = status_s.data();
+    joystick_c = joystick_s.data();
+
+    MQTTClient_publish(client, "/odri/current", std::strlen(current_c), current_c, 0, 0, &token);
+    MQTTClient_publish(client, "/odri/voltage", std::strlen(voltage_c), voltage_c, 0, 0, &token);
+    MQTTClient_publish(client, "/odri/energy", std::strlen(energy_c), energy_c, 0, 0, &token);
+    MQTTClient_publish(client, "/odri/status", std::strlen(status_c), status_c, 0, 0, &token);
+    MQTTClient_publish(client, "/odri/joystick", std::strlen(joystick_c), joystick_c, 0, 0, &token);
+  }
+
+  MQTTClient_disconnect(client, 10000);
+  MQTTClient_destroy(&client);
+}
+
+void MqttInterface::stop() {
+  std::lock_guard<std::mutex> guard(run_m);
+  run_ = false;
+}
+
+bool MqttInterface::getStop() {
+  std::lock_guard<std::mutex> guard(commands_m);
+  if (stop_) {
+    stop_ = false;
+    return true;
+  }
+  return false;
+}
+
+bool MqttInterface::getCalibrate() {
+  std::lock_guard<std::mutex> guard(commands_m);
+  if (calibrate_) {
+    calibrate_ = false;
+    return true;
+  }
+  return false;
+}
+
+bool MqttInterface::getRun() {
+  std::lock_guard<std::mutex> guard(run_m);
+  return run_;
+}
+
+std::string MqttInterface::getStatus() {
+  std::lock_guard<std::mutex> guard(data_m);
+  return status_;
+}
+
+std::string MqttInterface::getJoystick() {
+  std::lock_guard<std::mutex> guard(data_m);
+  return joystick_;
+}
+
+std::string MqttInterface::getCurrent() {
+  std::lock_guard<std::mutex> guard(data_m);
+  std::string ret = std::to_string(current_);
+  return ret;
+}
+
+std::string MqttInterface::getVoltage() {
+  std::lock_guard<std::mutex> guard(data_m);
+  std::string ret = std::to_string(voltage_);
+  return ret;
+}
+
+std::string MqttInterface::getEnergy() {
+  std::lock_guard<std::mutex> guard(data_m);
+  std::string ret = std::to_string(energy_);
+  return ret;
+}