diff --git a/scripts/Controller.py b/scripts/Controller.py
index 0a98dc67eb2c1d26a8c7b8077036226dd0d10849..0ec295130f27333fc67b8d27cb164325b86204e0 100644
--- a/scripts/Controller.py
+++ b/scripts/Controller.py
@@ -48,7 +48,7 @@ class dummyDevice:
 class Controller:
 
     def __init__(self, q_init, envID, velID, dt_tsid, dt_mpc, k_mpc, t, T_gait, T_mpc, N_SIMULATION, type_MPC,
-                 pyb_feedback, on_solo8, use_flat_plane, predefined_vel, enable_pyb_GUI):
+                 pyb_feedback, on_solo8, use_flat_plane, predefined_vel, enable_pyb_GUI, kf_enabled):
         """Function that runs a simulation scenario based on a reference velocity profile, an environment and
         various parameters to define the gait
 
@@ -68,6 +68,7 @@ class Controller:
             use_flat_plane (bool): to use either a flat ground or a rough ground
             predefined_vel (bool): to use either a predefined velocity profile or a gamepad
             enable_pyb_GUI (bool): to display PyBullet GUI or not
+            kf_enabled (bool): complementary filter (False) or kalman filter (True)
         """
 
         ########################################################################
@@ -99,7 +100,7 @@ class Controller:
 
         # Create Joystick, FootstepPlanner, Logger and Interface objects
         self.joystick, self.logger, self.estimator = utils_mpc.init_objects(
-            dt_tsid, dt_mpc, N_SIMULATION, k_mpc, T_gait, type_MPC, predefined_vel, self.h_init)
+            dt_tsid, dt_mpc, N_SIMULATION, k_mpc, T_gait, type_MPC, predefined_vel, self.h_init, kf_enabled)
 
         # Enable/Disable hybrid control
         self.enable_hybrid_control = True
diff --git a/scripts/LoggerControl.py b/scripts/LoggerControl.py
index 4bce112ba89d2703e2838db0ca050d875de748bb..a0cda5a0233f168b9b631c34ee2f5497ecf03976 100644
--- a/scripts/LoggerControl.py
+++ b/scripts/LoggerControl.py
@@ -39,6 +39,9 @@ class LoggerControl():
         self.esti_LP_alpha = np.zeros([logSize, 3])  # alpha parameter of the position complementary filter
         self.esti_LP_filt_x = np.zeros([logSize, 3])  # filtered output of the position complementary filter
 
+        self.esti_kf_X = np.zeros([logSize, 18])  # state of the Kalman filter
+        self.esti_kf_Z = np.zeros([logSize, 16])  # measurement for the Kalman filter
+
         # Loop
         self.loop_o_q_int = np.zeros([logSize, 19])  # position in world frame (esti_q_filt + dt * loop_o_v)
         self.loop_o_v = np.zeros([logSize, 18])  # estimated velocity in world frame
@@ -96,16 +99,19 @@ class LoggerControl():
         self.esti_FK_lin_vel[self.i] = estimator.FK_lin_vel[:]
         self.esti_FK_xyz[self.i] = estimator.FK_xyz[:]
         self.esti_xyz_mean_feet[self.i] = estimator.xyz_mean_feet[:]
-
-        self.esti_HP_x[self.i] = estimator.filter_xyz_vel.x
-        self.esti_HP_dx[self.i] = estimator.filter_xyz_vel.dx
-        self.esti_HP_alpha[self.i] = estimator.filter_xyz_vel.alpha
-        self.esti_HP_filt_x[self.i] = estimator.filter_xyz_vel.filt_x
-
-        self.esti_LP_x[self.i] = estimator.filter_xyz_pos.x
-        self.esti_LP_dx[self.i] = estimator.filter_xyz_pos.dx
-        self.esti_LP_alpha[self.i] = estimator.filter_xyz_pos.alpha
-        self.esti_LP_filt_x[self.i] = estimator.filter_xyz_pos.filt_x
+        if not estimator.kf_enabled:
+            self.esti_HP_x[self.i] = estimator.filter_xyz_vel.x
+            self.esti_HP_dx[self.i] = estimator.filter_xyz_vel.dx
+            self.esti_HP_alpha[self.i] = estimator.filter_xyz_vel.alpha
+            self.esti_HP_filt_x[self.i] = estimator.filter_xyz_vel.filt_x
+
+            self.esti_LP_x[self.i] = estimator.filter_xyz_pos.x
+            self.esti_LP_dx[self.i] = estimator.filter_xyz_pos.dx
+            self.esti_LP_alpha[self.i] = estimator.filter_xyz_pos.alpha
+            self.esti_LP_filt_x[self.i] = estimator.filter_xyz_pos.filt_x
+        else:
+            self.esti_kf_X[self.i] = estimator.kf.X[:, 0]
+            self.esti_kf_Z[self.i] = estimator.Z[:, 0]
 
         # Logging from the main loop
         self.loop_o_q_int[self.i] = loop.q_estim[:, 0]
@@ -465,11 +471,14 @@ class LoggerControl():
                  esti_LP_alpha=self.esti_LP_alpha,
                  esti_LP_filt_x=self.esti_LP_filt_x,
 
+                 esti_kf_X=self.esti_kf_X,
+                 esti_kf_Z=self.esti_kf_Z,
+
                  loop_o_q_int=self.loop_o_q_int,
                  loop_o_v=self.loop_o_v,
-                 loop_q_static=self.loop_q_static,
-                 loop_RPY_static=self.loop_RPY_static,
 
+                 planner_q_static=self.planner_q_static,
+                 planner_RPY_static=self.planner_RPY_static,
                  planner_xref=self.planner_xref,
                  planner_fsteps=self.planner_fsteps,
                  planner_gait=self.planner_gait,
diff --git a/scripts/main_solo12_control.py b/scripts/main_solo12_control.py
index bcbc1b74c6ac3933cacd1bf13fc89a7f4d9557d2..f7468d121840617cb37b52e4412b4d65e287b999 100644
--- a/scripts/main_solo12_control.py
+++ b/scripts/main_solo12_control.py
@@ -14,6 +14,7 @@ from LoggerControl import LoggerControl
 
 SIMULATION = True
 LOGGING = False
+PLOTTING = False
 
 if SIMULATION:
     from PyBulletSimulator import PyBulletSimulator
@@ -77,7 +78,7 @@ def control_loop(name_interface):
     ################################
 
     envID = 0  # Identifier of the environment to choose in which one the simulation will happen
-    velID = 1  # Identifier of the reference velocity profile to choose which one will be sent to the robot
+    velID = 2  # Identifier of the reference velocity profile to choose which one will be sent to the robot
 
     dt_wbc = DT  # Time step of the whole body control
     dt_mpc = 0.02  # Time step of the model predictive control
@@ -85,7 +86,7 @@ def control_loop(name_interface):
     t = 0.0  # Time
     T_gait = 0.32  # Duration of one gait period
     T_mpc = 0.32   # Duration of the prediction horizon
-    N_SIMULATION = 50000  # number of simulated wbc time steps
+    N_SIMULATION = 20000  # number of simulated wbc time steps
 
     # Which MPC solver you want to use
     # True to have PA's MPC, to False to have Thomas's MPC
@@ -103,6 +104,9 @@ def control_loop(name_interface):
     # If we are using a predefined reference velocity (True) or a joystick (False)
     predefined_vel = True
 
+    # Use complementary filter (False) or kalman filter (True) for the estimator
+    kf_enabled = False
+
     # Enable or disable PyBullet GUI
     enable_pyb_GUI = True
     if not SIMULATION:
@@ -113,7 +117,7 @@ def control_loop(name_interface):
 
     # Run a scenario and retrieve data thanks to the logger
     controller = Controller(q_init, envID, velID, dt_wbc, dt_mpc, k_mpc, t, T_gait, T_mpc, N_SIMULATION, type_MPC,
-                            pyb_feedback, on_solo8, use_flat_plane, predefined_vel, enable_pyb_GUI)
+                            pyb_feedback, on_solo8, use_flat_plane, predefined_vel, enable_pyb_GUI, kf_enabled)
 
     ####
 
@@ -124,12 +128,10 @@ def control_loop(name_interface):
         device = Solo12(name_interface, dt=DT)
         qc = QualisysClient(ip="140.93.16.160", body_id=0)
 
-    if LOGGING:
-        logger = Logger(device, qualisys=qc, logSize=N_SIMULATION)
-
-    loggerSensors = LoggerSensors(device, qualisys=qc, logSize=N_SIMULATION-3)
-    loggerControl = LoggerControl(dt_wbc, joystick=controller.joystick, estimator=controller.estimator,
-                                  loop=controller, planner=controller.planner, logSize=N_SIMULATION-3)
+    if LOGGING or PLOTTING:
+        loggerSensors = LoggerSensors(device, qualisys=qc, logSize=N_SIMULATION-3)
+        loggerControl = LoggerControl(dt_wbc, joystick=controller.joystick, estimator=controller.estimator,
+                                      loop=controller, planner=controller.planner, logSize=N_SIMULATION-3)
 
     # Number of motors
     nb_motors = device.nb_motors
@@ -148,11 +150,28 @@ def control_loop(name_interface):
     t = 0.0
     t_max = (N_SIMULATION-2) * dt_wbc
 
+    """log_cpt = 0
+    log_o_v = np.zeros((3, N_SIMULATION))
+    log_b_v = np.zeros((3, N_SIMULATION))
+    log_o_v_truth = np.zeros((3, N_SIMULATION))
+    log_b_v_truth = np.zeros((3, N_SIMULATION))
+    o_v = np.zeros((3, 1))
+    b_v = np.zeros((3, 1))"""
     while ((not device.hardware.IsTimeout()) and (t < t_max) and (not controller.myController.error)):
 
         # Update sensor data (IMU, encoders, Motion capture)
         device.UpdateMeasurment()
 
+        """rot_oMb = pin.Quaternion(np.array([device.baseOrientation]).transpose()).toRotationMatrix()
+        a = np.array([device.baseLinearAcceleration]).T
+        o_v[:, 0:1] += 0.002 * (rot_oMb @ a)
+        b_v[:, 0:1] = rot_oMb.T @ o_v
+        log_o_v[:, log_cpt] = o_v[:, 0]
+        log_b_v[:, log_cpt] = b_v[:, 0]
+        log_o_v_truth[:, log_cpt] = device.o_baseVel[:, 0]
+        log_b_v_truth[:, log_cpt] = device.b_baseVel[:]
+        log_cpt += 1"""
+
         # Desired torques
         controller.compute(device)
 
@@ -172,11 +191,10 @@ def control_loop(name_interface):
         device.SetDesiredJointTorque(controller.result.tau_ff.ravel())
 
         # Call logger
-        if LOGGING:
-            logger.sample(device, qualisys=qc, estimator=controller.estimator)
-        loggerSensors.sample(device, qc)
-        loggerControl.sample(controller.joystick, controller.estimator,
-                             controller, controller.planner, controller.myController)
+        if LOGGING or PLOTTING:
+            loggerSensors.sample(device, qc)
+            loggerControl.sample(controller.joystick, controller.estimator,
+                                 controller, controller.planner, controller.myController)
 
         # Send command to the robot
         for i in range(1):
@@ -251,7 +269,25 @@ def control_loop(name_interface):
 
     # controller.estimator.plot_graphs()
 
-    """import matplotlib.pylab as plt
+    """from matplotlib import pyplot as plt
+        
+    index6 = [1, 3, 5, 2, 4, 6]
+    plt.figure()
+    for i in range(6):
+        if i == 0:
+            ax0 = plt.subplot(3, 2, index6[i])
+        else:
+            plt.subplot(3, 2, index6[i], sharex=ax0)
+
+        if i < 3:
+            plt.plot(log_o_v_truth[i, :], c='r', linewidth=3)
+            plt.plot(log_o_v[i, :], c='b', linewidth=3)
+        else:
+            plt.plot(log_b_v_truth[i-3, :], c='r', linewidth=3)
+            plt.plot(log_b_v[i-3, :], c='b', linewidth=3)
+    plt.show()"""
+
+    """from matplotlib import pyplot as plt
     plt.figure()
     plt.plot(controller.t_list_filter[1:], 'r+')
     plt.plot(controller.t_list_planner[1:], 'g+')
@@ -265,7 +301,7 @@ def control_loop(name_interface):
     plt.title("Loop time [s]")
     plt.show(block=True)"""
 
-    """import matplotlib.pylab as plt
+    """from matplotlib import pyplot as plt
     N = len(controller.log_tmp2)
     t_range = np.array([k*0.002 for k in range(N)])
     plt.figure()
@@ -275,16 +311,13 @@ def control_loop(name_interface):
     plt.plot(t_range, controller.log_tmp4, 'g')
     # plt.show(block=True)"""
 
-    # controller.myController.saveAll(fileName="push_pyb_with_ff", log_date=False)
-    if LOGGING:
-        controller.myController.saveAll(fileName="data_control", log_date=True)
-        print("-- Controller log saved --")
-    # controller.myController.show_logs()
-    loggerControl.plotAll(loggerSensors)
+    # Plot recorded data
+    if PLOTTING:
+        loggerControl.plotAll(loggerSensors)
 
     # Save the logs of the Logger object
     if LOGGING:
-        logger.saveAll()
+        loggerControl.saveAll(loggerSensors)
         print("Log saved")
 
     if SIMULATION and enable_pyb_GUI:
diff --git a/scripts/utils_mpc.py b/scripts/utils_mpc.py
index 94bf8749bc27cebca6c396385c63b41319fc949f..96739fde8c5712314a9903bde85ce2a4a9709797 100644
--- a/scripts/utils_mpc.py
+++ b/scripts/utils_mpc.py
@@ -125,7 +125,7 @@ def init_robot(q_init, enable_viewer):
     return solo, fsteps_init, h_init
 
 
-def init_objects(dt_tsid, dt_mpc, k_max_loop, k_mpc, T_mpc, type_MPC, predefined, h_init):
+def init_objects(dt_tsid, dt_mpc, k_max_loop, k_mpc, T_mpc, type_MPC, predefined, h_init, kf_enabled):
     """Create several objects that are used in the control loop
 
     Args:
@@ -137,6 +137,7 @@ def init_objects(dt_tsid, dt_mpc, k_max_loop, k_mpc, T_mpc, type_MPC, predefined
         type_MPC (bool): which MPC you want to use (PA's or Thomas')
         predefined (bool): if we are using a predefined reference velocity (True) or a joystick (False)
         h_init (float): initial height of the robot base
+        kf_enabled (bool): complementary filter (False) or kalman filter (True)
     """
 
     # Create Joystick object
@@ -146,7 +147,7 @@ def init_objects(dt_tsid, dt_mpc, k_max_loop, k_mpc, T_mpc, type_MPC, predefined
     logger = Logger.Logger(k_max_loop, dt_tsid, dt_mpc, k_mpc, T_mpc, type_MPC)
 
     # Create Estimator object
-    estimator = Estimator.Estimator(dt_tsid, k_max_loop, h_init)
+    estimator = Estimator.Estimator(dt_tsid, k_max_loop, h_init, kf_enabled)
 
     return joystick, logger, estimator