From df4f2047307db0d1ceb2e2f54db0cc493e6acf06 Mon Sep 17 00:00:00 2001
From: m-guberina <gubi.guberina@gmail.com>
Date: Sat, 18 Nov 2023 23:01:43 +0100
Subject: [PATCH] nearly done i swear

---
 .../.drawing_from_input_drawing.py.swp        | Bin 28672 -> 32768 bytes
 python/examples/drawing_from_input_drawing.py |  82 +++--
 .../forcemode_example.py                      |   0
 python/examples/path_in_pixels.csv            |  41 +++
 .../test_traj_w_movej.py                      |   0
 .../test_traj_w_speedj.py                     |   0
 python/ur_simple_control/.managers.py.swp     | Bin 53248 -> 16384 bytes
 .../__pycache__/__init__.cpython-310.pyc      | Bin 312 -> 332 bytes
 .../__pycache__/managers.cpython-310.pyc      | Bin 0 -> 6218 bytes
 .../clik/.clik_point_to_point.py.swp          | Bin 16384 -> 20480 bytes
 .../clik/.clik_trajectory_following.py.swp    | Bin 16384 -> 20480 bytes
 .../clik_point_to_point.cpython-310.pyc       | Bin 0 -> 3943 bytes
 .../clik/clik_point_to_point.py               |  13 +-
 .../clik/clik_trajectory_following.py         |  35 +-
 .../__pycache__/create_dmp.cpython-310.pyc    | Bin 4336 -> 4354 bytes
 .../dmp/__pycache__/dmp.cpython-310.pyc       | Bin 0 -> 6620 bytes
 .../temporal_coupling.cpython-310.pyc         | Bin 2508 -> 2526 bytes
 .../dmp/{create_dmp.py => dmp.py}             |  99 +++++-
 .../drawing_gen/lasso_selector_demo_sgskip.py | 113 ------
 .../dmp/drawing_gen/path_in_pixels.csv        | 327 ------------------
 .../ur_simple_control/dmp/robotiq_gripper.py  | 291 ----------------
 .../dmp/temporal_coupling.py                  |  82 -----
 python/ur_simple_control/managers.py          |  12 +-
 .../util/.calib_board_hacks.py.swp            | Bin 0 -> 24576 bytes
 .../util/.robotiq_gripper.py.swp              | Bin 16384 -> 0 bytes
 .../__pycache__/draw_path.cpython-310.pyc     | Bin 0 -> 2061 bytes
 .../util/calib_board_hacks.py                 | 225 ++++++------
 python/ur_simple_control/util/draw_path.py    |  43 +--
 .../__pycache__/__init__.cpython-310.pyc      | Bin 0 -> 199 bytes
 .../__pycache__/visualize.cpython-310.pyc     | Bin 0 -> 816 bytes
 30 files changed, 372 insertions(+), 991 deletions(-)
 rename python/{ur_simple_control/dmp/leftovers => examples}/forcemode_example.py (100%)
 create mode 100644 python/examples/path_in_pixels.csv
 rename python/{ur_simple_control/dmp/leftovers => examples}/test_traj_w_movej.py (100%)
 rename python/{ur_simple_control/dmp/leftovers => examples}/test_traj_w_speedj.py (100%)
 create mode 100644 python/ur_simple_control/__pycache__/managers.cpython-310.pyc
 create mode 100644 python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc
 create mode 100644 python/ur_simple_control/dmp/__pycache__/dmp.cpython-310.pyc
 rename python/ur_simple_control/dmp/{create_dmp.py => dmp.py} (60%)
 delete mode 100644 python/ur_simple_control/dmp/drawing_gen/lasso_selector_demo_sgskip.py
 delete mode 100644 python/ur_simple_control/dmp/drawing_gen/path_in_pixels.csv
 delete mode 100644 python/ur_simple_control/dmp/robotiq_gripper.py
 delete mode 100644 python/ur_simple_control/dmp/temporal_coupling.py
 create mode 100644 python/ur_simple_control/util/.calib_board_hacks.py.swp
 delete mode 100644 python/ur_simple_control/util/.robotiq_gripper.py.swp
 create mode 100644 python/ur_simple_control/util/__pycache__/draw_path.cpython-310.pyc
 create mode 100644 python/ur_simple_control/visualize/__pycache__/__init__.cpython-310.pyc
 create mode 100644 python/ur_simple_control/visualize/__pycache__/visualize.cpython-310.pyc

diff --git a/python/examples/.drawing_from_input_drawing.py.swp b/python/examples/.drawing_from_input_drawing.py.swp
index 424abe01a262c1f14f8d73501a3dc4a74581419a..6cb848bc0e1c7948199fc53aa4c7507705b8526d 100644
GIT binary patch
delta 2985
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

delta 1458
zcmZo@U}|{4D3)Xp=IN_op=ZRvz`!8Dz!3i{B6V8mMzJ^i{HzT13=9lRAPEKr2II+s
z0``omlLH0h8Eq#Q3dl2hO`a$qJ~`6SWb*|975+&IEWE-j3=F?nAO;yv7F5Wt_v2z<
z5aVKC_{Yh>@S2l>;WQ@$!+uT%h7L{!22V}~1_n+BhW{K44BI&v81gw77}Pl!7<f4t
z82+*|Fl=OJU`S<WV31^IU^vUhz%Y%Cfgy;Efq|8cfnh5v14B701A`nZ#Kvzd3=B=I
z3=9#h3=Gat@xv?(n|~`DWSYzzoibS<mThuygf_pDjzUUmT4HHViLGI(uJL5WXxYh|
zBeW+^%9EY!pw2tlL5+3t1!ZLjTb*O`1!YdAN!Edr9gL+XyQwuW#V2k)t|rJhxj@5c
z@*>UJ$@*FW=4nOwxe6tzxdr(}i8=Af`K1LpnR)37nIM4@1;6|dXB~wQ=djcq$K+(^
z{Ji3lqQuO+)Rf5!H6<idatrj5i&7IyQsYx{3t)O&d;>PuX|=KPS}-y&)PSNufPukl
zvY<hB{UmM%h74{722XAV25D{v25xQ!h8J863|F`q7*269Fm!P-FnDt@Fi3JSFx=u~
zV3^Ixz>vbpz#z)Wz#sw&eGUeObPfgv3l0W`ckB!dbJ!UeJlGi+SlJmEUb8VUEMQ|`
z=wxGHNM&PSh-PD8Fl1w3P+((Vc*)AZu!fZ(ouP!4fx(=WfkBs*f#ER=14AbZ1A{FK
z1H(sV28N}~3=D0|3=CP!3=HPX3=CY%3=B`17#L15F)*xVVqmCcf_O)qiGkrWBLjmc
zGXsM%GXsMVGXuj%CI*ICObiU&ObiU|OcO6on!F*LW%2<-c~%Am1qFr42MqP$ELjm~
zs$^hbPyjQbN-`(w8zoMbbCuY<&M2FGa(u0~geF+KvO-RNVv0gZQDRnVa!GzsrOxDo
zwW3U!C6j%uttNL_OA8hx78R!!>7}QZ#3vS|7i(xjqFrXPw9P)Dl+5H32CzXn`RVZ>
z-sIOdx-4LZjIA<+;cTnR4-$!1FDzD%Rj^ekG@Hz5E4+D<Z4ndiYIX*OXbwo;P@OF3
zAYRYG&%khokAY!69|J=y9|MC19|OY^UIvEMybKIoybKJPybKH;ybKH<co-O#@Gvlx
z@h~tL@Gvll^Dr<x=VoA-!p*?o#m&HA%+0{?i;IC_H5UUzF&6_v6c+=7Iu`@OB~Av0
zotz8|?a;iY$H~C(mxF;}KL-QD5)KAEuyb5E7#RMsGca6WXJGik&cLvSoq-{Roq<7y
zoq<7`oq^#k8w0~*HU@@Eo3A<;vQFl+2$TZ_b)kZ-LQzRdYJ5>@a%yH-Dk#_-lS@hy
zb0+I$*s!IPXewwaOs>h0@&pGOD3uqNq!wtTl)$1RCAWYfB{fYUIX|zYC_l$1KffTn
zD6=FpFI}T3KPkUN2PTt~TBM_pscAJ?K5yIPU=O{?!5(hnAU7y0g!sGoD<r0*DCFdq
zD-<La7jF*s;ANd`5XHfql3Or2*VlZqK@{ucvr!zA<GeUF@A6G$oc!CDbF;4hbphVB
z%nS^Bp@o(0WWj{$dOj`&hC7@L46`^H7+N?P82mXI7|b~t7*shK7??R37@l!3Fs$QX
zV3^6lz|g|Mz~Ifnz@Wmx!0?crfng7{uySK(U|?rwV7SD_z_5pnfuV<ufx&@|fq{{Y
zf#EbO14A9OkaA~bU@%~1VBlwEVEDoUb_p{B59?+|mi5e_gugi|C5Hu)tWIS-*esa!
Go)rN3BuHfd

diff --git a/python/examples/drawing_from_input_drawing.py b/python/examples/drawing_from_input_drawing.py
index 89d1dab..31e7cb8 100644
--- a/python/examples/drawing_from_input_drawing.py
+++ b/python/examples/drawing_from_input_drawing.py
@@ -23,25 +23,30 @@
 #     package it and then have it one place instead of copying it everywhere
 # 12. make this a mainfile, put everything that could be turned into a function elsewhere
 
-from ur_simple_control.dmp.create_dmp import DMP
-from temporal_coupling import NoTC, TCVelAccConstrained
 import pinocchio as pin
 import numpy as np
 import matplotlib.pyplot as plt
 import copy
+import argparse
 from ur_simple_control.util.get_model import get_model
 from ur_simple_control.visualize.visualize import plotFromDict
+from ur_simple_control.util.draw_path import drawPath
+from ur_simple_control.dmp.dmp import DMP, NoTC,TCVelAccConstrained 
+# TODO merge these files as well, they don't deserve to be separate
+# TODO but first you need to clean up clik.py as specified there
 from ur_simple_control.clik.clik_point_to_point import getClikController
+from ur_simple_control.clik.clik_trajectory_following import map2DPathTo3DPlane
+from ur_simple_control.managers import ControlLoopManager, RobotManager
 
 #######################################################################
 #                            arguments                                #
 #######################################################################
 # TODO sort these somehow
-def get_args():
+def getArgs():
     #######################################################################
     #                          generic arguments                          #
     #######################################################################
-    parser = argparse.ArgumentParser(description='Make a drawing on screen,
+    parser = argparse.ArgumentParser(description='Make a drawing on screen,\
             watch the robot do it on the whiteboard.',
             formatter_class=argparse.ArgumentDefaultsHelpFormatter)
     # TODO this one won't really work but let's leave it here for the future
@@ -85,16 +90,16 @@ def get_args():
             This is used when generating the joint trajectory from the drawing.", \
             default=1e-2)
     # TODO add the rest
-    parser.add_argument('--controller', type=str, \
+    parser.add_argument('--clik-controller', type=str, \
             help="select which click algorithm you want", \
             default='dampedPseudoinverse', \
             choices=['dampedPseudoinverse', 'jacobianTranspose'])
         # maybe you want to scale the control signal
     parser.add_argument('--controller-speed-scaling', type=float, \
             default='1.0', help='not actually_used atm')
-    ############################
-    #  dmp specific arguments  #
-    ############################
+    #############################
+    #  dmp  specific arguments  #
+    #############################
     parser.add_argument('--temporal-coupling', action=argparse.BooleanOptionalAction, \
             help="whether you want to use temporal coupling", default=True)
     parser.add_argument('--kp', type=float, \
@@ -118,6 +123,17 @@ def get_args():
             help="force feedback proportional coefficient", \
             default=0.003)
     # TODO add low pass filtering and make it's parameters arguments too
+    #######################################################################
+    #                       task specific arguments                       #
+    #######################################################################
+    # TODO measure this for the new board
+    parser.add_argument('--board-width', type=float, \
+            help="width of the board (in meters) the robot will write on", \
+            default=0.35)
+    parser.add_argument('--board-height', type=float, \
+            help="height of the board (in meters) the robot will write on", \
+            default=0.4)
+    
 
     args = parser.parse_args()
     if args.gripper and args.simulation:
@@ -147,13 +163,15 @@ def controller():
 # you'd still need to specify what you're saving with self.that_variable so no matter
 # there's no running away from that in any case.
 # it's 1) for now, it's the only non-idealy-clean part of this solution, and it's ok really.
+# TODO but also look into something fancy like some decorator or something and try
+# to find option 3)
 
 # control loop to be passed to ControlLoopManager
 def controlLoopWriting(dmp, tc, controller, robot, i, past_data):
     breakFlag = False
     # TODO rename this into something less confusing
     save_past_dict = {}
-    log_dict = {}
+    log_item = {}
     dmp.step(robot.dt) # dmp step
     # temporal coupling step
     tau = dmp.tau + tc.update(dmp, robot.dt) * robot.dt
@@ -193,22 +211,40 @@ def controlLoopWriting(dmp, tc, controller, robot, i, past_data):
         breakFlag = True
 
     # log what you said you'd log
-    log_dict['qs'] = q6.reshape((6,))
-    log_dict['dmp_poss'] = dmp.pos.reshape((6,))
-    log_dict['dqs'] = dq.reshape((6,))
-    log_dict['dmp_vels'] = dmp.vel.reshape((6,))
+    log_item['qs'] = q6.reshape((6,))
+    log_item['dmp_poss'] = dmp.pos.reshape((6,))
+    log_item['dqs'] = dq.reshape((6,))
+    log_item['dmp_vels'] = dmp.vel.reshape((6,))
 
-    return breakFlag, save_past_dict, log_dict
+    return breakFlag, save_past_dict, log_item
 
 if __name__ == "__main__":
     #######################################################################
     #                           software setup                            #
     #######################################################################
-    args = parser.get_args()
-    clik_controller = getController(args)
+    args = getArgs()
+    clik_controller = getClikController(args)
     robot = RobotManager(args)
-    # load trajectory, create DMP based on it
-    dmp = DMP()
+    #######################################################################
+    #          drawing a path, making a joint trajectory for it           #
+    #######################################################################
+    
+    # draw the path on the screen
+    pixel_path = drawPath()
+    
+    # make it 3D
+    path = map2DPathTo3DPlane(pixel_path, args.board_width, args.board_height)
+    # TODO: run calibration here
+    # TODO: create calibration related arguments 
+    # add an offset of the marker (this is of course approximate)
+    # TODO: fix z axis in 2D to 3D path
+    # TODO: make this an argument once the rest is OK
+    path = path + np.array([0.0, 0.0, -0.0938])
+    # create a joint space trajectory based on the path
+    joint_trajectory = TODO
+
+    # create DMP based on the trajectory
+    dmp = DMP(joint_trajectory)
     if not args.temporal_coupling:
         tc = NoTC()
     else:
@@ -246,10 +282,14 @@ if __name__ == "__main__":
     #######################################################################
     # TODO: add marker picking
     # get up from the board
-    current_pose = rtde_receive.getActualTCPPose()
+    current_pose = robot.rtde_receive.getActualTCPPose()
     current_pose[2] = current_pose[2] + 0.03
-    rtde_control.moveL(current_pose)
+    robot.rtde_control.moveL(current_pose)
     # move to initial pose
     # this is a blocking call 
-    rtde_control.moveJ(dmp.pos.reshape((6,)))
+    robot.rtde_control.moveJ(dmp.pos.reshape((6,)))
+    loop_manager.run()
+    
+    # and now we can actually run
+
 
diff --git a/python/ur_simple_control/dmp/leftovers/forcemode_example.py b/python/examples/forcemode_example.py
similarity index 100%
rename from python/ur_simple_control/dmp/leftovers/forcemode_example.py
rename to python/examples/forcemode_example.py
diff --git a/python/examples/path_in_pixels.csv b/python/examples/path_in_pixels.csv
new file mode 100644
index 0000000..b236f1c
--- /dev/null
+++ b/python/examples/path_in_pixels.csv
@@ -0,0 +1,41 @@
+0.16240,0.57914
+0.16389,0.57914
+0.16537,0.57914
+0.19359,0.58663
+0.27228,0.59862
+0.32574,0.60311
+0.34801,0.60311
+0.38661,0.60311
+0.42819,0.60311
+0.47273,0.60311
+0.50986,0.59862
+0.55292,0.58963
+0.58261,0.58064
+0.58558,0.57764
+0.58558,0.57914
+0.57964,0.57465
+0.57073,0.57315
+0.56925,0.57315
+0.56776,0.57315
+0.56479,0.57315
+0.55589,0.57315
+0.54698,0.57764
+0.54549,0.58064
+0.53064,0.59113
+0.51579,0.60011
+0.50689,0.60760
+0.50540,0.60760
+0.49501,0.61210
+0.48610,0.61959
+0.48610,0.62108
+0.48610,0.62258
+0.50540,0.64655
+0.58261,0.68699
+0.62122,0.70497
+0.68655,0.73643
+0.72516,0.75140
+0.74743,0.75740
+0.81128,0.77837
+0.82910,0.78436
+0.83355,0.78436
+0.83355,0.78436
diff --git a/python/ur_simple_control/dmp/leftovers/test_traj_w_movej.py b/python/examples/test_traj_w_movej.py
similarity index 100%
rename from python/ur_simple_control/dmp/leftovers/test_traj_w_movej.py
rename to python/examples/test_traj_w_movej.py
diff --git a/python/ur_simple_control/dmp/leftovers/test_traj_w_speedj.py b/python/examples/test_traj_w_speedj.py
similarity index 100%
rename from python/ur_simple_control/dmp/leftovers/test_traj_w_speedj.py
rename to python/examples/test_traj_w_speedj.py
diff --git a/python/ur_simple_control/.managers.py.swp b/python/ur_simple_control/.managers.py.swp
index 0b0b860270552b6cb3f46e23f92ce3b1971f0e75..f697a6cfa3b4672a101af84fd21aa323b24910de 100644
GIT binary patch
delta 687
zcmZozz}(QlD3)Xp=IN_op=ZRvz`!8Dz|f)`nYv$nqu3jMel~`B1_lNukOTt*L&#)7
z0rC3(P!J3i4TaK-Q2HNKJ^;#J0i|K`f1&a){Xfv;|3Kwo`n{nVp_CK@GgN~Nl%5Th
zVce{kV9!5EfrVFrfq|h1Bq{)Qw1Rv61YQP)eqIKKZe9k4T3!Z*TwVqSWnKn`J3I^w
zvv?R70(lr1IC&Tt4stUvG;=dB#B(z+@N+XTyy9YDc*(`Uu!@U;p@EBm!JLbM;Rz=L
z!*WgrhD1&V23<}D1|3cY202a!1_4e6hA$ip44*j|7#?vjFr4FHV3^3kz>vtnP|py{
z!N3s1!N3r~!NB0k!N6e1!N72xoq=I3I|D;HI|G9ZI|IW9HU@_MYzz#oYzz#IYzz$P
zYzz#-Yzzz!Ss55Mure^TvNABlu`)2YvNABpvobI+ure^*WMN>~$il!7!ot9y&BDNN
zkC}mC4l@HoAu|Jm95VyM4<-hN?@S^L46RHI44O;~496HDVbjex@uJe?KV2M~%_~o`
zZT8g&WS#s$S7!4mT`Q(~H!cQ-OI(oT01M_#{0t09{0t1L{0t1d{0t0>`4|}b_!t-p
z`4|`+`4|{@`4|{3^D;2(=4D`*!pp$m%*()_#>>FK!OOsKhKGS+6AuGJDGvifIu8Sb
w5Dx>x9&QGPB5no-du|2>7H&u|U*Te4xXi`C4z~Ov*Jef*FD|ef<t<fM0nvAPfB*mh

literal 53248
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
YF(<Ps6<o$aqYYdkfd-MmNxPT<08AwO7XSbN

diff --git a/python/ur_simple_control/__pycache__/__init__.cpython-310.pyc b/python/ur_simple_control/__pycache__/__init__.cpython-310.pyc
index f0e52da6259b072f7fdf395595c1bd877a6aea0b..bf5a97e07d2695543ee14d691c26e196a331187f 100644
GIT binary patch
delta 107
zcmdnNbcTsHpO=@5fq{V`xhEoZ>O@{yMvaNulG3@XQLKy%=?p21ix{KWQka4nG?`z5
zlxea~j8^5l#aWhFT$-4ZS(WOi$v&}JUA%~mfq~%`dwhIiPELIMN`@j%1_p*A&WU>}
JSY#M@7y(yc8Yln&

delta 87
zcmX@Zw1bH^pO=@5fq{X+Zbf)%?L=N#MwN-$lH!aE=?p21ix{I=Q<#DoG?`z5lxVU{
pj8|p$(`1`CNnPj`dwhIiPELIMN`@j11_p*Aj)@m4SR@#D7y(x46a)YO

diff --git a/python/ur_simple_control/__pycache__/managers.cpython-310.pyc b/python/ur_simple_control/__pycache__/managers.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..82676cbf4c37426f13dd04a2b2699f68f9ee3f24
GIT binary patch
literal 6218
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
BGDiRa

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/clik/.clik_point_to_point.py.swp b/python/ur_simple_control/clik/.clik_point_to_point.py.swp
index 864b03fab06bf205414a942d9890f8385c8f24fb..44e6abddd15938267cc7d739954e6a98cbf46ee0 100644
GIT binary patch
delta 1245
zcmZo@U~E{xD3)Xp=IN_op=ZRvz`!8Dz!0Y%nYuP;qu3jMerASx1_lNukOTt*1J`6h
z0dY+hD9;K?b3tiFD9sF|12-EAtmmJkz{0D~$G}j`2Qi#$vY>);Jqter!%?UxGd}~v
zZ9WEu*?bHPUVID;UwIiAmhmz$gzz#jnD8<%eCJ_cn9ak$Fr9~ip`C|;!GMQ>;SM(g
z!whZ)1`loqhCf^k3@f-87=pPN7+AO%7^ZVFFnDq@FtBnmFr4RLU})rEVDRK%V0h2Y
zz_6X2fgy;Up`PIb8w0~8HU@@jHU<WJHU@@2tPBi?Ss56*SQ!}XSQ!}9SQ!}JvM?}g
zWMN<kU}0d8W?^8s&dk6tkC}mCE;9o|9Ww(%C^G{CGcyCj3MK}I8B7ce)0r3;{FxXS
z*qIm@_A@dtbTBe7s6azSK|w*GFh#*u!Ambh!C|wlVkpbx>l$*KH>j#JPoAVIxB06^
zCu_a3LP<tuu|j6CLVA9FijG27X>o}{UVe!}acV(gQDRAIib6?7szP~Ur9x(jLUBfZ
zX-<klQmT$ZPG)whLP~A{NNZYtkwR)kVs1fBsvd)~LQ-joLQ1|uZen(-LSk`oYEemM
zeqOOcNk(FcLUL+RNn&Q6LSj*RX>Mv>d`YoFMq*j2LP@?tYDH#o2}pm4zl*;@Zhl#+
zLSk}BX<|-Jr9x?OW?nkPsT#Q;{b`vwsS1gCDKLXdia|ys=E2;d08*f-H#ty$Gw)_b
z1_ohJ8WCV%2%Icvu)JQKi-F-KCj-MeP6mb<oD2*NoD2-!oD2+RoD2*MoD2+CI2afv
zb1*Pua4;|!aWF7^XJ=q|z|O!hjh%tPlbwM<m7Rg%FB=2HRW=5O18fWoC2R}~;%p2I
zOl%AcXIU8-Cb2Rwgt9U)D6ujy++|^4ILN}lu!MzyVKEB>!y*<2b%r(;28IF_28KWu
z1_oUg28RF43=Dgi85oL~85p#fA<h+I-uQ3}BcsCRI^&6qn*~hGS?hHa3KEM;;!_e!
z5;d(DlocQ$1qx?yEG8;smnRmbE94g`lxHNCq?V-?fkGuIRUtROC{-aRu|lCdvm^r?
zjtt6RvlKvPffOa@=N9Bt!sJsG90NQVlofLGQ%Z9Zi!w_p6)N)?Hb+@4W35k2VPLqy
zz`$?^l+Xki7+|^bKR*M*Z+-@b-TVv;lld7Kg83O3nD`kO*77kh#PKmO@bED(yy0bF
zSkKGA5X{TK;LppzV9(3I@PdbdVG0ieLjVs00|O5O!xnA^h6HW~25xQ!hCN&i4E|gU
z42)b140|~l7}_}*>KQCK85kHj85ovxFfinEFfed&FfgoOXJE);XJ9a9XJGiw#=x)z
zn$w)v7#O~>GBDg@Wnfs!%D|Ax%D}+E%D`}$g@K`;g@GZAg@GZIg@M70g@J*Wg@Iu=
wGXp~cGXp~aGXsM^GXn!VGXukZCI*IbCI$uvCXlBmKD@VCUojaYGsUq10AGs&pa1{>

delta 599
zcmZozz}V2hD3)Xp=IN_op=ZRvz`!8Dz)<=jBGoH&qu3jMekO)`1_lNukOTt*gTrJ&
z0dY=dC@)}hpul?mi60auDX{PgGcYjdGeYz`Ocqp7uJ_|-VBq6tV0gyIz_5&ufgzNS
zfq{XKfng&r14BG71A{#;0|OH;1H&>N28KmE3=ETa7#OU17#N;&GcYXXW?%^BW?*3F
zW?<ON#lR59#lXPN#lWzLlYt?GlYv2ilY!wD2LnS72LnS02Lr<|b_Rw+><kRC><kRQ
z*%%o1vN6;%w6QTTc(E}su(L5RoMUBRn99n);K|CsV93hA@PmbcVGj!fLo^EmgBlA1
z!y{$}hLy|=3@ex!7&@657!sHn82FeO7&bF8Ff3+bU|7V&z!1g6z#zoLz;KF@fnhQu
z#JkEMFGIsa0R?Qn@0h?c`HY6#=2$m%=E?SMa+_aibh1v?_P;tgSbrn05)%VM9VjRT
z7#IR33mPo1m*QezVBun5c*DuSu$>d)*&I#=1_w?ChW{K43|BZ980K*>FeGy@F!*pV
zFfeg2Fl=RKV3^3xz>vw#z~IQvz@Wp<!0>>LfuWg=fgz8Lfx(iEf#Dx31H(a928KSU
z|8-dz7z9`u82DKk82DHj7<gG37(TKv$TQrA2FeT;28Jva1_pH&28O%L3=C75K~CNH
sP?Sj+<i(u){DS!0#Jt4x)FQp2(#^ug6B#!zHnCu3(zM#_X|<gd05{fR3IG5A

diff --git a/python/ur_simple_control/clik/.clik_trajectory_following.py.swp b/python/ur_simple_control/clik/.clik_trajectory_following.py.swp
index 80ba7275dae3fbd9f50fa6b4ef4c35cbf0713b9d..2712234ef37d6e72b70c659ecaa1c192a007dda8 100644
GIT binary patch
delta 1629
zcmZo@U~E{xD4b*v=IN_op=ZRvz`!8Dz_3I+a-;AyX4cY@G+m3$@0dk+_?a2%85kIt
zKnfTb7{n$E3Wy7`KzY7UT4=MRz;XUb3M{;jxfvM3c_4;~O%_xzuRqGiz);J_z+lS9
z!0?urfnf<R14BG70|P%V1H(=p28MPXh>kP73=DfgV!R9tb9fjSI(Zlv%6J$Uf_NAh
zba@yU-f=T99N}hQILyt!aEP0Mp^=+`A%>fQL57=w;RP21!x}CIhSgjQ40E^`7*e?y
z7}U5J7(Q__)HCekWMJszWMDAoWMDAkWMI(bWMKHo!N9PYgMp!ugMlHJgMq<<gMopY
zgMr~KI|IXGb_Rwu><kPw><kQ^><kP-><kQ#*ccervoSDKu`w_NurV;GvN14xU}a!9
z#>&7jo0WlK7Apfo8Y=^XEh__qFe?Lt5Gw<NAS(ld0Bb!113N1N!vhuuhTSX-47*qu
z7}l^bFwAFRU?^f?U~pq$V31^CV31&8V0g{Uz;J<?fnfnN1H%+%1_mEy1_l;p28KOM
z3=F%O7#Px+7#MV!7#NtD7#OZHGB8|WWMF7xVqhp`VqgeiVqo~o$iVQ9k%8eABQ#n-
z)a0Xz{F{#|Hgnadq^2q4CKedE1SFPZgyb8$1mq;<rD_x;mSn^mx#%dAXQq^7=qO~Q
zW~OJ9Xj(BSD?mVgUUI5JW{E<1W=@VmVsc4oVopw_LQ<+iUTSJeYKlT?PH}2^Mru(i
zgR+93e~7D<LP<tuu|h7$7=^@Qh4R##9EGIRdWFn9g_4X^h0>DD9EG&ZoKzi!q|y?F
z@{Gii)Uwnfg|z%4g}nT79k^XdsR}9ic_3p${9XLPic2yQOVo=M^72a*5*3O-Ht1#~
z=7C(1R+N~Vs*sbLn6IOdoROH9o~i&+tN?Zy$jJKQjQrA^6on*^fr)u3Ah+ZxWP*)L
zEGaEY%uy)GSI9^#18GcEs8UF*$ShVU$j{6x$;?Yv$S*BX$WH@lQb@{AEJ|TeR;bXe
zR46V<EGhx}EWbcECpE1^AvwP&FSSTPBQFsYQea<|rxur_iWlW6<Rq44<|z~>7iAWd
zD3ljvf=r%#&@z5<jlRreVLidg6Es;STPu5QKB{LeSf7}}z~IHqz%UDx-2@mIV7cu9
zKLf))eg=jm{0t0D{0t27{0s~-{0t1A_!t<D^D!{Y;$vXw;$vXw<YQpy;A3EL=VM?{
z;$vWV#LK|2j+cR<h?jw(ke7iWiI;&vo0oy%4G#mu4ju-E79Iu$e;x*gzuXKAf4CXy
z8Qya<Fzn}MV5sC~U~uPVU@+!pVED(yz;Ka^fnhTj1H(!#28JRo1_mcC1_pjE28J7)
z3=Atc85l}A85kTm85qPk85mx3FfeT6U|{IsU|>k(U|>k#U|`VUU|?Y8U|_h(&cJYk
zoq^#xI|IWtb_RyC><kRc*clia*%=rb*i#r7ir5(#QrQ_8EZ7+sc-R>j?z1s4++$;4
z*vQ7fFpZ6YA&rfJA&QNGL5Pik;S?(aLlY|lLnA8#gAOYL!)F!-hLbD|46|7vAsENP
zz#z-Q!0?xufx&=<fkB^zf#Esx#)oZ8qPeNX47sTcxv9k&@hO=_@rg;r`8ku1Dk@Aq
zs^|!!#gOEXn49-2e&ehM<&vV*lG36)1yEjM0P#VLXe%AVSOr@JT|)&euna^%TOqM1
zy;u*D&A^J46><}^!C5RlH7^yE5J6cXQ6a6gq_ikip(r&cHL*AqsuY|Rz!@yFSRqj%
zB~?5(U!k}lH90daGg%=cF*#dD0jzZLeQkRdkXt6p=}2TESqF8S0my9#wiYD+gS9Fv
x6elO<K=J`d1t??Wf@MIwcw-j@TZOy=y^P|L#N=!Za0#MQrKt&4G5M{I3;;z}d`tiU

delta 912
zcmZozz}V2hD4b*v=IN_op=ZRvz`!8D!0^!}c%$$&=7|Zco8K{u@bEJ+)H5(JFo9$l
z7#LC}3kryD_7K>?Kk<XYBn1{;Nd^Xnql^%(DU$^i%<C8NF)-xwF)-xuF)*m{F)-ZY
zWnh@b%fK*|mw};xmw~~Rmw|zkmx19e4+Fy`9tMVsJPZt5c^DXac^DX~co-Pcc^DX+
zc^DYvco-P&b2Bh(<z`^m!p*?2nVW&3h?{}Imz#lsmz#m%CKm(4TrLKNIa~}3y<7|o
zVO$Ih;#>^%439Y(7}j$#FjR3eFlcZxFsO4fFi3GSFudYmU|7Pzz)-}&z!1m5z@W*&
z!0?Bif#DuI1H%<|28Oxp3=FyK3=CH63=GWd3=Egq7#J3?F)(DaF)%o?F))a+F)%!2
zWnkFO%D~XW%D~Xg%D@oL%D|w<%D}+F%D}+P%D}+Hn!>=q$jZR*gN1?NA`1h<8WskI
z)hrAQb6FS|Ca^FtB(pFun6of2aIr8jaI!Ek++k*5ILOSvFp-&op_Q3|!IqhU;VTmZ
z!&)W=hBZtK4B<=+4022i3||--7>+SQ!ukl~#D_AIk16s^&UF!-Z0n-9`L@e?&dEo#
zC)Zo)7{n^rDikD^WJH76S_(<|iA5>#<(VlZ84M71MrvkyMu~#0f`Oh1R0u2$7BMzu
zP*x~URmjUPS13+S%t=)!$;d2LNGvEQ$}cF&Oe{&w$*EK*$ydl_P*y0(PsvxvO-(E=
zElO2LN-e1`Ni9;yO{`2xWncigLBUobuRt%OxFj(-TSEgRqEn@*$xsCmuSzY-FV@h=
zNzDUGY3dkiY9eV%Pt8j!%FivSDA7>Y(+6pe&&-Q2$gD`sDb`CaE>qW0NJ-7f%*`xG
zEwWYDQP*TB@l&u>(8w#$ODsyvOHb7>G%(Oq&{r@t(9|nREzU?RNYwy|f$dRN$Vn|x
zFIGrS%*j#6EKx8tP$*7K&d*CJ)=?<WNGwS$OD&q*;2J%-L|<icnx5cf0XMI329Sdk
z(lg6a<8xEvOEOa9lM{0?lZp~cQd8n{^HWlD6f$!Q@{39o(o;(y0u05K#d;ve>t*H@
crxulH80aXd>*?u3P-#hKj=JXNqk7hY03hJr&Hw-a

diff --git a/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc b/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0dfee1861238ee36321ba4d1ea3b45c06492a33d
GIT binary patch
literal 3943
zcmd1j<>g{vU|<lIi%i`w&A{*&#6iYv3=9ko3=9m#yBHW4QW#Pga~Pr+!8B78Gni(H
zVgb{vQLHHpDNH$Rx$IHwj3BklIUKp1QJlG4QCy4+oD3-}DXc9FQQRqPDeNr_Q9LOe
zDV!|~QM{ZCDO@SsEeuh7DLg5>EeuiosRAi{*-S;zsoc#BQG%&lse;XnQ9`Lg3xpRk
zM2V#Gf%&4T?5X^zLaCz7%u!;goT);oVyS|e44DkgtWn~r;tM1eGB7fvFb0FMCjU#2
zulzI_Z?P977L{Zs=4dkA5^~PZD=Es)@yX9G@J-B1OiwMk#S@gDlwShnC4)4<FcSj<
z13Lo)gEJ^NSQr@?N*J;jQy5DavY1ksdYNh&Y8bMZQ<zH_vRFV~O=0V0VT6dWgT**f
zSdqjy!D3t}V%%Uc9uzU&64n&H6#f(exM_kVY$-x1!bl<_C9El;DPl+>;w7vp5-E~M
zB2p!+Dbgu2NFuT&>?v|7@+tBu3h7KKioL8**D95;rYNVVq^Lq{T)?rAp_Z|RF^jXP
zp@uPwtEi!bJ4LOTv5B#UF_=M9-LI-7s5DO@IVZn3HANvOKfgdBGp{VQs5n(2J2Nje
zH?br$xmW=i<fkc=B^G7omllImq!jBZ_$FqjDioI%r7BeBmnvlE<(DgzXC#&=lw_nT
zq~|B*C}b8ZB&DY1LlqR2<|%42-QrG3Elw`VEGWs$&%4E+mS2>cSW=Q&6rY@vSX^Ai
zqpMq-nOmBZ2$HVSD9=bO$w(~%TaZ|ks!&v#mzSBB4z?mRNCB!ezsOCK`4(GZGDy=c
zmW<S#f?Mn<scDI&IVDvBy1E6KdHKo78JYRI`FS~&Rffo>mM7+wD3s(YWR(_|C}if9
zq^1`omZU0_XO?6r!1Yye>*|(e7MCXGWLBkCd1BKKmxgFfPc29-DaqGSNGdH+@beFG
zwNl8-FHy+MEyzjDP0cGwO;M;!Eve$v)lDzTEGS4Vs!~8QRlO)xp|lw0QJ4xIU0qPH
z>ZTSI<rh_HgMv9NGcPemp&-9F6XbOTunat~G7<|4D#6Z4uNGP7{;;aWUX%G2OG#xx
zY7qwm149uf0|Nsnd~y>jbTdm*i@<?iTxFV@Sdp1qnyZkQlapVbn3R*M0GCzBE6q(x
zEmF|PECEGEu|i^rf~kRlN0nygf;L8mDn4D^#N_1E9H?Pc_lrOoQ@vOrD?c-@q*wu2
zQcs~cIWZ@(2<rZ_RE6aHyyB9?yb>LS+{6k6Lp^gHg~YrR1!z<%80eYkAty-~+sReI
z*)hn~E!0OL+%v>OA;iNoSPz^=N{b+AO(7*eS)n+wvRI)cBeNKkFx7KX6H^otD>6~t
zq>jyk5PuhcD~05Y)Z}bf3ePN7$W2YmD^52CgUj|HpBERTrl#l?=VYd&7FA73PApJ>
z`5r6-jta1|AY6z-m?u!^l6-~Y{M^)%3{V<KN-Zf*P0dp<00)Mlj)H-nsX|gEJXlb4
zLOEE2Bpp&HKCrLi*VQe_%+AQq%P-SSNz5&%(gcwp%b-z`nWs>anVpxPkzb}zl$u_e
zlUS5l1x_F7e^!3H<eL;=UnQuko1BxGt(y!fk8@Iss#J?pb5fH_6v{I)lQR^Ob25{&
z6%upO^NTV|GIGHQ6O`X>34?4)O$jJYEltUXmOHluvl5f@lQI+YLW&aeiVO0KQ#DzN
zK=m9VvEE`&&dAS9PA#sI(nYdX7aX3tAg5>MrB^W<>KRmtg0fp;a!F}oPEKWfDX5f7
zEXmbmhL{LS`CwzKT3s?zz*#dbGaXcv<(HNyWaO8FiiCnvXjulyp$eIK(7;7dpgagI
zgfjE<Kv`Nxp*X*&s8Yd7UqMeHGQU(IIWbQmBe5)1AwMstQo#@u|HY{aX*r4M#R^54
z=@}&odHLm<JhwO!i_!}ci;7ck@i`Wymx2n301&t6mMo0#0x8mpJyLTD++YRgEuO@b
zl=wubmRq7u`T04iiFy9u0yZ(n5mG3!rsd=(mfT{_%qzLYTwGFgiwkTQNMG?Sc4!H6
ziwohGTf%<%C7y`l%C)E{zetnm78_V!(Jhw5qV(dG3`H^w3=F>t^fU5vQ}xsHiwp8o
z5{tk*BLp|6G%rQJpa_)N^h=B4i@~K}JT%$p7gUyH<mX|L03|Mc5D{MhDm>y#@*xbp
zg34PQ>8T}P$BTgK^)Lno1~x_(CboZE%q)y-|GAjZNe-|GjAUYDVq*Kt!2+W}syUdM
z7&#c({&BECcsz_8j4Vt=atsU%$;^<9114D*7#Kjw2i%~rVPIgWVa#GEVa#G$z+3~W
za2W&`N*EWg)G%hTrZ7r^WWn@8rWytj262Xki~<ZbOactG%r(rx44O=SMT`s#44Q1W
z7(;F`<rUmw%K;VX>7bY@yTzPZnR<)0I3uwjRg>iwFE~f$<(I{Svd=9>uUlNHMMd#t
zsmUezMYos=Q^1h{A!I@2J2wLZgFPsGKyJ2RWMM1<i6k?D{Q)6BJ_GT=zTpG;h9Qfg
zhEaf_mZ^p*m_d`#Pm{4o9^^viA~lei>L5Y`M1W!*$ub^zBa4B7feU0ANF*8LJBU>b
z3?MehLa=29P|H#nvzdyxOBhR-KrOLmreIL(iy?(6o2f{sge8~(D#Hqr(PZ`md!Yzq
zv?kjvesJo5CZwFyq9Tx2z$(Cj1uoyffd$r3qzdu}W05qb>u(9Br<OS9WM)I#mN}_K
z{-A&Z6+c{zJd7a!@CX%YgAxNMFkwCdg(s-74ffF!P-C01mL-#+mbHdq0mDLuTDB6#
z1z>;GFl4dRuq|X}1o@67i?xO!i%pVY0ecNY7RN%yTJ{pg1)MeP3mLPxYB@@{vv?Np
z)^IFjtYOIF%VsDtEa6XKYG!0)NMWvJDPde7017FHi6C<pvea_cFxGI^a5OX3a@8;_
z5Uk-^$jHc0!<51z#!#GF!k+@N4{mES6C*<je+tNL5IcpSA_!LqLq#}hI2MR3WB~DM
zSU}D6G*F`D^mD7ycFqU27t>Sol2a8DlQS|?%TiNx6pB(4lQU95Rdz9`MFOrd6hks!
zFf%aRVlK!puHw(h%u7uyf;Lrb6{-Xh^T5>$LWC2})D*qNlAc-;c#F9pGw+sQT7FS^
zVo{1Wyn%X)H8(#cHRl#fN@7XkE#`dR%v&5@{+@mz@t!W=_Mm58*)3LIP^;+{OHO{e
z*)29mZYfd#r2$0-28LTKdHF@Tx41xR;=%2wTdV~|pkh)aIX}0cv?SFFRQPy7>!w?5
z#i@BIfhpj8nwnU2iyi9xTbw2EYK!|8E4bn>(gaz+n0bq{AhEb49_&cYq@vWsY`2`m
z^jmzziDjwr5UI@Ml3R?0x7dSS!EPu5XEShy!;;r-@k5h5s0##2wb`Jws=~m)z{1GF
z$iXDUD8|IYC<H3N7{!>ln7J4^m_-<c7=;-57`d2>+(EA5h>y=r%*>0A*Oa`)32*2Y
z>4D@}^Gb6ID#2lNizPX~pt1;5GTh=!E6qzT$<NOz2IsR|QW#~qUM{3RR$K(i=0%{K
z0xm$oSrU>5L0Jgyg1p4s)cANvh6MFjZ}F$3re)@(y5}e61b~9Q$P^S$;9%rN^7Abo
zP>&@ZYTGU5qS8D_NrYM^-Quvx%}*)KNwou&JjFT;3=A9$9E>2y!zjSW#KghFq0Pa<
Z#KOVBA;Tfh2A1Jq<Y5$G;$dX@0RZjET!H`q

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/clik/clik_point_to_point.py b/python/ur_simple_control/clik/clik_point_to_point.py
index c98b050..d5ce006 100644
--- a/python/ur_simple_control/clik/clik_point_to_point.py
+++ b/python/ur_simple_control/clik/clik_point_to_point.py
@@ -5,6 +5,10 @@ import argparse
 from functools import partial
 from ur_simple_control.managers import ControlLoopManager, RobotManager
 
+# TODO move actually using this (main file and arguments to an example file).
+# but do make assertions that certain arguments have to exist.
+# this is good, just not separated the way it should be, like dmp is for example.
+
 """
 Every imaginable magic number, flag and setting is put in here.
 This way the rest of the code is clean.
@@ -30,7 +34,7 @@ def get_args():
     parser.add_argument('--gripper', action=argparse.BooleanOptionalAction, \
             help="whether you're using the gripper", default=False)
     parser.add_argument('--goal-error', type=float, \
-            help="the final position error you are happy with", default=1e-3)
+            help="the final position error you are happy with", default=1e-2)
     parser.add_argument('--max-iterations', type=int, \
             help="maximum allowable iteration number (it runs at 500Hz)", default=100000)
     parser.add_argument('--acceleration', type=float, \
@@ -42,7 +46,7 @@ def get_args():
                     to something between 0 and 1, 0.5 by default \
                     BE CAREFUL WITH THIS.", default=0.5)
     parser.add_argument('--tikhonov-damp', type=float, \
-            help="damping scalar in tiknohov regularization", default=1e-2)
+            help="damping scalar in tiknohov regularization", default=1e-3)
     # TODO add the rest
     parser.add_argument('--clik-controller', type=str, \
             help="select which click algorithm you want", \
@@ -102,7 +106,9 @@ def getClikController(args):
 
 
 # modularity yo
-def controlLoopClik(robot, clik_controller, i):
+# past data to comply with the API
+# TODO make this a kwarg or whatever to be more lax with this
+def controlLoopClik(robot, clik_controller, i, past_data):
     breakFlag = False
     save_past_dict = {}
     # know where you are, i.e. do forward kinematics
@@ -132,7 +138,6 @@ def controlLoopClik(robot, clik_controller, i):
     return breakFlag, {}, {}
 
 
-
 if __name__ == "__main__": 
     args = get_args()
     robot = RobotManager(args)
diff --git a/python/ur_simple_control/clik/clik_trajectory_following.py b/python/ur_simple_control/clik/clik_trajectory_following.py
index 01d274b..dd2e244 100644
--- a/python/ur_simple_control/clik/clik_trajectory_following.py
+++ b/python/ur_simple_control/clik/clik_trajectory_following.py
@@ -10,27 +10,26 @@ import numpy as np
 import pinocchio as pin
 import os
 import sys
-sys.path.insert(0, '../../../util')
-from give_me_the_calibrated_model import get_model
 
 #######################################################################
-#                STEP 1: map the pixels to a 3D plane                 #
+#                    map the pixels to a 3D plane                     #
 #######################################################################
-
-# let's call it 10 seconds, whatever
-t = (np.arange(100) / 10).reshape((100,1))
-path = np.genfromtxt('./path_in_pixels.csv', delimiter=',')
-z = np.zeros((len(path),1))
-path = np.hstack((path,z))
-
-# todo measure better maybe
-# we now scale this appropriatelly to m
-board_width = 0.35
-board_height = 0.4
-path[:,0] = path[:,0] * board_width
-path[:,1] = path[:,1] * board_height
-# in the new coordinate system we're going in the -y direction
-path[:,1] = -1 * path[:,1] + board_height
+# x-y start in top-left corner (natual for western latin script writing)
+# and then it's natural to have the z axis pointing out of the board
+# TODO but that's not a right-handed frame lmao, change that where it should be
+# NOTE: this might as well be in the util file, but whatever for now, it will be done
+#       once it will actually be needed elsewhere
+def map2DPathTo3DPlane(path_2D, width, height):
+    z = np.zeros((len(path),1))
+    path_3D = np.hstack((path,z))
+    # scale the path to m
+    path[:,0] = path[:,0] * width
+    path[:,1] = path[:,1] * height
+    # in the new coordinate system we're going in the -y direction
+    # TODO this is a demo specific hack, 
+    # make it general for a future release
+    path[:,1] = -1 * path[:,1] + args.height
+    return path
 
 
 # now the path is appropriately scaled and in the first quadrant
diff --git a/python/ur_simple_control/dmp/__pycache__/create_dmp.cpython-310.pyc b/python/ur_simple_control/dmp/__pycache__/create_dmp.cpython-310.pyc
index 11b1d7280e1674320a8aea0e7af9628e66f5e298..e606d08bbcd11c09106b3e85b974b8b55a51c64a 100644
GIT binary patch
delta 210
zcmeyM*rddl&&$ijz`($e&mNj8BfgQ(go!b2vNMy7eL-bOMt+`tX;FM}W^O@FYJ75j
zUP)1Yj($pRfqrsPYGO%hd`fPCUP0w8j`;Y@yv&mLcs>ROhGGo{1_n0n&1;xk82PP1
z0wD8QnD`il7$^T{{?F(<`9Di1qxa-a)>_7Z$?R+;jG>cj*wPrICO>9NV~m~b#r~Z!
zVY3rQI3r`)<XN1X81p9ka{XW|-t5L5%EH(%c@F;@L0*u#G7Jn191L8H9J(AFlV=Kq
HG4cQaEbKa%

delta 192
zcmZot`k=^{&&$ijz`(%ZTH=+eD7=x+go!a^vNMy7Zc1)}er{!aaej_|a#3nxNossb
zZh>Aw<t>i*_{_Y_lK6NQ1_p*=4F(1VHm1${m|Ph7LF{6XX)G*!j6%$l1zG+xnoJgC
z?PRo>Je#$a(Q&dQTM47v<UY1EM(@dA+0q#OCdaUUXAImN!V%8M7(RIo=O)JZ$?;r2
o7*jS!aEG!m7EWHr|3;7*WRVO50|N&G7bAxX2hZfy0%43y02(AQT>t<8

diff --git a/python/ur_simple_control/dmp/__pycache__/dmp.cpython-310.pyc b/python/ur_simple_control/dmp/__pycache__/dmp.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e35c4b88f393d22f12a90e35d11ca47eef6680e6
GIT binary patch
literal 6620
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

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/dmp/__pycache__/temporal_coupling.cpython-310.pyc b/python/ur_simple_control/dmp/__pycache__/temporal_coupling.cpython-310.pyc
index 31d5b4d59ffa1b2859605ad73e9336eadddcd992..3862d1996a25cbedc00c96c38fb2a2a1341665e0 100644
GIT binary patch
delta 104
zcmX>jd{3A+pO=@5fq{YH{-@AXpNYJe8FME-w2>*OEXl~v(=RQGFV4&@$VrV)&d)0;
z%FoeH$t{?y&M3>sIoXvlhLL0QB1T_EM*htom?knZifwLUab#gsn0$m|EhF#bBF<1&
J7CvSnRsblqAJG5+

delta 86
zcmca7d`6fzpO=@5fq{YHF^gv^??m3qjL{Px+Hj@h7U<_z#uw-3Otxf{Wn`Zm&KSeU
rws{MqFC!!GW+vu|jEo|ir?5D(Fv?B7#<7->dvXhBC@T{mvk)r)8g~|Z

diff --git a/python/ur_simple_control/dmp/create_dmp.py b/python/ur_simple_control/dmp/dmp.py
similarity index 60%
rename from python/ur_simple_control/dmp/create_dmp.py
rename to python/ur_simple_control/dmp/dmp.py
index b9d7a6d..2e6c734 100644
--- a/python/ur_simple_control/dmp/create_dmp.py
+++ b/python/ur_simple_control/dmp/dmp.py
@@ -5,13 +5,15 @@ import numpy as np
 # 2. change hand-written numerical differentiation 
 #    to numpy calls (for code style more than anything)
 # 3. separate x into z and s variables, this is unnecessarily complicated
+# 4. ask mentors if there's ever a reason not to use temporal coupling,
+#    and if not, integrate it into the DMP class
 
 # k,d are constanst which determine the baseline uncostrained dynamics
 # these work fine, but it could be good to play around with them just to
 # see their effect. normally people set them so that you get critical damping
 # as the uncostrained system
 class DMP:
-    def __init__(self, k=100, d=20, a_s=1, n_bfs=100):
+    def __init__(self, trajectory, k=100, d=20, a_s=1, n_bfs=100):
         # TODO load the trajectory here
         # and then allocate all these with zeros of appopriate length
         # as this way they're basically declared twice
@@ -50,16 +52,23 @@ class DMP:
         self.path = None
 
         # actually init
-        # TODO pass other trajectories as arguments and etc to make this nice
-        self.load_trajectory()
+        # TODO handle this better, this is not optimal programming
+        if type(trajectory) == str:
+            self.load_trajectory_from_file(trajectory)
+        else:
+            self.load_trajectory(trajectory)
         self.fit()
 
+    def load_trajectory_from_file(self, file_path):
+        # load trajectory.  this is just joint positions.
+        data = np.genfromtxt(file_path, delimiter=',')
+        self.time = data[:, 0]
+        self.time = self.time.reshape(1, len(self.time))
+        self.y = np.array(data[:, 1:]).T
 
-    # TODO pass other trajectories as arguments and etc to make this nice
-    def load_trajectory(self):
+    def load_trajectory(self, trajectory):
         # load trajectory.  this is just joint positions.
-        trajectory_loadpath = './new_traj.csv'
-        data = np.genfromtxt(trajectory_loadpath, delimiter=',')
+        data = np.genfromtxt(file_path, delimiter=',')
         self.time = data[:, 0]
         self.time = self.time.reshape(1, len(self.time))
         self.y = np.array(data[:, 1:]).T
@@ -163,3 +172,79 @@ class DMP:
 
         # Reset state
         self.reset()
+
+
+class NoTC:
+    def update(self, dmp, dt):
+        return 0
+
+class TCVelAccConstrained:
+
+    def __init__(self, gamma_nominal, gamma_a, v_max, a_max, eps=0.001):
+        self.gamma_nominal = gamma_nominal
+        self.gamma_a = gamma_a
+        self.eps = eps
+        self.v_max = v_max.reshape((len(v_max), 1))
+        self.a_max = a_max.reshape((len(a_max), 1))
+
+    def generate_matrices(self, dmp, dt):
+        A = np.vstack((-dmp.z(), dmp.z()))
+        B = np.vstack((-self.a_max, -self.a_max))
+        C = np.vstack((dmp.h(), -dmp.h()))
+        D = np.vstack((-self.v_max, -self.v_max))
+        x_next = dmp.x + dmp.f(dmp.x) / dmp.tau * dt
+        A_next = np.vstack((-dmp.z(x_next), dmp.z(x_next)))
+        C_next = np.vstack((dmp.h(x_next), -dmp.h(x_next)))
+        return A, B, C, D, A_next, C_next
+
+    def update(self, dmp, dt):
+
+        A, B, C, D, A_next, C_next = self.generate_matrices(dmp, dt)
+
+        # Acceleration bounds
+        i = np.squeeze(A < 0)
+        if i.any():
+            taud_min_a = np.max(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
+        else:
+            taud_min_a = -np.inf
+        i = np.squeeze(A > 0)
+        if i.any():
+            taud_max_a = np.min(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
+        else:
+            taud_max_a = np.inf
+        # Velocity bounds
+        i = range(len(A_next))
+        tau_min_v = np.max(-A_next[i] / D[i])
+        taud_min_v = (tau_min_v - dmp.tau) / dt
+        # Feasibility bounds
+        ii = np.arange(len(A_next))[np.squeeze(A_next < 0)]
+        jj = np.arange(len(A_next))[np.squeeze(A_next > 0)]
+        tau_min_f = -np.inf
+        for i in ii:
+            for j in jj:
+                num = C_next[i] * abs(A_next[j]) + C_next[j] * abs(A_next[i])
+                if num > 0:
+                    den = abs(B[i] * A_next[j]) + abs(B[j] * A_next[i])
+                    tmp = np.sqrt(num / den)
+                    if tmp > tau_min_f:
+                        tau_min_f = tmp
+        taud_min_f = (tau_min_f - dmp.tau) / dt
+        # Nominal bound
+        taud_min_nominal = (dmp.tau0 - dmp.tau) / dt
+
+        taud_min = np.max((taud_min_a, taud_min_v, taud_min_f, taud_min_nominal))
+
+        # Base update law
+        ydd_bar = dmp.h() / (dmp.tau**2 * self.a_max)
+        if self.gamma_a > 0:
+            pot_a = self.gamma_a * np.sum(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
+        else:
+            pot_a = 0
+        #pot_a = self.gamma_a * np.amax(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
+        taud = self.gamma_nominal * (dmp.tau0 - dmp.tau) + dmp.tau * pot_a
+
+        # Saturate
+        taud = np.min((taud, taud_max_a))
+        taud = np.max((taud, taud_min))
+
+        return taud
diff --git a/python/ur_simple_control/dmp/drawing_gen/lasso_selector_demo_sgskip.py b/python/ur_simple_control/dmp/drawing_gen/lasso_selector_demo_sgskip.py
deleted file mode 100644
index f5a206f..0000000
--- a/python/ur_simple_control/dmp/drawing_gen/lasso_selector_demo_sgskip.py
+++ /dev/null
@@ -1,113 +0,0 @@
-"""
-==============
-Lasso Selector
-==============
-
-Interactively selecting data points with the lasso tool.
-
-This examples plots a scatter plot. You can then select a few points by drawing
-a lasso loop around the points on the graph. To draw, just click
-on the graph, hold, and drag it around the points you need to select.
-"""
-
-
-import numpy as np
-
-from matplotlib.path import Path
-from matplotlib.widgets import LassoSelector
-
-
-class SelectFromCollection:
-    """
-    Select indices from a matplotlib collection using `LassoSelector`.
-
-    Selected indices are saved in the `ind` attribute. This tool fades out the
-    points that are not part of the selection (i.e., reduces their alpha
-    values). If your collection has alpha < 1, this tool will permanently
-    alter the alpha values.
-
-    Note that this tool selects collection objects based on their *origins*
-    (i.e., `offsets`).
-
-    Parameters
-    ----------
-    ax : `~matplotlib.axes.Axes`
-        Axes to interact with.
-    collection : `matplotlib.collections.Collection` subclass
-        Collection you want to select from.
-    alpha_other : 0 <= float <= 1
-        To highlight a selection, this tool sets all selected points to an
-        alpha value of 1 and non-selected points to *alpha_other*.
-    """
-
-    def __init__(self, ax, collection, alpha_other=0.3):
-        self.canvas = ax.figure.canvas
-        self.collection = collection
-        self.alpha_other = alpha_other
-
-        self.xys = collection.get_offsets()
-        self.Npts = len(self.xys)
-
-        # Ensure that we have separate colors for each object
-        self.fc = collection.get_facecolors()
-        if len(self.fc) == 0:
-            raise ValueError('Collection must have a facecolor')
-        elif len(self.fc) == 1:
-            self.fc = np.tile(self.fc, (self.Npts, 1))
-
-        self.lasso = LassoSelector(ax, onselect=self.onselect)
-        self.ind = []
-
-    def onselect(self, verts):
-        path = Path(verts)
-        print(verts)
-        print(path)
-        self.ind = np.nonzero(path.contains_points(self.xys))[0]
-        self.fc[:, -1] = self.alpha_other
-        self.fc[self.ind, -1] = 1
-        self.collection.set_facecolors(self.fc)
-        #self.canvas.draw_idle()
-
-    def disconnect(self):
-        self.lasso.disconnect_events()
-        self.fc[:, -1] = 1
-        self.collection.set_facecolors(self.fc)
-        self.canvas.draw_idle()
-
-
-if __name__ == '__main__':
-    import matplotlib.pyplot as plt
-
-    # Fixing random state for reproducibility
-    np.random.seed(19680801)
-
-    data = np.random.rand(100, 2)
-
-    subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
-    fig, ax = plt.subplots(subplot_kw=subplot_kw)
-
-    pts = ax.scatter(data[:, 0], data[:, 1], s=80)
-    selector = SelectFromCollection(ax, pts)
-
-    def accept(event):
-        if event.key == "enter":
-            print("Selected points:")
-            print(selector.xys[selector.ind])
-            selector.disconnect()
-            ax.set_title("")
-            fig.canvas.draw()
-
-    fig.canvas.mpl_connect("key_press_event", accept)
-    ax.set_title("Press enter to accept selected points.")
-
-    plt.show()
-
-# %%
-#
-# .. admonition:: References
-#
-#    The use of the following functions, methods, classes and modules is shown
-#    in this example:
-#
-#    - `matplotlib.widgets.LassoSelector`
-#    - `matplotlib.path.Path`
diff --git a/python/ur_simple_control/dmp/drawing_gen/path_in_pixels.csv b/python/ur_simple_control/dmp/drawing_gen/path_in_pixels.csv
deleted file mode 100644
index 50cb591..0000000
--- a/python/ur_simple_control/dmp/drawing_gen/path_in_pixels.csv
+++ /dev/null
@@ -1,327 +0,0 @@
-0.30482,0.61994
-0.30334,0.61994
-0.30186,0.62144
-0.29891,0.62442
-0.29595,0.62890
-0.29299,0.63189
-0.28263,0.64383
-0.27227,0.65278
-0.26635,0.65726
-0.26191,0.66174
-0.25747,0.66323
-0.25155,0.66920
-0.24711,0.67368
-0.24416,0.67518
-0.23972,0.68115
-0.23824,0.68264
-0.23676,0.68562
-0.23528,0.69309
-0.23380,0.69757
-0.23380,0.70503
-0.23380,0.71249
-0.23380,0.71697
-0.23528,0.72444
-0.24120,0.74534
-0.24711,0.75429
-0.25747,0.76773
-0.26339,0.77370
-0.26783,0.77967
-0.27967,0.78713
-0.28559,0.79460
-0.29003,0.79758
-0.30038,0.80803
-0.30926,0.81549
-0.32998,0.82594
-0.33886,0.82893
-0.34478,0.83042
-0.35661,0.83341
-0.36253,0.83341
-0.36993,0.83341
-0.38325,0.83341
-0.39657,0.83192
-0.40249,0.83042
-0.41432,0.82744
-0.41728,0.82594
-0.42172,0.82445
-0.42912,0.81997
-0.43060,0.81848
-0.43356,0.81549
-0.44244,0.80803
-0.44984,0.79609
-0.45280,0.78863
-0.45576,0.77668
-0.45872,0.76773
-0.46168,0.75877
-0.46463,0.74683
-0.46759,0.72891
-0.46907,0.72444
-0.46907,0.72145
-0.46907,0.71548
-0.46907,0.71249
-0.46907,0.70652
-0.46907,0.70354
-0.46907,0.69906
-0.46907,0.69757
-0.46907,0.69607
-0.46907,0.69458
-0.46759,0.69607
-0.46463,0.70354
-0.46315,0.70951
-0.46020,0.72294
-0.46315,0.73936
-0.47647,0.75877
-0.47647,0.76026
-0.47795,0.76176
-0.47795,0.76325
-0.47943,0.76474
-0.52826,0.78116
-0.55934,0.78713
-0.57561,0.79161
-0.58005,0.79310
-0.58153,0.79310
-0.58301,0.79310
-0.58597,0.79310
-0.62149,0.78713
-0.65108,0.78265
-0.65552,0.78265
-0.66440,0.77818
-0.67624,0.77370
-0.69843,0.76474
-0.71027,0.75877
-0.72359,0.75280
-0.72951,0.75131
-0.73247,0.74832
-0.74134,0.74235
-0.74726,0.73787
-0.75318,0.73041
-0.76354,0.70951
-0.76798,0.69607
-0.76946,0.68712
-0.76946,0.66920
-0.76798,0.66174
-0.76502,0.65129
-0.76058,0.63338
-0.75910,0.63189
-0.75910,0.63039
-0.75614,0.62741
-0.75022,0.62293
-0.74282,0.61994
-0.73542,0.61696
-0.71767,0.61248
-0.70879,0.61099
-0.69991,0.60949
-0.69695,0.60949
-0.69103,0.60949
-0.68511,0.60800
-0.67180,0.60502
-0.66736,0.60502
-0.65996,0.60502
-0.65700,0.60502
-0.65108,0.60502
-0.64516,0.60651
-0.63776,0.60800
-0.62001,0.61397
-0.61557,0.61397
-0.60965,0.61397
-0.60817,0.61397
-0.60521,0.61397
-0.60373,0.61397
-0.60817,0.61248
-0.61853,0.60949
-0.63332,0.60352
-0.64516,0.60054
-0.65700,0.59606
-0.67032,0.59009
-0.69251,0.58113
-0.70731,0.57217
-0.71767,0.56770
-0.73690,0.55874
-0.74578,0.55426
-0.75910,0.54680
-0.76502,0.54232
-0.77538,0.53486
-0.78130,0.53187
-0.79165,0.51993
-0.79609,0.50948
-0.80201,0.49455
-0.80497,0.48559
-0.80793,0.47067
-0.80793,0.46619
-0.80793,0.46320
-0.80793,0.45574
-0.80793,0.45425
-0.80497,0.45126
-0.80053,0.44380
-0.78130,0.42439
-0.76946,0.41693
-0.74726,0.40648
-0.73986,0.40349
-0.72951,0.40200
-0.72211,0.40200
-0.70583,0.40349
-0.69695,0.40648
-0.68067,0.40946
-0.67476,0.41245
-0.66440,0.41544
-0.66144,0.41693
-0.65700,0.41842
-0.65108,0.42141
-0.63924,0.42887
-0.63332,0.43186
-0.62001,0.43633
-0.60669,0.44230
-0.60225,0.44529
-0.59189,0.45126
-0.58893,0.45275
-0.57709,0.46470
-0.57265,0.46917
-0.56674,0.47664
-0.56230,0.48410
-0.54898,0.50351
-0.54750,0.50948
-0.54454,0.51844
-0.54454,0.51993
-0.54306,0.52590
-0.54306,0.53038
-0.54158,0.53933
-0.54158,0.54232
-0.54158,0.54381
-0.54158,0.54232
-0.54306,0.54083
-0.54602,0.53336
-0.56082,0.50202
-0.56378,0.48410
-0.56526,0.47664
-0.56674,0.46470
-0.56674,0.45425
-0.56082,0.42439
-0.55786,0.41096
-0.55046,0.39454
-0.54750,0.39006
-0.54158,0.38409
-0.53270,0.37364
-0.53122,0.37065
-0.52234,0.36170
-0.51790,0.35572
-0.51495,0.35572
-0.50163,0.34826
-0.49127,0.34528
-0.47055,0.34229
-0.46168,0.34229
-0.44984,0.34229
-0.44392,0.34378
-0.42764,0.34677
-0.42024,0.34826
-0.41284,0.35125
-0.39805,0.35423
-0.39213,0.35572
-0.38473,0.35722
-0.37881,0.36020
-0.37585,0.36170
-0.37141,0.36468
-0.36253,0.37364
-0.35513,0.38259
-0.34626,0.40648
-0.34626,0.41245
-0.34626,0.42141
-0.34922,0.43484
-0.35218,0.44230
-0.35365,0.45275
-0.35661,0.46022
-0.35957,0.47365
-0.36549,0.48709
-0.36993,0.49455
-0.37141,0.50052
-0.37289,0.50351
-0.37437,0.50649
-0.37585,0.50799
-0.37585,0.50500
-0.37141,0.48858
-0.36549,0.47067
-0.35809,0.45873
-0.34626,0.44380
-0.33590,0.43335
-0.31518,0.41693
-0.30926,0.41245
-0.29003,0.39752
-0.27967,0.39304
-0.26191,0.38707
-0.25303,0.38558
-0.23676,0.38409
-0.22788,0.38409
-0.20568,0.38409
-0.19384,0.38409
-0.17609,0.38558
-0.16869,0.38707
-0.16129,0.39006
-0.14797,0.39603
-0.13909,0.40200
-0.12430,0.41096
-0.11098,0.41842
-0.10358,0.42290
-0.09618,0.42887
-0.09174,0.43186
-0.08730,0.43783
-0.08139,0.44828
-0.07695,0.46320
-0.07547,0.46917
-0.07399,0.48559
-0.07399,0.49306
-0.07399,0.50202
-0.07547,0.50799
-0.07547,0.51097
-0.07843,0.51993
-0.08286,0.53038
-0.08730,0.53933
-0.09174,0.54978
-0.09322,0.55277
-0.09470,0.55426
-0.09766,0.55725
-0.09914,0.55874
-0.10210,0.56173
-0.10950,0.56620
-0.11542,0.57068
-0.12726,0.57964
-0.13318,0.58412
-0.13466,0.58561
-0.14205,0.59158
-0.14501,0.59457
-0.15685,0.60203
-0.16425,0.60800
-0.17165,0.61248
-0.17905,0.61546
-0.18201,0.61696
-0.18497,0.61845
-0.19384,0.62144
-0.19680,0.62293
-0.20124,0.62293
-0.20716,0.62293
-0.21012,0.62293
-0.21752,0.62293
-0.22196,0.62144
-0.22788,0.62144
-0.23232,0.62144
-0.23676,0.61994
-0.23972,0.61994
-0.25599,0.61994
-0.26191,0.61845
-0.26635,0.61845
-0.27523,0.61845
-0.27819,0.61696
-0.28263,0.61696
-0.28559,0.61696
-0.28707,0.61546
-0.29151,0.61546
-0.29447,0.61546
-0.29595,0.61397
-0.30038,0.61248
-0.30334,0.61248
-0.30482,0.61248
-0.30926,0.61099
-0.31074,0.60949
-0.31666,0.60800
-0.31814,0.60651
-0.31962,0.60651
-0.32110,0.60651
-0.32110,0.60502
-0.32110,0.60502
diff --git a/python/ur_simple_control/dmp/robotiq_gripper.py b/python/ur_simple_control/dmp/robotiq_gripper.py
deleted file mode 100644
index a17ab18..0000000
--- a/python/ur_simple_control/dmp/robotiq_gripper.py
+++ /dev/null
@@ -1,291 +0,0 @@
-"""Module to control Robotiq's grippers - tested with HAND-E"""
-
-import socket
-import threading
-import time
-from enum import Enum
-from typing import Union, Tuple, OrderedDict
-
-class RobotiqGripper:
-    """
-    Communicates with the gripper directly, via socket with string commands, leveraging string names for variables.
-    """
-    # WRITE VARIABLES (CAN ALSO READ)
-    ACT = 'ACT'  # act : activate (1 while activated, can be reset to clear fault status)
-    GTO = 'GTO'  # gto : go to (will perform go to with the actions set in pos, for, spe)
-    ATR = 'ATR'  # atr : auto-release (emergency slow move)
-    ADR = 'ADR'  # adr : auto-release direction (open(1) or close(0) during auto-release)
-    FOR = 'FOR'  # for : force (0-255)
-    SPE = 'SPE'  # spe : speed (0-255)
-    POS = 'POS'  # pos : position (0-255), 0 = open
-    # READ VARIABLES
-    STA = 'STA'  # status (0 = is reset, 1 = activating, 3 = active)
-    PRE = 'PRE'  # position request (echo of last commanded position)
-    OBJ = 'OBJ'  # object detection (0 = moving, 1 = outer grip, 2 = inner grip, 3 = no object at rest)
-    FLT = 'FLT'  # fault (0=ok, see manual for errors if not zero)
-
-    ENCODING = 'UTF-8'  # ASCII and UTF-8 both seem to work
-
-    class GripperStatus(Enum):
-        """Gripper status reported by the gripper. The integer values have to match what the gripper sends."""
-        RESET = 0
-        ACTIVATING = 1
-        # UNUSED = 2  # This value is currently not used by the gripper firmware
-        ACTIVE = 3
-
-    class ObjectStatus(Enum):
-        """Object status reported by the gripper. The integer values have to match what the gripper sends."""
-        MOVING = 0
-        STOPPED_OUTER_OBJECT = 1
-        STOPPED_INNER_OBJECT = 2
-        AT_DEST = 3
-
-    def __init__(self):
-        """Constructor."""
-        self.socket = None
-        self.command_lock = threading.Lock()
-        self._min_position = 0
-        self._max_position = 255
-        self._min_speed = 0
-        self._max_speed = 255
-        self._min_force = 0
-        self._max_force = 255
-
-    def connect(self, hostname: str, port: int, socket_timeout: float = 2.0) -> None:
-        """Connects to a gripper at the given address.
-        :param hostname: Hostname or ip.
-        :param port: Port.
-        :param socket_timeout: Timeout for blocking socket operations.
-        """
-        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.socket.connect((hostname, port))
-        self.socket.settimeout(socket_timeout)
-
-    def disconnect(self) -> None:
-        """Closes the connection with the gripper."""
-        self.socket.close()
-
-    def _set_vars(self, var_dict: OrderedDict[str, Union[int, float]]):
-        """Sends the appropriate command via socket to set the value of n variables, and waits for its 'ack' response.
-        :param var_dict: Dictionary of variables to set (variable_name, value).
-        :return: True on successful reception of ack, false if no ack was received, indicating the set may not
-        have been effective.
-        """
-        # construct unique command
-        cmd = "SET"
-        for variable, value in var_dict.items():
-            cmd += f" {variable} {str(value)}"
-        cmd += '\n'  # new line is required for the command to finish
-        # atomic commands send/rcv
-        with self.command_lock:
-            self.socket.sendall(cmd.encode(self.ENCODING))
-            data = self.socket.recv(1024)
-        return self._is_ack(data)
-
-    def _set_var(self, variable: str, value: Union[int, float]):
-        """Sends the appropriate command via socket to set the value of a variable, and waits for its 'ack' response.
-        :param variable: Variable to set.
-        :param value: Value to set for the variable.
-        :return: True on successful reception of ack, false if no ack was received, indicating the set may not
-        have been effective.
-        """
-        return self._set_vars(OrderedDict([(variable, value)]))
-
-    def _get_var(self, variable: str):
-        """Sends the appropriate command to retrieve the value of a variable from the gripper, blocking until the
-        response is received or the socket times out.
-        :param variable: Name of the variable to retrieve.
-        :return: Value of the variable as integer.
-        """
-        # atomic commands send/rcv
-        with self.command_lock:
-            cmd = f"GET {variable}\n"
-            self.socket.sendall(cmd.encode(self.ENCODING))
-            data = self.socket.recv(1024)
-
-        # expect data of the form 'VAR x', where VAR is an echo of the variable name, and X the value
-        # note some special variables (like FLT) may send 2 bytes, instead of an integer. We assume integer here
-        var_name, value_str = data.decode(self.ENCODING).split()
-        if var_name != variable:
-            raise ValueError(f"Unexpected response {data} ({data.decode(self.ENCODING)}): does not match '{variable}'")
-        value = int(value_str)
-        return value
-
-    @staticmethod
-    def _is_ack(data: str):
-        return data == b'ack'
-
-    def _reset(self):
-        """
-        Reset the gripper.
-        The following code is executed in the corresponding script function
-        def rq_reset(gripper_socket="1"):
-            rq_set_var("ACT", 0, gripper_socket)
-            rq_set_var("ATR", 0, gripper_socket)
-
-            while(not rq_get_var("ACT", 1, gripper_socket) == 0 or not rq_get_var("STA", 1, gripper_socket) == 0):
-                rq_set_var("ACT", 0, gripper_socket)
-                rq_set_var("ATR", 0, gripper_socket)
-                sync()
-            end
-
-            sleep(0.5)
-        end
-        """
-        self._set_var(self.ACT, 0)
-        self._set_var(self.ATR, 0)
-        while (not self._get_var(self.ACT) == 0 or not self._get_var(self.STA) == 0):
-            self._set_var(self.ACT, 0)
-            self._set_var(self.ATR, 0)
-        time.sleep(0.5)
-
-
-    def activate(self, auto_calibrate: bool = True):
-        """Resets the activation flag in the gripper, and sets it back to one, clearing previous fault flags.
-        :param auto_calibrate: Whether to calibrate the minimum and maximum positions based on actual motion.
-        The following code is executed in the corresponding script function
-        def rq_activate(gripper_socket="1"):
-            if (not rq_is_gripper_activated(gripper_socket)):
-                rq_reset(gripper_socket)
-
-                while(not rq_get_var("ACT", 1, gripper_socket) == 0 or not rq_get_var("STA", 1, gripper_socket) == 0):
-                    rq_reset(gripper_socket)
-                    sync()
-                end
-
-                rq_set_var("ACT",1, gripper_socket)
-            end
-        end
-        def rq_activate_and_wait(gripper_socket="1"):
-            if (not rq_is_gripper_activated(gripper_socket)):
-                rq_activate(gripper_socket)
-                sleep(1.0)
-
-                while(not rq_get_var("ACT", 1, gripper_socket) == 1 or not rq_get_var("STA", 1, gripper_socket) == 3):
-                    sleep(0.1)
-                end
-
-                sleep(0.5)
-            end
-        end
-        """
-        if not self.is_active():
-            self._reset()
-            while (not self._get_var(self.ACT) == 0 or not self._get_var(self.STA) == 0):
-                time.sleep(0.01)
-
-            self._set_var(self.ACT, 1)
-            time.sleep(1.0)
-            while (not self._get_var(self.ACT) == 1 or not self._get_var(self.STA) == 3):
-                time.sleep(0.01)
-
-        # auto-calibrate position range if desired
-        if auto_calibrate:
-            self.auto_calibrate()
-
-    def is_active(self):
-        """Returns whether the gripper is active."""
-        status = self._get_var(self.STA)
-        return RobotiqGripper.GripperStatus(status) == RobotiqGripper.GripperStatus.ACTIVE
-
-    def get_min_position(self) -> int:
-        """Returns the minimum position the gripper can reach (open position)."""
-        return self._min_position
-
-    def get_max_position(self) -> int:
-        """Returns the maximum position the gripper can reach (closed position)."""
-        return self._max_position
-
-    def get_open_position(self) -> int:
-        """Returns what is considered the open position for gripper (minimum position value)."""
-        return self.get_min_position()
-
-    def get_closed_position(self) -> int:
-        """Returns what is considered the closed position for gripper (maximum position value)."""
-        return self.get_max_position()
-
-    def is_open(self):
-        """Returns whether the current position is considered as being fully open."""
-        return self.get_current_position() <= self.get_open_position()
-
-    def is_closed(self):
-        """Returns whether the current position is considered as being fully closed."""
-        return self.get_current_position() >= self.get_closed_position()
-
-    def get_current_position(self) -> int:
-        """Returns the current position as returned by the physical hardware."""
-        return self._get_var(self.POS)
-
-    def auto_calibrate(self, log: bool = True) -> None:
-        """Attempts to calibrate the open and closed positions, by slowly closing and opening the gripper.
-        :param log: Whether to print the results to log.
-        """
-        # first try to open in case we are holding an object
-        (position, status) = self.move_and_wait_for_pos(self.get_open_position(), 64, 1)
-        if RobotiqGripper.ObjectStatus(status) != RobotiqGripper.ObjectStatus.AT_DEST:
-            raise RuntimeError(f"Calibration failed opening to start: {str(status)}")
-
-        # try to close as far as possible, and record the number
-        (position, status) = self.move_and_wait_for_pos(self.get_closed_position(), 64, 1)
-        if RobotiqGripper.ObjectStatus(status) != RobotiqGripper.ObjectStatus.AT_DEST:
-            raise RuntimeError(f"Calibration failed because of an object: {str(status)}")
-        assert position <= self._max_position
-        self._max_position = position
-
-        # try to open as far as possible, and record the number
-        (position, status) = self.move_and_wait_for_pos(self.get_open_position(), 64, 1)
-        if RobotiqGripper.ObjectStatus(status) != RobotiqGripper.ObjectStatus.AT_DEST:
-            raise RuntimeError(f"Calibration failed because of an object: {str(status)}")
-        assert position >= self._min_position
-        self._min_position = position
-
-        if log:
-            print(f"Gripper auto-calibrated to [{self.get_min_position()}, {self.get_max_position()}]")
-
-    def move(self, position: int, speed: int, force: int) -> Tuple[bool, int]:
-        """Sends commands to start moving towards the given position, with the specified speed and force.
-        :param position: Position to move to [min_position, max_position]
-        :param speed: Speed to move at [min_speed, max_speed]
-        :param force: Force to use [min_force, max_force]
-        :return: A tuple with a bool indicating whether the action it was successfully sent, and an integer with
-        the actual position that was requested, after being adjusted to the min/max calibrated range.
-        """
-
-        def clip_val(min_val, val, max_val):
-            return max(min_val, min(val, max_val))
-
-        clip_pos = clip_val(self._min_position, position, self._max_position)
-        clip_spe = clip_val(self._min_speed, speed, self._max_speed)
-        clip_for = clip_val(self._min_force, force, self._max_force)
-
-        # moves to the given position with the given speed and force
-        var_dict = OrderedDict([(self.POS, clip_pos), (self.SPE, clip_spe), (self.FOR, clip_for), (self.GTO, 1)])
-        return self._set_vars(var_dict), clip_pos
-
-    def move_and_wait_for_pos(self, position: int, speed: int, force: int) -> Tuple[int, ObjectStatus]:  # noqa
-        """Sends commands to start moving towards the given position, with the specified speed and force, and
-        then waits for the move to complete.
-        :param position: Position to move to [min_position, max_position]
-        :param speed: Speed to move at [min_speed, max_speed]
-        :param force: Force to use [min_force, max_force]
-        :return: A tuple with an integer representing the last position returned by the gripper after it notified
-        that the move had completed, a status indicating how the move ended (see ObjectStatus enum for details). Note
-        that it is possible that the position was not reached, if an object was detected during motion.
-        """
-        set_ok, cmd_pos = self.move(position, speed, force)
-        if not set_ok:
-            raise RuntimeError("Failed to set variables for move.")
-
-        # wait until the gripper acknowledges that it will try to go to the requested position
-        while self._get_var(self.PRE) != cmd_pos:
-            time.sleep(0.001)
-
-        # wait until not moving
-        cur_obj = self._get_var(self.OBJ)
-        while RobotiqGripper.ObjectStatus(cur_obj) == RobotiqGripper.ObjectStatus.MOVING:
-            cur_obj = self._get_var(self.OBJ)
-
-        # report the actual position and the object status
-        final_pos = self._get_var(self.POS)
-        final_obj = cur_obj
-        return final_pos, RobotiqGripper.ObjectStatus(final_obj)
\ No newline at end of file
diff --git a/python/ur_simple_control/dmp/temporal_coupling.py b/python/ur_simple_control/dmp/temporal_coupling.py
deleted file mode 100644
index 0a43b4d..0000000
--- a/python/ur_simple_control/dmp/temporal_coupling.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-
-# TODO
-# make this comply with changes (to be) made in the dmp
-import numpy as np
-
-
-class NoTC:
-    def update(self, dmp, dt):
-        return 0
-
-
-class TCVelAccConstrained:
-
-    def __init__(self, gamma_nominal, gamma_a, v_max, a_max, eps=0.001):
-        self.gamma_nominal = gamma_nominal
-        self.gamma_a = gamma_a
-        self.eps = eps
-        self.v_max = v_max.reshape((len(v_max), 1))
-        self.a_max = a_max.reshape((len(a_max), 1))
-
-    def generate_matrices(self, dmp, dt):
-        A = np.vstack((-dmp.z(), dmp.z()))
-        B = np.vstack((-self.a_max, -self.a_max))
-        C = np.vstack((dmp.h(), -dmp.h()))
-        D = np.vstack((-self.v_max, -self.v_max))
-        x_next = dmp.x + dmp.f(dmp.x) / dmp.tau * dt
-        A_next = np.vstack((-dmp.z(x_next), dmp.z(x_next)))
-        C_next = np.vstack((dmp.h(x_next), -dmp.h(x_next)))
-        return A, B, C, D, A_next, C_next
-
-    def update(self, dmp, dt):
-
-        A, B, C, D, A_next, C_next = self.generate_matrices(dmp, dt)
-
-        # Acceleration bounds
-        i = np.squeeze(A < 0)
-        if i.any():
-            taud_min_a = np.max(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
-        else:
-            taud_min_a = -np.inf
-        i = np.squeeze(A > 0)
-        if i.any():
-            taud_max_a = np.min(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
-        else:
-            taud_max_a = np.inf
-        # Velocity bounds
-        i = range(len(A_next))
-        tau_min_v = np.max(-A_next[i] / D[i])
-        taud_min_v = (tau_min_v - dmp.tau) / dt
-        # Feasibility bounds
-        ii = np.arange(len(A_next))[np.squeeze(A_next < 0)]
-        jj = np.arange(len(A_next))[np.squeeze(A_next > 0)]
-        tau_min_f = -np.inf
-        for i in ii:
-            for j in jj:
-                num = C_next[i] * abs(A_next[j]) + C_next[j] * abs(A_next[i])
-                if num > 0:
-                    den = abs(B[i] * A_next[j]) + abs(B[j] * A_next[i])
-                    tmp = np.sqrt(num / den)
-                    if tmp > tau_min_f:
-                        tau_min_f = tmp
-        taud_min_f = (tau_min_f - dmp.tau) / dt
-        # Nominal bound
-        taud_min_nominal = (dmp.tau0 - dmp.tau) / dt
-
-        taud_min = np.max((taud_min_a, taud_min_v, taud_min_f, taud_min_nominal))
-
-        # Base update law
-        ydd_bar = dmp.h() / (dmp.tau**2 * self.a_max)
-        if self.gamma_a > 0:
-            pot_a = self.gamma_a * np.sum(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
-        else:
-            pot_a = 0
-        #pot_a = self.gamma_a * np.amax(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
-        taud = self.gamma_nominal * (dmp.tau0 - dmp.tau) + dmp.tau * pot_a
-
-        # Saturate
-        taud = np.min((taud, taud_max_a))
-        taud = np.max((taud, taud_min))
-
-        return taud
diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py
index 3afdb81..e55168d 100644
--- a/python/ur_simple_control/managers.py
+++ b/python/ur_simple_control/managers.py
@@ -14,7 +14,6 @@ import signal
 # TODO make the package work
 from ur_simple_control.util.get_model import get_model
 from ur_simple_control.util.robotiq_gripper import RobotiqGripper
-import argparse
 from collections import deque
 
 """
@@ -102,9 +101,12 @@ class ControlLoopManager:
                 # and we can be slow with initialization.
                 self.past_data[key].append(copy.deepcopy(save_past_dict[key]))
 
-        # TODO save and handle plotting data in the exact same fashion.
-        # also write out docs on what's available (and then assert what's defined
-        # to have to be in the list of available things)
+        # similar story for log_dict as for past_data,
+        # except this is not used in the control loop,
+        # and we pre-declare the sizes 
+        # TODO the itialization is done on client side,
+        # but i want to do it here. this is a big ick
+        self.log_dict = log_dict
 
         # if you just stop it the program with Ctrl-C, it will continue running
         # the last speedj lmao.
@@ -139,6 +141,8 @@ class ControlLoopManager:
     def run(self):
         for i in range(self.max_iterations):
             start = time.time()
+            # TODO make the arguments to controlLoop kwargs or whatever
+            # so that you don't have to declare them on client side if you're not using them
             breakFlag, latest_to_save_dict, log_entry_dict = self.controlLoop(i, self.past_data)
             # update past rolling window
             # TODO: write an assert assuring the keys are what's been promised
diff --git a/python/ur_simple_control/util/.calib_board_hacks.py.swp b/python/ur_simple_control/util/.calib_board_hacks.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..654ccdea21df40efc4deb0f2c418c7e9e9736fc5
GIT binary patch
literal 24576
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
C$o@kB

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/util/.robotiq_gripper.py.swp b/python/ur_simple_control/util/.robotiq_gripper.py.swp
deleted file mode 100644
index c8c21fa7784dcb063d1e16b0a39ee21db92da85c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 16384
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
SR>L(wbR|~AgA`jaFaQ9DW}8$1

diff --git a/python/ur_simple_control/util/__pycache__/draw_path.cpython-310.pyc b/python/ur_simple_control/util/__pycache__/draw_path.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4e8050f7d0467e3e6bb82fad86dbd2b2d79b9265
GIT binary patch
literal 2061
zcmd1j<>g{vU|{f9h)hl4W?*;>;vi#Y1_lNP1_p*=9|i`76owSW9EK=HFwK<99L2&2
z5@X6?&1H*XV`Ok=NMTN4X<<lVX=aLIPhm}AYhj4uNaajn&t@u8N#$r}U}Q*P3<hIO
zj+Y>N{4^PF@%khd7v~43=A<T<<QFA_gpn~5%n3RS3=FAY>!X-b7*m*97^0XV7Dll^
zEn`h#PvK}`h+<3O3}(>ey2bBOlvo~+Sd!tJn3tHIT9gbj3}!fp&BDOI;0*Gg90LPG
z4PzEV7Gn)VJYxw{4Py;M7IO+?FH;ReJWC2gFoPx&$gv#xdBtFtYO>y9OUq0zElRz`
zmYkSZmRMW_GO!3_;w{!3ke4)>Zm|@n=A_+XN~~DPPy`C;UupUo`MIh3>G{P4`6-D-
zV4e|zn^T&XqF+#ySdm$*Us@DjoS9pYlNz6#pI1_ppQB$;S(1^Thee{aBr``pr6{pH
zz96wAL$9Fn7Ds%1W?p7Ve7pq6cOXY`F^Vu&NuULY9!weTkdb0wU?^c&zz7NQ8b%j}
zX2yk}P+|gy3bS7_BP>K27#Kidz{<eD5Dc<bhJk@0ouP&ymaCSrhB1XflA(q%g;A0r
zooOOdAyY8JN~R)^-j^T(96Xv#x0v({ZZT$pc@Tn|fq~%`mrYJ)aY=H1Zh;*rriww<
z$S_ptpnC@vJ9;)b`N@en#ddlKjhf82nDPp4u_hK3C05>I0fm$%QxONqc-FGiqLN~W
zeV}M60$B=<N{|=8wn;Hz1|G~dln?-U2IM?&vI2#E4MP^g0>*_5j0`mlSxgI<K`e04
zG5Tq;6tRQs7fi`4PR`HEOHD3`Pc2K$D=98w1Br8j<1{lRCsmUX>{2u*-r_=NR04%K
zB%=8ktEA9F2B8omszFwPT^j(+1SyQ!OhsxXj44dbjEoE=psWC9)i6L@U&4~bn!*h7
zO$s>Y^|F9erLcolvn^nU`4H?&4!>Khsd*)-MO8eYAXg~J&&(?+wyF}*(+Bb6GxOpL
zGAmMZiuIC<%YHHHRI#Y)nWkwn-QrA1&B@HoEJ-c8#hjK~Qe_e1@8WNzP*j?ykerj5
zt&pFmP?C|V0M@JkGD@K&Um-U!J5?dGL?Kb3q$n{9T%uHJa@=ChPOZGfT2PdkS5hRx
zz`#%hikKoHP#CipCzhp_RFvFeF32gl#hRRxUz`e07vRW14|KM~<mA+X5=~Hm3otM+
za4~W)g0Kh^2O|#?%a1BC^uUK`@Y7@m<;%Rp+|>B^TU_z+x%nxjIUqJqe0*VPVh%*6
zhzI0AP)tHxsSM(RQze1`r%zDfEDmx6NSuR#gOP)UgN=v12qcbDjDpMpWlC@)`+@Uw
z3OGNfF!wUoGL$f8G1V}nu=Fy<Fx4{FGL<mbFf}vQGS@I>u`FOsVXa}#Vq3_>$WX(y
zfIWq6Avj4a-~dH(4RaQ#pk?<f;$>i9aMNVI#Zr-znR|<+5=8POmX_ofCnx5l#^>j0
zGT!1UE=?-P$uEh|F2BW}omv@RP?TC+3`y`+fgu^G3ZUeknU}7Rkys3h%%oHWLj_Rb
zmzh_ZUs|k?lbM&Qrw{<rrJ(K#N>l0}WsuMXCkBuKdEmsLr=ZDoizOv9xui$|6wMq^
z%ZtIm1Ib?8xdl0(!WES7ia^19i?cYjB)%lGBq#M2OL0biIXJOsvJ`27j9^a7OfTXD
zu{a=gKz<Q=(%=9&094_afZ~OZfq{XKU4W5;Nq_~EK-d_IjKSLD<8u=;^Wx(*xo)xM
zmF5;yLXx6jZej^2fO0aE^a?6LtXpgl8sY~bB>D2pl=RdRXr%*+aj?-vDmW6$Ee;z<
dYO@2CPsN~Q%fZ3J$iv3R&LPVo!o|q)9{_TC_&@*v

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/util/calib_board_hacks.py b/python/ur_simple_control/util/calib_board_hacks.py
index 44309a4..84539ec 100644
--- a/python/ur_simple_control/util/calib_board_hacks.py
+++ b/python/ur_simple_control/util/calib_board_hacks.py
@@ -3,135 +3,152 @@
 # where you use the previous estimate to try to hit the board at the
 # right orientation, thereby making the estimate more precise
 
-
 import pinocchio as pin
 import numpy as np
 import sys
-import os
-from os.path import dirname, join, abspath
 import time
-from pinocchio.visualize import GepettoVisualizer
-import gepetto.corbaserver
-from rtde_control import RTDEControlInterface as RTDEControl
-from rtde_receive import RTDEReceiveInterface as RTDEReceive
-from rtde_io import RTDEIOInterface
-import os
 import copy
-import signal
-from give_me_the_calibrated_model import get_model
-
-def handler(signum, frame):
-    print('sending 100 speedjs full of zeros')
-    for i in range(100):
-        vel_cmd = np.zeros(6)
-        rtde_control.speedJ(vel_cmd, 0.1, 1.0 / 500)
-    exit()
-
-
-rtde_control = RTDEControl("192.168.1.102")
-rtde_receive = RTDEReceive("192.168.1.102")
-rtde_io = RTDEIOInterface("192.168.1.102")
-rtde_io.setSpeedSlider(0.2)
-while not rtde_control.isConnected():
-    continue
-print("connected")
-
-signal.signal(signal.SIGINT, handler)
-
-urdf_path_relative = "../robot_descriptions/urdf/ur5e_with_robotiq_hande.urdf"
-urdf_path_absolute = os.path.abspath(urdf_path_relative)
-mesh_dir = "../robot_descriptions/"
-mesh_dir_absolute = os.path.abspath(mesh_dir)
-model, data = get_model(urdf_path_absolute, mesh_dir_absolute)
-
-init_pose = rtde_receive.getActualTCPPose()
-new_pose = copy.deepcopy(init_pose)
-#new_pose[0] += 0.05
-#new_pose[1] -= 0.1
-#rtde_control.moveL(new_pose)
-#exit()
-
-# max offset is (+0.3, -0.3)
-# generate 10 and try them out
-# but let's try to get it done with only 3 to begin with
-
-
-def estimate_R(positions):
-    # find the angle
+from ur_simple_control.managers import RobotManager
+
+"""
+Estimate a plane by making multiple contacts with it. 
+You need to start with a top left corner of it,
+and you thus don't need to find an offset (you have to know it in advance).
+TODO: test and make sure the above statement is in fact correct.
+Thus the offset does not matter, we only need the angle,
+i.e. the normal vector to the plane.
+Returns R because that's what I wan a 
+"""
+def fitNormalVector(positions):
     positions = np.array(positions)
-    #print("positions")
-    #print(*positions, sep=',\n')
-    # the offset does not matter, we only need the angle
-    # i.e. the normal vector to the plane
     n = np.linalg.lstsq(positions, np.ones(len(positions)), rcond=None)[0]
     #print("n", *n, sep=',')
     # normalize
+    # TODO why am i not doing this again?
     #n = n - 1
     n = n / np.linalg.norm(n)
-    #print("n normalized:", *n, sep=',')
+    print("if the following give you roughly the same number, it worked")
     for p in positions:
         print("cdot", p @ n)
+
+# constuct a frame around the found normal vector
+# we just assume the x axis is parallel with the robot's x axis
+# this is of course completly arbitrary, so
+# TODO fix the fact that you just assume the x axis
+# or write down why you don't need it (i'm honestly not sure atm, but it is late)
+def constructFrameFromNormalVector(R_intial_estimate, n):
     z_new = n
     x_new = np.array([1.0, 0.0, 0.0])
     y_new = np.cross(x_new, z_new)
     # just fix the signs idc
+    # TODO: find a reasonable solution to this sign problem
+    # --> idea: use signs from inital R estimate
+    #           and just force actually estimate R to have these
+    # old code stays here until fix is proven to work
+    #y_new[0] = np.abs(y_new[0])
+    #y_new[1] = np.abs(y_new[1]) * -1
+    #y_new[2] = np.abs(y_new[2]) * -1
+    #z_new[0] = np.abs(z_new[0])
+    #z_new[1] = np.abs(z_new[1])
+    #z_new[2] = np.abs(z_new[2]) * -1
     y_new[0] = np.abs(y_new[0])
-    y_new[1] = np.abs(y_new[1]) * -1
-    y_new[2] = np.abs(y_new[2]) * -1
+    y_new[1] = np.abs(y_new[1])
+    y_new[2] = np.abs(y_new[2])
     z_new[0] = np.abs(z_new[0])
     z_new[1] = np.abs(z_new[1])
-    z_new[2] = np.abs(z_new[2]) * -1
-    # y is good tho
+    z_new[2] = np.abs(z_new[2])
+    # y is good 'cos it was obtained with a cross
     R = np.hstack((x_new.reshape((3,1)), y_new.reshape((3,1))))
     R = np.hstack((R, z_new.reshape((3,1))))
+    # now ensure all the signs are the signs that you want,
+    # which we get from the initial estimate (which can not be that off)
+    for i in range(R.shape[0]):
+        for j in range(R.shape[1]):
+            # TODO ensure all signs are the same
+            continue
+
 
     print('rot mat to new frame:')
     print(*R, sep=',\n')
-
     return R
 
-# TODO change this, i just shoved the pen through the board
-speed = [0, 0, -0.3, 0, 0, 0]
-n_tests = 10
-positions = []
-R = np.array([[1.,         0.,         0.03236534],
-[ 0.,         -0.82404727,  0.56559577],
-[ 0. ,        -0.56559577, -0.82404727]])
-
-for i in range(n_tests):
-    rtde_control.moveUntilContact(speed)
-    q = rtde_receive.getActualQ()
-    q.append(0.0)
-    q.append(0.0)
-    pin.forwardKinematics(model, data, np.array(q))
-    print("pin:", *data.oMi[6].translation.round(4), *pin.rpy.matrixToRpy(data.oMi[6].rotation).round(4))
-    print("ur5:", *np.array(rtde_receive.getActualTCPPose()).round(4))
-    positions.append(copy.deepcopy(data.oMi[6].translation))
-    if i < n_tests -1:
-        current_pose = rtde_receive.getActualTCPPose()
-        new_pose = copy.deepcopy(current_pose)
-        new_pose[2] = init_pose[2]
-        rtde_control.moveL(new_pose)
-        new_pose[0] = init_pose[0] + np.random.random() * 0.3
-        new_pose[1] = init_pose[1] - np.random.random() * 0.2
-        rtde_control.moveL(new_pose)
-        # fix orientation
-        rpy = pin.rpy.matrixToRpy(R)
-        print("rpy", rpy)
-        if rpy[0] > 0.0:
-            rpy[0] = rpy[0] - 2*np.pi
-        # who knows if this is ok
-        new_pose[3] = rpy[0]
-        new_pose[4] = rpy[1]
-        new_pose[5] = rpy[2]
-        rtde_control.moveL(new_pose)
-    R = estimate_R(positions)
-        
-
-current_pose = rtde_receive.getActualTCPPose()
-new_pose = copy.deepcopy(current_pose)
-new_pose[2] = init_pose[2]
-rtde_control.moveL(new_pose)
-rtde_control.moveL(init_pose)
-
 
+def calibratePlane(robot, n_tests):
+    # TODO: 
+    # - tell the user what to do with prints, namely where to put the end-effector
+    #   to both not break things and also actually succeed
+    # - start freedrive
+    # - use some keyboard input [Y/n] as a blocking call,
+    #   release the freedrive and then start doing the calibration process
+    init_pose = robot.rtde_receive.getActualTCPPose()
+    new_pose = copy.deepcopy(init_pose)
+
+    # TODO change this, i just shoved the pen through the board
+    # the point is go up, but the frame is the TCP frame
+    speed = [0, 0, -0.3, 0, 0, 0]
+    n_tests = 10
+    # TODO: for the love of god please actually read this when you begin
+    # instead of having this horror here
+    # NOTE: old code remains here until fix is tested
+    #R = np.array([[1.,         0.,         0.03236534],
+    #[ 0.,         -0.82404727,  0.56559577],
+    #[ 0. ,        -0.56559577, -0.82404727]])
+    # get q, do forward kinematics, get current TCP R 
+    # NOTE: this is supposed to be run only after the initial TCP has been set
+    # TODO: move [above_sentence_code] into this function to ensure that's the case
+    q = robot.getQ()
+    pin.forwardKinematics(robot.model, robot.data, q)
+    # this apsolutely has to be deepcopied aka copy-constructed
+    R_intial_estimate = copy.deepcopy(robot.data.oMi[robot.JOINT_ID].rotation)
+
+    positions = []
+    for i in range(n_tests):
+        rtde_control.moveUntilContact(speed)
+        q = rtde_receive.getActualQ()
+        q.append(0.0)
+        q.append(0.0)
+        pin.forwardKinematics(model, data, np.array(q))
+        print("pin:", *data.oMi[6].translation.round(4), *pin.rpy.matrixToRpy(data.oMi[6].rotation).round(4))
+        print("ur5:", *np.array(rtde_receive.getActualTCPPose()).round(4))
+        positions.append(copy.deepcopy(data.oMi[6].translation))
+        if i < n_tests -1:
+            current_pose = rtde_receive.getActualTCPPose()
+            new_pose = copy.deepcopy(current_pose)
+            # go back up (assuming top-left is highest incline)
+            # TODO: make this assumption an argument, or print it at least
+            new_pose[2] = init_pose[2]
+            rtde_control.moveL(new_pose)
+            new_pose[0] = init_pose[0] + np.random.random() * 0.3
+            new_pose[1] = init_pose[1] - np.random.random() * 0.2
+            rtde_control.moveL(new_pose)
+            # fix orientation
+            rpy = pin.rpy.matrixToRpy(R)
+            print("rpy", rpy)
+            if rpy[0] > 0.0:
+                rpy[0] = rpy[0] - 2*np.pi
+            # who knows if this is ok
+            new_pose[3] = rpy[0]
+            new_pose[4] = rpy[1]
+            new_pose[5] = rpy[2]
+            rtde_control.moveL(new_pose)
+        n = fitNormalVector(positions)
+        R = constructFrameFromNormalVector(n)
+            
+
+    current_pose = rtde_receive.getActualTCPPose()
+    new_pose = copy.deepcopy(current_pose)
+    new_pose[2] = init_pose[2]
+    rtde_control.moveL(new_pose)
+    rtde_control.moveL(init_pose)
+
+if __name__ == "__main__":
+    robot = RobotManager()
+    # TODO make this an argument
+    n_tests = 10
+    # TODO: 
+    # - tell the user what to do with prints, namely where to put the end-effector
+    #   to both not break things and also actually succeed
+    # - start freedrive
+    # - use some keyboard input [Y/n] as a blocking call,
+    #   release the freedrive and then start doing the calibration process
+    calibratePlane(robot, n_tests)
diff --git a/python/ur_simple_control/util/draw_path.py b/python/ur_simple_control/util/draw_path.py
index 41498f2..b93166f 100644
--- a/python/ur_simple_control/util/draw_path.py
+++ b/python/ur_simple_control/util/draw_path.py
@@ -20,7 +20,7 @@ from matplotlib.widgets import LassoSelector
 # documentation and examples on Lasso and Path to see more.
 #from matplotlib.path import Path
 
-class DrawPath:
+class DrawPathManager:
     def __init__(self, ax):
         self.canvas = ax.figure.canvas
         self.lasso = LassoSelector(ax, onselect=self.onselect)
@@ -36,21 +36,20 @@ class DrawPath:
         self.canvas.draw_idle()
 
 
-# function we bind to key press even
-# made to save and exit
-def accept(event):
-    if event.key == "enter":
-        print("path points:")
-        print(selector.path)
-        selector.disconnect()
-        ax.set_title("")
-        # TODO: ensure this runs fine after packaging
-        np.savetxt("./path_in_pixels.csv", selector.path, delimiter=',', fmt='%.5f')
-        print("TODO: run clik on the pixel path to make it a trajectory")
-        # plt.close over exit so that we can call this from elsewhere and not kill the program
-        plt.close()
+    # function we bind to key press even
+    # made to save and exit
+    def accept(self, event):
+        if event.key == "enter":
+            print("path points:")
+            print(self.path)
+            self.disconnect()
+            # TODO: ensure this runs fine after packaging
+            np.savetxt("./path_in_pixels.csv", self.path, delimiter=',', fmt='%.5f')
+            print("TODO: run clik on the pixel path to make it a trajectory")
+            # plt.close over exit so that we can call this from elsewhere and not kill the program
+            plt.close()
 
-if __name__ == '__main__':
+def drawPath():
     # normalize both x and y to 0-1 range
     # we can multiply however we want later
     # idk about the number of points, but it's large enough to draw
@@ -60,11 +59,15 @@ if __name__ == '__main__':
     subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
     fig, ax = plt.subplots(subplot_kw=subplot_kw)
 
-    selector = DrawPath(ax)
-    
+    selector = DrawPathManager(ax)
 
-    fig.canvas.mpl_connect("key_press_event", accept)
+    # map key press to our function
+    # thankfully it didn't mind have self as the first argument
+    fig.canvas.mpl_connect("key_press_event", selector.accept)
     ax.set_title("The drawing has to be 1 continuous line. Press 'Enter' to accept the drawn path. ")
-
-    # this keeps running until you close the window or hit Enter
     plt.show()
+    return selector.path
+
+
+if __name__ == '__main__':
+    drawPath()
diff --git a/python/ur_simple_control/visualize/__pycache__/__init__.cpython-310.pyc b/python/ur_simple_control/visualize/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..88efef940c25032d0c34f0ec64c58af7190861fb
GIT binary patch
literal 199
zcmd1j<>g{vU|`7ViAV*}k3j@7W@KPsaA06yC}v?`U`SyIX3%8xTggxa5=Icevh*|Z
zb5r%x^NS1eQxc27JR<}*r!+4`zo00wBC}Y(v?#tfGq)foH9k2%ucRnHN57!5BqKi$
ui$qywacN>sW>u<we0*kJW=VX!UP0w84x8Nkl+v73JCGZSnHU%tSQr49+%|~-

literal 0
HcmV?d00001

diff --git a/python/ur_simple_control/visualize/__pycache__/visualize.cpython-310.pyc b/python/ur_simple_control/visualize/__pycache__/visualize.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..68ca46ae7f81ca421c192f85191a01c73b82c31f
GIT binary patch
literal 816
zcmd1j<>g{vU|<lL7?B#m!octt#6iYP3=9ko3=9m#3JeSkDGVu$ISf&ZV45kHIf{jm
zA%!W0xrHH$HH9&lL6hYrNUvWqNEe6&!rTlD3>*v$49*}^4lyt=lrSt{tYOSzTF6+-
zl)_lcoWfYkQo>xr+{{?QT*K1LD9%vJn#oYhR>G3Sx`3^OVF5eHjuMU<hGxcv%nKQ7
z*-JP<Y!`-D(-@{&j#|zVmIYijtR>7f93b5b8Ee>TIBgh8xIubqI3*dH8Jihh7-Ge1
zxj-_K3|TxiOf?K3nG}W;hE}E;t~4e|h8p%74oQX*-V~Nz7Dk3b8;IHkd<z*E846WP
zSQhYuSSbv_44SNdFF{@`Vq{=ocnKmjnQpNr=jY@X-D1s2OiIns6u8BdS8$6hu_!Sw
zJ@pn}Zem4zW=U#MVo7FxUhysF;*z3U%mq0mx0sT1Z!u@3mfYgV$;>M*NK8(>#hjCx
zcZ)MMuQV5=KJ^xRacNRPPJYQPR)}FNU=DjqVr6`GYUM4qoYeHxyp&rk#TohKn%uWI
zLDKOli6x1*SQ3lUi*GTO++xd%PtMON2GK?N<;A!7p+<s4<BRgkZ?Pv<#HVB?m)v3l
z`=a<3W9BUmkQrbr7_(L~6e%(=F#O8a&&bbB)lbhaF33+wECTb45Zs*7ycGR{qQr{K
zV*S#h_~Ojmf}GU&<ovvnqWm2Fg36MN{5&iYWtqjLi8+~7srqo1UP0w89*|Gmit=+^
zGLuU{NvK$Yfq{XCg@uWQQGkhsQHn``QH)W9QHPO_nTN4RnSp^plkFC3UTJPYWf2<#
z1H&!B+{6-)Avu{zdIgmr)-5&&T?9(@U@c&eArVR-jT|<)`6;D2sdk{qEe4sz!N9}F
G!v+9|;pD6U

literal 0
HcmV?d00001

-- 
GitLab