From e256910d97ab7e25a1925fa230d2899e16a897e9 Mon Sep 17 00:00:00 2001 From: m-guberina <gubi.guberina@gmail.com> Date: Wed, 4 Dec 2024 01:18:34 +0100 Subject: [PATCH] fixed path planning. i was an idiot when i did the multiprocessing by assuming planner will run slower. it's faster. now we don't pile on the data_queue. this should be shared memory too and i don't know why i'm avoiding that like the plague --- python/examples/cart_pulling.py | 8 ++- .../__pycache__/managers.cpython-312.pyc | Bin 51600 -> 53810 bytes python/ur_simple_control/managers.py | 44 ++++++++++++-- .../optimal_control/crocoddyl_mpc.py | 50 +++++++++++++--- .../path_generation/planner.py | 56 +++++++++++------- .../path_generation/tunnel_mpc_params.yaml | 3 +- .../__pycache__/get_model.cpython-312.pyc | Bin 13603 -> 13603 bytes .../__pycache__/visualize.cpython-312.pyc | Bin 16871 -> 17114 bytes .../ur_simple_control/visualize/visualize.py | 3 + 9 files changed, 129 insertions(+), 35 deletions(-) diff --git a/python/examples/cart_pulling.py b/python/examples/cart_pulling.py index 9df36a6..103355a 100644 --- a/python/examples/cart_pulling.py +++ b/python/examples/cart_pulling.py @@ -17,6 +17,9 @@ import importlib.util from ur_simple_control.path_generation.planner import starPlanner, getPlanningArgs, createMap import yaml +# TODO: +# - make reference step size in path_generator an argument here +# because we use that for path interpolation later on as well def get_args(): parser = getMinimalArgParser() @@ -24,6 +27,8 @@ def get_args(): parser = getClikArgs(parser) # literally just for goal error parser = getPlanningArgs(parser) parser.add_argument('--handlebar-height', type=float, default=0.5) + parser.add_argument('--base-to-handlebar-preferred-distance', type=float, default=0.7, \ + help="prefered path arclength from mobile base position to handlebar") argcomplete.autocomplete(parser) args = parser.parse_args() # TODO TODO TODO: REMOVE PRESET HACKS @@ -73,7 +78,8 @@ if __name__ == "__main__": planning_function = partial(starPlanner, goal) # TODO: ensure alignment in orientation between planner and actual robot - path_planner = ProcessManager(args, planning_function, None, 2, None) + path_planner = ProcessManager(args, planning_function, robot.q[:2], 3, None) + #time.sleep(5) # clik version #cartesianPathFollowingWithPlanner(args, robot, path_planner) # end-effector tracking version diff --git a/python/ur_simple_control/__pycache__/managers.cpython-312.pyc b/python/ur_simple_control/__pycache__/managers.cpython-312.pyc index 8b2e1e5ebef5450829084854b558d13de09d65bb..c2815be629cbe704bc81afe0a7c810441fb93951 100644 GIT binary patch delta 7570 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 delta 5767 zcmdnAgn7bbX1>$Byj%<n3=GSz`KIqZKao#@(P5(c?s`Us6owSW9K|R_Fs&4&l){k0 zlcSug5~Tu`<IPdcRf|#sv-xt=b2Xwgz-;~;&0MW0Ek*`Th7^GohA3?&26u)O!4`%T zq18+vix?Q9biiW5Eet6la4}u5m}m<_ir8u<26nK@D80=EjI4};Ot;trit>|Fi;Hiu z29~Clrf#0iq|VMLHTf`S2b(+t14EI*<Up<jZaEMW!r#1y>i{F8^5$9|K6Z$>0$6hM zG+_%SMw89wMc42%icYRky~%A4l5hYKPLmVVj2VqLPf;^qlrd#sU`S>Jy8}Y7F)%PN zGcYiGUcol`fx11T@n!{$>5PoCCoAZPPk!Gb%v2OIS@E>^<oQv;llin7Cx>c_Onzb^ z%v2;jd47r5WIip?$t$(3xY=viYnZCI7#M0fz{-EQi?DNKGchm}Sx*ko)#g_&(T3Q^ zz>vaH15+a`1kwTvEk=e3j6Ju&7SFN}o_s(@a`K;T!a_w%6PS89N+5y9z`&4YFxhab z=wySb!jpfxi;8f7jevTIkzoQ;j~UD4Ky3+-D<|7qvQA!9B0RZ&n<CidH+4iN-`162 zG@E?ULU{6IUE#@6db*Q$Sc**kFhh89o?i6iOl=WuJ|xGo)i9>8uLgw>0|NsiLnT)w z7m_T;<OzD>{G15+8ip+U$&FsZf?O$F2!B;_X>xB4(r0FrtP;x2EG|w>QAkNmOv%a2 zOI1j!d<k;=<Z1&4M};CsP>i{N2s;J_hFdHpnYpP&pt!un8ed$JT2KUzQfH7HdqI9d zPHI|7ksC<4Cx~#G{KvpXG!!Juk)B!-5?>ylTI2<i@tK@rIGNXmfq_Ajv&a`D5;&Q~ zNL$4p#0&swU{1|Txy6!_nU+?}$-uy%00TwFlOv5(nKm$OZZJ|~oczsr4|_c$gOJV# zx5+zAPO*U#6!YZ9QzDz^nntrRhEM)!9ce2HGS(JEB!LK!hi)<D72IO2N-fGShI%MB zKP5Hi7E@l?Ew<v+yp+I{A}5gI<jMUu#%}2#W(J7J1QB5Gf&HEZ;%0*gP*~k!FHS5= z^~q0%dJ`m`1|niWMC@b^TR9_;cW<#3XQt<s=H6mWD@x2wEeZsAnY}DECq6khrI;1w z;UZ&@Hk-*2w#tl-n`>;hGjf7F=%>kEls(zTUfn+kBwq+3Kw-I(p$H@m(Pa)21rc)@ z7#NDB85kH^7(Oy-uyT9~VU%SJWBlaA7{<t|`MH2ehm{|q&wR4YTFK3)?OO#5q(Hhs znu=sVELji%ipU~R@$wRsOK-83<mcxYWPV{}U?>Wo+z=opr^dj*kS^c)I&g;^r$do4 zNRJ8w14CxTcLs(c)yZ1|6xg6adMiLd_!d`Deo}r(d>$wOI6#U^C$j}AdE8=2Ni0b$ z0>yd}sMIXt2FZZ~Pz=Q42NB*Nq8LP!fP#)GudpZ<!~@5Z0Em?_IX}>XF=6tGzzlh? z%gaCtnakn}Z!ssv7Z!n20w^ODRZP|oDsu%T+gq%OMMa5~MR6blqClyW1(G^J&c4N4 zoSBjupH`ZeT#}ieR|GP&m<1YDkT4IL{3=L_v3oOXuoVlV>12oSNC}XtB6kJ`hLwz9 zql!VfOQFbk^2Tr(My|={!ll6qgXN0Wg6v}|S_rZmq@idXDB@tsqa)-Pc_&vzNHdyl zo)!_xBo0>2R}=<U4lbCBCo@H>)|Y|=CxZx3=oEo{E>c>Ml30@J21;)MIf==sxv6<2 zMbp87lJA?Q$pm)ZE%w6r^vtr<ykby9D=0wx70<xHP$e1!iZ0*8yu|d>B0X4s7GPpv zDBi)qz|g>OgIlP>{)Vvl^vTPj*Fk)x2=&!1w(_FXyyOgUNT7P`WQ-c4^5hROa*U>% z`D2S%>cJ6H0df})D0{k<1gGW|=NA=$a&1v0$Wx0!l7i`}C637@rHMHq&H--uMaij< zk|zPAA{9h{lgBEMTK2@U)FP0xmxIJXfvd?5@h*2-NqkXiVoGLSdNDW`7CGmDbTFlr z6y<{y7l0xGRM<lcAV`2L0|kf#N`NFM=42)nfkHS$ZL)LHS4Pv#mdW*O##=z9Yy}aB zSOF&ra71qdNq{1uXgi1na#~T?<ky*!dW%4O<Rk#%gVJP`5Q@Fva@cFKQPwI()6I9Y zm>C^G*|4aafq}tKlNDNqf%Gl`5lcbDY)DE27euUOi8-aID6zeCvSN+`W6@-%9Ct?3 z&0RUHET*7r{PI5o1H<!KGr_>V2wXxyY~d+N1{n*AmZFs)7AU(E&6|9rK-~zGt%@dq z1mV#E&N<NZ24<t!esr>Ip*UmhWYfYkkkXt9T$)Q4J!7p0Iiu(d$gr~@0%W_U#4YB; zoE&g=zQyNQQc{$eR9ceiT2z!@gxy&no##Nrc@P11A2>e1VebJFL%0+*@~n%%c?vDg zKsitoT26p6!Y!7P)Z!9|#}LKC<lPl&j0-kDs@T9%4|2DkCKtkax47Yn8CLDg1EoUl z^rFmyg4Ck;veX<%>P9#XlzgCpc#Ekp1tkoRfs&^%YBEVrEeT9H56Z2R1?#3Unr>cE zXU`-GjyQy&;3(Wb`A>ti5GZvN?E<BKCU6;7WIS23QIGNC<cLOlM$^qR8pRl$!DSF9 z#2@H}fC3Vn-9TpCVk=6_OUchInhFv|PSuk?Hfb>ZXPPYC9E}{^6Ph`g>N`P-!34+& zFTsU1h^xs*gq1~iLAt^AT>-JcB_SxTZgCXlmn4FU@LP-_n#|yGpy&uFxY=_P3kpCb z0mvo=1rBKGcYLyZn*t;IWQVphjHa7;+s)YOL5bh52;`O`OHgKFgs?#oTZCF`Y6>Az z|1Fl}oXmnEP=yTf0JxN6D=tV)P4Oz41#%^*^t#1flv<pTSde;)B`32O+MoiJW01OG z3j>2Z!!6Ftypq&(P<c}XE>}QF80MK9lOOhq$b;Js<(Me}(zp@ZEYf$Bk<oOs&m=|0 z$-gH|H2|eJNO6$}atXK??gg<xY2+45enDy;YRP?Iq86k3<ku4uz@{iMTD$=T1$z;G zgIJSu@{3bZO<FcthcR&S>xuqCau<2zuJR~6;Sszb<bIXMqsVl#$&^-3#?HyR<{ouD z3UbbR5P_O8A^8%K0?~3P*ehUPFz5SbPChbEo$VpWkj0Zf&J(K#<@;N#nRx}JCAV0M z3vx0`z*WsH=A6{LB14cmVG!{RM1Tu6a8m@_+5oi^G&vwC2owR3+8Ctr7E5}5V$Lnb z)LWb&Mm#toL9M)EP)i3|mw?mP<hJ={jPaZI&i}(A1~wGjUPQ?v=a;xK&Ymo`RG!gv zvd<*R$^J|KS*wG>ngbGFAg_T7z#>qBDyjy#6kJh)tHD|j7sb4eWonEoC$C=?3Nmj+ zJI_jHKTRe`fi63F#&QD%aCwa|>lTIyFP7^tZkVjIQfadJ3K6g=9qOEn3=Enqkkk&= z3$_?j@9z}`jN2ybtTbaZ-JHDgF{2TdKrMnNL1+<I#LLLQ059VvSFBcJ+%tLpYR`Ib zgBM&5F}i8W6oFgfO(6F+gNPOo0d6FNQ_V&Y7u1+3+6`iXYVjgam0AR@7Qv|tTvmX} z&!XEPCHFwYaS#E@Nk#8KtdAgq8Px1$Wi(@8C}IaOxj+ODBdC*<l9^mm#1G=Pf>eTC z2+oY{ATEf=pFDTXOmJ~m)DCKMi-211(-~43q8L*cqL@+`qnJ}TCugqJVyk4*<SO#s zJb&$H7EMqq1XMD8HehC8n9fkcSi=DF3#21k!;-?7t--)hq*uZ`d19%sB&f&)OCh?d zHB2>(HO!MI=!s3{-pnrws+_<oYFJX3k@ZflR^}8$*H$z6B8w<UA0x};#?8WvU|YBm zwt)E{odW1O!4}F_i%sU<!p{x2w1ju^!L7oAd|($aFff1}pjN{)`QjOo$)8k2CJX3_ z@x_BW0ALk)ay3ko1B*qOSgR(>Ye@<qWNKJz7~;7nCwj?)1_=0ybW1=bFj!Lx8@TsB zVX838Y=*f^V27;J;9z8&tf(b1xjtTcvVbP*<PF<IKsxJ-c#w3muLiZeA)Rc7N(N01 zKXBJalj#;)Nn%lYY6&Fkg@dBB2UK}*#1}w@PpS+9g8ZFbgM;IJ9sL~LU4yI?G8K}G zQWHy3Qxr-vQWcW(b8{2(QWOe7qbv$(`9%s<<^e(elN-0o$X6Gq=A`L?I~q{q^g#Wi zT1|eieUrCrHxU3g^ub*rNau5M><)=&c!ntgwO=*aAcYb*Ypn)3k0&!Pvm_pB^({US zBR(awC>7k7xy1#Rg){|0ojXVY1!?OBO}?;0M(7zc14D5bBe<O}BGJLp!#SC4=hDex zyF83<aP#+Dc3NKNR=mWmc!x*uf{5#Zl<RKc7u~|IyTx2|i@D$$dqF7fLPE;*grbWH zMOS!=C(qlZEFt85mB;4;GXswjxchmF9ptFQyp+igvcxw3-*uPKQWMmOUCCS|3d&ck zg~gdwskgWaN=xGN^2-x5OI9*Ld?|}uHh>}|ZnEfJc}BL$rh9D}O();YlAQd1SM6rb zea>tWpa}CTk_Y8ZC1h=rQ;yg$3Qt~m1f&C0$SR!N&H*l0*owp_-#;lXEeX;Csw|4Y zjYO0ZRq&JwquFG$Q?87rllfyM8J|s_*epFcd#MP2k#Y&BI}b^Yj5U)NCW}tKJ4u9N zHbV;2T;|n`lMAQHPo8~LcydN84<qN~iS6Q(bDKma8!Y0Qymp)T<ea6#s7A2BjhM{8 zT}VKgp#;?11skuzP-Hu~(OVLviKR%Tgmv<|lX4)-SY|V%uugt?MwW@qZ!+)MI5$pk zVnP(MMPeYoNq`7YP!}nJ!ke=swJ0|;FR>)G=n^PUkv$CJr%gU_R)yP|g@K{?B)I=K zS@GPN`h#MQLQYx?hqN3Soeh`|>w`#0Cy)zw;Vb~M8C01Tseo7-AOc(sq7|UvUO$L9 z1xk%Z&@l}OR*uhRQmnp=9~>Ab7oL~&VP-Y>%*Dm(%m_|bMIa5D`nNa>GV}72lQS~& zi$JZ1TdaAdxdoL);8p{;wggvNpaQmNG01<QlB#IQ<lE<K*ub%FH97Xe@%mfbiACwj z`MCu-sU@jJTA-}OTwGaP1ZpGPVlAmGNG&cB0f{o@7Z-uXoo;c0M-1}wbBc?=nbrhk zIA~y|2vik-T~~za&s!Wex%nxjIjMF<R*axwJ_d&31_lO(56p~{*IqPZ)SCSKqJnk+ kGb8^;1`zo@g)NekQU4<Yi2PnARL#if%=n1`Oo4*{0KPAzzyJUM diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py index 79b63f5..c64cd26 100644 --- a/python/ur_simple_control/managers.py +++ b/python/ur_simple_control/managers.py @@ -17,7 +17,7 @@ from ur_simple_control.util.get_model import get_model, heron_approximation, her 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 +from multiprocessing import Process, Queue, Lock, shared_memory # argcomplete is an external package which creates tab completion in shell # argparse is argument parsing from the standard library import argcomplete, argparse @@ -277,6 +277,10 @@ class ControlLoopManager: if self.args.visualize_manipulator: self.robot_manager.visualizer_manager.sendCommand({"q" : self.robot_manager.q, "T_w_e" : self.robot_manager.getT_w_e()}) + if self.robot_manager.robot_name == "heron": + T_base = self.robot_manager.data.oMi[1] + self.robot_manager.visualizer_manager.sendCommand({"T_base" : T_base}) + #if self.robot_manager.manipulator_visualizer_queue.qsize() < 5: # self.robot_manager.updateViz({"q" : self.robot_manager.q, # "T_w_e" : self.robot_manager.getT_w_e()}) @@ -997,6 +1001,7 @@ class ProcessManager: # need to create new ones, but i won't optimize in advance def __init__(self, args, side_function, init_command, comm_direction, init_value=None): self.args = args + self.comm_direction = comm_direction if comm_direction == 0: self.command_queue = Queue() @@ -1011,17 +1016,28 @@ class ProcessManager: self.data_queue = Queue() self.side_process = Process(target=side_function, args=(args, init_command, self.command_queue, self.data_queue,)) + # both ways, with shared memory for commands + if comm_direction == 3: + self.data_queue = Queue() + # "sending" the command via shared memory + shm_name = "command" + self.shm = shared_memory.SharedMemory(shm_name, create=True, size=init_command.nbytes) + self.shared_command = np.ndarray(init_command.shape, dtype=init_command.dtype, buffer=self.shm.buf) + self.shared_command[:] = init_command[:] + self.shared_command_lock = Lock() + # the process has to create its shared memory + self.side_process = Process(target=side_function, + args=(args, init_command, shm_name, self.shared_command_lock, self.data_queue,)) if type(side_function) == partial: self.side_process.name = side_function.func.__name__ else: self.side_process.name = side_function.__name__ + "_process" self.lastest_data = init_value - if self.args.debug_prints: - print(f"PROCESS_MANAGER: i created the command queue for {self.side_process.name}", self.command_queue) self.side_process.start() if self.args.debug_prints: - print("PROCESS_MANAGER: i am starting {self.side_process.name}") + print(f"PROCESS_MANAGER: i am starting {self.side_process.name}") + # TODO: enforce that # the key should be a string containing the command, @@ -1074,6 +1090,23 @@ class ProcessManager: #self.command_queue.get_nowait() self.command_queue.put_nowait(command) + # TODO: implement + def sendCommandViaSharedMemory(self, command): + """ + sendCommandViaSharedMemory + instead of having a queue for the commands, have a shared memory variable. + this makes sense if you want to send the latest command only, + instead of stacking up old commands in a queue. + the locking and unlocking of the shared memory happens here + and you don't have to think about it in the control loop nor + do you need to pollute half of robotmanager or whatever else + to deal with this. + """ + assert type(command) == np.ndarray + assert command.shape == self.shared_command.shape + self.shared_command_lock.acquire() + self.shared_command[:] = command[:] + self.shared_command_lock.release() def getData(self): if not self.data_queue.empty(): @@ -1081,6 +1114,9 @@ class ProcessManager: return copy.deepcopy(self.lastest_data) def terminateProcess(self): + if self.comm_direction == 3: + self.shm.close() + self.shm.unlink() if self.args.debug_prints: print(f"i am putting befree in {self.side_process.name}'s command queue to stop it") self.command_queue.put_nowait("befree") diff --git a/python/ur_simple_control/optimal_control/crocoddyl_mpc.py b/python/ur_simple_control/optimal_control/crocoddyl_mpc.py index 143ca68..078883c 100644 --- a/python/ur_simple_control/optimal_control/crocoddyl_mpc.py +++ b/python/ur_simple_control/optimal_control/crocoddyl_mpc.py @@ -221,13 +221,19 @@ def BaseAndEEPathFollowingMPCControlLoop(args, robot : RobotManager, solver : cr T_w_e = robot.getT_w_e() #p = T_w_e.translation[:2] p = q[:2] + print("CTRL:", p) + # NOTE: this is the actual position, not what the path suggested + # whether this or path reference should be put in is debateable. + # this feels more correct to me. + save_past_dict['path2D_untimed'] = p if not (type(path_planner) == types.FunctionType): - path_planner.sendFreshestCommand({'p' : p}) + #path_planner.sendFreshestCommand({'p' : p}) + path_planner.sendCommandViaSharedMemory(p) # NOTE: it's pointless to recalculate the path every time # if it's the same 2D path - + # get the path from the base from the current base position onward if type(path_planner) == types.FunctionType: pathSE3 = path_planner(T_w_e, i) else: @@ -242,19 +248,40 @@ def BaseAndEEPathFollowingMPCControlLoop(args, robot : RobotManager, solver : cr if data == "done": breakFlag = True - path_pol, path2D_untimed = data - path2D_untimed = np.array(path2D_untimed).reshape((-1,2)) + path_pol_base, path2D_untimed_base = data + #path2D_untimed_base.insert(0, p[1]) + #path2D_untimed_base.insert(0, p[0]) + path2D_untimed_base = np.array(path2D_untimed_base).reshape((-1,2)) # should be precomputed somewhere but this is nowhere near the biggest problem max_base_v = np.linalg.norm(robot.model.velocityLimit[:2]) # 1) make 6D path out of [[x0,y0],...] # that represents the center of the cart - pathSE3 = path2D_to_timed_SE3_base_and_ee(args, path_pol, path2D_untimed, max_base_v) + # TODO: USE THIS ONCE IMPLEMENTED + #pathSE3 = path2D_to_timed_SE3_base_and_ee(args, path_pol_base, path2D_untimed_base, max_base_v) + # TODO: separate out timing construction so that it can be used for the handlebar path as well + pathSE3_base = path2D_to_timed_SE3(args, path_pol_base, path2D_untimed_base, max_base_v, 0.0) # TODO: EVIL AND HAS TO BE REMOVED FROM HERE if args.visualize_manipulator: if i % 20 == 0: - robot.visualizer_manager.sendCommand({"path": pathSE3}) + robot.visualizer_manager.sendCommand({"path": pathSE3_base}) + # now find the previous path point of arclength base_to_handlebar_preferred_distance + # NOTE: this can be O(1) instead of O(n) but i can't be bothered + path_arclength = np.linalg.norm(p - past_data['path2D_untimed']) + handlebar_path_index = -1 + for i in range(-2, -1 * len(past_data['path2D_untimed']), -1): + if path_arclength > args.base_to_handlebar_preferred_distance: + handlebar_path_index = i + break + path_arclength += np.linalg.norm(past_data['path2D_untimed'][i - 1] - past_data['path2D_untimed'][i]) + # i shouldn't need to copy-paste everything but what can you do + arra = np.array(past_data['path2D_untimed']) + path2D_handlebar = np.vstack((arra[i:], path2D_untimed_base)) + # now we need to construct timing for this + + + x0 = np.concatenate([robot.getQ(), robot.getQd()]) solver.problem.x0 = x0 # warmstart solver with previous solution @@ -263,10 +290,10 @@ def BaseAndEEPathFollowingMPCControlLoop(args, robot : RobotManager, solver : cr us_init = list(solver.us[1:]) + [solver.us[-1]] for i, runningModel in enumerate(solver.problem.runningModels): - runningModel.differential.costs.costs['gripperPose' + str(i)].cost.residual.reference = pathSE3[i] + runningModel.differential.costs.costs['gripperPose' + str(i)].cost.residual.reference = pathSE3_base[i] # idk if that's necessary - solver.problem.terminalModel.differential.costs.costs['gripperPose'+str(args.n_knots)].cost.residual.reference = pathSE3[-1] + solver.problem.terminalModel.differential.costs.costs['gripperPose'+str(args.n_knots)].cost.residual.reference = pathSE3_base[-1] solver.solve(xs_init, us_init, args.max_solver_iter) xs = np.array(solver.xs) @@ -308,7 +335,12 @@ def BaseAndEEPathFollowingMPC(args, robot, x0, path_planner): 'qs' : np.zeros(robot.model.nq), 'dqs' : np.zeros(robot.model.nv) } - save_past_dict = {} + # TODO: put ensurance that save_past is not too small for this + # or make a specific argument for THIS past-moving-window size + # this is the end-effector's reference, so we should initialize that + # TODO: verify this initialization actually makes sense + T_w_e = robot.getT_w_e() + save_past_dict = {'path2D_untimed' : T_w_e.translation[:2]} loop_manager = ControlLoopManager(robot, controlLoop, args, save_past_dict, log_item) loop_manager.run() diff --git a/python/ur_simple_control/path_generation/planner.py b/python/ur_simple_control/path_generation/planner.py index 49658b0..38eeaf2 100644 --- a/python/ur_simple_control/path_generation/planner.py +++ b/python/ur_simple_control/path_generation/planner.py @@ -13,7 +13,7 @@ import pinocchio as pin import matplotlib.pyplot as plt import matplotlib.collections as plt_col -from multiprocessing import Queue +from multiprocessing import Queue, Lock, shared_memory def getPlanningArgs(parser): parser.add_argument('--planning-robot-params-file', type=str, @@ -462,7 +462,7 @@ def pathVisualizer(x0, goal, map_as_list, positions): def pathPointFromPathParam(n_pol, path_dim, path_pol, s): return [np.polyval(path_pol[j*(n_pol+1):(j+1)*(n_pol+1)], s) for j in range(path_dim)] -def path2D_to_timed_SE3(args, path_pol, path2D_untimed, max_base_v): +def path2D_to_timed_SE3(args, path_pol, path2D_untimed, max_base_v, path_height): """ path2D_to_timed_SE3 --------------------- @@ -514,18 +514,26 @@ def path2D_to_timed_SE3(args, path_pol, path2D_untimed, max_base_v): total_time = path_length / base_v # 2) we find the correspondence between s and time # TODO: read from where it should be, but seba checked that it's 5 for some reason + # TODO THIS IS N IN PATH PLANNING, MAKE THIS A SHARED ARGUMENT max_s = 5 t_to_s = max_s / total_time # 3) construct the ocp-timed 2D path + # TODO MAKE REFERENCE_STEP_SIZE A SHARED ARGUMENT + # TODO: we should know max s a priori + reference_step_size = 0.5 + s_vec = np.arange(0, len(path2D_untimed)) / reference_step_size + path2D = [] # time is i * args.ocp_dt for i in range(args.n_knots + 1): - s = (i * args.ocp_dt) * t_to_s - path2D.append(pathPointFromPathParam(args.n_pol, args.np, path_pol, s)) + # what it should be but gets stuck if we're not yet on path + #s = (i * args.ocp_dt) * t_to_s + # full path + s = i * (max_s / args.n_knots) + #path2D.append(pathPointFromPathParam(args.n_pol, args.np, path_pol, s)) + path2D.append(np.array([np.interp(s, s_vec, path2D_untimed[:,0]), + np.interp(s, s_vec, path2D_untimed[:,1])])) path2D = np.array(path2D) - #print("=" * 15) - #print(path2D_untimed) - #print('----------------------------------------') #################################################### # constructing the SE3 reference from [x,y] path # @@ -571,10 +579,8 @@ def path2D_to_timed_SE3(args, path_pol, path2D_untimed, max_base_v): rotation = pin.rpy.rpyToMatrix(0.0, 0.0, thetas[i]) rotation = pin.rpy.rpyToMatrix(np.pi/2, np.pi/2,0.0) @ rotation #rotation = np.eye(3) - translation = np.array([path2D[i][0], path2D[i][1], - args.handlebar_height]) + translation = np.array([path2D[i][0], path2D[i][1], path_height]) path.append(pin.SE3(rotation, translation)) - #print(path[-1].translation) return path @@ -633,7 +639,6 @@ def path2D_to_timed_SE3_base_and_ee(args, path_pol, path2D_untimed, max_base_v): y_diff = y_i_plus_1 - y_i y_diff = y_diff.reshape((-1,1)) path_length = np.sum(np.linalg.norm(np.hstack((x_diff, y_diff)), axis=1)) - print(path_length) total_time = path_length / base_v # 2) we find the correspondence between s (path parameter) and time # TODO: read from where max_s should be 5, but seba checked that it's 5 for some reason @@ -644,14 +649,12 @@ def path2D_to_timed_SE3_base_and_ee(args, path_pol, path2D_untimed, max_base_v): # TODO: tune this value!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 # TODO: tune this value!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 # TODO make this an argument - base_to_handlebar_prefered_distance = 0.7 # TODO: we need a function that takes time as input and spits - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 - need to have set interpolation to implement that +# need to have set interpolation to implement that # out a path point of distance base_to_handlebar_prefered_distance from time 0. # (it's the classic integral for curve length) # cart_to_base_prefered_distance as percentage of path length * size of s (again why the fuck isn't s=1????) - handlebar_to_base_as_s = (cart_to_base_prefered_distance / path_length) * max_s + handlebar_to_base_as_s = (args.base_to_handlebar_preferred_distance / path_length) * max_s path2D_mobile_base = [] path2D_cart = [] # time is i * args.ocp_dt @@ -711,13 +714,14 @@ def path2D_to_timed_SE3_base_and_ee(args, path_pol, path2D_untimed, max_base_v): translation = np.array([path2D_cart[i][0], path2D_cart[i][1], args.handlebar_height]) path.append(pin.SE3(rotation, translation)) - #print(path[-1].translation) return path # function to be put into ProcessManager, # spitting out path points -def starPlanner(goal, args, init_cmd, cmd_queue : Queue, data_queue : Queue): +#def starPlanner(goal, args, init_cmd, cmd_queue : Queue, data_queue : Queue): +# let's try shared memory +def starPlanner(goal, args, init_cmd, shm_name, lock : Lock, data_queue : Queue): """ starPlanner ------------ @@ -726,6 +730,11 @@ def starPlanner(goal, args, init_cmd, cmd_queue : Queue, data_queue : Queue): out path points and just the path points. goal and path are [x,y] """ + # shm stuff + shm = shared_memory.SharedMemory(name=shm_name) + # dtype is default, but i have to pass it + p_shared = np.ndarray((2,), dtype=np.float64, buffer=shm.buf) + p = np.zeros(2) # environment obstacles, _ = createMap() @@ -752,8 +761,11 @@ def starPlanner(goal, args, init_cmd, cmd_queue : Queue, data_queue : Queue): try: while True: # has to be a blocking call - cmd = cmd_queue.get() - p = cmd['p'] + #cmd = cmd_queue.get() + #p = cmd['p'] + lock.acquire() + p[:] = p_shared[:] + lock.release() if np.linalg.norm(p - goal) < convergence_threshold: data_queue.put("done") @@ -765,9 +777,13 @@ def starPlanner(goal, args, init_cmd, cmd_queue : Queue, data_queue : Queue): r0, rg, rho, obstacles_star = scene_updater.update(p, goal, obstacles) # compute the path path_pol, epsilon = path_gen.update(p, r0, rg, rho, obstacles_star) - data_queue.put((path_pol, path_gen.target_path)) + # TODO: this is stupid, just used shared memory bro + if data_queue.qsize() < 1: + data_queue.put((path_pol, path_gen.target_path)) except KeyboardInterrupt: + shm.close() + shm.unlink() if args.debug_prints: print("PLANNER: caught KeyboardInterrupt, i'm out") diff --git a/python/ur_simple_control/path_generation/tunnel_mpc_params.yaml b/python/ur_simple_control/path_generation/tunnel_mpc_params.yaml index 1f1ca86..5568e99 100644 --- a/python/ur_simple_control/path_generation/tunnel_mpc_params.yaml +++ b/python/ur_simple_control/path_generation/tunnel_mpc_params.yaml @@ -13,7 +13,7 @@ tunnel_mpc: max_compute_time: 10 crep: 1. reactivity: 1. - buffer: 1 + buffer: 0 # MPC ce: 100. @@ -29,6 +29,7 @@ tunnel_mpc: integration_method: 'euler' np: 2 n_pol: 10 + # TODO: test if this is the length of the path N: 5 dt: 0.2 solver_tol: 1.e-5 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 5f9c8d3e8db06097c501d6e568f9c82e342ef74f..0b9be5219556e6bda86aa8b5060d344b697ac177 100644 GIT binary patch delta 71 zcmZ3SwK$9KG%qg~0|Ntto}6F0n8ilE4s}MJ$<anilXHv&H=j~J!O8Z8fq|iT-ef*? cyUo`OZJ7mJ7#XcTM=&`vGFlb+FfcFx0L%;%00000 delta 71 zcmZ3SwK$9KG%qg~0|Ntt-W}ic)8-rbI@B4tCPy17P0leA+<Z#?1Si{P1_p-Wd6W6n Z?KWRCv}G1>W@NPb9L5BqihLLt7yuiF6l(wg 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 5e23ff210ab7394dfd4a3855298def2a26a4fc03..2095b13bf2b1b332271a3dd4614c22b5bfcd9ccb 100644 GIT binary patch delta 730 zcmaFf%y_Gnk?%AwFBby?1H-#U|MW)JjeHBGnUYv1Z<M|`*-FM_a)A-+<YE~~M)t|Q zGN%0X3=FmGHS8%I*%}NCMP-vO$|y5(PM#}&h>ek90%IP_<lVA|8QCW9mz4!;d?+i< z&L+vgz>p<1d7+x@<aKg9lRM<ZCSQ<~n7mC+N|qZWx0(@TI|BnFLk)Wh57=P28n!IO z$qQLU%u;wjN>X@1WDN_H#|PrAW<t`&57Ji5G=Z@vyM`@GdGbLu5t$m66n<2N6Bv7% zSQsWS_Dr9gE^o>xIC-x8c}AhhxeDIwx7b4BlM;(JZ&x_S$lbxfz_5~mfuUHFY4QZ6 z;K`?y_(VM}O6qPXzRF^KhlTS3m;MzNgAYvdliw<(G2arAoLr}@Gr37wLq%hf{S6WE z>0T4PW>j1h(YP*Rc2UG^L-7uajkVX!11_2eToDPJyiB=(N0&iD`Xeg?zwnPQCX<y^ zVkHlWyV`i@Gn^2W0+ITTHePznr*s*;^fu2>ImW8h&A`A=gdnmQ7#Kn{8E>)V7o_HC zvLMNHPwvnPW$fO3Ps^K;v3#<Yjyhx2<RBeQ#>UAtI<f-QAaiO!L@kJ@o4is-p0RcE zNgV~{HU<WUTP%6`DXF(u$}+2rZZQ=a-eM{=Dk=g61s?+ggTmyG?81}fbro3`F)%P( z-R!D6g_kjZ@-3@4#)+FPtwk9bS5Ee~5o4S+InBn8yA@=?Y!ESL@_rkC#?_PgZ9`eN zGcYiiZO*iP#cV$lBv%0<L_vf(h{ymDpztpOSy2R1y^^6w3?wQ7avz6HZhlH>PO4qe e!O4>x?Zwm?bw5QghB7khes*F`Vq_Ess|5g|k;Yp9 delta 637 zcmccB%J{sQk?%AwFBby?14H{o-}Lh?8~GMWGwooRyixk%<Wn+SjBJyy%9slKF)-A! z*RZFsXKOGp6qVL6XYoyLFcqC_qrk<;G1*r32v6RX8uk<>u(bB%Kn1bMs&b1NIVWq% z%L{W#GB7Z#W(3*6z`)2*!=A!5Ia*$RvWL9H<Vo^UrraR;6dn*+!;%8w@q&1(nUM7G zfy^#un!wm&Rl}C0Jb5FFuq=NKO9~&V$_b1;fh-IY7<<wt3o4jS_B7|7>@K@wvVk@) zqu^w5Meog7if0+Q+Zh-bRx&U!6u)4c?4%sb#d(2C{|bx22PWCcJCxHHZ%&q137b4u zC5K0oK|=Z?D+9mqk1qz3^$o-(Ypc3T9yE64c9&u}&L9OMr5tTMC7Dl3FnUUE?p8g< zs@287z)*xBvKSZ`LNpm~vE&z|=4rAZ$#hMw)(&Ot+I&&ln~||>vaGH;W94L5T}{S@ z$@#jn0#zV$szF2zh^U=BM^~P)W%3?f1;*CNcXcJW3PC>LV_;xVnEa7lc(Rb5BI`m1 z28K(UE%c`FGUiM^YaPcpVY7~nD5Jy*kO`p-3=Frpa|?3flk@ZPQj<%HW=@W@^%HFY zNzMWhvq3~Mh)9{-FD5hjhOH*!s>w`tp{&~&7#NH<$Jo7MR+#~kF9#8#Ai^9(WPk`z ts1|`-P_%7wmXj3Yfyu2-_F^iGx}Sm=Lm3%$KRYoeF)|7li7_xR0041`pPv8# diff --git a/python/ur_simple_control/visualize/visualize.py b/python/ur_simple_control/visualize/visualize.py index 3c039a0..2332454 100644 --- a/python/ur_simple_control/visualize/visualize.py +++ b/python/ur_simple_control/visualize/visualize.py @@ -172,6 +172,7 @@ def manipulatorVisualizer(model, collision_model, visual_model, args, cmd, queue # set shapes we know we'll use meshcat_shapes.frame(viz.viewer["Mgoal"], opacity=0.5) meshcat_shapes.frame(viz.viewer["T_w_e"], opacity=0.5) + meshcat_shapes.frame(viz.viewer["T_base"], opacity=0.5) print("MANIPULATORVISUALIZER: FULLY ONLINE") try: while True: @@ -187,6 +188,8 @@ def manipulatorVisualizer(model, collision_model, visual_model, args, cmd, queue viz.viewer["Mgoal"].set_transform(cmd["Mgoal"].homogeneous) if key == "T_w_e": viz.viewer["T_w_e"].set_transform(cmd["T_w_e"].homogeneous) + if key == "T_base": + viz.viewer["T_base"].set_transform(cmd["T_base"].homogeneous) if key == "q": viz.display(cmd["q"]) if key == "point": -- GitLab