diff --git a/python/ur_simple_control/__pycache__/managers.cpython-312.pyc b/python/ur_simple_control/__pycache__/managers.cpython-312.pyc index e8f0cf9924bbd4c123fcdc9cf58e2b3c93cdaf56..c40c23c490c43a9b9001a93bc44c2fce0a62027b 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__/basics.cpython-312.pyc b/python/ur_simple_control/basics/__pycache__/basics.cpython-312.pyc index 82aa642f4eee74e77dad389ccccdaa2651892031..45e09e3e1cb3ddfb458602f0e07a7f0aa3eee846 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/basics/basics.py b/python/ur_simple_control/basics/basics.py index 47977c2bfe829a356d1256c1170df6910239d235..8fd4b848a21b2b630645a4ddcc4eb220b5cbc727 100644 --- a/python/ur_simple_control/basics/basics.py +++ b/python/ur_simple_control/basics/basics.py @@ -63,6 +63,15 @@ def moveJP(args, robot, q_desired): print("MoveJP done: convergence achieved, reached destionation!") +# NOTE: it's probably a good idea to generalize this for different references: +# - only qs +# - qs and vs +# - whatever special case +# it could be better to have separate functions, whatever makes the code as readable +# as possible. +# also NOTE: there is an argument to be made for pre-interpolating the reference. +# this is because joint positions will be more accurate. +# if we integrate them with interpolated velocities. def jointTrajFollowingPDControlLoop(stop_at_final : bool, robot: RobotManager, reference, i, past_data): breakFlag = False save_past_dict = {} @@ -74,29 +83,50 @@ def jointTrajFollowingPDControlLoop(stop_at_final : bool, robot: RobotManager, r t = i * robot.dt # take the future (next) one # TODO: turn this into interpolation - t_index = int(np.ceil(t / reference['dt'])) + t_index_lower = int(np.floor(t / reference['dt'])) + t_index_upper = int(np.ceil(t / reference['dt'])) + # TODO: move to a different function later - if t_index >= len(reference['qs']): - t_index = len(reference['qs']) - 1 - if stop_at_final: - reference['vs'][t_index] = np.zeros(len(reference['vs'][t_index])) + if t_index_upper >= len(reference['qs']) - 1: + t_index_upper = len(reference['qs']) - 1 + q_ref = reference['qs'][t_index_upper] + if (t_index_upper == len(reference['qs']) - 1) and stop_at_final: + v_ref = np.zeros(len(reference['vs'][t_index_upper])) + else: + v_ref = reference['vs'][t_index_upper] # TODO: check if that's really the last - #if t_index == len(reference['qs']) - 1: + #if t_index_upper == len(reference['qs']) - 1: # breakFlag = True - # TODO NOTE TODO TODO: remove/change - if (t_index == len(reference['qs']) - 1) and \ - (np.linalg.norm(q - reference['qs'][-1]) < 1e-2): + # TODO NOTE TODO TODO: move under stop/don't stop at final argument + if (t_index_upper == len(reference['qs']) - 1) and \ + (np.linalg.norm(q - reference['qs'][-1]) < 1e-2) and \ + (np.linalg.norm(v) < 1e-2): breakFlag = True - error_q = reference['qs'][t_index] - q - error_v = reference['vs'][t_index] - v + # TODO: set q_refs and v_refs once + if (t_index_upper < len(reference['qs']) - 1) and (not breakFlag): + #angle = (reference['qs'][t_index_upper] - reference['qs'][t_index_lower]) / reference['dt'] + angle_v = (reference['vs'][t_index_upper] - reference['vs'][t_index_lower]) / reference['dt'] + time_difference =t - t_index_lower * reference['dt'] + v_ref = reference['vs'][t_index_lower] + angle_v * time_difference + # using pin.integrate to make this work for all joint types + # NOTE: not fully accurate as it could have been integrated with previous interpolated velocities, + # but let's go for it as-is for now + # TODO: make that work via past_data IF this is still too saw-looking + q_ref = pin.integrate(robot.model, reference['qs'][t_index_lower], reference['vs'][t_index_lower] * time_difference) + + + + + error_q = q_ref - q + error_v = v_ref - v Kp = 1.0 - Kd = 0.1 + Kd = 0.5 # feedforward feedback - v_cmd = reference['vs'][t_index] + Kp * error_q + Kd * error_v + v_cmd = v_ref + Kp * error_q + Kd * error_v qd_cmd = v_cmd[:6] robot.sendQd(v_cmd) @@ -104,8 +134,8 @@ def jointTrajFollowingPDControlLoop(stop_at_final : bool, robot: RobotManager, r log_item['error_v'] = error_v log_item['q'] = q log_item['v'] = v - log_item['reference_q'] = reference['qs'][t_index] - log_item['reference_v'] = reference['vs'][t_index] + log_item['reference_q'] = q_ref + log_item['reference_v'] = v_ref return breakFlag, {}, log_item diff --git a/python/ur_simple_control/clik/clik.py b/python/ur_simple_control/clik/clik.py index a422e1667bd1bebe55cce2ed816a8542a106ddca..3decba093e80e1377fe12691c3dd30f7a974897a 100644 --- a/python/ur_simple_control/clik/clik.py +++ b/python/ur_simple_control/clik/clik.py @@ -183,7 +183,7 @@ def controlLoopClik(robot, clik_controller, i, past_data): return breakFlag, {}, log_item -def moveUntilContactControlLoop(contact_detecting_force, speed, robot, clik_controller, i, past_data): +def moveUntilContactControlLoop(contact_detecting_force, speed, robot : RobotManager, clik_controller, i, past_data): """ moveUntilContactControlLoop --------------- @@ -198,7 +198,8 @@ def moveUntilContactControlLoop(contact_detecting_force, speed, robot, clik_cont #wrench = robot.getWrench() # you're already giving the speed in the EE i.e. body frame # so it only makes sense to have the wrench in the same frame - wrench = robot.getWrenchInEE() + #wrench = robot._getWrenchInEE() + wrench = robot.getWrench() # and furthermore it's a reasonable assumption that you'll hit the thing # in the direction you're going in. # thus we only care about wrenches in those direction coordinates @@ -241,7 +242,7 @@ def moveL(args, robot, goal_point): send a SE3 object as goal point. if you don't care about rotation, make it np.zeros((3,3)) """ - assert type(goal_point) == pin.pinocchio_pywrap.SE3 + #assert type(goal_point) == pin.pinocchio_pywrap.SE3 robot.Mgoal = copy.deepcopy(goal_point) clik_controller = getClikController(args) controlLoop = partial(controlLoopClik, robot, clik_controller) @@ -383,6 +384,7 @@ def clikCartesianPathIntoJointPath(path, args, robot, \ transf_body_to_task_frame = pin.SE3(R, p) q = copy.deepcopy(q_init) + pin.forwardKinematics(robot.model, robot.data, q) for i in range(len(path)): path[i] = transf_body_to_task_frame.act(path[i]) @@ -405,6 +407,8 @@ def clikCartesianPathIntoJointPath(path, args, robot, \ # and we aren't pressed on time when turning it into an array later) qs = [] for goal in path: + #print("goal", goal) + #print("T_w_e", robot.data.oMi[robot.JOINT_ID]) Mgoal = pin.SE3(R, goal) for i in range(n_iter): # TODO maybe hide pin call with RobotManager call 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 01c73c9ba60d4bd126027f16c31dbe867c811c25..55668f2b64c34f7d4c980310fea151591c9ef526 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/dmp/dmp.py b/python/ur_simple_control/dmp/dmp.py index 348cb0ac12eebefc45154825a423bf25451af4c3..5c3c490cd19f387f09bbc580609642136e98171d 100644 --- a/python/ur_simple_control/dmp/dmp.py +++ b/python/ur_simple_control/dmp/dmp.py @@ -20,9 +20,6 @@ def getDMPArgs(parser): ############################# 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", \ diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py index 3e4cbf9b0c26d7698bf4e363376a2526967d6205..91b4b43ad7ccb364c844688fd7b511a2024d08d4 100644 --- a/python/ur_simple_control/managers.py +++ b/python/ur_simple_control/managers.py @@ -125,7 +125,8 @@ def getMinimalArgParser(): # environment interaction parameters # ######################################## parser.add_argument('--contact-detecting-force', type=float, \ - default=1.3, help='the force used to detect contact (collision) in the moveUntilContact function') + #default=1.3, help='the force used to detect contact (collision) in the moveUntilContact function') + default=2.8, help='the force used to detect contact (collision) in the moveUntilContact function') parser.add_argument('--minimum-detectable-force-norm', type=float, \ help="we need to disregard noise to converge despite filtering. \ a quick fix is to zero all forces of norm below this argument threshold.", @@ -701,7 +702,7 @@ class RobotManager: if test: if not self.pinocchio_only: q = self.rtde_receive.getActualQ() - if self.args.gripper: + if self.args.gripper == "robotiq": # TODO: make it work or remove it #self.gripper_past_pos = self.gripper_pos # this is pointless by itself diff --git a/python/ur_simple_control/optimal_control/optimal_control.py b/python/ur_simple_control/optimal_control/optimal_control.py index e3fb969279a98988ac8ad84fff12e0db0b278096..4da6ba3fd504a8ce2f896bfcfef30e6fb798db3f 100644 --- a/python/ur_simple_control/optimal_control/optimal_control.py +++ b/python/ur_simple_control/optimal_control/optimal_control.py @@ -14,7 +14,7 @@ def get_OCP_args(parser : argparse.ArgumentParser): help="time length between state-control-pair decision variables") parser.add_argument("--n-knots", type=int, default=100, \ help="number of state-control-pair decision variables") - parser.add_argument("--stop-at-final", type=int, default=True, \ + parser.add_argument("--stop-at-final", type=int, default=1, \ help="the trajectory generated by the OCP will be followed. it might not have finally velocity 0. \ if this argument is set to true, the final velocity will be set to 0 (there will be overshoot).") return parser @@ -125,7 +125,13 @@ def IKOCP(args, robot : RobotManager, goal : pin.SE3): # NOTE: there are some possible parameters here that I'm not using xs = [x0] * (solver.problem.T + 1) us = solver.problem.quasiStatic([x0] * solver.problem.T) - solver.solve(xs, us, 5000, False, 1e-9) + + print("set goal:", goal) + start = time.time() + solver.solve(xs, us, 500, False, 1e-9) + end = time.time() + print("solved in:", end - start, "seconds") + #solver.solve() # get reference (state trajectory) # we aren't using controls because we only have velocity inputs @@ -143,10 +149,10 @@ if __name__ == "__main__": robot = RobotManager(args) # TODO: remove once things work robot.max_qd = 3.14 + print("velocity limits", robot.model.velocityLimit) robot.q = pin.randomConfiguration(robot.model) goal = pin.SE3.Random() goal.translation = np.random.random(3) * 0.4 - print("set goal:", goal) reference, solver = IKOCP(args, robot, goal) # we only work within -pi - pi (or 0-2pi idk anymore) #reference['qs'] = reference['qs'] % (2*np.pi) - np.pi 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 e346abfc3404c5e04c001cf4c8c41732952a3921..9550e0a266df8ffbbcd7f29cd2dc60a649e809dd 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/calib_board_hacks.py b/python/ur_simple_control/util/calib_board_hacks.py index d53d64851338f3a49892fe0f8a7fe3b2ce11ef08..1d7887c99474bd17a18b30043a0628b05053a458 100644 --- a/python/ur_simple_control/util/calib_board_hacks.py +++ b/python/ur_simple_control/util/calib_board_hacks.py @@ -16,11 +16,13 @@ def getBoardCalibrationArgs(parser): parser.add_argument('--board-width', type=float, \ help="width of the board (in meters) the robot will write on", \ #default=0.5) - default=0.25) + #default=0.25) + default=0.20) parser.add_argument('--board-height', type=float, \ help="height of the board (in meters) the robot will write on", \ #default=0.35) - default=0.25) + #default=0.25) + default=0.20) # TODO: add axis direction too!!!!!!!!!!!!!!!!! # and change the various offsets accordingly parser.add_argument('--board-axis', type=str, \ @@ -303,6 +305,7 @@ def calibratePlane(args, robot, plane_width, plane_height, n_tests): # THIS IS Y if args.board_axis == 'y': new_pose.translation[2] = init_pose.translation[2] - np.random.random() * plane_height + print("new pose for detection", new_pose) moveL(args, robot, new_pose) # fix orientation new_pose.rotation = R