From b71cca7b3165327eda418cfa0d70aa97d3a741ff Mon Sep 17 00:00:00 2001
From: m-guberina <gubi.guberina@gmail.com>
Date: Sat, 1 Mar 2025 20:16:22 +0100
Subject: [PATCH] did run dual arm ik ocp, but there's something evil there.
 removed final velocity to be 0 because it makes no sense for an mpc, did put
 a  comment to make it optional if there is mpc. wrote what we have and what's
 missing for RealHeronRobotManager

---
 examples/optimal_control/dual_arm_ik_mpc.py   |  6 +-
 .../optimal_control/abstract_croco_ocp.py     | 17 +++--
 .../croco_mpc_path_following.py               |  5 +-
 .../croco_mpc_point_to_point.py               |  8 ++-
 .../path_following_croco_ocp.py               | 11 ++-
 .../point_to_point_croco_ocp.py               | 69 ++++++++++---------
 6 files changed, 65 insertions(+), 51 deletions(-)

diff --git a/examples/optimal_control/dual_arm_ik_mpc.py b/examples/optimal_control/dual_arm_ik_mpc.py
index 7b00318..82a3cc2 100644
--- a/examples/optimal_control/dual_arm_ik_mpc.py
+++ b/examples/optimal_control/dual_arm_ik_mpc.py
@@ -21,7 +21,7 @@ def get_args():
 if __name__ == "__main__":
     args = get_args()
     robot = getRobotFromArgs(args)
-    T_w_goal = getRandomlyGeneratedGoal(args)
+    T_w_absgoal = getRandomlyGeneratedGoal(args)
     T_absgoal_lgoal = pin.SE3.Identity()
     T_absgoal_lgoal.translation[1] = 0.1
     T_absgoal_rgoal = pin.SE3.Identity()
@@ -29,9 +29,9 @@ if __name__ == "__main__":
 
     if args.visualizer:
         # TODO: document this somewhere
-        robot.visualizer_manager.sendCommand({"Mgoal": T_w_goal})
+        robot.visualizer_manager.sendCommand({"Mgoal": T_w_absgoal})
 
-    CrocoDualEEP2PMPC(args, robot, T_w_goal)
+    CrocoDualEEP2PMPC(args, robot, T_w_absgoal, T_absgoal_lgoal, T_absgoal_rgoal)
 
     if args.real:
         robot.stopRobot()
diff --git a/python/smc/control/optimal_control/abstract_croco_ocp.py b/python/smc/control/optimal_control/abstract_croco_ocp.py
index e2551af..2612724 100644
--- a/python/smc/control/optimal_control/abstract_croco_ocp.py
+++ b/python/smc/control/optimal_control/abstract_croco_ocp.py
@@ -1,4 +1,4 @@
-from smc.robots.robotmanager_abstract import AbstractRobotManager
+from smc.robots.abstract_robotmanager import AbstractRobotManager
 
 import numpy as np
 import crocoddyl
@@ -84,8 +84,12 @@ class CrocoOCP(abc.ABC):
 
         # put these costs into the running costs
         for i in range(self.args.n_knots):
-            self.runningCostModels[i].addCost("xReg", self.xRegCost, self.args.u_reg_cost)
-            self.runningCostModels[i].addCost("uReg", self.uRegCost, self.args.x_reg_cost)
+            self.runningCostModels[i].addCost(
+                "xReg", self.xRegCost, self.args.u_reg_cost
+            )
+            self.runningCostModels[i].addCost(
+                "uReg", self.uRegCost, self.args.x_reg_cost
+            )
         # and add the terminal cost, which is the distance to the goal
         # NOTE: shouldn't there be a final velocity = 0 here?
         # --> no if you're not stopping at the last knot!
@@ -123,12 +127,7 @@ class CrocoOCP(abc.ABC):
 
         # TODO: replace this with subclass or whatever call
         # to check if the robot has mobilebase interface
-        if (
-            self.robot.robot_name == "heron"
-            or self.robot.robot_name == "heronros"
-            or self.robot.robot_name == "mirros"
-            or self.robot.robot_name == "yumi"
-        ):
+        if self.robot.robot_name == "heron" or self.robot.robot_name == "myumi":
             self.xlb = self.xlb[1:]
             self.xub = self.xub[1:]
 
diff --git a/python/smc/control/optimal_control/croco_mpc_path_following.py b/python/smc/control/optimal_control/croco_mpc_path_following.py
index c2aa9cf..5e0fb60 100644
--- a/python/smc/control/optimal_control/croco_mpc_path_following.py
+++ b/python/smc/control/optimal_control/croco_mpc_path_following.py
@@ -393,7 +393,6 @@ def BaseAndEEPathFollowingMPC(
 
 # TODO: the robot put in is a whole body robot,
 # which you need to implement
-THIS IS THE STILL BROKEN ONE
 def BaseAndDualArmEEPathFollowingMPCControlLoop(
     args,
     robot,
@@ -413,6 +412,7 @@ def BaseAndDualArmEEPathFollowingMPCControlLoop(
     or an instance of ProcessManager which spits out path points
     by calling ProcessManager.getData()
     """
+    raise NotImplementedError
     breakFlag = False
     log_item = {}
     save_past_dict = {}
@@ -530,7 +530,6 @@ def BaseAndDualArmEEPathFollowingMPCControlLoop(
     return breakFlag, save_past_dict, log_item
 
 
-NOT TEMPLETIZED YET
 def BaseAndDualArmEEPathFollowingMPC(args, robot, path_planner):
     """
     CrocoEndEffectorPathFollowingMPC
@@ -540,7 +539,7 @@ def BaseAndDualArmEEPathFollowingMPC(args, robot, path_planner):
     a dynamics level, and velocities we command
     are actually extracted from the state x(q,dq).
     """
-
+    raise NotImplementedError("this has to be templetized like the previous cases")
     x0 = np.concatenate([robot.q, robot.v])
     ocp = BaseAndDualArmEEPathFollowingOCP(args, robot, x0)
     ocp.solveInitialOCP(x0)
diff --git a/python/smc/control/optimal_control/croco_mpc_point_to_point.py b/python/smc/control/optimal_control/croco_mpc_point_to_point.py
index 8d4b489..d794725 100644
--- a/python/smc/control/optimal_control/croco_mpc_point_to_point.py
+++ b/python/smc/control/optimal_control/croco_mpc_point_to_point.py
@@ -121,7 +121,10 @@ def CrocoDualEEP2PMPC(
     are actually extracted from the state x(q,dq)
     """
     x0 = np.concatenate([robot.q, robot.v])
-    ocp = DualArmIKOCP(args, robot, x0, T_w_absgoal)
+    T_w_lgoal = T_absgoal_l.act(T_w_absgoal)
+    T_w_rgoal = T_absgoal_r.act(T_w_absgoal)
+
+    ocp = DualArmIKOCP(args, robot, x0, (T_w_lgoal, T_w_rgoal))
     ocp.solveInitialOCP(x0)
 
     controlLoop = partial(
@@ -136,9 +139,10 @@ def CrocoDualEEP2PMPC(
     )
     log_item = {
         "qs": np.zeros(robot.nq),
-        "err_norm": np.zeros(1),
         "dqs": np.zeros(robot.nv),
         "dqs_cmd": np.zeros(robot.nv),
+        "l_err_norm": np.zeros(1),
+        "r_err_norm": np.zeros(1),
     }
     save_past_dict = {}
     loop_manager = ControlLoopManager(
diff --git a/python/smc/control/optimal_control/path_following_croco_ocp.py b/python/smc/control/optimal_control/path_following_croco_ocp.py
index d91b979..698bf71 100644
--- a/python/smc/control/optimal_control/path_following_croco_ocp.py
+++ b/python/smc/control/optimal_control/path_following_croco_ocp.py
@@ -2,7 +2,10 @@ from smc.control.optimal_control.abstract_croco_ocp import CrocoOCP
 from smc.robots.interfaces.mobile_base_interface import MobileBaseInterface
 from smc.robots.interfaces.single_arm_interface import SingleArmInterface
 from smc.robots.interfaces.dual_arm_interface import DualArmInterface
-from smc.robots.interfaces.whole_body_interface import SingleArmWholeBodyInterface, DualArmWholeBodyInterface
+from smc.robots.interfaces.whole_body_interface import (
+    SingleArmWholeBodyInterface,
+    DualArmWholeBodyInterface,
+)
 
 import numpy as np
 import crocoddyl
@@ -178,8 +181,12 @@ class BaseAndEEPathFollowingOCP(CrocoOCP):
         ].cost.residual.reference = pathSE3[-1]
 
 
+class DualArmEEPathFollowingOCP(CrocoOCP):
+    def __init__(self, args, robot: DualArmInterface, x0):
+        goal = None
+        raise NotImplementedError
+        super().__init__(args, robot, x0, goal)
 
-JUST THE DUAL ARM IS MISSING
 
 class BaseAndDualArmEEPathFollowingOCP(CrocoOCP):
     def __init__(self, args, robot: DualArmWholeBodyInterface, x0):
diff --git a/python/smc/control/optimal_control/point_to_point_croco_ocp.py b/python/smc/control/optimal_control/point_to_point_croco_ocp.py
index d404299..1b9625d 100644
--- a/python/smc/control/optimal_control/point_to_point_croco_ocp.py
+++ b/python/smc/control/optimal_control/point_to_point_croco_ocp.py
@@ -33,15 +33,17 @@ class SingleArmIKOCP(CrocoOCP):
         goalTrackingCost = crocoddyl.CostModelResidual(
             self.state, framePlacementResidual
         )
-        frameVelocityResidual = crocoddyl.ResidualModelFrameVelocity(
-            self.state,
-            self.robot.ee_frame_id,
-            pin.Motion(np.zeros(6)),
-            pin.ReferenceFrame.WORLD,
-        )
-        frameVelocityCost = crocoddyl.CostModelResidual(
-            self.state, frameVelocityResidual
-        )
+        # TODO: final velocity costs only make sense if you're running a single ocp, but not mpc!!
+        # TODO: have an argument or something to include or not include them!
+        # frameVelocityResidual = crocoddyl.ResidualModelFrameVelocity(
+        #    self.state,
+        #    self.robot.ee_frame_id,
+        #    pin.Motion(np.zeros(6)),
+        #    pin.ReferenceFrame.WORLD,
+        # )
+        # frameVelocityCost = crocoddyl.CostModelResidual(
+        #    self.state, frameVelocityResidual
+        # )
         for i in range(self.args.n_knots):
             self.runningCostModels[i].addCost(
                 "gripperPose" + str(i), goalTrackingCost, 1e2
@@ -49,7 +51,7 @@ class SingleArmIKOCP(CrocoOCP):
         self.terminalCostModel.addCost(
             "gripperPose" + str(self.args.n_knots), goalTrackingCost, 1e2
         )
-        self.terminalCostModel.addCost("velFinal", frameVelocityCost, 1e3)
+        # self.terminalCostModel.addCost("velFinal", frameVelocityCost, 1e3)
 
     # there is nothing to update in a point-to-point task
     def updateCosts(self, data):
@@ -76,13 +78,13 @@ class DualArmIKOCP(CrocoOCP):
         T_w_lgoal, T_w_rgoal = goal
         framePlacementResidual_l = crocoddyl.ResidualModelFramePlacement(
             self.state,
-            self.robot.model.l_ee_frame_id,
+            self.robot.l_ee_frame_id,
             T_w_lgoal.copy(),
             self.state.nv,
         )
         framePlacementResidual_r = crocoddyl.ResidualModelFramePlacement(
             self.state,
-            self.robot.model.r_ee_frame_id,
+            self.robot.r_ee_frame_id,
             T_w_rgoal.copy(),
             self.state.nv,
         )
@@ -92,24 +94,27 @@ class DualArmIKOCP(CrocoOCP):
         goalTrackingCost_r = crocoddyl.CostModelResidual(
             self.state, framePlacementResidual_r
         )
-        frameVelocityResidual_l = crocoddyl.ResidualModelFrameVelocity(
-            self.state,
-            self.robot.model.l_ee_frame_id,
-            pin.Motion(np.zeros(6)),
-            pin.ReferenceFrame.WORLD,
-        )
-        frameVelocityResidual_r = crocoddyl.ResidualModelFrameVelocity(
-            self.state,
-            self.robot.model.r_ee_frame_id,
-            pin.Motion(np.zeros(6)),
-            pin.ReferenceFrame.WORLD,
-        )
-        frameVelocityCost_l = crocoddyl.CostModelResidual(
-            self.state, frameVelocityResidual_l
-        )
-        frameVelocityCost_r = crocoddyl.CostModelResidual(
-            self.state, frameVelocityResidual_r
-        )
+        # TODO: final velocity costs only make sense if you're running a single ocp, but not mpc!!
+        # TODO: have an argument or something to include or not include them!
+
+        # frameVelocityCost_l = crocoddyl.CostModelResidual(
+        #    self.state, frameVelocityResidual_l
+        # frameVelocityResidual_l = crocoddyl.ResidualModelFrameVelocity(
+        #    self.state,
+        #    self.robot.l_ee_frame_id,
+        #    pin.Motion(np.zeros(6)),
+        #    pin.ReferenceFrame.WORLD,
+        # )
+        # frameVelocityResidual_r = crocoddyl.ResidualModelFrameVelocity(
+        #    self.state,
+        #    self.robot.r_ee_frame_id,
+        #    pin.Motion(np.zeros(6)),
+        #    pin.ReferenceFrame.WORLD,
+        # )
+        # )
+        # frameVelocityCost_r = crocoddyl.CostModelResidual(
+        #    self.state, frameVelocityResidual_r
+        # )
         for i in range(self.args.n_knots):
             self.runningCostModels[i].addCost(
                 "gripperPose_l" + str(i), goalTrackingCost_l, 1e2
@@ -123,8 +128,8 @@ class DualArmIKOCP(CrocoOCP):
         self.terminalCostModel.addCost(
             "gripperPose_r" + str(self.args.n_knots), goalTrackingCost_r, 1e2
         )
-        self.terminalCostModel.addCost("velFinal_l", frameVelocityCost_l, 1e3)
-        self.terminalCostModel.addCost("velFinal_r", frameVelocityCost_r, 1e3)
+        # self.terminalCostModel.addCost("velFinal_l", frameVelocityCost_l, 1e3)
+        # self.terminalCostModel.addCost("velFinal_r", frameVelocityCost_r, 1e3)
 
     # there is nothing to update in a point-to-point task
     def updateCosts(self, data):
-- 
GitLab