diff --git a/.gitignore b/.gitignore index 4b08d60d9276447654672ad42b1b1277a9bd3a04..af1c19092c6423e9143b1efb01c16bd7c21eeb7d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ build/ **__pycache__ .vscode/ **.pickle -*csv +*.csv diff --git a/python/examples/data/clik_run_001.pickle b/python/examples/data/clik_run_001.pickle deleted file mode 100644 index a00c271660647b3458b7f932971396e12d08ac22..0000000000000000000000000000000000000000 Binary files a/python/examples/data/clik_run_001.pickle and /dev/null differ diff --git a/python/examples/data/clik_run_001_args.pickle b/python/examples/data/clik_run_001_args.pickle deleted file mode 100644 index aed77b21c0ed22d104f9b656933c8df387e1f497..0000000000000000000000000000000000000000 Binary files a/python/examples/data/clik_run_001_args.pickle and /dev/null differ diff --git a/python/examples/data/latest_run b/python/examples/data/latest_run index 747204f13bea6585dc9fde6f2f60978ab70560cc..4680ab807b8ec0484caccccb3060d4052566c3bb 100644 Binary files a/python/examples/data/latest_run and b/python/examples/data/latest_run differ diff --git a/python/examples/data/test2_0.pickle b/python/examples/data/test2_0.pickle deleted file mode 100644 index fc57d202f31f4278b74dddecd55f61deb411beac..0000000000000000000000000000000000000000 Binary files a/python/examples/data/test2_0.pickle and /dev/null differ diff --git a/python/examples/drawing_from_input_drawing.py b/python/examples/drawing_from_input_drawing.py index 05d53990d35dc103fc0de8322f6bb6b84fa170ec..a9240db63994c88ea41ad992b91a50761f70e460 100644 --- a/python/examples/drawing_from_input_drawing.py +++ b/python/examples/drawing_from_input_drawing.py @@ -178,7 +178,8 @@ def controlLoopWriting(args, robot : RobotManager, dmp, tc, i, past_data): # first-order low pass filtering instead # beta is a smoothing coefficient, smaller values smooth more, has to be in [0,1] - wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + #wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + wrench = args.beta * wrench + (1 - args.beta) * np.average(np.array(past_data['wrench']), axis=0) wrench = Z @ wrench #J = pin.computeJointJacobian(robot.model, robot.data, q, robot.JOINT_ID) @@ -347,7 +348,7 @@ if __name__ == "__main__": path_pose.translation = path_points_3D[i] path.append(plane_pose.act(path_pose)) - if args.viz_path: + if args.viz_test_path: print( """ look at the viz now! we're constructing a trajectory for the drawing. @@ -356,7 +357,7 @@ if __name__ == "__main__": ) joint_trajectory = clikCartesianPathIntoJointPath(args, robot, path, \ clikController, q_init, plane_pose) - if args.viz_path: + if args.viz_test_path: answer = input("did the movement of the manipulator look reasonable? [Y/n]") if not (answer == "Y" or answer == "y"): print("well if it doesn't look reasonable i'll just exit!") diff --git a/python/examples/joint_trajectory.csv b/python/examples/joint_trajectory.csv index 553d3888af1730d39cba390893138d0c52293bd7..90d134cd621bb90a419f8a13d0345bd798f314b0 100644 --- a/python/examples/joint_trajectory.csv +++ b/python/examples/joint_trajectory.csv @@ -1,25 +1,88 @@ -0.00000,1.11039,-1.23013,-1.62170,-1.02108,1.93437,-0.29909 -0.41667,1.11035,-1.23011,-1.62174,-1.02106,1.93439,-0.29911 -0.83333,1.11011,-1.23000,-1.62196,-1.02098,1.93454,-0.29927 -1.25000,1.10978,-1.22987,-1.62223,-1.02087,1.93475,-0.29950 -1.66667,1.10939,-1.22974,-1.62252,-1.02075,1.93499,-0.29976 -2.08333,1.10786,-1.22945,-1.62340,-1.02036,1.93598,-0.30082 -2.50000,1.10587,-1.22930,-1.62426,-1.01994,1.93730,-0.30219 -2.91667,1.10163,-1.22958,-1.62535,-1.01929,1.94016,-0.30513 -3.33333,1.07429,-1.24078,-1.62039,-1.01907,1.95955,-0.32456 -3.75000,1.06133,-1.24717,-1.61681,-1.01942,1.96883,-0.33391 -4.16667,1.04725,-1.25502,-1.61189,-1.02018,1.97898,-0.34418 -4.58333,1.01307,-1.27717,-1.59639,-1.02341,2.00376,-0.36958 -5.00000,1.00018,-1.28613,-1.58982,-1.02499,2.01307,-0.37931 -5.41667,0.99126,-1.29307,-1.58416,-1.02654,2.01951,-0.38611 -5.83333,0.98462,-1.29829,-1.57992,-1.02772,2.02430,-0.39120 -6.25000,0.94619,-1.32935,-1.55485,-1.03495,2.05185,-0.42114 -6.66667,0.93695,-1.33717,-1.54837,-1.03696,2.05844,-0.42847 -7.08333,0.91212,-1.36116,-1.52643,-1.04427,2.07601,-0.44844 -7.50000,0.90656,-1.36660,-1.52144,-1.04599,2.07993,-0.45297 -7.91667,0.89635,-1.37651,-1.51249,-1.04907,2.08710,-0.46132 -8.33333,0.88664,-1.38707,-1.50215,-1.05277,2.09389,-0.46934 -8.75000,0.88579,-1.38800,-1.50123,-1.05311,2.09448,-0.47005 -9.16667,0.88494,-1.38893,-1.50032,-1.05344,2.09508,-0.47076 -9.58333,0.88490,-1.38897,-1.50028,-1.05345,2.09510,-0.47079 -10.00000,0.88486,-1.38901,-1.50024,-1.05347,2.09513,-0.47082 +0.00000,1.20178,-1.41060,-1.33105,-1.11327,1.86782,-0.23666 +0.11494,1.20175,-1.41059,-1.33108,-1.11326,1.86783,-0.23668 +0.22989,1.20172,-1.41058,-1.33110,-1.11324,1.86784,-0.23669 +0.34483,1.20170,-1.41056,-1.33113,-1.11323,1.86785,-0.23671 +0.45977,1.20139,-1.41056,-1.33118,-1.11316,1.86801,-0.23691 +0.57471,1.14847,-1.43710,-1.30858,-1.11705,1.90490,-0.27292 +0.68966,1.11306,-1.45819,-1.29040,-1.12150,1.93063,-0.29768 +0.80460,1.06526,-1.49092,-1.26088,-1.13029,1.96580,-0.33204 +0.91954,1.02978,-1.51889,-1.23371,-1.13958,1.99182,-0.35824 +1.03448,0.94706,-1.59438,-1.15607,-1.16900,2.05165,-0.42188 +1.14943,0.86796,-1.68166,-1.05970,-1.20921,2.10733,-0.48659 +1.26437,0.86399,-1.68647,-1.05417,-1.21164,2.11008,-0.48996 +1.37931,0.86106,-1.69011,-1.04994,-1.21349,2.11211,-0.49245 +1.49425,0.85906,-1.69251,-1.04722,-1.21469,2.11349,-0.49415 +1.60920,0.85799,-1.69374,-1.04587,-1.21528,2.11423,-0.49506 +1.72414,0.85595,-1.69602,-1.04341,-1.21634,2.11564,-0.49680 +1.83908,0.85373,-1.69832,-1.04108,-1.21734,2.11716,-0.49870 +1.95402,0.84988,-1.70160,-1.03843,-1.21841,2.11981,-0.50199 +2.06897,0.84767,-1.70208,-1.03954,-1.21780,2.12132,-0.50386 +2.18391,0.84693,-1.68337,-1.07525,-1.20110,2.12180,-0.50436 +2.29885,0.84908,-1.66678,-1.10429,-1.18766,2.12029,-0.50240 +2.41379,0.86246,-1.62010,-1.17900,-1.15368,2.11101,-0.49074 +2.52874,0.88257,-1.56432,-1.26407,-1.11577,2.09697,-0.47356 +2.64368,0.89362,-1.53460,-1.30887,-1.09609,2.08920,-0.46423 +2.75862,0.91309,-1.46684,-1.41464,-1.05020,2.07538,-0.44791 +2.87356,0.91885,-1.45127,-1.43772,-1.04043,2.07128,-0.44315 +2.98851,0.93546,-1.39590,-1.52183,-1.00530,2.05938,-0.42951 +3.10345,0.93875,-1.38488,-1.53846,-0.99845,2.05701,-0.42683 +3.21839,0.94620,-1.35924,-1.57698,-0.98280,2.05164,-0.42078 +3.33333,0.95208,-1.34205,-1.60196,-0.97286,2.04741,-0.41606 +3.44828,0.95494,-1.33386,-1.61376,-0.96821,2.04535,-0.41377 +3.56322,0.95706,-1.32792,-1.62227,-0.96488,2.04381,-0.41207 +3.67816,0.95831,-1.32475,-1.62672,-0.96316,2.04291,-0.41108 +3.79310,0.95895,-1.32319,-1.62889,-0.96232,2.04245,-0.41057 +3.90805,0.95964,-1.32157,-1.63112,-0.96147,2.04195,-0.41003 +4.02299,0.96035,-1.31995,-1.63333,-0.96062,2.04144,-0.40946 +4.13793,0.96084,-1.31894,-1.63468,-0.96011,2.04109,-0.40908 +4.25287,0.96166,-1.31727,-1.63691,-0.95927,2.04050,-0.40843 +4.36782,0.96164,-1.31727,-1.63691,-0.95926,2.04051,-0.40844 +4.48276,0.96161,-1.31730,-1.63688,-0.95927,2.04053,-0.40847 +4.59770,0.91620,-1.37147,-1.57978,-0.97878,2.07285,-0.44460 +4.71264,0.90509,-1.38474,-1.56583,-0.98377,2.08069,-0.45364 +4.82759,0.87952,-1.41497,-1.53452,-0.99516,2.09858,-0.47475 +4.94253,0.85807,-1.44115,-1.50713,-1.00546,2.11345,-0.49280 +5.05747,0.84749,-1.45377,-1.49423,-1.01037,2.12073,-0.50183 +5.17241,0.82776,-1.47792,-1.46936,-1.01997,2.13422,-0.51887 +5.28736,0.81754,-1.49050,-1.45648,-1.02502,2.14116,-0.52781 +5.40230,0.80945,-1.50051,-1.44624,-1.02907,2.14662,-0.53494 +5.51724,0.80645,-1.50427,-1.44238,-1.03061,2.14864,-0.53761 +5.63218,0.80446,-1.50676,-1.43982,-1.03163,2.14998,-0.53937 +5.74713,0.80346,-1.50801,-1.43853,-1.03215,2.15065,-0.54026 +5.86207,0.80343,-1.50805,-1.43849,-1.03216,2.15067,-0.54029 +5.97701,0.80247,-1.50927,-1.43724,-1.03266,2.15132,-0.54115 +6.09195,0.80147,-1.51052,-1.43595,-1.03318,2.15199,-0.54203 +6.20690,0.79945,-1.51296,-1.43352,-1.03415,2.15334,-0.54383 +6.32184,0.79880,-1.51327,-1.43359,-1.03409,2.15378,-0.54441 +6.43678,0.79553,-1.51067,-1.44127,-1.03058,2.15595,-0.54729 +6.55172,0.79358,-1.49913,-1.46348,-1.02084,2.15721,-0.54895 +6.66667,0.79698,-1.47294,-1.50627,-1.00252,2.15489,-0.54576 +6.78161,0.81662,-1.40963,-1.59790,-0.96469,2.14157,-0.52809 +6.89655,0.82336,-1.39122,-1.62339,-0.95443,2.13698,-0.52211 +7.01149,0.84132,-1.33826,-1.69706,-0.92545,2.12464,-0.50634 +7.12644,0.84923,-1.31680,-1.72605,-0.91437,2.11918,-0.49948 +7.24138,0.85622,-1.29952,-1.74871,-0.90591,2.11435,-0.49347 +7.35632,0.86926,-1.26257,-1.79815,-0.88778,2.10528,-0.48234 +7.47126,0.87211,-1.25342,-1.81061,-0.88325,2.10328,-0.47991 +7.58621,0.87519,-1.24446,-1.82252,-0.87899,2.10113,-0.47729 +7.70115,0.87855,-1.23535,-1.83439,-0.87482,2.09878,-0.47446 +7.81609,0.88134,-1.22837,-1.84328,-0.87175,2.09683,-0.47212 +7.93103,0.88219,-1.22619,-1.84607,-0.87079,2.09623,-0.47141 +8.04598,0.88354,-1.22294,-1.85015,-0.86939,2.09528,-0.47027 +8.16092,0.88356,-1.22290,-1.85021,-0.86937,2.09527,-0.47026 +8.27586,0.88424,-1.22132,-1.85217,-0.86871,2.09480,-0.46969 +8.39080,0.88447,-1.22074,-1.85291,-0.86845,2.09463,-0.46949 +8.50575,0.88469,-1.22016,-1.85366,-0.86820,2.09448,-0.46931 +8.62069,0.88469,-1.22013,-1.85370,-0.86818,2.09448,-0.46931 +8.73563,0.85976,-1.23839,-1.84493,-0.86906,2.11171,-0.49009 +8.85057,0.82320,-1.27328,-1.81991,-0.87542,2.13667,-0.52139 +8.96552,0.77157,-1.33116,-1.77224,-0.89020,2.17119,-0.56738 +9.08046,0.75924,-1.34581,-1.75974,-0.89441,2.17930,-0.57869 +9.19540,0.74291,-1.36572,-1.74257,-0.90030,2.18994,-0.59386 +9.31034,0.73094,-1.38007,-1.73055,-0.90448,2.19767,-0.60513 +9.42529,0.71819,-1.39573,-1.71726,-0.90919,2.20584,-0.61726 +9.54023,0.71613,-1.39833,-1.71501,-0.91000,2.20716,-0.61924 +9.65517,0.71510,-1.39963,-1.71388,-0.91041,2.20781,-0.62023 +9.77011,0.71407,-1.40094,-1.71274,-0.91083,2.20847,-0.62122 +9.88506,0.71304,-1.40225,-1.71160,-0.91124,2.20912,-0.62221 +10.00000,0.71301,-1.40229,-1.71156,-0.91126,2.20914,-0.62224 diff --git a/python/examples/log_analysis_example.py b/python/examples/log_analysis_example.py new file mode 100644 index 0000000000000000000000000000000000000000..e540fea5dfe8e19df9e1809ecbf4930d4044e577 --- /dev/null +++ b/python/examples/log_analysis_example.py @@ -0,0 +1,14 @@ +import pinocchio as pin +import numpy as np +import argparse +from ur_simple_control.managers import getMinimalArgParser +from ur_simple_control.util.logging_utils import LogManager + + +if __name__ == "__main__": + log_manager = LogManager(None) + log_manager.loadLog('./data/ft_readings_9.pickle') + # pickling does not save this attribute somehow???? + #log_manager.are_logs_vectorized_flag = False + log_manager.plotAllControlLoops() + diff --git a/python/examples/test_gripper.py b/python/examples/old_or_experimental/test_gripper.py similarity index 100% rename from python/examples/test_gripper.py rename to python/examples/old_or_experimental/test_gripper.py diff --git a/python/examples/path_in_pixels.csv b/python/examples/path_in_pixels.csv index a547354a96600b510c8cddbd40dd12f16f8a1d77..d26413b033264908c12ecab921c508243c1a8e96 100644 --- a/python/examples/path_in_pixels.csv +++ b/python/examples/path_in_pixels.csv @@ -1,25 +1,88 @@ -0.16462,0.49814 -0.16462,0.49814 -0.16610,0.49814 -0.16759,0.49814 -0.16907,0.49814 -0.17351,0.49814 -0.17796,0.49814 -0.18536,0.49814 -0.22092,0.50270 -0.23573,0.50270 -0.25203,0.50270 -0.29351,0.50270 -0.30980,0.50270 -0.32165,0.50573 -0.33054,0.50573 -0.38387,0.50573 -0.39721,0.50573 -0.43572,0.51181 -0.44461,0.51181 -0.46091,0.51181 -0.47720,0.51637 -0.47869,0.51637 -0.48017,0.51637 -0.48017,0.51637 -0.48017,0.51637 +0.17444,0.82632 +0.17039,0.82632 +0.16837,0.82632 +0.16635,0.82632 +0.17848,0.83020 +0.25736,0.83408 +0.30590,0.83149 +0.37466,0.82891 +0.42926,0.82891 +0.56881,0.82632 +0.72050,0.81986 +0.72859,0.81857 +0.73465,0.81857 +0.73870,0.81728 +0.74072,0.81599 +0.74477,0.81469 +0.74881,0.81211 +0.75488,0.80565 +0.75083,0.79014 +0.70027,0.76042 +0.68005,0.74879 +0.62746,0.71777 +0.56477,0.67772 +0.53241,0.65316 +0.46769,0.58209 +0.44949,0.56917 +0.39691,0.50714 +0.38679,0.49422 +0.36252,0.46450 +0.34432,0.44640 +0.33623,0.43736 +0.33016,0.43090 +0.32612,0.42831 +0.32410,0.42702 +0.32208,0.42573 +0.32005,0.42444 +0.31803,0.42444 +0.31601,0.42314 +0.34837,0.43865 +0.36859,0.44770 +0.45151,0.47613 +0.47174,0.47871 +0.51825,0.48517 +0.55870,0.49034 +0.57893,0.49034 +0.61735,0.49292 +0.63758,0.49292 +0.65376,0.49292 +0.65982,0.49292 +0.66387,0.49292 +0.66589,0.49292 +0.66589,0.49292 +0.66791,0.49292 +0.66994,0.49292 +0.67398,0.49163 +0.66791,0.47096 +0.64567,0.44899 +0.62140,0.43219 +0.58702,0.40634 +0.51016,0.35207 +0.48792,0.33656 +0.42926,0.28358 +0.40500,0.26291 +0.38477,0.24740 +0.34634,0.20734 +0.33825,0.19571 +0.32814,0.18666 +0.31803,0.17762 +0.30994,0.17116 +0.30792,0.16857 +0.30387,0.16599 +0.30387,0.16599 +0.30185,0.16470 +0.30185,0.16340 +0.30185,0.16211 +0.31601,0.16340 +0.38882,0.16986 +0.44342,0.17503 +0.53039,0.18020 +0.55263,0.18020 +0.58297,0.18020 +0.60522,0.17762 +0.62949,0.17633 +0.63353,0.17633 +0.63555,0.17633 +0.63758,0.17633 +0.63960,0.17633 +0.63960,0.17633 diff --git a/python/examples/planar_dragging_via_top_contact_force.py b/python/examples/planar_dragging_via_top_contact_force.py deleted file mode 100644 index 8e7a82458a292c5549fea9dd9999b36376d9f688..0000000000000000000000000000000000000000 --- a/python/examples/planar_dragging_via_top_contact_force.py +++ /dev/null @@ -1,248 +0,0 @@ -import pinocchio as pin -import numpy as np -import matplotlib.pyplot as plt -import copy -import argparse -import time -from functools import partial -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 clik 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, moveL, moveUntilContact -from ur_simple_control.clik.clik_trajectory_following import map2DPathTo3DPlane, clikCartesianPathIntoJointPath -from ur_simple_control.managers import ControlLoopManager, RobotManager -from ur_simple_control.util.calib_board_hacks import calibratePlane, getSpeedInDirectionOfN -from ur_simple_control.visualize.visualize import plotFromDict -from ur_simple_control.basics.basics import moveJ - -####################################################################### -# arguments # -####################################################################### - -def getArgs(): - ####################################################################### - # generic arguments # - ####################################################################### - 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 - parser.add_argument('--simulation', action=argparse.BooleanOptionalAction, - help="whether you are running the UR simulator. \ - NOTE: doesn't actually work because it's not a physics simulator", \ - default=False) - parser.add_argument('--pinocchio-only', action=argparse.BooleanOptionalAction, - help="whether you want to just integrate with pinocchio.\ - NOTE: doesn't actually work because it's not a physics simulator", \ - default=False) - parser.add_argument('--visualize', action=argparse.BooleanOptionalAction, - help="whether you want to visualize with gepetto, but \ - NOTE: not implemented yet", default=False) - parser.add_argument('--gripper', action=argparse.BooleanOptionalAction, \ - help="whether you're using the gripper", default=False) - parser.add_argument('--acceleration', type=float, \ - help="robot's joints acceleration. scalar positive constant, \ - max 1.7, and default 0.4. \ - BE CAREFUL WITH THIS. the urscript doc says this is 'lead axis acceleration'.\ - TODO: check what this means", default=0.3) - parser.add_argument('--speed-slider', type=float,\ - help="cap robot's speed with the speed slider \ - to something between 0 and 1, 1.0 by default because for dmp. \ - BE CAREFUL WITH THIS.", default=1.0) - parser.add_argument('--max-iterations', type=int, \ - help="maximum allowable iteration number (it runs at 500Hz)", default=50000) - ####################################################################### - # your controller specific arguments # - ####################################################################### - # not applicable here, but leaving it in the case it becomes applicable - # it's also in the robot manager even though it shouldn't be - parser.add_argument('--past-window-size', type=int, \ - help="how many timesteps of past data you want to save", default=5) - parser.add_argument('--goal-error', type=float, \ - help="the final position error you are happy with. NOTE: not used here", \ - default=1e-3) - # TODO: test the interaction of this and the overall demo - parser.add_argument('--tikhonov-damp', type=float, \ - help="damping scalar in tikhonov regularization.\ - This is used when generating the joint trajectory from the drawing.", \ - default=1e-2) - # TODO add the rest - 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 # - ############################# - parser.add_argument('--temporal-coupling', action=argparse.BooleanOptionalAction, \ - help="whether you want to use temporal coupling", default=True) - parser.add_argument('--kp', type=float, \ - help="proportial control constant for position errors", \ - default=1.0) - parser.add_argument('--tau0', type=float, \ - help="total time needed for trajectory. if you use temporal coupling,\ - you can still follow the path even if it's too fast", \ - default=5) - parser.add_argument('--gamma-nominal', type=float, \ - help="positive constant for tuning temporal coupling: the higher,\ - the fast the return rate to nominal tau", \ - default=1.0) - parser.add_argument('--gamma-a', type=float, \ - help="positive constant for tuning temporal coupling, potential term", \ - default=0.5) - parser.add_argument('--eps-tc', type=float, \ - help="temporal coupling term, should be small", \ - default=0.001) - parser.add_argument('--alpha', type=float, \ - help="force feedback proportional coefficient", \ - default=0.007) - # 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.5) - parser.add_argument('--board-height', type=float, \ - help="height of the board (in meters) the robot will write on", \ - default=0.35) - parser.add_argument('--calibration', action=argparse.BooleanOptionalAction, \ - help="whether you want to do calibration", default=False) - parser.add_argument('--draw-new', action=argparse.BooleanOptionalAction, \ - help="whether draw a new picture, or use the saved path path_in_pixels.csv", default=True) - parser.add_argument('--pick_up_marker', action=argparse.BooleanOptionalAction, \ - help=""" - whether the robot should pick up the marker. - NOTE: THIS IS FROM A PREDEFINED LOCATION. - """, default=True) - parser.add_argument('--find-marker-offset', action=argparse.BooleanOptionalAction, \ - help=""" - whether you want to do find marker offset (recalculate TCP - based on the marker""", default=False) - parser.add_argument('--n-calibration-tests', type=int, \ - help="number of calibration tests you want to run", default=10) - parser.add_argument('--clik-goal-error', type=float, \ - help="the clik error you are happy with", default=1e-2) - parser.add_argument('--max-init-clik-iterations', type=int, \ - help="number of max clik iterations to get to the first point", default=10000) - parser.add_argument('--max-running-clik-iterations', type=int, \ - help="number of max clik iterations between path points", default=1000) - args = parser.parse_args() - if args.gripper and args.simulation: - raise NotImplementedError('Did not figure out how to put the gripper in \ - the simulation yet, sorry :/ . You can have only 1 these flags right now') - return args - - - - -####################################################################### -# control loop # -####################################################################### - -# feedforward velocity, feedback position and force for impedance -def controller(): - pass - - -# control loop to be passed to ControlLoopManager -def controlLoopPlanarDragging(dmp, tc, controller, robot, i, past_data): - breakFlag = False - # TODO rename this into something less confusing - save_past_dict = {} - log_item = {} - dmp.step(robot.dt) # dmp step - # temporal coupling step - tau = dmp.tau + tc.update(dmp, robot.dt) * robot.dt - dmp.set_tau(tau) - q = robot.getQ() - Z = np.diag(np.ones(6)) - - wrench = robot.getWrench() - wrench = np.average(np.array(past_data['wrench']), axis=0) - - # first-order low pass filtering - # beta is a smoothing coefficient, smaller values smooth more, has to be in [0,1] - beta = 0.007 - #wrench = beta * wrench + (1 - beta) * past_data['wrench'][-1] - - wrench = robot.getMtool().toDualActionMatrix().T @ wrench - wrench = Z @ wrench - # deepcopy for good coding practise (and correctness here) - save_past_dict['wrench'] = copy.deepcopy(wrench) - # rolling average - if i % 100 == 0: - print(wrench) - J = pin.computeJointJacobian(robot.model, robot.data, q, robot.JOINT_ID) - dq = robot.getQd()[:6].reshape((6,1)) - # get joitn - tau = J.T @ wrench - tau = tau[:6].reshape((6,1)) - # compute control law: - #vel_cmd = dmp.vel + args.kp * (dmp.pos - q[:6].reshape((6,1))) + args.alpha * tau - vel_cmd = np.zeros(6) - robot.sendQd(vel_cmd) - - # TODO find a better criterion for stopping - if (np.linalg.norm(dmp.vel) < 0.0001) and (i > 5000): - breakFlag = True - # immediatelly stop if something weird happened (some non-convergence) - if np.isnan(vel_cmd[0]): - breakFlag = True - - # log what you said you'd log - # TODO fix the q6 situation (hide this) - log_item['wrench'] = wrench[:6].reshape((6,)) - - return breakFlag, save_past_dict, log_item - -if __name__ == "__main__": - ####################################################################### - # software setup # - ####################################################################### - args = getArgs() - clikController = getClikController(args) - robot = RobotManager(args) - - # calibrate FT first - speed_down = np.array([0,0,-1,0,0,0]) - moveUntilContact(args, robot, speed_down) - m_goal_up = robot.getMtool() - m_goal_up.translation[2] += 0.1 - moveL(args, robot, m_goal_up) - - # controlLoopManager will populate the queue with these initial values -# save_past_dict = { -# 'wrench' : np.zeros(6), -# } -# # here you give it it's initial value -# log_dict = { -# 'wrench': np.zeros((args.max_iterations, 6)), -# } -# controlLoop = partial(controlLoopPlanarDragging, dmp, tc, controller, robot) -# loop_manager = ControlLoopManager(robot, controlLoop, args, save_past_dict, log_dict) -# ####################################################################### -# # physical setup # -# ####################################################################### -# # TODO: add marker picking -# # get up from the board -# current_pose = robot.getMtool() -# # and now we can actually run -# log_dict, final_iteration = loop_manager.run() -# mtool = robot.getMtool() -# mtool.translation[1] = mtool.translation[1] - 0.1 -# moveL(args, robot, mtool) - - plotFromDict(log_dict, args) - robot.stopHandler(None, None) - robot.stopHandler(None, None) - robot.stopHandler(None, None) - # plot results - plotFromDict(log_dict, args) - # TODO: add some math to analyze path precision diff --git a/python/examples/point_impedance_control.py b/python/examples/point_impedance_control.py index 84801cf8cf749aca9d86a7f575986992ce1da7c7..f8c5527a65a6864dba07f88d1c54e3a916fee9dd 100644 --- a/python/examples/point_impedance_control.py +++ b/python/examples/point_impedance_control.py @@ -11,14 +11,7 @@ from ur_simple_control.clik.clik import getClikArgs, getClikController, moveL, m from ur_simple_control.managers import getMinimalArgParser, ControlLoopManager, RobotManager from ur_simple_control.basics.basics import moveJPI -####################################################################### -# arguments # -####################################################################### - def getArgs(): - ####################################################################### - # generic arguments # - ####################################################################### parser = getMinimalArgParser() parser = getClikArgs(parser) parser.add_argument('--kp', type=float, \ @@ -36,10 +29,6 @@ def getArgs(): return args -####################################################################### -# control loop # -####################################################################### - # feedforward velocity, feedback position and force for impedance def controller(): pass @@ -60,7 +49,8 @@ def controlLoopPointImpedance(args, q_init, controller, robot : RobotManager, i, #wrench = np.average(np.array(past_data['wrench']), axis=0) # first-order low pass filtering instead # beta is a smoothing coefficient, smaller values smooth more, has to be in [0,1] - wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + #wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + wrench = args.beta * wrench + (1 - args.beta) * np.average(np.array(past_data['wrench']), axis=0) if not args.z_only: Z = np.diag(np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0])) else: @@ -108,7 +98,8 @@ def controlLoopCartesianPointImpedance(args, Mtool_init, clik_controller, robot wrench = robot.getWrench() log_item['wrench_raw'] = wrench.reshape((6,)) save_past_dict['wrench'] = copy.deepcopy(wrench) - wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + #wrench = args.beta * wrench + (1 - args.beta) * past_data['wrench'][-1] + wrench = args.beta * wrench + (1 - args.beta) * np.average(np.array(past_data['wrench']), axis=0) # good generic values #Z = np.diag(np.array([1.0, 1.0, 2.0, 1.0, 1.0, 1.0])) # but let's stick to the default for now @@ -145,13 +136,7 @@ def controlLoopCartesianPointImpedance(args, Mtool_init, clik_controller, robot if __name__ == "__main__": - ####################################################################### - # software setup # - ####################################################################### - args = getArgs() - if args.debug_prints: - print("you will get a lot of stuff printed out, as requested") clikController = getClikController(args) robot = RobotManager(args) @@ -183,29 +168,14 @@ if __name__ == "__main__": controlLoop = partial(controlLoopCartesianPointImpedance, args, Mtool_init, clikController, robot) loop_manager = ControlLoopManager(robot, controlLoop, args, save_past_dict, log_item) - - #moveJ(args, robot, dmp.pos.reshape((6,))) - # and now we can actually run loop_manager.run() - #plotFromDict(log_dict, args) - # plotting is now initiated in stophandler because then we get the plot - # even if we end sooner - #loop_manager.stopHandler(None, None) - # TODO: add some math to analyze path precision - if not args.pinocchio_only: robot.stopRobot() if args.save_log: + robot.log_manager.saveLog() robot.log_manager.plotAllControlLoops() if args.visualize_manipulator: robot.killManipulatorVisualizer() - - if args.save_log: - robot.log_manager.saveLog() - - - - #loop_manager.stopHandler(None, None) diff --git a/python/examples/test_movej.py b/python/examples/test_movej.py deleted file mode 100644 index be853026c99557a5533ae34e0542f8a42fa640d2..0000000000000000000000000000000000000000 --- a/python/examples/test_movej.py +++ /dev/null @@ -1,204 +0,0 @@ - -import pinocchio as pin -import numpy as np -import matplotlib.pyplot as plt -import copy -import argparse -import time -from functools import partial -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 clik 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, moveL, moveUntilContact -from ur_simple_control.clik.clik_trajectory_following import map2DPathTo3DPlane, clikCartesianPathIntoJointPath -from ur_simple_control.managers import ControlLoopManager, RobotManager -from ur_simple_control.util.calib_board_hacks import calibratePlane, getSpeedInDirectionOfN -from ur_simple_control.basics.basics import moveJ -import matplotlib - -####################################################################### -# arguments # -####################################################################### - -def getArgs(): - ####################################################################### - # generic arguments # - ####################################################################### - 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 - parser.add_argument('--simulation', action=argparse.BooleanOptionalAction, - help="whether you are running the UR simulator. \ - NOTE: doesn't actually work because it's not a physics simulator", \ - default=False) - parser.add_argument('--pinocchio-only', action=argparse.BooleanOptionalAction, - help="whether you want to just integrate with pinocchio.\ - NOTE: doesn't actually work because it's not a physics simulator", \ - default=False) - parser.add_argument('--visualize-manipulator', action=argparse.BooleanOptionalAction, - help="whether you want to visualize the manipulator and workspace with meshcat", default=False) - parser.add_argument('--real-time-plotting', action=argparse.BooleanOptionalAction, - help="whether you want to have some real-time matplotlib graphs (parts of log_dict you select)", default=False) - parser.add_argument('--gripper', action=argparse.BooleanOptionalAction, \ - help="whether you're using the gripper", default=False) - parser.add_argument('--acceleration', type=float, \ - help="robot's joints acceleration. scalar positive constant, \ - max 1.7, and default 0.4. \ - BE CAREFUL WITH THIS. the urscript doc says this is 'lead axis acceleration'.\ - TODO: check what this means", default=0.3) - parser.add_argument('--speed-slider', type=float,\ - help="cap robot's speed with the speed slider \ - to something between 0 and 1, 1.0 by default because for dmp. \ - BE CAREFUL WITH THIS.", default=1.0) - parser.add_argument('--max-iterations', type=int, \ - help="maximum allowable iteration number (it runs at 500Hz)", default=500000) - ####################################################################### - # your controller specific arguments # - ####################################################################### - # not applicable here, but leaving it in the case it becomes applicable - # it's also in the robot manager even though it shouldn't be - parser.add_argument('--past-window-size', type=int, \ - help="how many timesteps of past data you want to save", default=5) - parser.add_argument('--goal-error', type=float, \ - help="the final position error you are happy with. NOTE: not used here", \ - default=1e-3) - # TODO: test the interaction of this and the overall demo - parser.add_argument('--tikhonov-damp', type=float, \ - help="damping scalar in tikhonov regularization.\ - This is used when generating the joint trajectory from the drawing.", \ - default=1e-2) - # TODO add the rest - 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 # - ############################# - parser.add_argument('--temporal-coupling', action=argparse.BooleanOptionalAction, \ - help="whether you want to use temporal coupling", default=True) - parser.add_argument('--kp', type=float, \ - help="proportial control constant for position errors", \ - default=1.0) - parser.add_argument('--kv', type=float, \ - help="damping in impedance control", \ - default=0.001) - parser.add_argument('--tau0', type=float, \ - help="total time needed for trajectory. if you use temporal coupling,\ - you can still follow the path even if it's too fast", \ - default=5) - parser.add_argument('--gamma-nominal', type=float, \ - help="positive constant for tuning temporal coupling: the higher,\ - the fast the return rate to nominal tau", \ - default=1.0) - parser.add_argument('--gamma-a', type=float, \ - help="positive constant for tuning temporal coupling, potential term", \ - default=0.5) - parser.add_argument('--eps-tc', type=float, \ - help="temporal coupling term, should be small", \ - default=0.001) - parser.add_argument('--alpha', type=float, \ - help="force feedback proportional coefficient", \ - default=0.05) - parser.add_argument('--beta', type=float, \ - help="low-pass filter beta parameter", \ - default=0.01) - ####################################################################### - # 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.3) - parser.add_argument('--board-height', type=float, \ - help="height of the board (in meters) the robot will write on", \ - default=0.3) - parser.add_argument('--calibration', action=argparse.BooleanOptionalAction, \ - help="whether you want to do calibration", default=False) - parser.add_argument('--draw-new', action=argparse.BooleanOptionalAction, \ - help="whether draw a new picture, or use the saved path path_in_pixels.csv", default=True) - parser.add_argument('--pick_up_marker', action=argparse.BooleanOptionalAction, \ - help=""" - whether the robot should pick up the marker. - NOTE: THIS IS FROM A PREDEFINED LOCATION. - """, default=True) - parser.add_argument('--find-marker-offset', action=argparse.BooleanOptionalAction, \ - help=""" - whether you want to do find marker offset (recalculate TCP - based on the marker""", default=False) - parser.add_argument('--n-calibration-tests', type=int, \ - help="number of calibration tests you want to run", default=10) - parser.add_argument('--clik-goal-error', type=float, \ - help="the clik error you are happy with", default=1e-2) - parser.add_argument('--max-init-clik-iterations', type=int, \ - help="number of max clik iterations to get to the first point", default=10000) - parser.add_argument('--max-running-clik-iterations', type=int, \ - help="number of max clik iterations between path points", default=1000) - parser.add_argument('--debug-prints', action=argparse.BooleanOptionalAction, \ - help="print some debug info", default=False) - - args = parser.parse_args() - if args.gripper and args.simulation: - raise NotImplementedError('Did not figure out how to put the gripper in \ - the simulation yet, sorry :/ . You can have only 1 these flags right now') - return args - - -if __name__ == "__main__": - ####################################################################### - # software setup # - ####################################################################### - - #matplotlib.use('tkagg') - args = getArgs() - if args.debug_prints: - print("you will get a lot of stuff printed out, as requested") - clikController = getClikController(args) - robot = RobotManager(args) - - # calibrate FT first - #wrench_offset = robot.calibrateFT() - - # TODO and NOTE the weight, TCP and inertial matrix needs to be set on the robot - # you already found an API in rtde_control for this, just put it in initialization - # under using/not-using gripper parameters - # ALSO NOTE: to use this you need to change the version inclusions in - # ur_rtde due to a bug there in the current ur_rtde + robot firmware version - # (the bug is it works with the firmware verion, but ur_rtde thinks it doesn't) - # here you give what you're saving in the rolling past window - # it's initial value. - # controlLoopManager will populate the queue with these initial values -# save_past_dict = { -# 'wrench' : np.zeros(6), -# } -# # here you give it it's initial value -# log_item = { -# 'qs' : np.zeros(robot.n_arm_joints), -# 'dqs' : np.zeros(robot.n_arm_joints), -# 'wrench_raw' : np.zeros(6), -# 'wrench_used' : np.zeros(6), -# } - q_init = robot.getQ() - -# controlLoop = partial(controlLoopPointImpedance, q_init, controller, robot) -# loop_manager = ControlLoopManager(robot, controlLoop, args, save_past_dict, log_item) - - q_init[5] += 0.1 - moveJ(args, robot, q_init) - # and now we can actually run -# loop_manager.run() - - #plotFromDict(log_dict, args) - # plotting is now initiated in stophandler because then we get the plot - # even if we end sooner - # TODO: add some math to analyze path precision - - - - diff --git a/python/ur_simple_control.egg-info/SOURCES.txt b/python/ur_simple_control.egg-info/SOURCES.txt index 2ee2c2bb928eebc5b4fada560343da2315a9ec36..6ac766121c788ec1d445bbbec43e5015235151f4 100644 --- a/python/ur_simple_control.egg-info/SOURCES.txt +++ b/python/ur_simple_control.egg-info/SOURCES.txt @@ -27,12 +27,9 @@ examples/joint_trajectory.csv examples/path_following_mpc.py examples/path_in_pixels.csv examples/pin_contact3d.py -examples/planar_dragging_via_top_contact_force.py examples/point_impedance_control.py examples/pushing_via_friction_cones.py examples/test_crocoddyl_opt_ctrl.py -examples/test_gripper.py -examples/test_movej.py examples/__pycache__/robotiq_gripper.cpython-310.pyc examples/data/clik_comparison_0.pickle examples/data/clik_comparison_1.pickle diff --git a/python/ur_simple_control/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/__pycache__/__init__.cpython-312.pyc index 6cbe15e807a9d591b4daa2bb718e2ee6f594d68b..e85b1e4e44d05747ce2ca03bebd75077c0d0aa51 100644 Binary files a/python/ur_simple_control/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/__pycache__/managers.cpython-312.pyc b/python/ur_simple_control/__pycache__/managers.cpython-312.pyc index 264baf9e4f1638bebd2db4c6ceb8f873c61fa407..08cab676ac3eb5e9425e00ae79331b2574792e80 100644 Binary files a/python/ur_simple_control/__pycache__/managers.cpython-312.pyc and b/python/ur_simple_control/__pycache__/managers.cpython-312.pyc differ diff --git a/python/ur_simple_control/basics/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/basics/__pycache__/__init__.cpython-312.pyc index ab90bd5b2c4a7c3713769660b0a981284e5218e1..90f7a9633aa4ec8f8144b86339c2c17b3825f0c6 100644 Binary files a/python/ur_simple_control/basics/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/basics/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc b/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc index cc48db49956e5152a92dda0aa88ecd852b9cd0ee..b1e46579879d5b082e636e725db1b2c84e396044 100644 Binary files a/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc and b/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc differ diff --git a/python/ur_simple_control/clik/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/clik/__pycache__/__init__.cpython-312.pyc index ae377943be843c28581a25e2d49812d836316b2d..f8bb567b50b60daa7ddfa22992641874ea904ffb 100644 Binary files a/python/ur_simple_control/clik/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/clik/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/clik/clik.py b/python/ur_simple_control/clik/clik.py index 7612509c01d7059305d4df9f10b48707790071a7..fa1f575f175253673488f0d4adfd5aefa7f9ad77 100644 --- a/python/ur_simple_control/clik/clik.py +++ b/python/ur_simple_control/clik/clik.py @@ -56,7 +56,7 @@ def getClikArgs(parser): help="number of max clik iterations to get to the first point", default=10000) parser.add_argument('--max-running-clik-iterations', type=int, \ help="number of max clik iterations between path points", default=1000) - parser.add_argument('--viz-path', action=argparse.BooleanOptionalAction, \ + parser.add_argument('--viz-test-path', action=argparse.BooleanOptionalAction, \ help="number of max clik iterations between path points", default=False) return parser @@ -204,6 +204,7 @@ def moveUntilContactControlLoop(args, robot : RobotManager, speed, clik_controll # compute the joint velocities. qd = clik_controller(J, speed) robot.sendQd(qd) + log_item['qs'] = q.reshape((robot.model.nq,)) log_item['wrench'] = wrench.reshape((6,)) return breakFlag, {}, log_item @@ -220,8 +221,6 @@ def moveUntilContact(args, robot, speed): log_item = {'wrench' : np.zeros(6)} loop_manager = ControlLoopManager(robot, controlLoop, args, {}, log_item) loop_manager.run() - # TODO: remove, this isn't doing anything - time.sleep(0.01) print("Collision detected!!") def moveL(args, robot : RobotManager, goal_point): @@ -389,9 +388,13 @@ def clikCartesianPathIntoJointPath(args, robot, path, \ moveL(sim_args, sim_robot, pose) # loop logs is a dict, dict keys list preserves input order new_q = sim_robot.q.copy() - if args.viz_path: - robot.updateViz(sim_robot.q, sim_robot.T_w_e) - time.sleep(0.02) + if args.viz_test_path: + # look into visualize.py for details on what's available + T_w_e = sim_robot.getT_w_e() + robot.updateViz({"q" : new_q, + "T_w_e" : T_w_e, + "point" : T_w_e.copy()}) + time.sleep(0.005) qs.append(new_q[:6]) # plot this on the real robot diff --git a/python/ur_simple_control/dmp/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/dmp/__pycache__/__init__.cpython-312.pyc index 7ea4cdffdac18fc953fc8e9b815ef847824199c3..2f9b2824737ebed52a6982e9abb3a3a070851fdd 100644 Binary files a/python/ur_simple_control/dmp/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/dmp/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/dmp/__pycache__/dmp.cpython-312.pyc b/python/ur_simple_control/dmp/__pycache__/dmp.cpython-312.pyc index 625e7f6cada01c136ee98a287887a025f5e1de34..af096cd0eb3d6119386239959f2086f901c097ba 100644 Binary files a/python/ur_simple_control/dmp/__pycache__/dmp.cpython-312.pyc and b/python/ur_simple_control/dmp/__pycache__/dmp.cpython-312.pyc differ diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py index d09e663410af99c37417d74fc01345c2aef2e1c4..7e2693edabb58c152f3f0480c5c5839db3cbe1d8 100644 --- a/python/ur_simple_control/managers.py +++ b/python/ur_simple_control/managers.py @@ -17,6 +17,8 @@ from ur_simple_control.util.logging_utils import LogManager from multiprocessing import Process, Queue import argparse from sys import exc_info +from types import NoneType +from os import getpid """ general notes @@ -98,7 +100,7 @@ def getMinimalArgParser(): parser.add_argument('--speed-slider', type=float,\ help="cap robot's speed with the speed slider \ to something between 0 and 1, 0.5 by default \ - BE CAREFUL WITH THIS.", default=0.5) + BE CAREFUL WITH THIS.", default=1.0) parser.add_argument("--start-from-current-pose", action=argparse.BooleanOptionalAction, \ help="if connected to the robot, read the current pose and set it as the initial pose for the robot. \ very useful and convenient when running simulation before running on real", \ @@ -191,6 +193,7 @@ class ControlLoopManager: def __init__(self, robot_manager, controlLoop, args, save_past_item, log_item): signal.signal(signal.SIGINT, self.stopHandler) + self.pid = getpid() self.max_iterations = args.max_iterations self.robot_manager = robot_manager self.controlLoop = controlLoop @@ -270,7 +273,6 @@ class ControlLoopManager: #if key not in self.log_dict.keys(): # raise KeyError("you need to provide log items you promised!") # break - #self.robot_manager.stopHandler(None, None) self.log_dict[key].append(log_item[key]) # TODO: do it this way if running on the real robot. @@ -281,10 +283,8 @@ class ControlLoopManager: # don't send what wasn't ready if self.args.visualize_manipulator: if self.robot_manager.manipulator_visualizer_queue.qsize() < 5: - self.robot_manager.manipulator_visualizer_queue.put_nowait({"q" : self.robot_manager.q, - "T_w_e" : self.robot_manager.getT_w_e()}) -# if self.args.debug_prints: -# print("manipulator_visualizer_queue size status:", self.robot_manager.manipulator_visualizer_queue.qsize()) + self.robot_manager.updateViz({"q" : self.robot_manager.q, + "T_w_e" : self.robot_manager.getT_w_e()}) if self.args.real_time_plotting: # don't put new stuff in if it didn't handle the previous stuff. # it's a plotter, who cares if it's late. @@ -323,15 +323,13 @@ class ControlLoopManager: if self.args.debug_prints: print("i am putting befree in plotter_queue to stop the real time visualizer") self.plotter_queue.put_nowait("befree") - # just fcks me over when i call again from stopHandler, - # and that really needs to work - #self.plotter_queue.close() - # give it time to become free - #time.sleep(0.1) - # TODO: check if this is causing a delay - self.real_time_plotter_process.terminate() - if self.args.debug_prints: - print("terminated real_time_plotter_process") + try: + self.real_time_plotter_process.terminate() + if self.args.debug_prints: + print("terminated real_time_plotter_process") + except AttributeError: + if self.args.debug_prints: + print("real-time-plotter is dead already") if self.args.save_log: self.robot_manager.log_manager.storeControlLoopRun(self.log_dict, self.controlLoop.func.__name__, self.final_iteration) @@ -346,6 +344,12 @@ class ControlLoopManager: nor does stopJ do anything, so it goes to freedriveMode and then exits it, which actually stops ur robots at least. """ + # when we make a new process, it inherits signal handling. + # which means we call this more than once. + # and that could lead to race conditions. + # but if we exit immediatealy it's fine + if getpid() != self.pid: + return print('sending 300 speedjs full of zeros and exiting') for i in range(300): vel_cmd = np.zeros(self.robot_manager.model.nv) @@ -360,41 +364,53 @@ class ControlLoopManager: self.robot_manager.rtde_control.freedriveMode() if self.args.save_log: + print("saving log") + # this does not get run if you exited with ctrl-c + self.robot_manager.log_manager.storeControlLoopRun(self.log_dict, self.controlLoop.func.__name__, self.final_iteration) self.robot_manager.log_manager.saveLog() - # set kill command and join visualization processes - # TODO: actually send them a SIGINT and a SIGKILL if necessary + + #################################### + # kill real-time-plotter process # + #################################### if self.args.real_time_plotting: if self.args.debug_prints: print("i am putting befree in plotter_queue to stop the real time visualizer") self.plotter_queue.put_nowait("befree") - self.real_time_plotter_process.terminate() - if self.args.debug_prints: - print("terminated real_time_plotter_process") - - #self.real_time_plotter_process.kill() - #self.real_time_plotter_process.terminate() + # for good measure + time.sleep(0.1) + #if type(self.real_time_plotter_process) != NoneType: + try: + self.real_time_plotter_process.terminate() + if self.args.debug_prints: + print("terminated real_time_plotter_process") + except AttributeError: + if self.args.debug_prints: + print("real-time-plotter is dead already") + ############################# + # kill visualizer process # + ############################# if self.args.visualize_manipulator: if self.args.debug_prints: print("i am putting befree in manipulator to stop the manipulator visualizer") self.robot_manager.manipulator_visualizer_queue.put_nowait({"befree" : "befree"}) - #time.sleep(1) - #self.robot_manager.manipulator_visualizer_process.join() - self.robot_manager.manipulator_visualizer_process.terminate() - if self.args.debug_prints: - print("terminated manipulator_visualizer_process") - #self.robot_manager.manipulator_visualizer_process.kill() -# self.robot_manager.manipulator_visualizer_process.terminate() -# if self.args.debug_prints: -# print("joined manipulator_visualizer_process") -# self.robot_manager.manipulator_visualizer_process.kill() -# if self.args.debug_prints: -# print("joined manipulator_visualizer_process") - - # let's plot the loop you stopped - for key in self.log_dict: - self.log_dict[key] = np.array(self.log_dict[key]) - plotFromDict(self.log_dict, self.final_iteration, self.args) + # for good measure + time.sleep(0.1) + #if type(self.robot_manager.manipulator_visualizer_process) != NoneType: + try: + self.robot_manager.manipulator_visualizer_process.terminate() + if self.args.debug_prints: + print("terminated manipulator_visualizer_process") + except AttributeError: + if self.args.debug_prints: + print("real-time-plotter is dead already") + + # let's plot the loop you stopped. + # --> but then we stop here and can't kill the program with ctrl-c + # and that is insufferable. if you want the plot open the log + #for key in self.log_dict: + # self.log_dict[key] = np.array(self.log_dict[key]) + #plotFromDict(self.log_dict, self.final_iteration, self.args) if not self.args.pinocchio_only: self.robot_manager.rtde_control.endFreedriveMode() @@ -432,7 +448,8 @@ class RobotManager: def __init__(self, args): self.args = args self.pinocchio_only = args.pinocchio_only - self.simulation = args.simulation + if self.args.simulation: + self.args.robot_ip = "127.0.0.1" # load model # collision and visual models are none if args.visualize == False self.robot_name = args.robot @@ -524,8 +541,7 @@ class RobotManager: # same note as v_q, but it's a_q. self.a_q = np.zeros(self.model.nv) # initialize and connect the interfaces - self.simulation = args.simulation - if (not args.simulation) and (not args.pinocchio_only) : + if not args.pinocchio_only: # NOTE: you can't connect twice, so you can't have more than one RobotManager. # if this produces errors like "already in use", and it's not already in use, # try just running your new program again. it could be that the socket wasn't given @@ -534,21 +550,16 @@ class RobotManager: self.rtde_control = RTDEControlInterface(args.robot_ip) self.rtde_receive = RTDEReceiveInterface(args.robot_ip) self.rtde_io = RTDEIOInterface(args.robot_ip) + self.rtde_io.setSpeedSlider(args.speed_slider) # NOTE: the force/torque sensor just has large offsets for no reason, # and you need to minus them to have usable readings. # we provide this with calibrateFT self.wrench_offset = self.calibrateFT() - - elif not args.pinocchio_only: - self.rtde_control = RTDEControlInterface("127.0.0.1") - self.rtde_receive = RTDEReceiveInterface("127.0.0.1") - self.rtde_io = RTDEIOInterface("127.0.0.1") + else: + self.wrench_offset = np.zeros(6) self.speed_slider = args.speed_slider - if not args.pinocchio_only: - self.rtde_io.setSpeedSlider(args.speed_slider) - # TODO: make general for other robots if args.pinocchio_only and args.start_from_current_pose: self.rtde_receive = RTDEReceiveInterface(args.robot_ip) q = self.rtde_receive.getActualQ() @@ -595,8 +606,6 @@ class RobotManager: def getWrench(self): return self.wrench.copy() - - def calibrateFT(self): """ calibrateFT @@ -1000,7 +1009,7 @@ class RobotManager: else: raise NotImplementedError("freedrive function only written for ur5e") - def updateViz(self, q : np.ndarray, T_w_e : pin.SE3): + def updateViz(self, viz_dict : dict): """ updateViz --------- @@ -1009,8 +1018,7 @@ class RobotManager: because it shouldn't - it should only update the visualizer """ if self.args.visualize_manipulator: - self.manipulator_visualizer_queue.put_nowait({"q" : q, - "T_w_e" : T_w_e}) + self.manipulator_visualizer_queue.put_nowait(viz_dict) else: if self.args.debug_prints: print("you didn't select viz") diff --git a/python/ur_simple_control/robot_descriptions/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/robot_descriptions/__pycache__/__init__.cpython-312.pyc index edcc33b2f845e875e6c72b885b613763e7842272..115adf251a4a1d068f6e90128ff1d264ae83feaa 100644 Binary files a/python/ur_simple_control/robot_descriptions/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/robot_descriptions/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/robot_descriptions/urdf/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/robot_descriptions/urdf/__pycache__/__init__.cpython-312.pyc index 6ad113721478b35bbd5d12ab47516bb8e525a9e8..ed7affc060b9b7a1b0d62afa8325a68bc6052396 100644 Binary files a/python/ur_simple_control/robot_descriptions/urdf/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/robot_descriptions/urdf/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/util/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/util/__pycache__/__init__.cpython-312.pyc index 213dacf5bf110b7ab38111a6ec0543745a646fef..388924771e93bdbcaeb01a6e13de839f5951627b 100644 Binary files a/python/ur_simple_control/util/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/util/__pycache__/__init__.cpython-312.pyc differ diff --git a/python/ur_simple_control/util/__pycache__/calib_board_hacks.cpython-312.pyc b/python/ur_simple_control/util/__pycache__/calib_board_hacks.cpython-312.pyc index 35be94c5823e1b794d4e860079a820d5833a2d05..a2f53dd7883b0d046ebcfd3d6c264f4d33166614 100644 Binary files a/python/ur_simple_control/util/__pycache__/calib_board_hacks.cpython-312.pyc and b/python/ur_simple_control/util/__pycache__/calib_board_hacks.cpython-312.pyc differ diff --git a/python/ur_simple_control/util/__pycache__/draw_path.cpython-312.pyc b/python/ur_simple_control/util/__pycache__/draw_path.cpython-312.pyc index 2c3ff4b5d9548da33d7e17b7acc30f20acf90019..6ec614f01aa747b47466c72e79dea207cfadecc0 100644 Binary files a/python/ur_simple_control/util/__pycache__/draw_path.cpython-312.pyc and b/python/ur_simple_control/util/__pycache__/draw_path.cpython-312.pyc differ 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 18daa3d1842a6fdb72871be0062ebe3e3a1de737..d2682d9cab363be813bfcb81248a50cd94b44b00 100644 Binary files a/python/ur_simple_control/util/__pycache__/get_model.cpython-312.pyc and b/python/ur_simple_control/util/__pycache__/get_model.cpython-312.pyc differ diff --git a/python/ur_simple_control/util/__pycache__/logging_utils.cpython-312.pyc b/python/ur_simple_control/util/__pycache__/logging_utils.cpython-312.pyc index a3adaa98121287f462d494b5f9a5e08e370b88be..0813aa172509b934f2449f5619bc850471096527 100644 Binary files a/python/ur_simple_control/util/__pycache__/logging_utils.cpython-312.pyc and b/python/ur_simple_control/util/__pycache__/logging_utils.cpython-312.pyc differ diff --git a/python/ur_simple_control/util/logging_utils.py b/python/ur_simple_control/util/logging_utils.py index 948637e31866e25fdedb6a586cd9be16ecf795c7..31c7e15b6f676658deaac11a78c5881d8fedf361 100644 --- a/python/ur_simple_control/util/logging_utils.py +++ b/python/ur_simple_control/util/logging_utils.py @@ -89,11 +89,15 @@ class LogManager: (including the data and the args). Uses default (un)pickling. """ - log_file = open(save_file_path, 'rb') - tmp_dict = pickle.load(log_file) - log_file.close() - self.__dict__.clear() - self.__dict__.update(tmp_dict) + if os.path.exists(save_file_path): + log_file = open(save_file_path, 'rb') + tmp_dict = pickle.load(log_file) + log_file.close() + self.__dict__.clear() + self.__dict__.update(tmp_dict) + else: + print("you didn't give me a correct save_file_path! exiting") + exit() def plotAllControlLoops(self): if not self.are_logs_vectorized_flag: diff --git a/python/ur_simple_control/visualize/__pycache__/__init__.cpython-312.pyc b/python/ur_simple_control/visualize/__pycache__/__init__.cpython-312.pyc index 68ab8a11a32c6a9fe3e82b02daf0c28c1d668557..ef461beee0f1f95021b9d5b6ac3926ed0403e6b3 100644 Binary files a/python/ur_simple_control/visualize/__pycache__/__init__.cpython-312.pyc and b/python/ur_simple_control/visualize/__pycache__/__init__.cpython-312.pyc differ 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 1dfd5ff4a37a424e79548a590c7d32a9aa37bd4d..6a671df2b112d230043f2a4c639f5bcbd088f65b 100644 Binary files a/python/ur_simple_control/visualize/__pycache__/visualize.cpython-312.pyc and b/python/ur_simple_control/visualize/__pycache__/visualize.cpython-312.pyc differ diff --git a/python/ur_simple_control/visualize/manipulator_comparison_visualizer.py b/python/ur_simple_control/visualize/manipulator_comparison_visualizer.py index 9537c1573b4cd6ace510792eeb22e1f23c9d07f1..064d192f8de93a3156ae6978bce6b2ce1984b66a 100644 --- a/python/ur_simple_control/visualize/manipulator_comparison_visualizer.py +++ b/python/ur_simple_control/visualize/manipulator_comparison_visualizer.py @@ -44,13 +44,13 @@ class ManipulatorComparisonManager: self.logm1 = LogManager(None) self.logm1.loadLog(args.log_file1) else: - print("you did not give me a valid path, exiting") + print("you did not give me a valid path for log1, exiting") exit() if os.path.exists(args.log_file2): self.logm2 = LogManager(None) self.logm2.loadLog(args.log_file2) else: - print("you did not give me a valid path, exiting") + print("you did not give me a valid path for log2, exiting") exit() self.manipulator_visualizer_cmd_queue = Queue() diff --git a/python/ur_simple_control/visualize/meshcat_viewer_wrapper/visualizer.py b/python/ur_simple_control/visualize/meshcat_viewer_wrapper/visualizer.py index 82ebdf4f9eadebab5fa660fe7a0bb697dcc2fb0e..781dfc3de0c97693b0ce006dba3b64c24f11ab2d 100644 --- a/python/ur_simple_control/visualize/meshcat_viewer_wrapper/visualizer.py +++ b/python/ur_simple_control/visualize/meshcat_viewer_wrapper/visualizer.py @@ -38,6 +38,9 @@ class MeshcatVisualizer(PMV): url=None, autoclean=False, ): + # there will be times when i just want to drop in points + # which will never be changed + self.n_points = 0 if robot is not None: super().__init__(robot.model, robot.collision_model, robot.visual_model) elif model is not None: @@ -52,7 +55,7 @@ class MeshcatVisualizer(PMV): server = None if robot is not None or model is not None: - self.initViewer(loadModel=True, viewer=server) + self.initViewer(loadModel=True, viewer=server, open=True) else: self.viewer = server if server is not None else meshcat.Visualizer() @@ -77,12 +80,24 @@ class MeshcatVisualizer(PMV): material = materialFromColor(color) self.viewer[name].set_object(meshcat.geometry.Ellipsoid(dims), material) + def addPoint(self, point : pin.SE3, radius=5e-3, color=[1, 0, 0, 0.8]): + point_name = f"world/point_{self.n_points}" + self.addSphere(point_name, radius, color) + self.applyConfiguration(point_name, point) + self.n_points += 1 + + def addPath(self, name, path : list[pin.SE3], radius=5e-3, color=[1, 0, 0, 0.8]): + for i, point in enumerate(path): + self.addSphere(f"world/path_{name}_point_{i}", radius, color) + self.applyConfiguration(f"world/path_{name}_point_{i}", point) + def applyConfiguration(self, name, placement): if isinstance(placement, list) or isinstance(placement, tuple): placement = np.array(placement) if isinstance(placement, pin.SE3): - R, p = placement.rotation, placement.translation - T = np.r_[np.c_[R, p], [[0, 0, 0, 1]]] + #R, p = placement.rotation, placement.translation + #T = np.r_[np.c_[R, p], [[0, 0, 0, 1]]] + T = placement.homogeneous elif isinstance(placement, np.ndarray): if placement.shape == (7,): # XYZ-quat R = pin.Quaternion(np.reshape(placement[3:], [4, 1])).matrix() diff --git a/python/ur_simple_control/visualize/visualize.py b/python/ur_simple_control/visualize/visualize.py index 55459a54f7a43dc95cbee1f88453003c0550f1ca..0272ad7c454588e4994d03fa27d3f09c551ef6b9 100644 --- a/python/ur_simple_control/visualize/visualize.py +++ b/python/ur_simple_control/visualize/visualize.py @@ -3,9 +3,9 @@ import matplotlib.pyplot as plt from collections import deque, namedtuple import time import copy -from pinocchio.visualize import MeshcatVisualizer +#from pinocchio.visualize import MeshcatVisualizer # TODO: use wrapped meshcat visualizer to have access to more nifty plotting -#from ur_simple_control.visualize.meshcat_viewer_wrapper.visualizer import MeshcatVisualizer +from ur_simple_control.visualize.meshcat_viewer_wrapper.visualizer import MeshcatVisualizer import meshcat_shapes # tkinter stuff for later reference @@ -162,17 +162,11 @@ def realTimePlotter(args, queue): def manipulatorVisualizer(args, model, collision_model, visual_model, queue): - # for whatever reason the hand-e files don't have/ - # meshcat can't read scaling information. - # so we scale manually - init_target_frame = False - init_ee_frame = False - #meshcat_shapes.frame(viewer["end_effector_target"], opacity=0.5) - # TODO: use wrapped meshcat visualizer to have access to more nifty plotting - #viz = MeshcatVisualizer(model=model, collision_model=collision_model, visual_model=visual_model) - viz = MeshcatVisualizer(model, collision_model, visual_model) - viz.initViewer(open=True) + viz = MeshcatVisualizer(model=model, collision_model=collision_model, visual_model=visual_model) viz.loadViewerModel() + # 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) print("MANIPULATORVISUALIZER: FULLY ONLINE") try: while True: @@ -185,21 +179,13 @@ def manipulatorVisualizer(args, model, collision_model, visual_model, queue): viz.viewer.window.server_proc.wait() break if key == "Mgoal": - # having this via flag is stupid, but i can't - # be bothered with something else rn - if init_target_frame == False: - meshcat_shapes.frame(viz.viewer["Mgoal"], opacity=0.5) - init_target_frame = True viz.viewer["Mgoal"].set_transform(cmd["Mgoal"].homogeneous) if key == "T_w_e": - # having this via flag is stupid, but i can't - # be bothered with something else rn - if init_ee_frame == False: - meshcat_shapes.frame(viz.viewer["T_w_e"], opacity=0.5) - init_ee_frame = True viz.viewer["T_w_e"].set_transform(cmd["T_w_e"].homogeneous) if key == "q": viz.display(cmd["q"]) + if key == "point": + viz.addPoint(cmd["point"]) except KeyboardInterrupt: if args.debug_prints: @@ -389,7 +375,6 @@ def logPlotter(args, log, cmd_queue, ack_queue): # NOTE: this is stupid, i just want to catch the resize event #if not (counter % 50 == 0): if True: - print(counter) canvas.blit(fig.bbox) canvas.flush_events() else: