diff --git a/examples/math_understanding/path6d_from_path2d.py b/examples/math_understanding/path6d_from_path2d.py
index 8efa02bc57dc3aa9b70960105369ed614f23c61a..41a2da95d176ce42cdd314bd004505732e99fb89 100644
--- a/examples/math_understanding/path6d_from_path2d.py
+++ b/examples/math_understanding/path6d_from_path2d.py
@@ -123,9 +123,9 @@ for p in pathSE3_handlebar:
 #    rotation = np.eye(3)
 #    some_path.append(pin.SE3(rotation, translation))
 for i in range(100):
-    visualizer_manager.sendCommand({"frame_path": pathSE3_handlebar})
+    visualizer_manager.sendCommand({"fixed_frame_path": pathSE3_handlebar})
     # visualizer_manager.sendCommand({"frame_path": some_path})
-    visualizer_manager.sendCommand({"path": pathSE3_handlebar})
+    visualizer_manager.sendCommand({"fixed_path": pathSE3_handlebar})
     time.sleep(1)
 print("send em")
 
diff --git a/examples/math_understanding/rotate_around_z.py b/examples/math_understanding/rotate_around_z.py
index 0c8b1e8d44d0eb4829184cd2838df71d24c34506..fbc5583bc4ef35fb6937aaf9af413fddb6d5bfea 100644
--- a/examples/math_understanding/rotate_around_z.py
+++ b/examples/math_understanding/rotate_around_z.py
@@ -7,7 +7,8 @@ import meshcat_shapes
 
 A = pin.SE3.Identity()
 B = pin.SE3.Identity()
-B.rotation = pin.rpy.rpyToMatrix(0.0, 0.0, np.random.random())
+theta_z = np.random.random()
+B.rotation = pin.rpy.rpyToMatrix(0.0, 0.0, theta_z)
 B.translation += np.random.random(3)
 
 interpolated = []
diff --git a/examples/navigation/mobile_base_navigation.py b/examples/navigation/mobile_base_navigation.py
index 8ab2d287959307213895169158bf680520c860a1..446cd99e2cd30a7c3b87f85ba7e708339cfdba73 100644
--- a/examples/navigation/mobile_base_navigation.py
+++ b/examples/navigation/mobile_base_navigation.py
@@ -158,11 +158,11 @@ if __name__ == "__main__":
         path2D[:, 1] = path2D[:, 1] * args.map_height
         path2D = np.hstack((path2D, np.zeros((len(path2D), 1))))
         robot.updateViz({"fixed_path": path2D})
-        CrocoBaseP2PMPC(args, robot, path2D[0])
+        # CrocoBaseP2PMPC(args, robot, path2D[0])
         path_planner = partial(fixedPathPlanner, [0], path2D)
 
-    CrocoBasePathFollowingMPC(args, robot, x0, path_planner)
-    # cartesianPathFollowingWithPlanner(args, robot, path_planner)
+    # CrocoBasePathFollowingMPC(args, robot, x0, path_planner)
+    cartesianPathFollowingWithPlanner(args, robot, path_planner, 0.0)
     # MPCWithCLIKFallback(args, robot, path_planner)
 
     if args.real:
diff --git a/examples/ros/dummy_cmds_pub.py b/examples/ros/dummy_cmds_pub.py
index cd733707d1af7661054b6ececeefbeb811387a39..8b68dbca6ec447aaccd0abb294edd953a3e52aca 100755
--- a/examples/ros/dummy_cmds_pub.py
+++ b/examples/ros/dummy_cmds_pub.py
@@ -14,6 +14,7 @@
 
 
 import rclpy
+from rclpy.time import Time
 from rclpy.node import Node
 from rclpy.executors import MultiThreadedExecutor
 from geometry_msgs.msg import Twist, PoseWithCovarianceStamped
@@ -87,6 +88,10 @@ class DummyNode(Node):
         self, args, robot: RealMobileYumiRobotManager, loop_manager: ControlLoopManager
     ):
         super().__init__("dummy_cmds_pub_node")
+        self.set_parameters(
+            [rclpy.parameter.Parameter("use_sim_time", rclpy.Parameter.Type.BOOL, True)]
+        )
+        self.wait_for_sim_time()
         self.robot = robot
         self.loop_manager = loop_manager
         self.args = args
@@ -141,10 +146,13 @@ class DummyNode(Node):
             JointState, f"{self._ns}/platform/joints_cmd", 1
         )
         self.robot.set_publisher_joints_cmd(self._cmd_pub)
-        self._cmd_pub = self.create_publisher(JointState, f"{self._ns}joints_cmd", 1)
+        # self._cmd_pub = self.create_publisher(JointState, f"{self._ns}joints_cmd", 1)
         self.sub_base_odom = self.create_subscription(
             Odometry, f"{self._ns}/platform/odometry", self.callback_base_odom, 1
         )
+        self.get_logger().info(f"{self._ns}/platform/joints_cmd")
+        self.get_logger().info(f"{self._ns}/platform/odometry")
+        self.get_logger().info(f"{self._ns}/platform/joint_states")
 
     ##########
     # base is a twist which is constructed from the first 3 msg.velocities
@@ -156,14 +164,24 @@ class DummyNode(Node):
 
     def send_cmd(self):
         breakFlag = self.loop_manager.run_one_iter(self.loop_manager.current_iteration)
+        if breakFlag:
+            self.get_logger().info("control loop finished")
+
+        msg = self.empty_msg
+        for i in range(3):
+            msg.velocity[i] = self.robot._v[i]
+        for i in range(15, 29):
+            msg.velocity[i] = self.robot._v[i - 12]
+
+        # msg.header.stamp = Time().to_msg()
+        ## msg.header.stamp = self.get_clock().now().to_msg()
+        msg.header.stamp = self.get_clock().now().to_msg()
+        # msg.velocity[21] = 1.0
+        # msg.velocity[28] = 1.0
+        self._cmd_pub.publish(msg)
 
-        # msg = self.empty_msg
-        # for i in range(3):
-        #    msg.velocity[i] = self.robot._v[i]
-        # for i in range(15, 29):
-        #    msg.velocity[i] = self.robot._v[i - 12]
-        # self.get_logger().info(str(self.robot._v))
-        # self._cmd_pub.publish(msg)
+        # self.get_logger().info("SEND_JOINTS_CMD ON TIMER" + str(msg))
+        # self.get_logger().info(str(Time()))
 
     def callback_base_odom(self, msg: Odometry):
         # self.robot._v[0] = msg.twist.twist.linear.x
@@ -186,14 +204,22 @@ class DummyNode(Node):
             self.robot._q[1] = msg.pose.pose.position.y
             self.robot._q[2] = np.cos(th)
             self.robot._q[3] = np.sin(th)
+        # self.get_logger().info("ODOM CALLBACK" + str(msg))
 
     def callback_arms_state(self, msg: JointState):
         if self.loop_manager.current_iteration < 200 or self.args.unreal:
             self.robot._q[-14:-7] = msg.position[-14:-7]
             self.robot._q[-7:] = msg.position[-7:]
-        # self.get_logger().info(str(msg))
+        # self.get_logger().info("JOINT_STATE CALLBACK" + str(msg))
         # self.get_logger().info(str(self.loop_manager.current_iteration))
 
+    def wait_for_sim_time(self):
+        """Wait for the /clock topic to start publishing."""
+        self.get_logger().info("Waiting for simulated time to be active...")
+        while not self.get_clock().now().nanoseconds > 0:
+            rclpy.spin_once(self, timeout_sec=0.1)
+        self.get_logger().info("Simulated time is now active!")
+
 
 # def main(args=None):
 def main(args=None):
@@ -210,14 +236,19 @@ def main(args=None):
     T_absgoal_r = pin.SE3.Identity()
     T_absgoal_r.translation = np.array([0.0, -0.2, 0.0])
     # loop_manager = CrocoIKMPC(args, robot, goal, run=False)
-    # robot._mode = robot.control_mode.upper_body
-    # loop_manager = moveJP(robot._comfy_configuration, args_smc, robot, run=False)
-    # loop_manager = moveLDualArm(
-    #    args_smc, robot, T_w_absgoal, T_absgoal_l, T_absgoal_r, run=False
-    # )
-    # loop_manager = moveL(args_smc, robot, T_w_absgoal, run=False)
-    robot._mode = robot.control_mode.whole_body
-    loop_manager = CrocoBaseP2PMPC(args_smc, robot, np.zeros(3), run=False)
+    # TODO: put all loops and corresponding modes in this list
+    # then in cmd_pub callback go to the next loop
+    # once you get a breakFlag == True
+    loops_n_modes = []
+    mode = robot.control_mode.upper_body
+    loop_manager = moveJP(robot._comfy_configuration, args_smc, robot, run=False)
+    loops_n_modes.append(mode, loop_manager)
+    loop_manager = moveLDualArm(
+        args_smc, robot, T_w_absgoal, T_absgoal_l, T_absgoal_r, run=False
+    )
+    loops_n_modes.append(mode, loop_manager)
+    # robot._mode = robot.control_mode.whole_body
+    # loop_manager = CrocoBaseP2PMPC(args_smc, robot, np.zeros(3), run=False)
 
     rclpy.init(args=args)
 
diff --git a/examples/ros/navigation_example.py b/examples/ros/navigation_example.py
index 52ae0990347976133b543025358a5a9628b2f80b..f20b10ad94891fde296f9be1ca1953c718a8f959 100644
--- a/examples/ros/navigation_example.py
+++ b/examples/ros/navigation_example.py
@@ -127,7 +127,7 @@ def get_args():
     args.ctrl_freq = 50
     # NOTE: does not work due to ctrl-c being overriden
     args.save_log = True
-    args.run_name = "pls"
+    args.run_name = "nav_pls"
     args.index_runs = True
     return args
 
@@ -190,6 +190,7 @@ class DummyNode(Node):
         self._cmd_pub = self.create_publisher(
             JointState, f"{self._ns}/platform/joints_cmd", 1
         )
+        self.get_logger().info(f"{self._ns}/platform/joints_cmd")
         self.robot.set_publisher_joints_cmd(self._cmd_pub)
         self._cmd_pub = self.create_publisher(JointState, f"{self._ns}joints_cmd", 1)
         self.sub_base_odom = self.create_subscription(
diff --git a/examples/ros/stop_robot.py b/examples/ros/stop_robot.py
index 5561e75d2907784a39910011fc79cae63ecee3ef..ee3a252e8885e2da80cdfa340238618e953df908 100644
--- a/examples/ros/stop_robot.py
+++ b/examples/ros/stop_robot.py
@@ -41,7 +41,7 @@ class DummyNode(Node):
         self.get_logger().info(f"### Starting dummy example under namespace {self._ns}")
 
         self._cmd_pub = self.create_publisher(
-            JointState, f"{self._ns}/platform/joints_cmd", 1
+            JointState, f"/{self._ns}/platform/joints_cmd", 1
         )
         self.empty_msg = JointState()
         for i in range(29):
diff --git a/python/smc/control/cartesian_space/cartesian_space_trajectory_following.py b/python/smc/control/cartesian_space/cartesian_space_trajectory_following.py
index 949d83dec5d9dde3caca689c3f409c4bf46be26c..280cb399b0a07d0c8ae7b00c41eb41093ce50661 100644
--- a/python/smc/control/cartesian_space/cartesian_space_trajectory_following.py
+++ b/python/smc/control/cartesian_space/cartesian_space_trajectory_following.py
@@ -21,6 +21,7 @@ import types
 def cartesianPathFollowingControlLoop(
     ik_solver: Callable[[np.ndarray, np.ndarray], np.ndarray],
     path: list[pin.SE3] | np.ndarray,
+    rot_x: float,
     args: Namespace,
     robot: SingleArmInterface,
     t: int,
@@ -34,12 +35,12 @@ def cartesianPathFollowingControlLoop(
 
     # TODO: refactor this horror out of here
     if type(path) == np.ndarray:
-        path = path2D_to_SE3(path[:, :2], 0.0)
+        path = path2D_to_SE3(path[:, :2], 0.0, rot_x)
     # TODO: arbitrary bs, read a book and redo this
     # NOTE: assuming the first path point coincides with current pose
     SEerror = robot.T_w_e.actInv(path[1])
-    V_path = pin.log6(path[0].actInv(path[1])).vector
-    err_vector = pin.log6(SEerror).vector + V_path
+    # V_path = pin.log6(path[0].actInv(path[1])).vector
+    err_vector = pin.log6(SEerror).vector  # + V_path
     J = robot.getJacobian()
     v_cmd = ik_solver(J, err_vector)
 
diff --git a/python/smc/control/control_loop_manager.py b/python/smc/control/control_loop_manager.py
index d7bfefb8a9b59f0337eadddd1400cf989e06cf6d..d67efe15579fcab42b123c4e865dc27e0e23c733 100644
--- a/python/smc/control/control_loop_manager.py
+++ b/python/smc/control/control_loop_manager.py
@@ -75,6 +75,7 @@ class ControlLoopManager:
         self.args: Namespace = args
         self.iter_n: int = 0
         self.past_data: dict[str, deque[np.ndarray]] = {}
+        self.current_iteration = 0
         # NOTE: viz update rate is a magic number that seems to work fine and i don't have
         # any plans to make it smarter
         if args.viz_update_rate < 0 and args.ctrl_freq > 0:
@@ -114,6 +115,7 @@ class ControlLoopManager:
         it's the controlLoop's responsibility to break if it achieved it's goals.
         this is done via the breakFlag
         """
+        self.current_iteration += 1
         # NOTE: all required pre-computations are handled here
         self.robot_manager._step()
         # TODO make the arguments to controlLoop kwargs or whatever
@@ -185,7 +187,9 @@ class ControlLoopManager:
 
     def run(self):
         self.final_iteration = 0
+        self.current_iteration = 0
         for i in range(self.max_iterations):
+            self.current_iteration = i
             start = time.time()
             breakFlag = self.run_one_iter(i)
 
diff --git a/python/smc/control/controller_templates/path_following_template.py b/python/smc/control/controller_templates/path_following_template.py
index 49aa904b984fd466d9610e7de9d25a2f657c9303..76fa3d074872032946873c3ba3af21b261bdf2e0 100644
--- a/python/smc/control/controller_templates/path_following_template.py
+++ b/python/smc/control/controller_templates/path_following_template.py
@@ -52,7 +52,7 @@ def PathFollowingFromPlannerCtrllLoopTemplate(
             breakFlag = True
 
         if data == "done" or data is None:
-            robot.sendVelocityCommand(np.zeros(robot.model.nv))
+            robot.sendVelocityCommand(np.zeros(robot.nv))
             log_item["qs"] = robot.q
             log_item["dqs"] = robot.v
             return breakFlag, save_past_item, log_item
diff --git a/python/smc/control/joint_space/joint_space_point_to_point.py b/python/smc/control/joint_space/joint_space_point_to_point.py
index 06bc77d001d1f683a152955de5b50d1c9c0d29ad..823e1970271116790019f6ab0d5e2b96fcaf21bf 100644
--- a/python/smc/control/joint_space/joint_space_point_to_point.py
+++ b/python/smc/control/joint_space/joint_space_point_to_point.py
@@ -55,7 +55,9 @@ def moveJControlLoop(
 # fix this by tuning or whatever else.
 # MOVEL works just fine, so apply whatever's missing for there here
 # and that's it.
-def moveJP(q_desired: np.ndarray, args: Namespace, robot: AbstractRobotManager) -> None:
+def moveJP(
+    q_desired: np.ndarray, args: Namespace, robot: AbstractRobotManager, run=True
+) -> ControlLoopManager | None:
     """
     moveJP
     ---------------
@@ -72,9 +74,10 @@ def moveJP(q_desired: np.ndarray, args: Namespace, robot: AbstractRobotManager)
         "err_norm": np.zeros((1,)),
     }
     loop_manager = ControlLoopManager(robot, controlLoop, args, {}, log_item)
-    loop_manager.run()
-    if args.debug_prints:
-        print("MoveJP done: convergence achieved, reached destionation!")
+    if run:
+        loop_manager.run()
+    else:
+        return loop_manager
 
 
 def moveJPIControlLoop(
diff --git a/python/smc/control/optimal_control/abstract_croco_ocp.py b/python/smc/control/optimal_control/abstract_croco_ocp.py
index f7a6a6aa09bce8a7c145aa0a075b822a3ad1d21e..6aa842201b646636ce47820011722c8c7ea9e8b0 100644
--- a/python/smc/control/optimal_control/abstract_croco_ocp.py
+++ b/python/smc/control/optimal_control/abstract_croco_ocp.py
@@ -240,10 +240,11 @@ class CrocoOCP(abc.ABC):
         # solver = crocoddyl.SolverIpopt(problem)
         # TODO: select other solvers from arguments
         self.solver = crocoddyl.SolverBoxFDDP(self.problem)
-        if self.args.debug_prints:
-            self.solver.setCallbacks(
-                [crocoddyl.CallbackVerbose(), crocoddyl.CallbackLogger()]
-            )
+
+    #        if self.args.debug_prints:
+    #            self.solver.setCallbacks(
+    #                [crocoddyl.CallbackVerbose(), crocoddyl.CallbackLogger()]
+    #            )
 
     # NOTE: used by csqp
     def createMimSolver(self) -> None:
@@ -257,10 +258,11 @@ class CrocoOCP(abc.ABC):
         # solver = mim_solvers.SolverSQP(problem)
         # TODO: select other solvers from arguments
         self.solver = mim_solvers.SolverCSQP(self.problem)
-        if self.args.debug_prints:
-            self.solver.setCallbacks(
-                [mim_solvers.CallbackVerbose(), mim_solvers.CallbackLogger()]
-            )
+
+    #        if self.args.debug_prints:
+    #            self.solver.setCallbacks(
+    #                [mim_solvers.CallbackVerbose(), mim_solvers.CallbackLogger()]
+    #            )
 
     # this shouldn't really depend on x0 but i can't be bothered
     def solveInitialOCP(self, x0: np.ndarray):
diff --git a/python/smc/control/optimal_control/croco_path_following/mpc/base_reference_mpc.py b/python/smc/control/optimal_control/croco_path_following/mpc/base_reference_mpc.py
index 8a1399373896312db1bc69141a2e34ae7880fb7a..1f5a2b594974434d2f9d04c6c2b015e8d4a79e31 100644
--- a/python/smc/control/optimal_control/croco_path_following/mpc/base_reference_mpc.py
+++ b/python/smc/control/optimal_control/croco_path_following/mpc/base_reference_mpc.py
@@ -51,6 +51,8 @@ def CrocoBasePathFollowingMPCControlLoop(
         xs = np.array(ocp.solver.xs)
         v_cmd = xs[1, robot.model.nq :]
 
+    # NOTE: dirty hack for wholebody mode
+    # v_cmd[3:] = 0.0
     err_vector_base = np.linalg.norm(p - path_base[0][:2])  # z axis is irrelevant
     log_item = {}
     log_item["err_norm_base"] = np.linalg.norm(err_vector_base).reshape((1,))
diff --git a/python/smc/control/optimal_control/croco_point_to_point/mpc/base_reference_mpc.py b/python/smc/control/optimal_control/croco_point_to_point/mpc/base_reference_mpc.py
index 0399371fad1fffe53c10dfc6014f142740cb6da5..d74fc556bbdc82aeaa086cf99aac0ac547f9e491 100644
--- a/python/smc/control/optimal_control/croco_point_to_point/mpc/base_reference_mpc.py
+++ b/python/smc/control/optimal_control/croco_point_to_point/mpc/base_reference_mpc.py
@@ -14,6 +14,8 @@ from functools import partial
 from collections import deque
 from argparse import Namespace
 
+from IPython import embed
+
 
 def CrocoBaseP2PMPCControlLoop(
     ocp: CrocoOCP,
@@ -29,11 +31,14 @@ def CrocoBaseP2PMPCControlLoop(
     """
     # set initial state from sensor
     x0 = np.concatenate([robot.q, robot.v])
+    # embed()
     ocp.warmstartAndReSolve(x0)
     xs = np.array(ocp.solver.xs)
     # NOTE: for some reason the first value is always some wild bs
-    vel_cmd = xs[1, robot.model.nq :]
-    return vel_cmd, {}, {}
+    v_cmd = xs[1, robot.model.nq :]
+    # NOTE: dirty hack to work if wholebody mode, don't ask
+    v_cmd[3:] = 0.0
+    return v_cmd, {}, {}
 
 
 def CrocoBaseP2PMPC(
diff --git a/python/smc/path_generation/path_math/path2d_to_6d.py b/python/smc/path_generation/path_math/path2d_to_6d.py
index 752429325a86aa80631ac172e0d25daf550b2f6b..5adcce9c23af09c9dd597eb6017b00b8da4da7bc 100644
--- a/python/smc/path_generation/path_math/path2d_to_6d.py
+++ b/python/smc/path_generation/path_math/path2d_to_6d.py
@@ -2,7 +2,9 @@ import pinocchio as pin
 import numpy as np
 
 
-def path2D_to_SE3(path2D: np.ndarray, path_height: float) -> list[pin.SE3]:
+def path2D_to_SE3(
+    path2D: np.ndarray, path_height: float, rot_x: float
+) -> list[pin.SE3]:
     """
     path2D_SE3
     ----------
@@ -35,13 +37,22 @@ def path2D_to_SE3(path2D: np.ndarray, path_height: float) -> list[pin.SE3]:
     for i in range(len(path2D) - 1):
         # first set the x axis to be in the theta direction
         # TODO: make sure this one makes sense
+        # rotation = np.array(
+        #    [
+        #        [np.cos(thetas[i]), np.sin(thetas[i]), 0.0],
+        #        [np.sin(thetas[i]), -np.cos(thetas[i]), 0.0],
+        #        [0.0, 0.0, -1.0],
+        #    ]
+        # )
         rotation = np.array(
             [
-                [np.cos(thetas[i]), np.sin(thetas[i]), 0.0],
-                [np.sin(thetas[i]), -np.cos(thetas[i]), 0.0],
-                [0.0, 0.0, -1.0],
+                [np.cos(thetas[i]), -np.sin(thetas[i]), 0.0],
+                [np.sin(thetas[i]), np.cos(thetas[i]), 0.0],
+                [0.0, 0.0, 1.0],
             ]
         )
+        rot_mat_x = pin.rpy.rpyToMaxtrix(rox_t, 0.0, 0.0)
+        rotation = rot_mat_x @ rotation
         # rotation = pin.rpy.rpyToMatrix(0.0, 0.0, thetas[i])
         # rotation = pin.rpy.rpyToMatrix(np.pi / 2, np.pi / 2, 0.0) @ rotation
         translation = np.array([path2D[i][0], path2D[i][1], path_height])
diff --git a/python/smc/robots/abstract_robotmanager.py b/python/smc/robots/abstract_robotmanager.py
index baa81d88320cea0f6982a8f0e25c68dff3cb8507..6c10a00b76eaba0263334541df4851587b515406 100644
--- a/python/smc/robots/abstract_robotmanager.py
+++ b/python/smc/robots/abstract_robotmanager.py
@@ -331,10 +331,7 @@ class AbstractRobotManager(abc.ABC):
         else:
             print("not implemented yet, so nothing is going to happen!")
 
-
-    def getJacobian(self) -> np.ndarray:
-        ...
-
+    def getJacobian(self) -> np.ndarray: ...
 
     ########################################################################################
     # visualizer management. ideally transferred elsewhere
diff --git a/python/smc/robots/implementations/mobile_yumi.py b/python/smc/robots/implementations/mobile_yumi.py
index f1d6850da7139b95cde04805d08865dfbbb95595..35671a7a13f13e2e5e15dd34fd9595f37a2d3e1f 100644
--- a/python/smc/robots/implementations/mobile_yumi.py
+++ b/python/smc/robots/implementations/mobile_yumi.py
@@ -11,6 +11,7 @@ from smc.robots.abstract_robotmanager import AbstractRobotManager
 import pinocchio as pin
 from argparse import Namespace
 import numpy as np
+from importlib.util import find_spec
 
 if find_spec("rclpy"):
     from rclpy.time import Time
@@ -120,28 +121,33 @@ class RealMobileYumiRobotManager(AbstractMobileYuMiRobotManager):
         print("set publisher_joints_cmd into RobotManager")
 
     def sendVelocityCommandToReal(self, v: np.ndarray):
-        #        qd_base = qd[:3]
-        #        qd_left = qd[3:10]
-        #        qd_right = qd[10:]
-        #        self.publisher_vel_base(qd_base)
-        #        self.publisher_vel_left(qd_left)
-        #        self.publisher_vel_right(qd_right)
-        empty_msg = JointState()
-        for i in range(29):
-            empty_msg.velocity.append(0.0)
-        msg = empty_msg
-        msg.header.stamp = Time().to_msg()
-        for i in range(3):
-            msg.velocity[i] = v[i]
-        for i in range(15, 29):
-            msg.velocity[i] = v[i - 12]
-
-        self.publisher_joints_cmd.publish(msg)
-
-    # TODO: define set initial pose by reading it from the real robot (well, the appropriate ros2 topic in this case)
+
+        if self.args.unreal:
+            if any(np.isnan(v)):
+                v = np.zeros(self.model.nv)
+            self._v = v
+            # empty_msg = JointState()
+            # for i in range(29):
+            #    empty_msg.velocity.append(0.0)
+            # msg = empty_msg
+            # msg.header.stamp = Time().to_msg()
+            # for i in range(3):
+            #    msg.velocity[i] = v[i]
+            # for i in range(15, 29):
+            #    msg.velocity[i] = v[i - 12]
+            # if hasattr(self, "publisher_joints_cmd"):
+            #    self.publisher_joints_cmd.publish(msg)
+
+        else:
+            self._v = v
+            # NOTE: we update joint angles here, and _updateQ does nothing (there is no communication)
+            self._q = pin.integrate(self.model, self._q, v * self._dt)
+
+    # NOTE: handled by a topic callback
     def _updateQ(self):
         pass
 
+    # NOTE: handled by a topic callback
     def _updateV(self):
         pass
 
@@ -157,6 +163,18 @@ class RealMobileYumiRobotManager(AbstractMobileYuMiRobotManager):
     def connectToRobot(self):
         pass
 
+    def setInitialPose(self):
+        self._q = pin.randomConfiguration(
+            self.model, self.model.lowerPositionLimit, self.model.upperPositionLimit
+        )
+        # pin.RandomConfiguration does not work well for planar joint,
+        # or at least i remember something along those lines being the case
+        self._q[0] = np.random.random() * 0.1
+        self._q[1] = np.random.random() * 0.1
+        theta = np.random.random() * 2 * np.pi - np.pi
+        self._q[2] = np.cos(theta)
+        self._q[3] = np.sin(theta)
+
     # TODO: create simulated gripper class to support the move, open, close methods - it's a mess now
     # in simulation we can just set the values directly
     def connectToGripper(self):
diff --git a/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py b/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py
index 90e833ee646d86ad4c0fefbc6304e3afc2032f2d..b947cbaa3fae5cc21ce81706cde6b8c6ad7671f4 100644
--- a/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py
+++ b/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py
@@ -42,8 +42,9 @@ class MeshcatVisualizer(PMV):
         # there will be times when i just want to drop in points
         # which will never be changed
         self.n_points = 0
-        self.n_path_points = 0
+        # self.n_path_points = 0
         self.add_path_points_set = set()
+        self.add_fixed_path_points_set = set()
         self.n_frame_path_points = 0
         self.add_frame_path_points_set = set()
         self.n_obstacles = 0
@@ -112,22 +113,28 @@ class MeshcatVisualizer(PMV):
         self, name, path: list[pin.SE3] | np.ndarray, radius=5e-3, color=[0, 0, 1, 0.8]
     ):
         # NOTE: there's too much of them so the visualization is slow
-        self.n_path_points = len(path) if len(path) < 5 else 5
+        # self.n_path_points = len(path) if len(path) < 5 else 5
         if name == "fixed_path":
             color = [1, 0, 0, 0.8]
+        path_viz = path.copy()
         if type(path) == np.ndarray:
             # complete the quartenion
+            # if path.shape[1] == 2:
             path_viz = np.hstack((path, np.zeros((len(path), 3))))
             path_viz = np.hstack((path_viz, np.ones((len(path), 1))))
-        else:
-            path_viz = path.copy()
         index_step = len(path_viz) // 5
         for i, point in enumerate(path_viz):
-            if (i % index_step != 0) and name != "fixed_path":
+            if (i % index_step != 0) and "fixed" not in name:
                 continue
-            if i not in self.add_path_points_set:
-                self.addSphere(f"world/path_{name}_point_{i}", radius, color)
-                self.add_path_points_set.add(i)
+            # TODO: refactor ugly bs with same code under different if
+            if name == "path":
+                if i not in self.add_path_points_set:
+                    self.addSphere(f"world/path_{name}_point_{i}", radius, color)
+                    self.add_path_points_set.add(i)
+            if name == "fixed_path":
+                if i not in self.add_fixed_path_points_set:
+                    self.addSphere(f"world/path_{name}_point_{i}", radius, color)
+                    self.add_path_points_set.add(i)
             self.applyConfiguration(f"world/path_{name}_point_{i}", point)
         # self.n_path_points = max(i, self.n_path_points)
 
diff --git a/python/smc/visualization/visualizer.py b/python/smc/visualization/visualizer.py
index 3abc3df4232c841325df26899628405c086004cb..5a816e5aee8b7c9fb35379dc176abf7b13071f52 100644
--- a/python/smc/visualization/visualizer.py
+++ b/python/smc/visualization/visualizer.py
@@ -24,6 +24,7 @@ def manipulatorVisualizer(
     viz = MeshcatVisualizer(
         model=model, collision_model=collision_model, visual_model=visual_model
     )
+
     viz.loadViewerModel()
     # display the initial pose
     viz.display(cmd["q"])
@@ -69,15 +70,13 @@ def manipulatorVisualizer(
                 if key == "obstacle_box":
                     # stupid and evil but there is no time
                     viz.addBoxObstacle(cmd["obstacle_box"][0], cmd["obstacle_box"][1])
-                if key == "path":
-                    # stupid and evil but there is no time
-                    viz.addPath("path", cmd["path"])
-                if key == "fixed_path":
-                    # stupid and evil but there is no time
-                    viz.addPath("fixed_path", cmd["fixed_path"])
-                if key == "frame_path":
+                if "path" in key:
                     # stupid and evil but there is no time
-                    viz.addFramePath("", cmd["frame_path"])
+                    if not "frame" in key:
+                        viz.addPath(key, cmd[key])
+                    else:
+                        # stupid and evil but there is no time
+                        viz.addFramePath(key, cmd[key])
 
     except KeyboardInterrupt:
         if args.debug_prints: