From ae6eb938511af6d97639e74d9328f486236a7898 Mon Sep 17 00:00:00 2001
From: m-guberina <gubi.guberina@gmail.com>
Date: Tue, 5 Nov 2024 12:27:49 +0100
Subject: [PATCH] added meshcat visualization for goal and current ee position
 as frames

---
 .../__pycache__/managers.cpython-312.pyc      | Bin 43272 -> 44399 bytes
 .../basics/__pycache__/basics.cpython-312.pyc | Bin 8614 -> 8792 bytes
 python/ur_simple_control/basics/basics.py     |   7 +-
 python/ur_simple_control/managers.py          |  85 ++++++++++--------
 .../crocoddyl_optimal_control.py              |  16 ++--
 .../__pycache__/get_model.cpython-312.pyc     | Bin 4144 -> 7559 bytes
 python/ur_simple_control/util/get_model.py    |  78 ++++++++++++++++
 .../__pycache__/visualize.cpython-312.pyc     | Bin 16886 -> 17386 bytes
 .../ur_simple_control/visualize/visualize.py  |  38 ++++++--
 9 files changed, 173 insertions(+), 51 deletions(-)

diff --git a/python/ur_simple_control/__pycache__/managers.cpython-312.pyc b/python/ur_simple_control/__pycache__/managers.cpython-312.pyc
index b59fcce0499fab94884093e38ecf948933a2717a..eebd716670a2552ef6b2850384768b390ae8cf3d 100644
GIT binary patch
delta 7967
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

delta 7091
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
J7(gUAC;@9`)UyBp

diff --git a/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc b/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc
index e1ec0d0b99d4fb96948b9ab5c2c7409a97300de5..1faaaed581604ec4087a48d6b79a04fa2e648a92 100644
GIT binary patch
delta 753
zcmZ4He8YwJG%qg~0|NuY331KzDI0kMIT%-Mj^~)f9LSg@0}@BYDV*6F3=BoAHM}((
zRa^`VwSqO+)p3E<DVB)C^k>OUb`%tyypdbPn4^YwH8VuKR<MSzh7)X(Pzraga0*YY
zNDW_&aJ^s^D+5Cn0|P^?XboeQ;$%lb;mNi<0^Gbd3=9l4LN)9ue3K)1WL5dWeBK)N
z6ag@cuZBHE5X@rDWT;_JV-9A}6q-DXM_K+BOKFj5>Mhoc)S~>nbcppI?4gVY_LHyh
zSTYJu=Hm^Ozr|IQpOjw`pO=`MdW$P1Gc7H(C^auRwMdYGfk9Jjau)AW)?zUR28PM9
ze70Nx3=9n33=9m#b2g{&J!Q1w;JwZ+evw^#hS?={#T!E6GZZIkcCg=I=Ya~FUt(9f
zBP2RqZ=&7;(dE($rB@_w5WOs9-oZXOP(YdS!R7{mL}nL51_p*ABM_ktB6LB7F^Dh$
z5vCwQ9^@LHB2Y*cfgDk!2@>T65!N8WZnCO~4!0wSsRkmPCdY{AvxYD*FihG!K_r8P
z(QNWhi5LqfkQ^wQio!swa0Uj3TbzX{@rlVLrHMI35+K0{kRVTPVnuvrUP)?tQDRP!
z@8n)d8`fk728QLE&q*F()&;3S7@^5h1a^2dOnVW?;3^B>{IXQ90ME$+>{^pw%Bo6$
z3@G9ODT25e#0mlht$~Q>WNSG!MyJV1aw@E#X!^dnTTYmf(Pr{|`9cA(he3WR0-KON
kSwW$Rv3l}i1qU%#Mn>fgE*}^`^Z}XAVEU8a<ev&_0h%kQ?*IS*

delta 605
zcmccNvdo$HG%qg~0|NuYyd}!%EE{<PIT+10$8$_#w&bnhsN!N^s1>Z?tKkH*gi<(b
zg;Tg{MQZqJglhz=SQ!|q7#J98MQcP;7*e>U7;4387_($27s?7ti>_t_naaSx$WS9#
z!=A!p!@$5$BUHnl!aMm4kE|*mn9p0op281i@zt=W2!L6vnG7}TY0SY4nu3%0c$LM|
zA?AFrhcX`67jZH$FiZ~MwPfU<+{GKpUL?rCz@RBU`5*66;ahBlDe=j<DaGOp3=9fj
zFgZX<eDV=KMJ`_k1_o~i28QC&&F}f1GIH>XOi1j^Y;d2<C#cMGgI8#R(FDhi$Og9?
zn~ek$nO*c57#NBSK!i4k&;=2OAi@Yl7=s9Tki|Sj%pf+%^de0Vix)&#f(V<**F|)=
zZ9z;m5Mei&PgI{Zkb!}rf3uTl1`DIf<kgZf7Iq*xkb{eYL97r428LUlg(>lg$t9(U
zIYkm6!BCJOPi|sGd}dxrYI;#(PLbzidnp^%1O^6%C7T<hjxZ~N)F6z|WGMnWJOZY@
zC}eV~T(l@iLlF;15aLD<%YX7!IXgzX$s+P9tSJl(3|}_e$_q0xT1^gAC=>wu4CLq{
ou-25xmlT>9D<+33I*2(jGAeIy`M?0856FB5)1N#huU1?O01hLB*8l(j

diff --git a/python/ur_simple_control/basics/basics.py b/python/ur_simple_control/basics/basics.py
index aeb9534..c8f48d0 100644
--- a/python/ur_simple_control/basics/basics.py
+++ b/python/ur_simple_control/basics/basics.py
@@ -120,14 +120,17 @@ def jointTrajFollowingPDControlLoop(stop_at_final : bool, robot: RobotManager, r
 
 
 
-    error_q = q_ref - q
+    if robot.robot_name == "ur5e":
+        error_q = q_ref - q
+    if robot.robot_name == "heron":
+        error_q = pin.difference(robot.model, q, q_ref) #/ robot.dt
     error_v = v_ref - v
     Kp = 1.0
     Kd = 0.5
 
     #          feedforward                      feedback 
     v_cmd = v_ref + Kp * error_q #+ Kd * error_v
-    qd_cmd = v_cmd[:6]
+    #qd_cmd = v_cmd[:6]
     robot.sendQd(v_cmd)
 
     log_item['error_qs'] = error_q
diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py
index dfffff5..a23fba3 100644
--- a/python/ur_simple_control/managers.py
+++ b/python/ur_simple_control/managers.py
@@ -1,12 +1,5 @@
 # TODO rename all private variables to start with '_'
-# TODO: neither visualization works without printing from manager, 
-#       make this make sense dude (but it does work with that, so this aint prio)
-# TODO: just read the q and update everything every timestep, don't deepcopy,
-# TODO: rewrite all getSomething functions to updateSomething functions,
-#       and then make the getSomething function just be return self.something.copy()
-# --> just create a RobotManager.step() function, update everything there
-# don't do forwardKinematics 2 extra times for no good reason. make that the libraries
-# responsibility, not the users
+# TODO: make importing nicer with __init__.py files
 import pinocchio as pin
 import numpy as np
 import time
@@ -17,12 +10,13 @@ from ur_simple_control.util.grippers.robotiq.robotiq_gripper import RobotiqGripp
 from ur_simple_control.util.grippers.on_robot.twofg import TWOFG
 import copy
 import signal
-from ur_simple_control.util.get_model import get_model
+from ur_simple_control.util.get_model import get_model, heron_approximation
 from collections import deque
 from ur_simple_control.visualize.visualize import plotFromDict, realTimePlotter, manipulatorVisualizer
 from ur_simple_control.util.logging_utils import LogManager
 from multiprocessing import Process, Queue
 import argparse
+from sys import exc_info
 
 """
 general notes
@@ -75,6 +69,9 @@ def getMinimalArgParser():
     #################################################
     #  general arguments: connection, plotting etc  #
     #################################################
+    parser.add_argument('--robot', type=str, \
+            help="which robot you're running or simulating", default="ur5e", \
+            choices=['ur5e', 'heron'])
     parser.add_argument('--simulation', action=argparse.BooleanOptionalAction, \
             help="whether you are running the UR simulator", default=False)
     parser.add_argument('--robot-ip', type=str, 
@@ -273,7 +270,8 @@ class ControlLoopManager:
                 # don't send what wasn't ready
                 if self.args.visualize_manipulator:
                     if self.robot_manager.manipulator_visualizer_queue.qsize() < 5:
-                        self.robot_manager.manipulator_visualizer_queue.put_nowait(self.robot_manager.q)
+                        self.robot_manager.manipulator_visualizer_queue.put_nowait({"q" : self.robot_manager.q,
+                                                                                    "T_w_e" : self.robot_manager.getT_w_e()})
 #                    if self.args.debug_prints:
 #                        print("manipulator_visualizer_queue size status:", self.robot_manager.manipulator_visualizer_queue.qsize())
                 if self.args.real_time_plotting:
@@ -334,7 +332,7 @@ class ControlLoopManager:
         """
         print('sending 300 speedjs full of zeros and exiting')
         for i in range(300):
-            vel_cmd = np.zeros(6)
+            vel_cmd = np.zeros(self.robot_manager.model.nv)
             #self.robot_manager.rtde_control.speedJ(vel_cmd, 0.1, 1.0 / 500)
             self.robot_manager.sendQd(vel_cmd)
         # hopefully this actually stops it
@@ -363,7 +361,7 @@ class ControlLoopManager:
         if self.args.visualize_manipulator:
             if self.args.debug_prints:
                 print("i am putting befree in manipulator to stop the manipulator visualizer")
-            self.robot_manager.manipulator_visualizer_queue.put_nowait("befree")
+            self.robot_manager.manipulator_visualizer_queue.put_nowait({"befree" : "befree"})
             #time.sleep(1)
             #self.robot_manager.manipulator_visualizer_process.join()
             self.robot_manager.manipulator_visualizer_process.terminate()
@@ -421,8 +419,14 @@ class RobotManager:
         self.simulation = args.simulation
         # load model
         # collision and visual models are none if args.visualize == False
-        self.model, self.collision_model, self.visual_model, self.data = \
-             get_model()
+        self.robot_name = args.robot
+        if self.robot_name == "ur5e":
+            self.model, self.collision_model, self.visual_model, self.data = \
+                 get_model()
+        if self.robot_name == "heron":
+            self.model, self.collision_model, self.visual_model, self.data = \
+                 heron_approximation()
+
         # start visualize manipulator process if selected.
         # has to be started here because it lives throughout the whole run
         if args.visualize_manipulator:
@@ -529,7 +533,7 @@ class RobotManager:
             q = np.array(q)
             self.q = q
             if args.visualize_manipulator:
-                self.manipulator_visualizer_queue.put(q)
+                self.manipulator_visualizer_queue.put({"q" : q})
 
 
         # do it once to get T_w_e
@@ -816,24 +820,31 @@ class RobotManager:
         """
         # we're hiding the extra 2 prismatic joint shenanigans from the control writer
         # because there you shouldn't need to know this anyway
-        qd_cmd = qd[:6]
-        # np.clip is ok with bounds being scalar, it does what it should
-        # (but you can also give it an array)
-        qd_cmd = np.clip(qd_cmd, -1 * self.max_qd, self.max_qd)
-        if not self.pinocchio_only:
-            # speedj(qd, scalar_lead_axis_acc, hangup_time_on_command)
-            self.rtde_control.speedJ(qd_cmd, self.acceleration, self.dt)
-        else:
-            # this one takes all 8 elements of qd since we're still in pinocchio
-            # this is ugly, todo: fix
-            qd = qd[:6]
-            qd = qd_cmd.reshape((6,))
-            qd = list(qd)
-            qd.append(0.0)
-            qd.append(0.0)
-            qd = np.array(qd)
-            self.v_q = qd
-            self.q = pin.integrate(self.model, self.q, qd * self.dt)
+        if self.robot_name == "ur5e":
+            qd_cmd = qd[:6]
+            # np.clip is ok with bounds being scalar, it does what it should
+            # (but you can also give it an array)
+            qd_cmd = np.clip(qd_cmd, -1 * self.max_qd, self.max_qd)
+            if not self.pinocchio_only:
+                # speedj(qd, scalar_lead_axis_acc, hangup_time_on_command)
+                self.rtde_control.speedJ(qd_cmd, self.acceleration, self.dt)
+            else:
+                # this one takes all 8 elements of qd since we're still in pinocchio
+                # this is ugly, todo: fix
+                qd = qd[:6]
+                qd = qd_cmd.reshape((6,))
+                qd = list(qd)
+                qd.append(0.0)
+                qd.append(0.0)
+                qd = np.array(qd)
+                self.v_q = qd
+                self.q = pin.integrate(self.model, self.q, qd * self.dt)
+
+        # TODO: implement real thing
+        if self.robot_name == "heron":
+                self.v_q = qd
+                self.q = pin.integrate(self.model, self.q, qd * self.dt)
+
 
     def openGripper(self):
         if self.gripper is None:
@@ -901,7 +912,7 @@ class RobotManager:
                 for i in range(len(goal_list)):
                    goal_list[i] = float(goal_list[i])
             except:
-                e = sys.exc_info()
+                e = exc_info()
                 print("The input is not in the expected format. Try again.")
                 print(e)
             if e == "ok":
@@ -912,6 +923,10 @@ class RobotManager:
         # NOTE i'm not deepcopying this on purpose
         # but that might be the preferred thing, we'll see
         self.Mgoal = Mgoal
+        if self.args.visualize_manipulator:
+            # TODO document this somewhere
+            self.manipulator_visualizer_queue.put(
+                    {"Mgoal" : Mgoal})
         return Mgoal
 
     def killManipulatorVisualizer(self):
@@ -929,7 +944,7 @@ class RobotManager:
         if self.args.debug_prints:
             print("i am putting befree in plotter_queue to stop the manipulator visualizer")
         # putting this command tells our process to kill the meshcat zmq server process
-        self.manipulator_visualizer_queue.put_nowait("befree")
+        self.manipulator_visualizer_queue.put_nowait({"befree" : "befree"})
         time.sleep(0.1)
         self.manipulator_visualizer_process.terminate()
         if self.args.debug_prints:
diff --git a/python/ur_simple_control/optimal_control/crocoddyl_optimal_control.py b/python/ur_simple_control/optimal_control/crocoddyl_optimal_control.py
index 152e0f9..8faf38a 100644
--- a/python/ur_simple_control/optimal_control/crocoddyl_optimal_control.py
+++ b/python/ur_simple_control/optimal_control/crocoddyl_optimal_control.py
@@ -20,8 +20,6 @@ def get_OCP_args(parser : argparse.ArgumentParser):
     return parser
                         
 
-# TODO: use fddp and incorporate torque (i.e. velocity constraints)
-#   --> those will correspond to max_qd and acceleration attributes in robotmanager 
 def CrocoIKOCP(args, robot : RobotManager, goal : pin.SE3):
     # create torque bounds which correspond to percentage
     # of maximum allowed acceleration 
@@ -87,9 +85,14 @@ def CrocoIKOCP(args, robot : RobotManager, goal : pin.SE3):
     bounds = crocoddyl.ActivationBounds(xlb, xub, 1.0)
     xLimitResidual = crocoddyl.ResidualModelState(state, x0, actuation.nu)
     xLimitActivation = crocoddyl.ActivationModelQuadraticBarrier(bounds)
-    limitCost = crocoddyl.CostModelResidual(state, xLimitActivation, xLimitResidual)
-    runningCostModel.addCost("limitCost", limitCost, 1e3)
-    terminalCostModel.addCost("limitCost", limitCost, 1e3)
+
+    # TOOODOOO ADD THE SAME FOR WHOLE HERON
+    if robot.robot_name == "ur5e":
+        limitCost = crocoddyl.CostModelResidual(state, xLimitActivation, xLimitResidual)
+        runningCostModel.addCost("limitCost", limitCost, 1e3)
+        terminalCostModel.addCost("limitCost", limitCost, 1e3)
+
+
     # NOTE: i have no idea how to incorporate this into anything
     # we need to add state constraints for things to make sense
     # NOTE!!!: there are no hard inequality constraints on states
@@ -158,6 +161,9 @@ if __name__ == "__main__":
     robot.max_qd = 3.14 
     print("velocity limits", robot.model.velocityLimit)
     robot.q = pin.randomConfiguration(robot.model)
+    robot.q[0] = 0.1
+    robot.q[1] = 0.1
+    print(robot.q)
     goal = pin.SE3.Random()
     goal.translation = np.random.random(3) * 0.4
     reference, solver = CrocoIKOCP(args, robot, goal)
diff --git a/python/ur_simple_control/util/__pycache__/get_model.cpython-312.pyc b/python/ur_simple_control/util/__pycache__/get_model.cpython-312.pyc
index 4f3cd82c660184ddd923df726a18a1539e1dba3b..7fb311856ef9a0ccfa2de4ba05ba86e1b0356785 100644
GIT binary patch
delta 3149
zcmdm>&~D9lnwOW0fq{YHtAJ+uV%dp&5{v;8)lC&r7*m*XIHR~Y8B$nU7^1jSSX&sP
zcv9F}7@~M9nKaoqW)$);DsR5Uvx8|eAETI>6(a+~bcPhhT80#+TE-NHTBa0+TILjn
zT9y(<kntd##WcB&QC5`+NrVL?j*4rTY8XlwCMPh;x^ke(fOshkHH@oSK`aJTv+<gw
z4E7>K7mP$PiMfPvvI3KgYz@<DsB>#sYnW=7YglSn(^!HTG@1RXLMKP@Xc-mfr<If^
z7NzPJ<rjmnZgPHJNn&PRYEiL%Mt*Lper|qBYK~rMQA%1>I9OzI9*<Z(L2VhSMfrL0
zDXGQDMVSR9nfZD8zMetxMfpkjC7SF-LJSNHMPeXA97ITf2uTnj1tMe^7#K9!isV3S
z1rT8jB1}MpDTpv*aAja9W@BJrPymA>a|Q;6Tm0#%CGikz!EP?HW?*25W?*0_UckV>
z(7^D4jX|oA@dAt32Q~)DBE}0WqLb(I71TfB=IgiUw3y)9ZQtPXfLmaK{sNl~A{V$#
zFR+*vSu!v%B*Q`&L~}AQFfcPPFnqqn0!ko=s9z0|Wnf^4VPRmXWvFGWWvXQ^0jUIw
zXJLs>h>m(tyr(eMu*Aa^BWc5uVj$WW7;0Hlm}=Qlm}}Wfn80>0Ffe3cNf%kXFj)i*
zH-n=_k|m2DApv96u$M4T7GRdChpDXL$P$K0B51fQ+iIu>YdMizBZ5!~V`YKj8^(ds
zDJ&_hDQqe1a5K1SSh7H=fq@|$ssuvSaMo}k8Bd~TS3?7sk)cF-@+&r3Ux=kp(OPcu
zO|IoBVV>;6F00Q`!&$>!!-FrV;GX0yQJk#9Av5^^GhclTZ#*bRfPGoRnxzhApb#~@
zu#C*eP{Wd?i6RN+Af*~DumB2?!d1hW!i*yp>!C`KLO=&9ghXZOA#tEgSkZ-W9Fj8(
zpo);F8kQP{8rB-76qL}0*^i_UU#eXV%K4zI#>Bu-%U8=^!<PjrAdqx}n6R{2D^SCq
z1u8p0f=JkfA=Z_Fp;j=3r^Zw;3u+{iJVO~nF=LNVjbN4;vM7XID})?-g7Kgd3oKJ3
zl)_sj#K2H1R3lU)7%vSLWME+Eac5zu;j7`tmo#elYXrcBGoRlr?%e#O%$(Htq{QOX
zTM|f|_=23oyu_mTto+Qpk|I#fuYU<DDAOS}J+MzV27}A?>9b~nz)kyGoJsi=@x>X5
z1*w`W&mrnQ*guCz@3b#+0+p$bpdyq7WL*&`EN-!6B<7{0|5^F*l5bLgy{2rD1xOVr
zmEL0Y1yu>RSn?8cQ*ZIQ*Qe&^rj`^{f<=o!rNk``&y>`>lFX9ITO5fgDPAC_-Vy*)
zU_}97FWh2D&M&CE#qODxT2zvmc#GYwC_mRJzv7l)VnIP_UW!wGN@YksSl2D)wB(#y
z%pgfVcc^v#Nm;4MB}D=Z^$ZL}f*{v(=B5^BIOpf&7u^y}Oi4ji2zH5E5y;7`5Q-B_
zg;W-#-eUFg_w)<7#SO6-?8aMM$wjG&C8;inC5fP_1>#4DrNy_vRs|;~=A_=@tOr?}
z46;^J_!cL)>WNP*%Dp9=oS&1ES)7@l7mpAWD9bD^P0T?O;Ydj=Nd#*UgeXIb>|0{#
zsrk83#mM4Z;OLJB$3Q)2L1IyAUP*jr$}N6~ctK8La%ygBUdb&HUw<c0AJ=#%$6(iZ
zurK31U2gFt<)>7}gDUxw%)}xGP~h=_g^)CYYz9SZJd(XdpnO&Yt%DgDZn1zAaol1o
zE(S&WWJez1dPrR?45^0`3kr(zD>8EvK@EVS90mr4LQs7y!33(0pE!CQmcGbh*Wh`9
zU+IF1$%c$C91M~&^Eqd7&gQ<rB6>qs>jI1D6&9&GvI^H_^)AZlU6wVtz#?@+P`knF
zhJav$=Myo>>FE>GuZyW&6jQq_rqSU4p`MLFM)$h3=|ySN4Vg!TuRDfbbPT=h7=D9C
z`Z|xoMIMFAJW30^J~K1Q7+heH_#(g{B0k-EqV;uQwTr@P3yM}4-{9e&ApDt`QADi4
z=K~u9tJrlG^@}X(7c^{k<eYIn?|#z#x=+kSpP0)&aaUO4?+6G_XP?MEgLy{q0_DpB
zY7O<CcSI$ohffT@E~<J_RQ0l`dV}8`X}Rmtx)-H&S7cwX_P-Dqbs;9}dQASsnEcBz
zg_os^F0e>EQB_|au`uG2p2KBT#|tbHS6Gy8ut;5J(YeT?b3xbf3X2oeEpiuG<mMF5
zubf%ALhOQp%YncH_1E2_FS<uxc8|Rhmw3HCF8g9!_Vu{Ji*bdQ<%_Pclzd@hkd~XT
zKU4pLmi3Ov3m$P75(+L96<;Z>xL#Uwv9#tp149|38`DP!^%+EYFnwlVkoIJ{$Rgh0
z+F^5pTi`mk^hIvz%iOXJE+5z!1ZA%a=v)!d>0r6REjS@$dgR2&OWbld1VpCuc~9i)
zaJ(ZcKR;q-#3ePW%d*xTE<Jt^cz7p>c6xO<-jJ2+aOw5?z{?=0`$2$#M{t79bs^=8
zLdutgR2S522)V#*d4a_e-0afin>>Zzv*H$8MnOSZa!!#ysQdvJLZEgXI5Dkc0IP%~
zIS!lL{FKt1RJ)=Q1_lODtG5`GT0bx|GBSQ-Vr69c%)`JaahpNtHUrmf2F|+-s<#<L
cK8WxzvV4*<Vl?|yz$n6K_F2b>(F$xR0Fyu2b^rhX

delta 117
zcmZp--k`vDnwOW0fq{YH?d@M_wfqzLBp7Wbs+;m~GNiDyFhp@yGHJ4ItSRJSRNDNG
zX9p9LCfDR+GM;Kh77PpwD;bI`85kIf%o!LMesS33=BJeAq}mlZFfcGMGB7X{t4{Wj
TmE->)!o$e&S;~mf46GUeB`X}#

diff --git a/python/ur_simple_control/util/get_model.py b/python/ur_simple_control/util/get_model.py
index 2d624ba..a5737ee 100644
--- a/python/ur_simple_control/util/get_model.py
+++ b/python/ur_simple_control/util/get_model.py
@@ -9,6 +9,7 @@ import numpy as np
 import sys
 import os
 from importlib.resources import files
+import hppfcl as fcl
 
 # can't get the urdf reading with these functions to save my life, idk what or why
 
@@ -83,3 +84,80 @@ def get_model():
 
     return model, collision_model, visual_model, data
 
+# this gives me a flying joint for the camera,
+# and a million joints for wheels -> it's unusable
+# TODO: look what's done in pink, see if this can be usable
+# after you've removed camera joint and similar.
+def get_heron_model():
+    
+    #urdf_path_relative = files('ur_simple_control.robot_descriptions.urdf').joinpath('ur5e_with_robotiq_hande_FIXED_PATHS.urdf')
+    urdf_path_absolute = "/home/gospodar/home2/gospodar/lund/praxis/software/ros/ros-containers/home/model.urdf"
+    #mesh_dir = files('ur_simple_control')
+    #mesh_dir_absolute = os.path.abspath(mesh_dir)
+    mesh_dir_absolute = "/home/gospodar/lund/praxis/software/ros/ros-containers/home/heron_description/MIR_robot"
+
+    model = None
+    collision_model = None
+    visual_model = None
+    # this command just calls the ones below it. both are kept here
+    # in case pinocchio people decide to change their api.
+    #model, collision_model, visual_model = pin.buildModelsFromUrdf(urdf_path_absolute, mesh_dir_absolute)
+    model = pin.buildModelFromUrdf(urdf_path_absolute)
+    visual_model = pin.buildGeomFromUrdf(model, urdf_path_absolute, pin.GeometryType.VISUAL, None, mesh_dir_absolute)
+    collision_model = pin.buildGeomFromUrdf(model, urdf_path_absolute, pin.GeometryType.COLLISION, None, mesh_dir_absolute)
+
+    data = pin.Data(model)
+
+    return model, collision_model, visual_model, data
+
+def heron_approximation():
+    # arm + gripper 
+    model_arm, collision_model_arm, visual_model_arm, data_arm = get_model()
+
+    # mobile base as planar joint (there's probably a better
+    # option but whatever right now)
+    model_mobile_base = pin.Model()
+    model_mobile_base.name = "mobile_base"
+    geom_model_mobile_base = pin.GeometryModel()
+    joint_name = "mobile_base_planar_joint"
+    parent_id = 0
+    # TEST
+    joint_placement = pin.SE3.Identity()
+    #joint_placement.rotation = pin.rpy.rpyToMatrix(0, -np.pi/2, 0) 
+    #joint_placement.translation[2] = 0.2
+    MOBILE_BASE_JOINT_ID = model_mobile_base.addJoint(parent_id, pin.JointModelPlanar(), 
+            joint_placement.copy(), joint_name)
+    #print("OBJECT_JOINT_ID",OBJECT_JOINT_ID)
+    #body_inertia = pin.Inertia.FromBox(args.box_mass, box_dimensions[0], 
+    #        box_dimensions[1], box_dimensions[2])
+
+    # pretty much random numbers
+    # TODO: find heron (mir) numbers
+    body_inertia = pin.Inertia.FromBox(30, 0.5, 
+            0.3, 0.4)
+    # maybe change placement to sth else depending on where its grasped
+    model_mobile_base.appendBodyToJoint(MOBILE_BASE_JOINT_ID, body_inertia, pin.SE3.Identity()) 
+    box_shape = fcl.Box(0.5, 0.3, 0.4) 
+    body_placement = pin.SE3.Identity()
+    geometry_mobile_base = pin.GeometryObject("box_shape", MOBILE_BASE_JOINT_ID, box_shape, body_placement.copy())
+
+    geometry_mobile_base.meshColor = np.array([1., 0.1, 0.1, 1.])
+    geom_model_mobile_base.addGeometryObject(geometry_mobile_base)
+
+    # have to add the frame manually
+    model_mobile_base.addFrame(pin.Frame('base',MOBILE_BASE_JOINT_ID,0,joint_placement.copy(),pin.FrameType.JOINT) )
+
+    # frame-index should be 1
+    model, visual_model = pin.appendModel(model_mobile_base, model_arm, geom_model_mobile_base, visual_model_arm, 1, pin.SE3.Identity())
+    data = model.createData()
+    
+    # fix gripper
+    for geom in visual_model.geometryObjects:
+        if "hand" in geom.name:
+            s = geom.meshScale
+            geom.meshcolor = np.array([1.0, 0.1, 0.1, 1.0])
+            # this looks exactly correct lmao
+            s *= 0.001
+            geom.meshScale = s
+
+    return model, visual_model.copy(), visual_model, data
diff --git a/python/ur_simple_control/visualize/__pycache__/visualize.cpython-312.pyc b/python/ur_simple_control/visualize/__pycache__/visualize.cpython-312.pyc
index eaf4ae636a0f3e0494bc8ae3166c0c46fe1bf886..7039720b6b1d9858d08e7c3911c57c5324a85ff2 100644
GIT binary patch
delta 2583
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

delta 2184
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
D(HRc^

diff --git a/python/ur_simple_control/visualize/visualize.py b/python/ur_simple_control/visualize/visualize.py
index 8c78735..0215e59 100644
--- a/python/ur_simple_control/visualize/visualize.py
+++ b/python/ur_simple_control/visualize/visualize.py
@@ -4,11 +4,12 @@ from collections import deque, namedtuple
 import time
 import copy
 from pinocchio.visualize import MeshcatVisualizer
+import meshcat_shapes
 
-# tkinter stuff
-from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
-from tkinter import *
-from tkinter.ttk import *
+# tkinter stuff for later reference
+#from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
+#from tkinter import *
+#from tkinter.ttk import *
 
 # rows and cols are flipped lel
 def getNRowsMColumnsFromTotalNumber(n_plots):
@@ -162,6 +163,10 @@ def manipulatorVisualizer(args, model, collision_model, visual_model, queue):
     # for whatever reason the hand-e files don't have/
     # meshcat can't read scaling information.
     # so we scale manually
+    init_target_frame = False
+    init_ee_frame = False
+    # if we go for manipulator end-effector
+    #meshcat_shapes.frame(viewer["end_effector_target"], opacity=0.5)
     for geom in visual_model.geometryObjects:
         if "hand" in geom.name:
             s = geom.meshScale
@@ -180,16 +185,31 @@ def manipulatorVisualizer(args, model, collision_model, visual_model, queue):
     print("MANIPULATORVISUALIZER: FULLY ONLINE")
     try:
         while True:
-            q = queue.get()
-            if type(q) == str:
-                print("got str q")
-                if q == "befree":
+            cmd = queue.get()
+            for key in cmd:
+                if key == "befree":
                     if args.debug_prints:
                         print("MANIPULATORVISUALIZER: got befree, manipulatorVisualizer out")
                     viz.viewer.window.server_proc.kill()
                     viz.viewer.window.server_proc.wait()
                     break
-            viz.display(q)
+                if key == "Mgoal":
+                    # having this via flag is stupid, but i can't
+                    # be bothered with something else rn
+                    if init_target_frame == False:
+                        meshcat_shapes.frame(viz.viewer["Mgoal"], opacity=0.5)
+                        init_target_frame = True
+                    viz.viewer["Mgoal"].set_transform(cmd["Mgoal"].homogeneous)
+                if key == "T_w_e":
+                    # having this via flag is stupid, but i can't
+                    # be bothered with something else rn
+                    if init_ee_frame == False:
+                        meshcat_shapes.frame(viz.viewer["T_w_e"], opacity=0.5)
+                        init_ee_frame = True
+                    viz.viewer["T_w_e"].set_transform(cmd["T_w_e"].homogeneous)
+                if key == "q":
+                    viz.display(cmd["q"])
+
     except KeyboardInterrupt:
         if args.debug_prints:
             print("MANIPULATORVISUALIZER: caught KeyboardInterrupt, i'm out")
-- 
GitLab