diff --git a/python/ur_simple_control/visualize/.manipulator_visual_motion_analyzer.py.swp b/python/ur_simple_control/visualize/.manipulator_visual_motion_analyzer.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..ba65be11a0473d207f62e43b83c0564e7d9518bf Binary files /dev/null and b/python/ur_simple_control/visualize/.manipulator_visual_motion_analyzer.py.swp differ diff --git a/python/ur_simple_control/visualize/.visualize.py.swp b/python/ur_simple_control/visualize/.visualize.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..85c39c3b20e714208f92a4c7bc7a2afcfe88cc4e Binary files /dev/null and b/python/ur_simple_control/visualize/.visualize.py.swp differ diff --git a/python/ur_simple_control/visualize/main.py b/python/ur_simple_control/visualize/main.py index 19b36264102f5a3a6e5d31bc079d1cee1815c609..8f380f43380949be9947cf2fa05b47fd9c8ad353 100644 --- a/python/ur_simple_control/visualize/main.py +++ b/python/ur_simple_control/visualize/main.py @@ -30,9 +30,9 @@ ik_env.goal[2] = 0.2 ik_env.render() -ik_env.robot.setJoints(q) -ik_env.robot.calcJacobian() -print(ik_env.robot.p_e) +ik_env.robots[0].setJoints(q) +ik_env.robots[0].calcJacobian() +print(ik_env.robots[0].p_e) #print(type(init_q)) #exit() @@ -43,14 +43,14 @@ controller = invKinm_dampedSquares while True: start = time.time() q = rtde_r.getActualQ() - ik_env.robot.setJoints(q) - ik_env.robot.calcJacobian() - q_dots = controller(ik_env.robot, ik_env.goal) - thetas = np.array([joint.theta for joint in ik_env.robot.joints]) + ik_env.robots[0].setJoints(q) + ik_env.robots[0].calcJacobian() + q_dots = controller(ik_env.robots[0], ik_env.goal) + thetas = np.array([joint.theta for joint in ik_env.robots[0].joints]) ik_env.render() #print(ik_env.robot.p_e.copy()) #print(ik_env.goal) - distance = np.linalg.norm(ik_env.robot.p_e.copy() - ik_env.goal) + distance = np.linalg.norm(ik_env.robots[0].p_e.copy() - ik_env.goal) print(distance) if distance < 0.01: t_start = rtde_c.initPeriod() diff --git a/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py b/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py index 1442111f3213da9bda29de5541d33cb535bb58f7..fe8a6d1f0ce4f9eed36ecc5544ba7d61e4c8af9f 100644 --- a/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py +++ b/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py @@ -18,18 +18,22 @@ from robot_stuff.inv_kinm import * from make_run import makeRun import numpy as np -import sys +# it is the best solution for a particular problem +from collections import namedtuple # needed to communicate with the gui in real time from multiprocessing import Queue +# for local thread which manages local queue (can be made better, +# but again, who cares, all of this is ugly as hell anyway ('cos it's front-end)) +import threading # don't want to refactor yet, but obv # TODO: refactor, have normal names for things # it's just for getting the fps reading while optimizing -import time as ttime +import time # TODO: call update_point function with the current slider value after updating -# stuff like eliipse on/off so that you don't need to move the button to get it +# stuff like elipse on/off so that you don't need to move the button to get it # just call the slider string value to get the current slider value # TODO: finish writing up reseting to the same starting position (joint values) @@ -123,10 +127,11 @@ ManipulatorVisualMotionAnalyzer # so that they have names. the for loop functions the same way, # but you get to know what you have, which might be useful later. class ManipulatorVisualMotionAnalyzer: - def __init__(self, root, queue, data=data): + def __init__(self, root, queue, real_time_flag, **kwargs): # need to put this in the main program, # so you need to pass it here to use it self.root = root + self.real_time_flag = real_time_flag self.root.wm_title("Embedding in Tk") # for real-time updates self.queue = queue @@ -143,24 +148,24 @@ class ManipulatorVisualMotionAnalyzer: #self.SCALING_FACTOR_WIDTH = 0.5 self.SCALING_FACTOR_HEIGHT = 0.3 self.SCALING_FACTOR_WIDTH = 0.3 + # dicts not because they have to be, but just so that + # they are named because that might be useful + # and because names are the only thing keeping horrendous this code together + # TODO: current evil sharing of pointers (thanks python lmao) needs to be deleted + # ofc delete from ik_env, retain here (they're in both spots rn) + # NOTE: you need to do ax.draw(artist) for blitting. so each artist needs to be connected + # to its particular artist. so they can't all be in one dict. + # we'll just increase the dict depth by 1, and add a named tuple to layer 1 (layer of axis) + self.AxisAndArtists = namedtuple("AxAndArtists", "ax artists") + self.axes_and_updating_artists = {} + # TODO: maybe do the same for fixed artists. right now they're saved just to have them on hand + # in case they'll be needed for something + self.fixed_artists = {} + # messes up rotating the 3d plot + # you should catch the event and then draw + # but i aint doing that + self.blit = True - ##################################################### - # LAYOUT OF THE GUI # - # putting plots into: frames -> notebooks -> tabs # - ##################################################### - self.notebook_left = Notebook(root, height=int(self.SCREEN_HEIGHT)) - self.notebook_right = Notebook(root, height=int(self.SCREEN_HEIGHT)) - self.frame_manipulator = Frame(self.notebook_left) - self.frame_manip_graphs = Frame(self.notebook_right) - self.frame_imu = Frame(self.notebook_right) - self.frame_ee = Frame(self.notebook_left) - self.tabs_left = self.notebook_left.add(self.frame_manipulator, text='manipulator') - self.tabs_left = self.notebook_left.add(self.frame_ee, text="end-effector") - self.tabs_right = self.notebook_right.add(self.frame_manip_graphs, text='manipulator-graphs') - self.tabs_right = self.notebook_right.add(self.frame_imu, text="ee-graphs") - self.notebook_left.grid(row=0, column=0, sticky='ew') - self.notebook_right.grid(row=0, column=1, sticky='ew') - ######################## # run related things # ######################## @@ -168,7 +173,7 @@ class ManipulatorVisualMotionAnalyzer: # we won't be generating runs here later self.n_iters = 200 # the word time is used for timing - self.t = np.arange(n_iters) + self.t = np.arange(self.n_iters) # local kinematics integrator # but this thing handles plotting # only plotting needs to be run, so feel free to @@ -178,7 +183,7 @@ class ManipulatorVisualMotionAnalyzer: # all of them in all figures, this is scitzo af bruv self.ik_env = InverseKinematicsEnv() # TODO: do this depending on the number of runs you'll be loading - #self.ik_env.robots.append(Robot_raw(robot_name="no_sim")) + self.ik_env.robots.append(Robot_raw(robot_name="no_sim")) self.ik_env.damping = 25 # putting it into this class so that python remembers it 'cos reasons, whatever # TODO: load this from run log files later @@ -189,30 +194,187 @@ class ManipulatorVisualMotionAnalyzer: # but deliver the same format. # TODO: ensure you're saving AT LEAST what's required here # NOTE: the jacobian svd is computed offline in these - self.ik_env.data.append(makeRun(controller1, ik_env, n_iters, 0)) - self.ik_env.data.append(makeRun(controller2, ik_env, n_iters, 1)) + self.ik_env.data.append(makeRun(self.controller1, self.ik_env, self.n_iters, 0)) + self.ik_env.data.append(makeRun(self.controller2, self.ik_env, self.n_iters, 1)) + # ugly front end code is ugly. + # i hate front end and this is why. + # actual placing of plots in all this comes later because tkinter complains otherwise + ##################################################### + # LAYOUT OF THE GUI # + # putting plots into: frames -> notebooks -> tabs # + ##################################################### + self.notebook_left = Notebook(root, height=int(self.SCREEN_HEIGHT)) + self.notebook_right = Notebook(root, height=int(self.SCREEN_HEIGHT)) + self.frame_manipulator = Frame(self.notebook_left) + self.frame_manip_graphs = Frame(self.notebook_right) + self.frame_imu = Frame(self.notebook_right) + self.frame_ee = Frame(self.notebook_left) + self.tabs_left = self.notebook_left.add(self.frame_manipulator, text='manipulator') + self.tabs_left = self.notebook_left.add(self.frame_ee, text="end-effector") + self.tabs_right = self.notebook_right.add(self.frame_manip_graphs, text='manipulator-graphs') + self.tabs_right = self.notebook_right.add(self.frame_imu, text="ee-graphs") + self.notebook_left.grid(row=0, column=0, sticky='ew') + self.notebook_right.grid(row=0, column=1, sticky='ew') + + ####################################################################### + # PLACING ELEMENTS IN THE GUI # + ####################################################################### + # NOTE: this thing is not used + self.same_starting_position_on_off_var = IntVar() + self.same_starting_position_on_off_var.set(0) + self.same_starting_position_checkbutton= Checkbutton(root, text = "same starting position on/off", + variable = self.same_starting_position_on_off_var, + onvalue = 1, + offvalue = 0, + # command=same_starting_position_cmd, + ) + + # LEFT PANE BELOW MANIP/EE PLOTS + self.frame_below_manipulator_plot = Frame(self.frame_manipulator) + self.frame_below_manipulator_plot.grid(column=0, row=3) + + # set controller 1 + self.frame_controller_menu1 = Frame(self.frame_below_manipulator_plot) + self.controller_string1 = StringVar(self.frame_controller_menu1) + self.controller_string1.set("invKinm_dampedSquares") # default value + self.controller_menu1 = OptionMenu(self.frame_controller_menu1, self.controller_string1, + "invKinmQPSingAvoidE_kI", + "invKinm_Jac_T", + "invKinm_PseudoInv", + "invKinm_dampedSquares", + "invKinm_PseudoInv_half", + "invKinmQP", + "invKinmQPSingAvoidE_kI", + "invKinmQPSingAvoidE_kM", + "invKinmQPSingAvoidManipMax", + ) + self.controller_string1.set("invKinm_dampedSquares") + self.controller_menu1.grid(column=1, row=0) + Label(self.frame_controller_menu1, text="Robot 1 controller:", background='yellow').grid(row=0, column=0, pady=4, padx = 4) + self.frame_controller_menu1.grid(column=0, row=0) + + # set controller 2 + self.frame_controller_menu2 = Frame(self.frame_below_manipulator_plot) + self.controller_string2 = StringVar(self.frame_controller_menu2) + self.controller_menu2 = OptionMenu(self.frame_controller_menu2, self.controller_string2, + "invKinmQPSingAvoidE_kI", + "invKinm_Jac_T", + "invKinm_PseudoInv", + "invKinm_dampedSquares", + "invKinm_PseudoInv_half", + "invKinmQP", + "invKinmQPSingAvoidE_kI", + "invKinmQPSingAvoidE_kM", + "invKinmQPSingAvoidManipMax", + ) + self.controller_string2.set("invKinm_Jac_T") # default value + Label(self.frame_controller_menu1, text="Robot 1 controller:", background='black', foreground='white').grid(row=0, column=0, pady=4, padx = 4) + self.controller_menu2.grid(column=1, row=0) + Label(self.frame_controller_menu2, text="Robot 2 controller:", background='#EE82EE').grid(row=0, column=0, pady=4, padx = 4) + self.frame_controller_menu2.grid(column=0, row=1) + + + self.ellipse_on_off_var = IntVar() + self.ellipse_on_off_var.set(1) + + self.ellipse_checkbutton= Checkbutton(self.frame_below_manipulator_plot, text = "ellipse on/off", + variable = self.ellipse_on_off_var, + onvalue = 1, + offvalue = 0, + command=self.add_remove_ellipse, + ) + self.ellipse_checkbutton.grid(column=1, row=0) + + + self.frame_goal_x = Frame(self.frame_below_manipulator_plot) + Label(self.frame_goal_x, text="goal x").grid(row=0, column=0, pady=4, padx = 4) + self.slider_goal_x = Scale(self.frame_goal_x, from_=-1.0, to=1.0, length=self.SLIDER_SIZE, orient=HORIZONTAL, + command=self.update_goal_x) + self.slider_goal_x.grid(column=1, row=0) + self.frame_goal_x.grid(column=1, row=1) + + self.frame_goal_y = Frame(self.frame_below_manipulator_plot) + Label(self.frame_goal_y, text="goal y").grid(row=0, column=0, pady=4, padx = 4) + self.slider_goal_y = Scale(self.frame_goal_y, from_=-1.0, to=1.0, length=self.SLIDER_SIZE, orient=HORIZONTAL, + command=self.update_goal_y) + self.slider_goal_y.grid(column=1, row=0) + self.frame_goal_y.grid(column=1, row=2) + + + self.frame_goal_z = Frame(self.frame_below_manipulator_plot) + Label(self.frame_goal_z, text="goal z").grid(row=0, column=0, pady=4, padx = 4) + self.slider_goal_z = Scale(self.frame_goal_z, from_=-1.0, to=1.0, length=self.SLIDER_SIZE, orient=HORIZONTAL, + command=self.update_goal_z) + self.slider_goal_z.grid(column=1, row=0) + self.frame_goal_z.grid(column=1, row=3) + + + self.frame_update = Frame(self.frame_manip_graphs) + Label(self.frame_update, text="Time").grid(row=0, column=0, pady=4, padx = 4) + self.slider_update = Scale(self.frame_update, from_=0, to=self.n_iters - 1, length=self.SLIDER_SIZE, orient=HORIZONTAL, + command=self.update_points)#, label="Frequency [Hz]") + self.slider_update.grid(column=1, row=0) + self.frame_update.grid(column=0, row=3) + + self.frame_update2 = Frame(self.frame_imu) + Label(self.frame_update2, text="Time").grid(row=0, column=0, pady=4, padx = 4) + self.slider_update = Scale(self.frame_update2, from_=0, to=self.n_iters - 1, length=self.SLIDER_SIZE, orient=HORIZONTAL, + command=self.update_points)#, label="Frequency [Hz]") + self.slider_update.grid(column=1, row=0) + self.frame_update2.grid(column=0, row=3) + + + self.button_quit = Button(master=self.frame_manip_graphs, text="Quit", command=root.destroy) + self.button_reset = Button(master=self.frame_manip_graphs, text="New run", command=self.reset) + self.button_play = Button(master=self.frame_manip_graphs, text="Play", command=self.play) + self.button_play.grid(column=0, row=4) + self.button_reset.grid(column=0, row=5) + self.button_quit.grid(column=0, row=6) + + self.button_quit2 = Button(master=self.frame_imu, text="Quit", command=root.destroy) + self.button_reset2 = Button(master=self.frame_imu, text="New run", command=self.reset) + self.button_play2 = Button(master=self.frame_imu, text="Play", command=self.play) + self.button_play2.grid(column=0, row=4) + self.button_reset2.grid(column=0, row=5) + self.button_quit2.grid(column=0, row=6) + + self.slider_goal_x.set(self.ik_env.goal[0]) + self.slider_goal_y.set(self.ik_env.goal[1]) + self.slider_goal_z.set(self.ik_env.goal[2]) + + + ################################ + # ALL PLOTS ARE DEFINED HERE # + ################################ # how to add plots will be documented below on an easier example ####################################################################### # UNUSED PLOT # ####################################################################### - self.fig_ee = Figure(figsize=(SCREEN_WIDTH/DPI*SCALING_FACTOR_WIDTH, SCREEN_HEIGHT/DPI*SCALING_FACTOR_HEIGHT), dpi=DPI) + self.fig_ee = Figure(figsize=(self.SCREEN_WIDTH/self.DPI*self.SCALING_FACTOR_WIDTH, self.SCREEN_HEIGHT/self.DPI*self.SCALING_FACTOR_HEIGHT), dpi=self.DPI) self.rec3D_ax = self.fig_ee.add_subplot(projection='3d') self.rec3D_ax.set(xticklabels=[], yticklabels=[], zticklabels=[]) + # tkinterize self.canvas_ee = FigureCanvasTkAgg(self.fig_ee, master=self.frame_ee) self.canvas_ee_widget = self.canvas_ee.get_tk_widget() self.canvas_ee_widget.grid(row=0, column=0) self.canvas_ee._tkcanvas.grid(row=1, column=0) + # draw before getting the background self.canvas_ee.draw() + self.background_ee = self.canvas_ee.copy_from_bbox(self.fig_ee.bbox) + # TODO: append artists to either fixed or updating artists dicts ####################################################################### # MANIPULATOR PLOT # ####################################################################### # robot plot - self.fig_manipulator = Figure(figsize=(SCREEN_WIDTH/DPI*SCALING_FACTOR_WIDTH, SCREEN_HEIGHT/DPI*SCALING_FACTOR_HEIGHT), dpi=DPI) + self.fig_manipulator = Figure(figsize=(self.SCREEN_WIDTH/self.DPI*self.SCALING_FACTOR_WIDTH, self.SCREEN_HEIGHT/self.DPI*self.SCALING_FACTOR_HEIGHT), dpi=self.DPI) + # TODO: fix evil pointer sharing between this class and ik_env self.ik_env.ax = self.fig_manipulator.add_subplot(projection='3d') + # read comment on top of init to see what this is + self.axes_and_updating_artists["ax_manipulators"] = self.AxisAndArtists(self.ik_env.ax, {}) # fix array sizes to be the workspace as that won't change. otherwise it's updated as you go, # and that's impossible to look at. self.ik_env.ax.plot(np.array([0]), np.array([0]), np.array([1.5]), c='b') @@ -226,20 +388,36 @@ class ManipulatorVisualMotionAnalyzer: # but it of course works on a single robot too for robot_index, robot in enumerate(self.ik_env.robots): robot.initDrawing(self.ik_env.ax, self.link_colors[robot_index]) + # this could be named better, but i can't be bothered right now + for i, link in enumerate(robot.lines): + for j, line in enumerate(link): + # constuct a name that unique at least + self.axes_and_updating_artists["ax_manipulators"].artists["robot_" + str(robot_index) + "_link_" + str(i) + "_line_" + str(j)] = line # ee point - # TODO: blit the point because it moves - self.ik_env.p_e_point_plots.append(drawPoint(ik_env.ax, ik_env.data[robot_index]['p_es'][0], 'red', 'o')) + ee_point_plot = drawPoint(self.ik_env.ax, self.ik_env.data[robot_index]['p_es'][0], 'red', 'o') + self.ik_env.p_e_point_plots.append(ee_point_plot) + self.axes_and_updating_artists["ax_manipulators"].artists["ee_point_plot"] = ee_point_plot # plot ee position trajectory. not blitted because it is fixed # TODO: blit it for real-time operation - self.trajectory_plot, = ik_env.ax.plot(ik_env.data[robot_index]['p_es'][:,0], ik_env.data[robot_index]['p_es'][:,1], ik_env.data[robot_index]['p_es'][:,2], color='blue') - trajectory_plots.append(trajectory_plot) + trajectory_plot, = self.ik_env.ax.plot(self.ik_env.data[robot_index]['p_es'][:,0], \ + self.ik_env.data[robot_index]['p_es'][:,1], self.ik_env.data[robot_index]['p_es'][:,2], color='blue') + # TODO stop having shared pointers all over the place, it's evil + self.trajectory_plots.append(trajectory_plot) + if self.real_time_flag: + self.axes_and_updating_artists["ax_manipulators"].artists["trajectory_plot_" + str(robot_index)] = \ + trajectory_plot + raise NotImplementedError("real time ain't implemented yet, sorry") + else: + self.fixed_artists["trajectory_plot_" + str(robot_index)] = trajectory_plot + # goal point # only makes sense for clik, but keep it here anyway, it doesn't hurt # TODO: add a button to turn it off - self.ik_env.goal_point_plot = drawPoint(ik_env.ax, ik_env.goal, 'maroon', '*') + goal_point_plot = drawPoint(self.ik_env.ax, self.ik_env.goal, 'maroon', '*') + self.ik_env.goal_point_plot = goal_point_plot + self.fixed_artists["goal_point_plot"] = goal_point_plot # the manipulability ellipses - # TODO: BLIT THEM for robot_index, robot in enumerate(self.ik_env.robots): radii = 1.0/self.ik_env.data[robot_index]["manip_ell_eigenvals"][0] * 0.1 u = np.linspace(0.0, 2.0 * np.pi, 60) @@ -253,9 +431,15 @@ class ManipulatorVisualMotionAnalyzer: # although, again, primary purpose is to log stuff for later [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], self.ik_env.data[robot_index]["manip_elip_svd_rots"][0]) + self.ik_env.data[robot_index]['p_es'][0] - self.ik_env.ellipsoid_surf_plots.append(self.ik_env.ax.plot_surface(x, y, z, rstride=3, cstride=3, + ellipsoid_surf_plot = self.ik_env.ax.plot_surface(x, y, z, rstride=3, cstride=3, color='pink', linewidth=0.1, - alpha=0.3, shade=True)) + alpha=0.3, shade=True) + self.ik_env.ellipsoid_surf_plots.append(ellipsoid_surf_plot) + # TODO: current evil sharing of pointers (thanks python lmao) needs to be deleted + # ofc delete from ik_env, retain here +# TODO: put back in if possible +# self.axes_and_updating_artists["ax_manipulators"].artists["ellipsoid_surf_plot_"+ str(robot_index)] = \ +# ellipsoid_surf_plot # tkinterize the figure/canvas self.canvas_manipulator = FigureCanvasTkAgg(self.fig_manipulator, master=self.frame_manipulator) @@ -269,68 +453,110 @@ class ManipulatorVisualMotionAnalyzer: self.canvas_manipulator_widget.grid(row=0, column=0) self.canvas_manipulator._tkcanvas.grid(row=1, column=0) # i probably don't need this draw, but who cares - self.canvas_manipulator.draw() + #self.canvas_manipulator.draw() ####################################################################### # manipulability plots # ####################################################################### + # NOTE: code for each plot is replicated, + # and there are more for loops than necessary. + # but honestly this is more readable because you know which subplot you're making and with what. + # TODO: maybe make it automatic later by making tabs etc automatic via dicts. + # but as it stands right now, it's fine, i won't do it unless there is a distinct need for it. # manipulability ellipsoid eigenvalues - self.fig_manip_graphs = Figure(figsize=(SCREEN_WIDTH/DPI*SCALING_FACTOR_WIDTH, SCREEN_HEIGHT/DPI*SCALING_FACTOR_HEIGHT), dpi=DPI) + self.fig_manip_graphs = Figure(figsize=(self.SCREEN_WIDTH/self.DPI*self.SCALING_FACTOR_WIDTH, self.SCREEN_HEIGHT/self.DPI*self.SCALING_FACTOR_HEIGHT), dpi=self.DPI) # NOTE: this ax object lives on in some other matplotlib object # so i don't have to save it - ax = self.fig_manip_graphs.add_subplot(311) - ax.set_title('Manipulability ellipsoid eigenvalues') - ax.grid() - ax.set_xticks([]) + ax_eigens = self.fig_manip_graphs.add_subplot(311) + self.axes_and_updating_artists["ax_eigens"] = self.AxisAndArtists(ax_eigens, {}) + ax_eigens.set_title('Manipulability ellipsoid eigenvalues') + ax_eigens.grid() + ax_eigens.set_xticks([]) self.eigen1_lines = [] self.eigen2_lines = [] self.eigen3_lines = [] - for robot_index, robot in enumerate(ik_env.robots): - eigen1_line, = ax.plot(time, ik_env.data[robot_index]["manip_ell_eigenvals"][:,0], color=link_colors[robot_index]) + + for robot_index, robot in enumerate(self.ik_env.robots): + eigen1_line, = ax_eigens.plot(self.t, \ + self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,0], color=self.link_colors[robot_index]) self.eigen1_lines.append(eigen1_line) - eigen2_line, = ax.plot(time, ik_env.data[robot_index]["manip_ell_eigenvals"][:,1], color=link_colors[robot_index]) + eigen2_line, = ax_eigens.plot(self.t, \ + self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,1], color=self.link_colors[robot_index]) self.eigen2_lines.append(eigen2_line) - eigen3_line, = ax.plot(time, ik_env.data[robot_index]["manip_ell_eigenvals"][:,2], color=link_colors[robot_index]) + eigen3_line, = ax_eigens.plot(self.t, \ + self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,2], color=self.link_colors[robot_index]) self.eigen3_lines.append(eigen3_line) - # TODO: blit this line - self.point_in_time_eigen1_line = ax.axvline(x=0, color='red') + if self.real_time_flag: + # TODO: put it in updating artists, but then also actuall update it + self.axes_and_updating_artists["ax_eigens"].artists["eigen1_line_" + str(robot_index)] = eigen1_line + self.axes_and_updating_artists["ax_eigens"].artists["eigen2_line_" + str(robot_index)] = eigen2_line + self.axes_and_updating_artists["ax_eigens"].artists["eigen3_line_" + str(robot_index)] = eigen3_line + raise NotImplementedError("real time ain't implemented yet, sorry") + else: + self.fixed_artists["eigen1_line_" + str(robot_index)] = eigen1_line + self.fixed_artists["eigen2_line_" + str(robot_index)] = eigen2_line + self.fixed_artists["eigen3_line_" + str(robot_index)] = eigen3_line + self.point_in_time_eigen1_line = ax_eigens.axvline(x=0, color='red', animated=True) + self.axes_and_updating_artists["ax_eigens"].artists["point_in_time_eigen1_line"] = self.point_in_time_eigen1_line # manipulability index (volume of manipulability ellipsoid) - ax = self.fig_manip_graphs.add_subplot(312) - ax.set_title('Manipulability index') - ax.grid() - ax.set_xticks([]) + ax_manips = self.fig_manip_graphs.add_subplot(312) + ax_manips.set_title('Manipulability index') + self.axes_and_updating_artists["ax_manips"] = self.AxisAndArtists(ax_manips, {}) + ax_manips.grid() + ax_manips.set_xticks([]) self.manip_index_lines = [] - for robot_index, robot in enumerate(ik_env.robots): - manip_index_line, = ax.plot(time, ik_env.data[robot_index]['manip_indeces'], color=link_colors[robot_index]) + for robot_index, robot in enumerate(self.ik_env.robots): + manip_index_line, = ax_manips.plot(self.t, self.ik_env.data[robot_index]['manip_indeces'], color=self.link_colors[robot_index]) self.manip_index_lines.append(manip_index_line) - self.point_in_time_manip_index_line = ax.axvline(x=0, color='red') + if self.real_time_flag: + # TODO: put it in updating artists, but then also actuall update it + self.axes_and_updating_artists["ax_manips"].artists["manip_index_line_" + str(robot_index)] = manip_index_line + raise NotImplementedError("real time ain't implemented yet, sorry") + else: + self.fixed_artists["manip_index_line_" + str(robot_index)] = manip_index_line + self.point_in_time_manip_index_line = ax_manips.axvline(x=0, color='red', animated=True) + self.axes_and_updating_artists["ax_manips"].artists["point_in_time_manip_index_line"] = self.point_in_time_manip_index_line # dist to goal (this could be/should be elsewhere) - ax = self.fig_manip_graphs.add_subplot(313) - ax.set_title('Distance to goal') - ax.grid() - ax.set_xlabel('iter') + ax_goal_dists = self.fig_manip_graphs.add_subplot(313) + ax_goal_dists.set_title('Distance to goal') + self.axes_and_updating_artists["ax_goal_dists"] = self.AxisAndArtists(ax_goal_dists, {}) + ax_goal_dists.grid() + ax_goal_dists.set_xlabel('iter') self.dist_to_goal_lines = [] - for robot_index, robot in enumerate(ik_env.robots): - self.dist_to_goal_line, = ax.plot(time, ik_env.data[robot_index]['dists_to_goal'], color=link_colors[robot_index]) - dist_to_goal_lines.append(dist_to_goal_line) - # TODO: blit this line - self.point_in_time_dist_to_goal_line = ax.axvline(x=0, color='red') - # tkinterize canvas + for robot_index, robot in enumerate(self.ik_env.robots): + dist_to_goal_line, = ax_goal_dists.plot(self.t, self.ik_env.data[robot_index]['dists_to_goal'], \ + color=self.link_colors[robot_index]) + self.dist_to_goal_lines.append(dist_to_goal_line) + if self.real_time_flag: + # TODO: put it in updating artists, but then also actuall update it + self.axes_and_updating_artists["ax_goal_dists"].artists["dist_to_goal_line" + str(robot_index)] = \ + dist_to_goal_line + raise NotImplementedError("real time ain't implemented yet, sorry") + else: + self.fixed_artists["dist_to_goal_line" + str(robot_index)] = dist_to_goal_line + self.point_in_time_dist_to_goal_line = ax_goal_dists.axvline(x=0, color='red', animated=True) + self.axes_and_updating_artists["ax_goal_dists"].artists["point_in_time_dist_to_goal_line"] = \ + self.point_in_time_dist_to_goal_line + + # tkinterize canvas for the whole figure (all subplots) self.canvas_manip_graphs = FigureCanvasTkAgg(self.fig_manip_graphs, master=self.frame_manip_graphs) + self.canvas_manip_graphs.draw() + # save background for blitting + self.background_manip_graphs = self.canvas_manip_graphs.copy_from_bbox(self.fig_manip_graphs.bbox) # put matplotlib toolbar below the plot self.canvas_manip_graphs_widget = self.canvas_manip_graphs.get_tk_widget() self.canvas_manip_graphs_widget.grid(row=0, column=0) self.canvas_manip_graphs._tkcanvas.grid(row=1, column=0) - self.canvas_manip_graphs.draw() + #self.canvas_manip_graphs.draw() ####################################################################### # IMU plots # ####################################################################### - self.fig_imu = Figure(figsize=(SCREEN_WIDTH/DPI*SCALING_FACTOR_WIDTH, SCREEN_HEIGHT/DPI*SCALING_FACTOR_HEIGHT), dpi=DPI) + self.fig_imu = Figure(figsize=(self.SCREEN_WIDTH/self.DPI*self.SCALING_FACTOR_WIDTH, self.SCREEN_HEIGHT/self.DPI*self.SCALING_FACTOR_HEIGHT), dpi=self.DPI) self.v_x_lines = [] self.v_y_lines = [] self.v_z_lines = [] @@ -340,16 +566,22 @@ class ManipulatorVisualMotionAnalyzer: ax_v_x = self.fig_imu.add_subplot(321) ax_v_x.grid() + self.axes_and_updating_artists["ax_v_x"] = self.AxisAndArtists(ax_v_x, {}) ax_v_y = self.fig_imu.add_subplot(322) ax_v_y.grid() + self.axes_and_updating_artists["ax_v_y"] = self.AxisAndArtists(ax_v_y, {}) ax_v_z = self.fig_imu.add_subplot(323) ax_v_z.grid() + self.axes_and_updating_artists["ax_v_z"] = self.AxisAndArtists(ax_v_z, {}) ax_omega_x = self.fig_imu.add_subplot(324) ax_omega_x.grid() + self.axes_and_updating_artists["ax_omega_x"] = self.AxisAndArtists(ax_omega_x, {}) ax_omega_y = self.fig_imu.add_subplot(325) ax_omega_y.grid() + self.axes_and_updating_artists["ax_omega_y"] = self.AxisAndArtists(ax_omega_y, {}) ax_omega_z = self.fig_imu.add_subplot(326) ax_omega_z.grid() + self.axes_and_updating_artists["ax_omega_z"] = self.AxisAndArtists(ax_omega_z, {}) ax_v_x.set_title('Linear velocity x') ax_v_y.set_title('Linear velocity y') ax_v_z.set_title('Linear velocity z') @@ -362,178 +594,80 @@ class ManipulatorVisualMotionAnalyzer: ax_omega_x.set_xticks([]) ax_omega_y.set_xticks([]) ax_omega_z.set_xticks([]) - for robot_index, robot in enumerate(ik_env.robots): + for robot_index, robot in enumerate(self.ik_env.robots): v_x_line, = ax_v_x.plot(self.t, self.ik_env.data[robot_index]["vs"][:,0], color=self.link_colors[robot_index]) v_y_line, = ax_v_y.plot(self.t, self.ik_env.data[robot_index]["vs"][:,1], color=self.link_colors[robot_index]) v_z_line, = ax_v_z.plot(self.t, self.ik_env.data[robot_index]["vs"][:,2], color=self.link_colors[robot_index]) - omega_x_line, = ax_omega_x.plot(self.t, self.ik_env.data[robot_index]["vs"][:,3], color=self.link_colors[robot_index]) - omega_y_line, = ax_omega_y.plot(self.t, self.ik_env.data[robot_index]["vs"][:,4], color=self.link_colors[robot_index]) - omega_z_line, = ax_omega_z.plot(self.t, self.ik_env.data[robot_index]["vs"][:,5], color=self.link_colors[robot_index]) + omega_x_line, = ax_omega_x.plot(self.t, \ + self.ik_env.data[robot_index]["vs"][:,3], color=self.link_colors[robot_index]) + omega_y_line, = ax_omega_y.plot(self.t, \ + self.ik_env.data[robot_index]["vs"][:,4], color=self.link_colors[robot_index]) + omega_z_line, = ax_omega_z.plot(self.t, \ + self.ik_env.data[robot_index]["vs"][:,5], color=self.link_colors[robot_index]) self.v_x_lines.append(v_x_line) self.v_y_lines.append(v_y_line) self.v_z_lines.append(v_z_line) self.omega_x_lines.append(omega_x_line) self.omega_y_lines.append(omega_y_line) self.omega_z_lines.append(omega_z_line) - - # TODO: blit these - self.point_in_time_ax_v_x_line = ax_v_x.axvline(x=0, color='red') - self.point_in_time_ax_v_y_line = ax_v_y.axvline(x=0, color='red') - self.point_in_time_ax_v_z_line = ax_v_z.axvline(x=0, color='red') - self.point_in_time_ax_omega_x_line = ax_omega_x.axvline(x=0, color='red') - self.point_in_time_ax_omega_y_line = ax_omega_y.axvline(x=0, color='red') - self.point_in_time_ax_omega_z_line = ax_omega_z.axvline(x=0, color='red') + if self.real_time_flag: + # TODO: put it in updating artists, but then also actuall update it + self.axes_and_updating_artists["ax_v_x"].artists["v_x_line" + str(robot_index)] = v_x_line + self.axes_and_updating_artists["ax_v_z"].artists["v_y_line" + str(robot_index)] = v_y_line + self.axes_and_updating_artists["ax_v_z"].artists["v_z_line" + str(robot_index)] = v_z_line + self.axes_and_updating_artists["ax_omega_x"].artists["omega_x_line" + str(robot_index)] = omega_x_line + self.axes_and_updating_artists["ax_omega_x"].artists["omega_y_line" + str(robot_index)] = omega_y_line + self.axes_and_updating_artists["ax_omega_x"].artists["omega_z_line" + str(robot_index)] = omega_z_line + raise NotImplementedError("real time ain't implemented yet, sorry") + else: + self.fixed_artists["v_x_line" + str(robot_index)] = v_x_line + self.fixed_artists["v_y_line" + str(robot_index)] = v_y_line + self.fixed_artists["v_z_line" + str(robot_index)] = v_z_line + self.fixed_artists["omega_x_line" + str(robot_index)] = omega_x_line + self.fixed_artists["omega_y_line" + str(robot_index)] = omega_y_line + self.fixed_artists["omega_z_line" + str(robot_index)] = omega_z_line + + self.point_in_time_ax_v_x_line = ax_v_x.axvline(x=0, color='red', animated=True) + self.point_in_time_ax_v_y_line = ax_v_y.axvline(x=0, color='red', animated=True) + self.point_in_time_ax_v_z_line = ax_v_z.axvline(x=0, color='red', animated=True) + self.point_in_time_ax_omega_x_line = ax_omega_x.axvline(x=0, color='red', animated=True) + self.point_in_time_ax_omega_y_line = ax_omega_y.axvline(x=0, color='red', animated=True) + self.point_in_time_ax_omega_z_line = ax_omega_z.axvline(x=0, color='red', animated=True) + self.axes_and_updating_artists["ax_v_x"].artists["point_in_time_ax_v_x_line"] = self.point_in_time_ax_v_x_line + self.axes_and_updating_artists["ax_v_z"].artists["point_in_time_ax_v_y_line"] = self.point_in_time_ax_v_y_line + self.axes_and_updating_artists["ax_v_z"].artists["point_in_time_ax_v_z_line"] = self.point_in_time_ax_v_z_line + self.axes_and_updating_artists["ax_omega_x"].artists["point_in_time_ax_omega_x_line"] = \ + self.point_in_time_ax_omega_x_line + self.axes_and_updating_artists["ax_omega_x"].artists["point_in_time_ax_omega_y_line"] = \ + self.point_in_time_ax_omega_y_line + self.axes_and_updating_artists["ax_omega_x"].artists["point_in_time_ax_omega_z_line"] = \ + self.point_in_time_ax_omega_z_line self.canvas_imu = FigureCanvasTkAgg(self.fig_imu, master=self.frame_imu) + self.canvas_imu.draw() + self.background_imu = self.canvas_imu.copy_from_bbox(self.fig_imu.bbox) self.canvas_imu_widget = self.canvas_manip_graphs.get_tk_widget() self.canvas_imu_widget.grid(row=0, column=0) self.canvas_imu._tkcanvas.grid(row=1, column=0) - self.canvas_imu.draw() + #self.canvas_imu.draw() # i don't even remember what these toolbars are lol # pack_toolbar=False will make it easier to use a layout manager later on. - toolbar_manipulator = NavigationToolbar2Tk(canvas_manipulator, frame_manipulator, pack_toolbar=False) - toolbar_manipulator.update() - toolbar_manipulator.grid(column=0, row=2) - toolbar_manip_graphs = NavigationToolbar2Tk(canvas_manip_graphs, frame_manip_graphs, pack_toolbar=False) - toolbar_manip_graphs.update() - toolbar_manip_graphs.grid(column=0, row=2) - toolbar_ee = NavigationToolbar2Tk(canvas_ee, frame_ee, pack_toolbar=False) - toolbar_ee.update() - toolbar_ee.grid(column=0, row=2) - toolbar_imu = NavigationToolbar2Tk(canvas_imu, frame_imu, pack_toolbar=False) - toolbar_imu.update() - toolbar_imu.grid(column=0, row=2) - - - -# NOTE: this thing is not used -same_starting_position_on_off_var = IntVar() -same_starting_position_on_off_var.set(0) -same_starting_position_checkbutton= Checkbutton(root, text = "same starting position on/off", - variable = same_starting_position_on_off_var, - onvalue = 1, - offvalue = 0, -# command=same_starting_position_cmd, - ) - - -####################################################################### -# PLACING ELEMENTS IN THE GUI # -####################################################################### - # TODO put this into init - -# LEFT PANE BELOW MANIP/EE PLOTS -frame_below_manipulator_plot = Frame(frame_manipulator) -frame_below_manipulator_plot.grid(column=0, row=3) - -# set controller 1 -frame_controller_menu1 = Frame(frame_below_manipulator_plot) -controller_string1 = StringVar(frame_controller_menu1) -controller_string1.set("invKinm_dampedSquares") # default value -controller_menu1 = OptionMenu(frame_controller_menu1, controller_string1, - "invKinmQPSingAvoidE_kI", - "invKinm_Jac_T", - "invKinm_PseudoInv", - "invKinm_dampedSquares", - "invKinm_PseudoInv_half", - "invKinmQP", - "invKinmQPSingAvoidE_kI", - "invKinmQPSingAvoidE_kM", - "invKinmQPSingAvoidManipMax", - ) -controller_string1.set("invKinm_dampedSquares") -controller_menu1.grid(column=1, row=0) -Label(frame_controller_menu1, text="Robot 1 controller:", background='yellow').grid(row=0, column=0, pady=4, padx = 4) -frame_controller_menu1.grid(column=0, row=0) - -# set controller 2 -frame_controller_menu2 = Frame(frame_below_manipulator_plot) -controller_string2 = StringVar(frame_controller_menu2) -controller_menu2 = OptionMenu(frame_controller_menu2, controller_string2, - "invKinmQPSingAvoidE_kI", - "invKinm_Jac_T", - "invKinm_PseudoInv", - "invKinm_dampedSquares", - "invKinm_PseudoInv_half", - "invKinmQP", - "invKinmQPSingAvoidE_kI", - "invKinmQPSingAvoidE_kM", - "invKinmQPSingAvoidManipMax", - ) -controller_string2.set("invKinm_Jac_T") # default value -Label(frame_controller_menu1, text="Robot 1 controller:", background='black', foreground='white').grid(row=0, column=0, pady=4, padx = 4) -controller_menu2.grid(column=1, row=0) -Label(frame_controller_menu2, text="Robot 2 controller:", background='#EE82EE').grid(row=0, column=0, pady=4, padx = 4) -frame_controller_menu2.grid(column=0, row=1) - - -ellipse_on_off_var = IntVar() -ellipse_on_off_var.set(1) - -ellipse_checkbutton= Checkbutton(frame_below_manipulator_plot, text = "ellipse on/off", - variable = ellipse_on_off_var, - onvalue = 1, - offvalue = 0, - command=add_remove_ellipse, - ) -ellipse_checkbutton.grid(column=1, row=0) - - -frame_goal_x = Frame(frame_below_manipulator_plot) -Label(frame_goal_x, text="goal x").grid(row=0, column=0, pady=4, padx = 4) -slider_goal_x = Scale(frame_goal_x, from_=-1.0, to=1.0, length=SLIDER_SIZE, orient=HORIZONTAL, - command=update_goal_x) -slider_goal_x.grid(column=1, row=0) -frame_goal_x.grid(column=1, row=1) - -frame_goal_y = Frame(frame_below_manipulator_plot) -Label(frame_goal_y, text="goal y").grid(row=0, column=0, pady=4, padx = 4) -slider_goal_y = Scale(frame_goal_y, from_=-1.0, to=1.0, length=SLIDER_SIZE, orient=HORIZONTAL, - command=update_goal_y) -slider_goal_y.grid(column=1, row=0) -frame_goal_y.grid(column=1, row=2) - - -frame_goal_z = Frame(frame_below_manipulator_plot) -Label(frame_goal_z, text="goal z").grid(row=0, column=0, pady=4, padx = 4) -slider_goal_z = Scale(frame_goal_z, from_=-1.0, to=1.0, length=SLIDER_SIZE, orient=HORIZONTAL, - command=update_goal_z) -slider_goal_z.grid(column=1, row=0) -frame_goal_z.grid(column=1, row=3) - - -frame_update = Frame(frame_manip_graphs) -Label(frame_update, text="Time").grid(row=0, column=0, pady=4, padx = 4) -slider_update = Scale(frame_update, from_=0, to=n_iters - 1, length=SLIDER_SIZE, orient=HORIZONTAL, - command=update_points)#, label="Frequency [Hz]") -slider_update.grid(column=1, row=0) -frame_update.grid(column=0, row=3) - -frame_update2 = Frame(frame_imu) -Label(frame_update2, text="Time").grid(row=0, column=0, pady=4, padx = 4) -slider_update = Scale(frame_update2, from_=0, to=n_iters - 1, length=SLIDER_SIZE, orient=HORIZONTAL, - command=update_points)#, label="Frequency [Hz]") -slider_update.grid(column=1, row=0) -frame_update2.grid(column=0, row=3) - - -button_quit = Button(master=frame_manip_graphs, text="Quit", command=root.destroy) -button_reset = Button(master=frame_manip_graphs, text="New run", command=reset) -button_reset.grid(column=0, row=4) -button_quit.grid(column=0, row=5) - -button_quit2 = Button(master=frame_imu, text="Quit", command=root.destroy) -button_reset2 = Button(master=frame_imu, text="New run", command=reset) -button_reset2.grid(column=0, row=4) -button_quit2.grid(column=0, row=5) - -update_points(0) -slider_goal_x.set(ik_env.goal[0]) -slider_goal_y.set(ik_env.goal[1]) -slider_goal_z.set(ik_env.goal[2]) - - + self.toolbar_manipulator = NavigationToolbar2Tk(self.canvas_manipulator, self.frame_manipulator, pack_toolbar=False) + self.toolbar_manipulator.update() + self.toolbar_manipulator.grid(column=0, row=2) + self.toolbar_manip_graphs = NavigationToolbar2Tk(self.canvas_manip_graphs, self.frame_manip_graphs, pack_toolbar=False) + self.toolbar_manip_graphs.update() + self.toolbar_manip_graphs.grid(column=0, row=2) + self.toolbar_ee = NavigationToolbar2Tk(self.canvas_ee, self.frame_ee, pack_toolbar=False) + self.toolbar_ee.update() + self.toolbar_ee.grid(column=0, row=2) + self.toolbar_imu = NavigationToolbar2Tk(self.canvas_imu, self.frame_imu, pack_toolbar=False) + self.toolbar_imu.update() + self.toolbar_imu.grid(column=0, row=2) + + # update once to finish initialization + self.update_points(0) ####################################################################### # functions for widgets to control the plots # @@ -549,78 +683,106 @@ slider_goal_z.set(ik_env.goal[2]) # you define what needs to happen to plots in Figure below, # and call canvas.draw def update_points(self, new_val): - start = ttime.time() - #fig_manipulator.canvas.restore_region(background_manipulator) - self.canvas_manipulator.restore_region(self.background_manipulator) + start = time.time() + if self.blit: + self.canvas_manipulator.restore_region(self.background_manipulator) + # always blit the rest + self.canvas_ee.restore_region(self.background_ee) + self.canvas_manip_graphs.restore_region(self.background_manip_graphs) + self.canvas_imu.restore_region(self.background_imu) index = int(np.floor(float(new_val))) # ee plot here, but NOTE: UNUSED + # all these are in lists as that's what the line plot wants, + # despite the fact that we have single points + self.point_in_time_eigen1_line.set_xdata([self.t[index]]) + self.point_in_time_manip_index_line.set_xdata([self.t[index]]) + self.point_in_time_dist_to_goal_line.set_xdata([self.t[index]]) + self.point_in_time_ax_v_x_line.set_xdata([self.t[index]]) + self.point_in_time_ax_v_y_line.set_xdata([self.t[index]]) + self.point_in_time_ax_v_z_line.set_xdata([self.t[index]]) + self.point_in_time_ax_omega_x_line.set_xdata([self.t[index]]) + self.point_in_time_ax_omega_y_line.set_xdata([self.t[index]]) + self.point_in_time_ax_omega_z_line.set_xdata([self.t[index]]) + self.ik_env.ax.set_title(str(index) + 'th iteration toward goal') # animate 3d manipulator for robot_index, robot in enumerate(self.ik_env.robots): self.ik_env.robots[robot_index].setJoints(self.ik_env.data[robot_index]["qs"][index]) self.ik_env.robots[robot_index].drawStateAnim() - - # NEW AND BROKEN - for link in robot.lines: - for line in link: - self.ik_env.ax.draw_artist(line) - # all these are in lists as that's what the line plot wants, - # despite the fact that we have single points - self.point_in_time_eigen1_line.set_xdata([time[index]]) - self.point_in_time_manip_index_line.set_xdata([time[index]]) - self.point_in_time_dist_to_goal_line.set_xdata([time[index]]) - self.point_in_time_ax_v_x_line.set_xdata([time[index]]) - self.point_in_time_ax_v_y_line.set_xdata([time[index]]) - self.point_in_time_ax_v_z_line.set_xdata([time[index]]) - self.point_in_time_ax_omega_x_line.set_xdata([time[index]]) - self.point_in_time_ax_omega_y_line.set_xdata([time[index]]) - self.point_in_time_ax_omega_z_line.set_xdata([time[index]]) - - # ellipsoid update - radii = 1.0/self.ik_env.data[robot_index]["manip_ell_eigenvals"][index] * 0.1 - u = np.linspace(0.0, 2.0 * np.pi, 60) - v = np.linspace(0.0, np.pi, 60) - x = radii[0] * np.outer(np.cos(u), np.sin(v)) - y = radii[1] * np.outer(np.sin(u), np.sin(v)) - z = radii[2] * np.outer(np.ones_like(u), np.cos(v)) - for i in range(len(x)): - for j in range(len(x)): - [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], self.ik_env.data[robot_index]["manip_elip_svd_rots"][index]) + self.ik_env.data[robot_index]['p_es'][index] +# for link in robot.lines: +# for line in link: +# self.ik_env.ax.draw_artist(line) + self.ik_env.p_e_point_plots[robot_index].set_data([self.ik_env.data[robot_index]['p_es'][index][0]], [self.ik_env.data[robot_index]['p_es'][index][1]]) + self.ik_env.p_e_point_plots[robot_index].set_3d_properties([self.ik_env.data[robot_index]['p_es'][index][2]]) if self.ellipse_on_off_var.get(): + self.blit = False try: self.ik_env.ellipsoid_surf_plots[robot_index].remove() except ValueError: pass + + # ellipsoid update + radii = 1.0/self.ik_env.data[robot_index]["manip_ell_eigenvals"][index] * 0.1 + u = np.linspace(0.0, 2.0 * np.pi, 60) + v = np.linspace(0.0, np.pi, 60) + x = radii[0] * np.outer(np.cos(u), np.sin(v)) + y = radii[1] * np.outer(np.sin(u), np.sin(v)) + z = radii[2] * np.outer(np.ones_like(u), np.cos(v)) + for i in range(len(x)): + for j in range(len(x)): + [x[i,j],y[i,j],z[i,j]] = \ + np.dot([x[i,j],y[i,j],z[i,j]], self.ik_env.data[robot_index]["manip_elip_svd_rots"][index]) \ + + self.ik_env.data[robot_index]['p_es'][index] self.ik_env.ellipsoid_surf_plots[robot_index] = self.ik_env.ax.plot_surface(x, y, z, rstride=3, cstride=3, color='pink', linewidth=0.1, alpha=0.3, shade=True) - - self.ik_env.p_e_point_plots[robot_index].set_data([ik_env.data[robot_index]['p_es'][index][0]], [ik_env.data[robot_index]['p_es'][index][1]]) - self.ik_env.p_e_point_plots[robot_index].set_3d_properties([ik_env.data[robot_index]['p_es'][index][2]]) - # TODO: blit the rest - canvas_manipulator.blit(fig_manipulator.bbox) - canvas_manipulator.flush_events() - canvas_manip_graphs.draw() - # non blitted (bad) - canvas_imu.draw() - self.canvas_ee.draw() + else: + self.blit = True + + # now draw all updating artists all at once + # for whatever reason it does not update robot lines, so i have that above + for ax_key in self.axes_and_updating_artists: + for artist_key in self.axes_and_updating_artists[ax_key].artists: + self.axes_and_updating_artists[ax_key].ax.draw_artist(\ + self.axes_and_updating_artists[ax_key].artists[artist_key]) + + if self.blit: + self.canvas_manipulator.blit(self.fig_manipulator.bbox) + self.canvas_manipulator.flush_events() + if not self.blit: + self.canvas_manipulator.draw() + # always blit the other ones, this is just because of the surf plot + self.canvas_ee.blit(self.fig_ee.bbox) + self.canvas_ee.flush_events() + self.canvas_manip_graphs.blit(self.fig_manip_graphs.bbox) + self.canvas_manip_graphs.flush_events() + self.canvas_imu.blit(self.fig_imu.bbox) + self.canvas_imu.flush_events() +# self.canvas_imu.draw() +# self.canvas_ee.draw() # TODO update may not be needed as we're going by slider here - root.update() - end = ttime.time() + self.root.update() + end = time.time() print("time per update:", end - start) print("fps", 1 / (end - start)) + def drawAll(self): + self.canvas_ee.draw() + self.canvas_manipulator.draw() + self.canvas_manip_graphs.draw() + self.canvas_imu.draw() + def update_goal_x(self, new_val): goal_x = float(new_val) self.ik_env.goal[0] = goal_x self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]]) self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]]) - self.canvas_ee.draw() +# self.canvas_ee.draw() self.canvas_manipulator.draw() - self.canvas_manip_graphs.draw() +# self.canvas_manip_graphs.draw() # TODO update may not be needed as we're going by slider here self.root.update() @@ -629,9 +791,9 @@ slider_goal_z.set(ik_env.goal[2]) self.ik_env.goal[1] = goal_y self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]]) self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]]) - self.canvas_ee.draw() +# self.canvas_ee.draw() self.canvas_manipulator.draw() - self.canvas_manip_graphs.draw() +# self.canvas_manip_graphs.draw() # TODO update may not be needed as we're going by slider here self.root.update() @@ -640,58 +802,69 @@ slider_goal_z.set(ik_env.goal[2]) self.ik_env.goal[2] = goal_z self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]]) self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]]) - self.canvas_ee.draw() +# self.canvas_ee.draw() self.canvas_manipulator.draw() - self.canvas_manip_graphs.draw() +# self.canvas_manip_graphs.draw() # TODO update may not be needed as we're going by slider here self.root.update() + def drawAndUpdateBackground(self): + self.drawAll() + self.background_ee = self.canvas_ee.copy_from_bbox(self.fig_ee.bbox) + self.background_manipulator = self.canvas_manipulator.copy_from_bbox(self.fig_manipulator.bbox) + self.background_manip_graphs = self.canvas_manip_graphs.copy_from_bbox(self.fig_manip_graphs.bbox) + self.background_imu = self.canvas_imu.copy_from_bbox(self.fig_imu.bbox) -# TODO fix - def reset(): - ik_env.reset() + def reset(self): + self.ik_env.reset() # ik_env.goal_point_plot.remove() # ik_env.goal_point_plot = drawPoint(ik_env.ax, ik_env.goal, 'red', 'o') - # print(controller_string1.get()) - # print(controller_string2.get()) - controller1 = getController(controller_string1.get()) - controller2 = getController(controller_string2.get()) - controllers = [controller1, controller2] - for robot_index, robot in enumerate(ik_env.robots): - ik_env.data.append(makeRun(controllers[robot_index], ik_env, n_iters, robot_index)) - trajectory_plots[robot_index].set_data(ik_env.data[robot_index]['p_es'][:,0], ik_env.data[robot_index]['p_es'][:,1]) - trajectory_plots[robot_index].set_3d_properties(ik_env.data[robot_index]['p_es'][:,2]) - eigen1_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,0]) - eigen2_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,1]) - eigen3_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,2]) - manip_index_lines[robot_index].set_ydata(ik_env.data[robot_index]['manip_indeces']) - dist_to_goal_lines[robot_index].set_ydata(ik_env.data[robot_index]['dists_to_goal']) - update_points(0) - canvas_ee.draw() - canvas_manipulator.draw() - canvas_manip_graphs.draw() - root.update() - - def play(): - pass + self.controller1 = getController(self.controller_string1.get()) + self.controller2 = getController(self.controller_string2.get()) + controllers = [self.controller1, self.controller2] + for robot_index, robot in enumerate(self.ik_env.robots): + self.ik_env.data.append(makeRun(controllers[robot_index], self.ik_env, self.n_iters, robot_index)) + self.trajectory_plots[robot_index].set_data(self.ik_env.data[robot_index]['p_es'][:,0], self.ik_env.data[robot_index]['p_es'][:,1]) + self.trajectory_plots[robot_index].set_3d_properties(self.ik_env.data[robot_index]['p_es'][:,2]) + self.eigen1_lines[robot_index].set_ydata(self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,0]) + self.eigen2_lines[robot_index].set_ydata(self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,1]) + self.eigen3_lines[robot_index].set_ydata(self.ik_env.data[robot_index]["manip_ell_eigenvals"][:,2]) + self.manip_index_lines[robot_index].set_ydata(self.ik_env.data[robot_index]['manip_indeces']) + self.dist_to_goal_lines[robot_index].set_ydata(self.ik_env.data[robot_index]['dists_to_goal']) + self.update_points(0) + self.drawAndUpdateBackground() + self.root.update() + +# TODO: use the same API you use for real-time plotting: +# --> just manually put things into the queue here + def play(self): + for i in range(self.n_iters): + self.update_points(i) # ellipse on/off - def add_remove_ellipse(): + def add_remove_ellipse(self): + # this just deletes them le mao + # for artist_key in self.axes_and_updating_artists["ax_manipulators"].artists: + # if "robot" in artist_key: + # self.axes_and_updating_artists["ax_manipulators"].artists[artist_key].set_animated(bool(self.ellipse_on_off_var)) + try: - for robot_index, robot in enumerate(ik_env.robots): - ik_env.ellipsoid_surf_plots[robot_index].remove() + for robot_index, robot in enumerate(self.ik_env.robots): + self.ik_env.ellipsoid_surf_plots[robot_index].remove() except ValueError: pass + self.drawAndUpdateBackground() + self.root.update() -if name == "__main__": +if __name__ == "__main__": queue = Queue() root = Tk() - gui = ManipulatorVisualMotionAnalyzer(root, queue) + gui = ManipulatorVisualMotionAnalyzer(root, queue, False, data=None) - # have it 'cos from tkinter import * + # have mainloop 'cos from tkinter import * mainloop() # alternative if someone complains #root.mainloop() diff --git a/python/ur_simple_control/visualize/robot_stuff/InverseKinematics.py b/python/ur_simple_control/visualize/robot_stuff/InverseKinematics.py index 9cd579d94725f7e951d9a585bbc5869f95604d50..b6c453967b5d9955d19f933e7bd2e47fc5ba9c3e 100644 --- a/python/ur_simple_control/visualize/robot_stuff/InverseKinematics.py +++ b/python/ur_simple_control/visualize/robot_stuff/InverseKinematics.py @@ -23,9 +23,11 @@ class InverseKinematicsEnv: print('env created') self.chill_reset = False # TODO write a convenience dh_parameter loading function - self.robot = Robot_raw(robot_name="no_sim") - self.robots = [self.robot] - self.init_qs_robot = [] + #self.robot = Robot_raw(robot_name="no_sim") + #self.robots = [self.robot] + #self.init_qs_robot = [] + self.robots = [Robot_raw(robot_name="no_sim")] + self.init_qs_robots = [] self.damping = 5 self.error_vec = None self.n_of_points_done = 0 @@ -67,7 +69,7 @@ class InverseKinematicsEnv: def simpleStep(self, q_dots, damping, index): - self.robot.forwardKinmViaPositions(q_dots / self.damping, damping) + self.robots[index].forwardKinmViaPositions(q_dots / self.damping, damping) self.n_of_tries_for_point += 1 # done = False # if error_test(self.robot.p_e, self.goal): @@ -117,15 +119,15 @@ class InverseKinematicsEnv: # initialize to a random starting state and check whether it makes any sense thetas = [] - for joint in self.robot.joints: + for joint in self.robots[0].joints: thetas.append(6.28 * np.random.random() - 3.14) - self.robot.forwardKinmViaPositions(thetas, 1) + self.robots[0].forwardKinmViaPositions(thetas, 1) if self.chill_reset == True: sensibility_check = False while not sensibility_check: thetas = [] - for joint in self.robot.joints: + for joint in self.robots[0].joints: thetas.append(6.28 * np.random.random() - 3.14) self.robot.forwardKinmViaPositions(thetas , 1) if calculateManipulabilityIndex(self.robot) > 0.15: @@ -133,10 +135,13 @@ class InverseKinematicsEnv: # for i, joint in enumerate(self.robots[robot_index].joints): # joint.theta = self.robots[0].joints[i].theta + for robot_index in range(1, len(self.robots)): + for i, joint in enumerate(self.robots[robot_index].joints): + joint.theta = self.robots[0].joints[i].theta # NOTE: not needed and i'm not fixing _get_obs for more robots - obs = self._get_obs() - return obs +# obs = self._get_obs() +# return obs def render(self, mode='human', width=500, height=500): try: @@ -155,22 +160,22 @@ class InverseKinematicsEnv: plt.xlim([-1.5,1.5]) plt.ylim([-0.5,1.5]) color_link = 'black' - self.robot.initDrawing(self.ax, color_link) + self.robots[0].initDrawing(self.ax, color_link) self.drawingInited = True plt.pause(0.1) # put this here for good measure - self.robot.drawStateAnim() + self.robots[0].drawStateAnim() self.bg = self.fig.canvas.copy_from_bbox(self.fig.bbox) # manual blitting basically # restore region self.fig.canvas.restore_region(self.bg) # updating all the artists (set new properties (position bla)) - self.robot.drawStateAnim() + self.robots[0].drawStateAnim() # now you need to manually draw all the artist (otherwise you update everything) # thank god that's just lines, all in a list. # btw, that should definitely be a dictionary, not a list, # this makes the code fully unreadable (although correct). - for link in self.robot.lines: + for link in self.robots[0].lines: for line in link: self.ax.draw_artist(line) self.fig.canvas.blit(self.fig.bbox) diff --git a/python/ur_simple_control/visualize/robot_stuff/__pycache__/InverseKinematics.cpython-310.pyc b/python/ur_simple_control/visualize/robot_stuff/__pycache__/InverseKinematics.cpython-310.pyc index c59cab0f7519bb21e35ad76ebfa41a84b0376333..3fd6e4c1b57dbd18d122b40fa6d9a98e2a34fbde 100644 Binary files a/python/ur_simple_control/visualize/robot_stuff/__pycache__/InverseKinematics.cpython-310.pyc and b/python/ur_simple_control/visualize/robot_stuff/__pycache__/InverseKinematics.cpython-310.pyc differ diff --git a/python/ur_simple_control/visualize/robot_stuff/__pycache__/forw_kinm.cpython-310.pyc b/python/ur_simple_control/visualize/robot_stuff/__pycache__/forw_kinm.cpython-310.pyc index 8d2d9b38d7d0ce710da387e407cfcc3cab8e0f3f..9bf21a63a8d2e7f40aea156cae95fc80c0768c7a 100644 Binary files a/python/ur_simple_control/visualize/robot_stuff/__pycache__/forw_kinm.cpython-310.pyc and b/python/ur_simple_control/visualize/robot_stuff/__pycache__/forw_kinm.cpython-310.pyc differ diff --git a/python/ur_simple_control/visualize/robot_stuff/forw_kinm.py b/python/ur_simple_control/visualize/robot_stuff/forw_kinm.py index 0a54f807779e36f9c913ea72e29e149c5dfd516e..39a2c6960cbd5e86a801c9ad1f764392f3a7e42d 100644 --- a/python/ur_simple_control/visualize/robot_stuff/forw_kinm.py +++ b/python/ur_simple_control/visualize/robot_stuff/forw_kinm.py @@ -133,14 +133,14 @@ class Robot_raw: z_hat = self.joints[j].HomMat[0:3,2] p = self.joints[j].HomMat[0:3,3] - #line_x, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'r')#, animated=True) - #line_y, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'g')#, animated=True) - #line_z, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'b')#, animated=True) - #line_p, = self.ax.plot(np.array([]),np.array([]),np.array([]), self.color_link)#, animated=True) - line_x, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'r', animated=True) - line_y, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'g', animated=True) - line_z, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'b', animated=True) - line_p, = self.ax.plot(np.array([]),np.array([]),np.array([]), self.color_link, animated=True) + line_x, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'r')#, animated=True) + line_y, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'g')#, animated=True) + line_z, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'b')#, animated=True) + line_p, = self.ax.plot(np.array([]),np.array([]),np.array([]), self.color_link)#, animated=True) + #line_x, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'r', animated=True) + #line_y, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'g', animated=True) + #line_z, = self.ax.plot(np.array([]),np.array([]),np.array([]), 'b', animated=True) + #line_p, = self.ax.plot(np.array([]),np.array([]),np.array([]), self.color_link, animated=True) self.lines += [[line_x, line_y, line_z, line_p]] avg_link_lenth += self.joints[j].d + self.joints[j].r