diff --git a/examples/cart_pulling/path6d_from_path2d.py b/examples/cart_pulling/path6d_from_path2d.py new file mode 100644 index 0000000000000000000000000000000000000000..00c0d23cbd060d4f2dacbe529b3bf2ba77618e0b --- /dev/null +++ b/examples/cart_pulling/path6d_from_path2d.py @@ -0,0 +1,105 @@ +from smc import getRobotFromArgs +from smc import getMinimalArgParser +from smc.control.cartesian_space import getClikArgs +from smc.path_generation.planner import getPlanningArgs +from smc.control.optimal_control.croco_mpc_path_following import initializePastData +from smc.path_generation.path_math.path2d_to_6d import path2D_to_SE3_fixed +from smc.path_generation.path_math.path_to_trajectory import path2D_timed +from smc.control.optimal_control.util import get_OCP_args + +from smc.path_generation.path_math.cart_pulling_path_math import ( + time_base_path, + construct_EE_path, +) + +import yaml +import numpy as np +from functools import partial +import numpy as np +import time + + +def get_args(): + parser = getMinimalArgParser() + parser = get_OCP_args(parser) + parser = getClikArgs(parser) # literally just for goal error + parser = getPlanningArgs(parser) + parser.add_argument( + "--handlebar-height", + type=float, + default=0.5, + help="heigh of handlebar of the cart to be pulled", + ) + parser.add_argument( + "--base-to-handlebar-preferred-distance", + type=float, + default=0.5, + help="prefered path arclength from mobile base position to handlebar", + ) + args = parser.parse_args() + return args + + +args = get_args() +args.past_window_size = 100 +args.robot = "heron" +robot = getRobotFromArgs(args) +robot._step() +robot.visualizer_manager.sendCommand({"q": robot.q}) +input("press Enter to continue") +print(robot.q) + +max_base_v = np.linalg.norm(robot._max_v[:2]) +dt = 1 / args.ctrl_freq + +path2D_handlebar = initializePastData( + args, robot.T_w_e, robot.base_position2D, max_base_v +) +# path2D_handlebar = np.linspace(0, 1, args.past_window_size).reshape((-1, 1)) +# path2D_handlebar = np.hstack((path2D_handlebar, path2D_handlebar)) +print(path2D_handlebar.shape) +path3D_handlebar = np.hstack( + (path2D_handlebar, np.ones((len(path2D_handlebar), 1)) * robot.T_w_e.translation[2]) +) +# print(path3D_handlebar.shape) +# robot.visualizer_manager.sendCommand({"path": path2D_handlebar}) +robot.visualizer_manager.sendCommand({"path": path3D_handlebar}) +print( + "we initialize path ee poses with this 2D path (z axis adjusted just for visual clarity" +) +print(path3D_handlebar) +# print(path2D_handlebar) +input("press Enter to continue") + +# path you already traversed +# time_past = np.linspace(0.0, args.past_window_size * dt, args.past_window_size) +x = np.linspace(0.0, args.past_window_size * dt, args.past_window_size) +# x = np.linspace(0.0, 2.0, 200) +x = x.reshape((-1, 1)) +y = np.sin(x) +past_data = {} +past_data["path2D_untimed"] = np.hstack((x, y)) + +# path you get from path planner +x = np.linspace(0.0, args.past_window_size * dt, args.past_window_size) +# x = np.linspace(2.0, 4.0, 200) +x = x.reshape((-1, 1)) +y = np.sin(x) +path2D_untimed_base = np.hstack((x, y)) + +p = path2D_untimed_base[-1] +path2D_untimed_base = np.array(path2D_untimed_base).reshape((-1, 2)) + +path_base = time_base_path(args, path2D_untimed_base, max_base_v) +print(path_base) +pathSE3_handlebar = construct_EE_path(args, p, past_data["path2D_untimed"]) + +for i in range(100): + visualizer_manager.sendCommand({"frame_path": pathSE3_handlebar}) + # visualizer_manager.sendCommand({"frame_path": some_path}) + visualizer_manager.sendCommand({"path": path_base}) + time.sleep(1) +print("send em") + +time.sleep(10) +visualizer_manager.terminateProcess() diff --git a/examples/graz/cartesian_pose_command_server.py b/examples/graz/cartesian_pose_command_server.py index e63702faf1631862f232ca951325dc173a4d3957..8349916faccc471345173177826850aee4d174ad 100644 --- a/examples/graz/cartesian_pose_command_server.py +++ b/examples/graz/cartesian_pose_command_server.py @@ -1,11 +1,10 @@ +from smc import getMinimalArgParser +from smc.multiprocessing.process_manager import ProcessManager +from smc.multiprocessing.networking.server import server_sender +from smc.multiprocessing.networking.client import client_receiver + import pinocchio as pin import numpy as np -from smc.managers import ( - ProcessManager, - getMinimalArgParser, -) -from smc.networking.server import server_sender -from smc.networking.client import client_receiver import time diff --git a/examples/graz/clik_client.py b/examples/graz/clik_client.py index 019f99e51e542fa25df83a3ecbf9a2a5cbaa3f7a..aca40dc8f90f809159bfb3804b72cce1f7e3edeb 100644 --- a/examples/graz/clik_client.py +++ b/examples/graz/clik_client.py @@ -1,15 +1,20 @@ +from smc.multiprocessing.networking.client import client_receiver, client_sender +from smc.multiprocessing.process_manager import ProcessManager +from smc.robots.interfaces.force_torque_sensor_interface import ( + ForceTorqueOnSingleArmWrist, +) +from smc.control.cartesian_space.ik_solvers import getIKSolver +from smc.control.cartesian_space.cartesian_space_point_to_point import moveL +from smc.control.cartesian_space.utils import getClikArgs +from smc.control.control_loop_manager import ControlLoopManager +from smc import ( + getMinimalArgParser, + getRobotFromArgs, +) + import pinocchio as pin import numpy as np from functools import partial -from smc.networking.client import client_receiver, client_sender -from smc.networking.server import server_sender -from smc.clik.clik import * -from smc.managers import ( - ProcessManager, - getMinimalArgParser, - ControlLoopManager, - RobotManager, -) def get_args(): @@ -30,10 +35,10 @@ def get_args(): def controlLoopClikExternalGoal( - robot: RobotManager, + robot: ForceTorqueOnSingleArmWrist, receiver: ProcessManager, sender: ProcessManager, - clik_controller, + ik_solver, i, past_data, ): @@ -46,8 +51,8 @@ def controlLoopClikExternalGoal( log_item = {} save_past_dict = {} - q = robot.getQ() - T_w_e = robot.getT_w_e() + q = robot.q + T_w_e = robot.T_w_e data = receiver.getData() T_goal = data["T_goal"] # print(T_goal) @@ -64,29 +69,26 @@ def controlLoopClikExternalGoal( ) if qd_cmd is None: print("the controller you chose didn't work, using dampedPseudoinverse instead") - qd_cmd = dampedPseudoinverse(1e-2, J, err_vector) + qd_cmd = ik_solver(1e-2, J, err_vector) # NOTE: this will also receive a velocity # i have no idea what to do with that velocity - robot.sendQd(qd_cmd) + robot.sendVelocityCommand(qd_cmd) # NOTE: this one is in the base frame! (as it should be) # it is saved in robotmanager (because it's a private variable, # yes this is evil bla bla) - wrench_in_robot = robot.getWrench() - robot._getWrench() - wrench = robot.getWrench() - robot.wrench = wrench_in_robot - sender.sendCommand({"wrench": wrench}) + # NOTE: idk whether i'm sending this or wrench_ee lule + sender.sendCommand({"wrench": robot.wrench_base}) - log_item["qs"] = robot.getQ().reshape((robot.model.nq,)) - log_item["dqs"] = robot.getQd().reshape((robot.model.nv,)) + log_item["qs"] = robot.q + log_item["dqs"] = robot.v log_item["err_vector"] = err_vector return breakFlag, save_past_dict, log_item if __name__ == "__main__": args = get_args() - robot = RobotManager(args) + robot = getRobotFromArgs(args) translation = np.array(args.init_pose[:3]) orientation = pin.Quaternion(np.array(args.init_pose[3:])) init_goal = pin.SE3(orientation, translation) @@ -102,7 +104,7 @@ if __name__ == "__main__": client_receiver, {"T_goal": pin.SE3.Identity(), "v": np.zeros(6)}, 4, - init_value={"T_goal": robot.getT_w_e(), "v": np.zeros(6)}, + init_value={"T_goal": robot.T_w_e, "v": np.zeros(6)}, ) # wrench_sender: 6666 args.port = args.port_wrench @@ -112,7 +114,7 @@ if __name__ == "__main__": "dqs": np.zeros((robot.model.nv,)), "err_vector": np.zeros((6,)), } - clik_controller = getClikController(args, robot) + clik_controller = getIKSolver(args, robot) control_loop = partial( controlLoopClikExternalGoal, robot, receiver, sender, clik_controller ) @@ -120,15 +122,12 @@ if __name__ == "__main__": loop_manager.run() # get expected behaviour here (library can't know what the end is - you have to do this here) - if not args.pinocchio_only: + if args.real: robot.stopRobot() if args.save_log: - robot.log_manager.plotAllControlLoops() + robot._log_manager.saveLog() + robot._log_manager.plotAllControlLoops() if args.visualizer: robot.killManipulatorVisualizer() - - if args.save_log: - robot.log_manager.saveLog() - # loop_manager.stopHandler(None, None) diff --git a/python/smc.egg-info/SOURCES.txt b/python/smc.egg-info/SOURCES.txt index 5772872e2ac62db9911730a91afc02a76bf290ed..7063d2e2f5226b842a6f07eb62e33bdd05bf2379 100644 --- a/python/smc.egg-info/SOURCES.txt +++ b/python/smc.egg-info/SOURCES.txt @@ -1,9 +1,356 @@ LICENSE.txt README.md setup.py +initial_python_solution/main.py +initial_python_solution/make_run.py +initial_python_solution/manipulator_visual_motion_analyzer.py +initial_python_solution/__pycache__/make_run.cpython-310.pyc +initial_python_solution/__pycache__/make_run.cpython-311.pyc +initial_python_solution/arms/another_debug_dh +initial_python_solution/arms/j2n6s300_dh_params +initial_python_solution/arms/j2s7s300_dh_params +initial_python_solution/arms/kinova_jaco_params +initial_python_solution/arms/kuka_lbw_iiwa_dh_params +initial_python_solution/arms/lbr_iiwa_jos_jedan_dh +initial_python_solution/arms/robot_parameters2 +initial_python_solution/arms/testing_dh_parameters +initial_python_solution/arms/ur10e_dh_parameters_from_the_ur_site +initial_python_solution/arms/ur5e_dh +initial_python_solution/example_code/blit_in_tk.py +initial_python_solution/example_code/blit_test.py +initial_python_solution/example_code/dark_background_example.py +initial_python_solution/example_code/ellipse.py +initial_python_solution/example_code/embedding_in_tk_sgskip.py +initial_python_solution/example_code/manager_anim.py +initial_python_solution/example_code/run_classic_ik_algs.py +initial_python_solution/robot_stuff/InverseKinematics.py +initial_python_solution/robot_stuff/drawing.py +initial_python_solution/robot_stuff/drawing_for_anim.py +initial_python_solution/robot_stuff/follow_curve.py +initial_python_solution/robot_stuff/forw_kinm.py +initial_python_solution/robot_stuff/inv_kinm.py +initial_python_solution/robot_stuff/joint_as_hom_mat.py +initial_python_solution/robot_stuff/utils.py +initial_python_solution/robot_stuff/webots_api_helper_funs.py +initial_python_solution/robot_stuff/__pycache__/InverseKinematics.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/InverseKinematics.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/drawing.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/drawing.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/drawing_for_anim.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/drawing_for_anim.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/follow_curve.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/follow_curve.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/forw_kinm.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/forw_kinm.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/inv_kinm.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/inv_kinm.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/joint_as_hom_mat.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/joint_as_hom_mat.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/utils.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/utils.cpython-311.pyc +initial_python_solution/robot_stuff/__pycache__/webots_api_helper_funs.cpython-310.pyc +initial_python_solution/robot_stuff/__pycache__/webots_api_helper_funs.cpython-311.pyc smc/__init__.py smc.egg-info/PKG-INFO smc.egg-info/SOURCES.txt smc.egg-info/dependency_links.txt smc.egg-info/not-zip-safe -smc.egg-info/top_level.txt \ No newline at end of file +smc.egg-info/top_level.txt +smc/control/__init__.py +smc/control/control_loop_manager.py +smc/control/freedrive.py +smc/control/cartesian_space/__init__.py +smc/control/cartesian_space/cartesian_space_compliant_control.py +smc/control/cartesian_space/cartesian_space_point_to_point.py +smc/control/cartesian_space/cartesian_space_trajectory_following.py +smc/control/cartesian_space/ik_solvers.py +smc/control/cartesian_space/utils.py +smc/control/cartesian_space/experimental/traiettoria.py +smc/control/cartesian_space/experimental/whole_body_clik.py +smc/control/dmp/__init__.py +smc/control/dmp/dmp.py +smc/control/dmp/notes.md +smc/control/joint_space/__init__.py +smc/control/joint_space/joint_space_point_to_point.py +smc/control/joint_space/joint_space_trajectory_following.py +smc/control/optimal_control/__init__.py +smc/control/optimal_control/abstract_croco_ocp.py +smc/control/optimal_control/create_pinocchio_casadi_ocp.py +smc/control/optimal_control/croco_mpc_path_following.py +smc/control/optimal_control/croco_mpc_point_to_point.py +smc/control/optimal_control/notes.md +smc/control/optimal_control/path_following_croco_ocp.py +smc/control/optimal_control/point_to_point_croco_ocp.py +smc/control/optimal_control/util.py +smc/logging/__init__.py +smc/logging/logger.py +smc/multiprocessing/__init__.py +smc/multiprocessing/multiprocess_manager.py +smc/multiprocessing/process_manager.py +smc/multiprocessing/networking/__init__.py +smc/multiprocessing/networking/client.py +smc/multiprocessing/networking/message_specs.proto +smc/multiprocessing/networking/message_specs_pb2.py +smc/multiprocessing/networking/notes.md +smc/multiprocessing/networking/server.py +smc/multiprocessing/networking/todos.md +smc/multiprocessing/networking/util.py +smc/path_generation/OLD_sebas_path_generator_WITH_EVERYTHING.py +smc/path_generation/README.md +smc/path_generation/__init__.py +smc/path_generation/cartesian_to_joint_space_path_mapper.py +smc/path_generation/path_generator.py +smc/path_generation/planner.py +smc/path_generation/robot_params.yaml +smc/path_generation/scene_updater.py +smc/path_generation/setup.py +smc/path_generation/tunnel_mpc_params.yaml +smc/path_generation/maps/premade_maps.py +smc/path_generation/mobile_manipulation_challenge.egg-info/PKG-INFO +smc/path_generation/mobile_manipulation_challenge.egg-info/SOURCES.txt +smc/path_generation/mobile_manipulation_challenge.egg-info/dependency_links.txt +smc/path_generation/mobile_manipulation_challenge.egg-info/requires.txt +smc/path_generation/mobile_manipulation_challenge.egg-info/top_level.txt +smc/path_generation/path_math/cart_pulling_path_math.py +smc/path_generation/path_math/path2d_to_6d.py +smc/path_generation/path_math/path_to_trajectory.py +smc/path_generation/star_navigation/README.md +smc/path_generation/star_navigation/setup.py +smc/path_generation/star_navigation/config/__init__.py +smc/path_generation/star_navigation/config/load_config.py +smc/path_generation/star_navigation/config/scene.py +smc/path_generation/star_navigation/config/params/dmp_ctrl_params.yaml +smc/path_generation/star_navigation/config/params/pfmpc_artificial_reference_params.yaml +smc/path_generation/star_navigation/config/params/pfmpc_ds_params.yaml +smc/path_generation/star_navigation/config/params/pfmpc_obstacle_constraints_params.yaml +smc/path_generation/star_navigation/config/params/robot_params.yaml +smc/path_generation/star_navigation/config/params/soads_ctrl_params.yaml +smc/path_generation/star_navigation/motion_control/__init__.py +smc/path_generation/star_navigation/motion_control/dmp/__init__.py +smc/path_generation/star_navigation/motion_control/dmp/dmp.py +smc/path_generation/star_navigation/motion_control/pfmpc_artificial_reference/__init__.py +smc/path_generation/star_navigation/motion_control/pfmpc_artificial_reference/motion_controller.py +smc/path_generation/star_navigation/motion_control/pfmpc_artificial_reference/mpc.py +smc/path_generation/star_navigation/motion_control/pfmpc_artificial_reference/mpc_build/.gitignore +smc/path_generation/star_navigation/motion_control/pfmpc_ds/__init__.py +smc/path_generation/star_navigation/motion_control/pfmpc_ds/motion_controller.py +smc/path_generation/star_navigation/motion_control/pfmpc_ds/mpc.py +smc/path_generation/star_navigation/motion_control/pfmpc_ds/path_generator.py +smc/path_generation/star_navigation/motion_control/pfmpc_ds/workspace_modification.py +smc/path_generation/star_navigation/motion_control/pfmpc_ds/mpc_build/.gitignore +smc/path_generation/star_navigation/motion_control/pfmpc_obstacle_constraints/__init__.py +smc/path_generation/star_navigation/motion_control/pfmpc_obstacle_constraints/motion_controller.py +smc/path_generation/star_navigation/motion_control/pfmpc_obstacle_constraints/mpc.py +smc/path_generation/star_navigation/motion_control/pfmpc_obstacle_constraints/mpc_build/.gitignore +smc/path_generation/star_navigation/motion_control/soads/__init__.py +smc/path_generation/star_navigation/motion_control/soads/soads.py +smc/path_generation/star_navigation/robot/__init__.py +smc/path_generation/star_navigation/robot/bicycle.py +smc/path_generation/star_navigation/robot/mobile_robot.py +smc/path_generation/star_navigation/robot/omnidirectional.py +smc/path_generation/star_navigation/robot/unicycle.py +smc/path_generation/star_navigation/scripts/compute_time.py +smc/path_generation/star_navigation/scripts/run_simulation.py +smc/path_generation/star_navigation/scripts/simulate_several_controllers.py +smc/path_generation/star_navigation/scripts/simulate_several_initpos.py +smc/path_generation/star_navigation/scripts/test_soads.py +smc/path_generation/star_navigation/star_navigation.egg-info/PKG-INFO +smc/path_generation/star_navigation/star_navigation.egg-info/SOURCES.txt +smc/path_generation/star_navigation/star_navigation.egg-info/dependency_links.txt +smc/path_generation/star_navigation/star_navigation.egg-info/top_level.txt +smc/path_generation/star_navigation/starworlds/LICENSE +smc/path_generation/star_navigation/starworlds/README.md +smc/path_generation/star_navigation/starworlds/requirements.txt +smc/path_generation/star_navigation/starworlds/setup.py +smc/path_generation/star_navigation/starworlds/obstacles/__init__.py +smc/path_generation/star_navigation/starworlds/obstacles/ellipse.py +smc/path_generation/star_navigation/starworlds/obstacles/motion_model.py +smc/path_generation/star_navigation/starworlds/obstacles/obstacle.py +smc/path_generation/star_navigation/starworlds/obstacles/polygon.py +smc/path_generation/star_navigation/starworlds/obstacles/starshaped_obstacle.py +smc/path_generation/star_navigation/starworlds/obstacles/starshaped_polygon.py +smc/path_generation/star_navigation/starworlds/obstacles/starshaped_primitive_combination.py +smc/path_generation/star_navigation/starworlds/starshaped_hull/__init__.py +smc/path_generation/star_navigation/starworlds/starshaped_hull/cluster_and_starify.py +smc/path_generation/star_navigation/starworlds/starshaped_hull/starshaped_hull.py +smc/path_generation/star_navigation/starworlds/starworlds.egg-info/PKG-INFO +smc/path_generation/star_navigation/starworlds/starworlds.egg-info/SOURCES.txt +smc/path_generation/star_navigation/starworlds/starworlds.egg-info/dependency_links.txt +smc/path_generation/star_navigation/starworlds/starworlds.egg-info/requires.txt +smc/path_generation/star_navigation/starworlds/starworlds.egg-info/top_level.txt +smc/path_generation/star_navigation/starworlds/tests/test_cluster_and_starify.py +smc/path_generation/star_navigation/starworlds/tests/test_obstacles.py +smc/path_generation/star_navigation/starworlds/tests/test_starshaped_hull.py +smc/path_generation/star_navigation/starworlds/tests/test_timing.py +smc/path_generation/star_navigation/starworlds/tests/test_utils.py +smc/path_generation/star_navigation/starworlds/utils/__init__.py +smc/path_generation/star_navigation/starworlds/utils/cg.py +smc/path_generation/star_navigation/starworlds/utils/misc.py +smc/path_generation/star_navigation/visualization/__init__.py +smc/path_generation/star_navigation/visualization/scene_gui.py +smc/path_generation/star_navigation/visualization/video_writer.py +smc/path_generation/star_navigation/visualization/figures/.gitignore +smc/path_generation/star_navigation/visualization/videos/.gitignore +smc/path_generation/starworld_tunnel_mpc/README.md +smc/path_generation/starworld_tunnel_mpc/setup.py +smc/path_generation/starworld_tunnel_mpc/config/__init__.py +smc/path_generation/starworld_tunnel_mpc/config/load_config.py +smc/path_generation/starworld_tunnel_mpc/config/scene.py +smc/path_generation/starworld_tunnel_mpc/config/params/robot_params.yaml +smc/path_generation/starworld_tunnel_mpc/config/params/soads_ctrl_params.yaml +smc/path_generation/starworld_tunnel_mpc/config/params/tunnel_mpc_convergence_params.yaml +smc/path_generation/starworld_tunnel_mpc/config/params/tunnel_mpc_params.yaml +smc/path_generation/starworld_tunnel_mpc/motion_control/__init__.py +smc/path_generation/starworld_tunnel_mpc/motion_control/soads/__init__.py +smc/path_generation/starworld_tunnel_mpc/motion_control/soads/soads.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/__init__.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/path_generator.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/tunnel_mpc.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/tunnel_mpc_controller.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/workspace_modification.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc/mpc_build/.gitignore +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/__init__.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/path_generator.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/tunnel_mpc.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/tunnel_mpc_controller.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/workspace_modification.py +smc/path_generation/starworld_tunnel_mpc/motion_control/tunnel_mpc_convergence/mpc_build/.gitignore +smc/path_generation/starworld_tunnel_mpc/robot/__init__.py +smc/path_generation/starworld_tunnel_mpc/robot/bicycle.py +smc/path_generation/starworld_tunnel_mpc/robot/mobile_robot.py +smc/path_generation/starworld_tunnel_mpc/robot/omnidirectional.py +smc/path_generation/starworld_tunnel_mpc/robot/unicycle.py +smc/path_generation/starworld_tunnel_mpc/starworld_tunnel_mpc.egg-info/PKG-INFO +smc/path_generation/starworld_tunnel_mpc/starworld_tunnel_mpc.egg-info/SOURCES.txt +smc/path_generation/starworld_tunnel_mpc/starworld_tunnel_mpc.egg-info/dependency_links.txt +smc/path_generation/starworld_tunnel_mpc/starworld_tunnel_mpc.egg-info/requires.txt +smc/path_generation/starworld_tunnel_mpc/starworld_tunnel_mpc.egg-info/top_level.txt +smc/path_generation/starworld_tunnel_mpc/tests/test_motion_control.py +smc/path_generation/starworld_tunnel_mpc/tests/test_soads.py +smc/path_generation/starworld_tunnel_mpc/visualization/__init__.py +smc/path_generation/starworld_tunnel_mpc/visualization/scene_gui.py +smc/path_generation/starworlds/LICENSE +smc/path_generation/starworlds/README.md +smc/path_generation/starworlds/requirements.txt +smc/path_generation/starworlds/setup.py +smc/path_generation/starworlds/obstacles/__init__.py +smc/path_generation/starworlds/obstacles/ellipse.py +smc/path_generation/starworlds/obstacles/motion_model.py +smc/path_generation/starworlds/obstacles/obstacle.py +smc/path_generation/starworlds/obstacles/polygon.py +smc/path_generation/starworlds/obstacles/starshaped_obstacle.py +smc/path_generation/starworlds/obstacles/starshaped_polygon.py +smc/path_generation/starworlds/obstacles/starshaped_primitive_combination.py +smc/path_generation/starworlds/starshaped_hull/__init__.py +smc/path_generation/starworlds/starshaped_hull/cluster_and_starify.py +smc/path_generation/starworlds/starshaped_hull/starshaped_hull.py +smc/path_generation/starworlds/starworlds.egg-info/PKG-INFO +smc/path_generation/starworlds/starworlds.egg-info/SOURCES.txt +smc/path_generation/starworlds/starworlds.egg-info/dependency_links.txt +smc/path_generation/starworlds/starworlds.egg-info/requires.txt +smc/path_generation/starworlds/starworlds.egg-info/top_level.txt +smc/path_generation/starworlds/tests/test_cluster_and_starify.py +smc/path_generation/starworlds/tests/test_obstacles.py +smc/path_generation/starworlds/tests/test_starshaped_hull.py +smc/path_generation/starworlds/tests/test_timing.py +smc/path_generation/starworlds/tests/test_utils.py +smc/path_generation/starworlds/utils/__init__.py +smc/path_generation/starworlds/utils/cg.py +smc/path_generation/starworlds/utils/misc.py +smc/robots/__init__.py +smc/robots/abstract_simulated_robot.py +smc/robots/notes_on_getting_model_from_urdf.md +smc/robots/robotmanager_abstract.py +smc/robots/utils.py +smc/robots/grippers/__init__.py +smc/robots/grippers/abstract_gripper.py +smc/robots/grippers/on_robot/twofg.py +smc/robots/grippers/robotiq/robotiq_gripper.py +smc/robots/implementations/__init__.py +smc/robots/implementations/heron.py +smc/robots/implementations/mir.py +smc/robots/implementations/mobile_yumi.py +smc/robots/implementations/ur5e.py +smc/robots/interfaces/dual_arm_interface.py +smc/robots/interfaces/force_torque_sensor_interface.py +smc/robots/interfaces/mobile_base_interface.py +smc/robots/interfaces/single_arm_interface.py +smc/robots/robot_descriptions/TODO_PUT_IN_FILES_FROM_HERE_INTO_YUMI_LOCAL_URDF +smc/robots/robot_descriptions/__init__.py +smc/robots/robot_descriptions/my_robot_calibration.yaml +smc/robots/robot_descriptions/yumi.urdf +smc/robots/robot_descriptions/yumi_local.urdf +smc/robots/robot_descriptions/config/__init__.py +smc/robots/robot_descriptions/config/ur5e/__init__.py +smc/robots/robot_descriptions/config/ur5e/default_kinematics.yaml +smc/robots/robot_descriptions/config/ur5e/joint_limits.yaml +smc/robots/robot_descriptions/config/ur5e/physical_parameters.yaml +smc/robots/robot_descriptions/config/ur5e/visual_parameters.yaml +smc/robots/robot_descriptions/meshes/__init__.py +smc/robots/robot_descriptions/meshes/robotiq_85_coupler.stl +smc/robots/robot_descriptions/meshes/ur5e/__init__.py +smc/robots/robot_descriptions/meshes/ur5e/robotiq_85_coupler.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/__init__.py +smc/robots/robot_descriptions/meshes/ur5e/collision/base.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/finger_1-collision.dae +smc/robots/robot_descriptions/meshes/ur5e/collision/finger_2-collision.dae +smc/robots/robot_descriptions/meshes/ur5e/collision/forearm.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/hand-e-collision.dae +smc/robots/robot_descriptions/meshes/ur5e/collision/shoulder.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/upperarm.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/wrist1.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/wrist2.stl +smc/robots/robot_descriptions/meshes/ur5e/collision/wrist3.stl +smc/robots/robot_descriptions/meshes/ur5e/visual/__init__.py +smc/robots/robot_descriptions/meshes/ur5e/visual/base.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/finger_1.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/finger_2.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/forearm.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/hand-e.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/shoulder.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/upperarm.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/wrist1.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/wrist2.dae +smc/robots/robot_descriptions/meshes/ur5e/visual/wrist3.dae +smc/robots/robot_descriptions/urdf/__init__.py +smc/robots/robot_descriptions/urdf/ur5e_with_robotiq_hande.urdf +smc/robots/robot_descriptions/urdf/ur5e_with_robotiq_hande_FIXED_PATHS.urdf +smc/util/__init__.py +smc/util/calib_board_hacks.py +smc/util/define_random_goal.py +smc/util/draw_path.py +smc/util/encapsulating_ellipses.py +smc/util/freedrive.py +smc/util/map2DPathTo3DPlane.py +smc/vision/__init__.py +smc/vision/vision.py +smc/visualization/__init__.py +smc/visualization/manipulator_comparison_visualizer.py +smc/visualization/manipulator_visual_motion_analyzer.py +smc/visualization/path_visualizer.py +smc/visualization/plotters.py +smc/visualization/visualizer.py +smc/visualization/arms/another_debug_dh +smc/visualization/arms/j2n6s300_dh_params +smc/visualization/arms/j2s7s300_dh_params +smc/visualization/arms/kinova_jaco_params +smc/visualization/arms/kuka_lbw_iiwa_dh_params +smc/visualization/arms/lbr_iiwa_jos_jedan_dh +smc/visualization/arms/robot_parameters2 +smc/visualization/arms/testing_dh_parameters +smc/visualization/arms/ur10e_dh_parameters_from_the_ur_site +smc/visualization/arms/ur5e_dh +smc/visualization/meshcat_viewer_wrapper/__init__.py +smc/visualization/meshcat_viewer_wrapper/colors.py +smc/visualization/meshcat_viewer_wrapper/visualizer.py +smc/visualization/obsolete_to_be_removed/main.py +smc/visualization/obsolete_to_be_removed/make_run.py +smc/visualization/robot_stuff/InverseKinematics.py +smc/visualization/robot_stuff/drawing.py +smc/visualization/robot_stuff/drawing_for_anim.py +smc/visualization/robot_stuff/follow_curve.py +smc/visualization/robot_stuff/forw_kinm.py +smc/visualization/robot_stuff/inv_kinm.py +smc/visualization/robot_stuff/joint_as_hom_mat.py +smc/visualization/robot_stuff/utils.py +smc/visualization/robot_stuff/webots_api_helper_funs.py \ No newline at end of file diff --git a/python/smc/control/optimal_control/croco_mpc_path_following.py b/python/smc/control/optimal_control/croco_mpc_path_following.py index 57299aafdb0b103f14df354e90d1bbc98ad12b9b..bd1ec8913f3221895e32b6924751640e5138a172 100644 --- a/python/smc/control/optimal_control/croco_mpc_path_following.py +++ b/python/smc/control/optimal_control/croco_mpc_path_following.py @@ -305,23 +305,24 @@ def BaseAndEEPathFollowingFromPlannerMPCControlLoop( return breakFlag, save_past_dict, log_item -def initializePastData(args: Namespace, T_w_e: SE3, p_base: np.ndarray) -> np.ndarray: +def initializePastData(args: Namespace, T_w_e: SE3, p_base: np.ndarray, max_base_v: float) -> np.ndarray: # prepopulate past data to make base and cart be on the same path in the past # (which didn't actually happen because this just started) p_ee = T_w_e.translation[:2] straight_line_path = np.linspace(p_ee, p_base, args.past_window_size) + straight_line_path_timed = path2D_timed(args, straight_line_path, max_base_v) # time it the same way the base path is timed - time_past = np.linspace( - 0.0, args.past_window_size * (1 / args.ctrl_freq), args.past_window_size - ) - s = np.linspace(0.0, args.n_knots * args.ocp_dt, args.past_window_size) - path2D_handlebar = np.hstack( - ( - np.interp(s, time_past, straight_line_path[:, 0]).reshape((-1, 1)), - np.interp(s, time_past, straight_line_path[:, 1]).reshape((-1, 1)), - ) - ) - #return path2D_handlebar +# time_past = np.linspace( +# 0.0, args.past_window_size * (1 / args.ctrl_freq), args.past_window_size +# ) +# s = np.linspace(0.0, args.n_knots * args.ocp_dt, args.past_window_size) +# path2D_handlebar = np.hstack( +# ( +# np.interp(s, time_past, straight_line_path[:, 0]).reshape((-1, 1)), +# np.interp(s, time_past, straight_line_path[:, 1]).reshape((-1, 1)), +# ) +# ) +# return path2D_handlebar return straight_line_path @@ -344,7 +345,9 @@ def BaseAndEEPathFollowingMPC( ocp = BaseAndEEPathFollowingOCP(args, robot, x0) ocp.solveInitialOCP(x0) - path2D_handlebar = initializePastData(args, T_w_e, robot.q[:2]) + max_base_v = np.linalg.norm(robot._max_v[:2]) + + path2D_handlebar = initializePastData(args, T_w_e, robot.q[:2], float(max_base_v)) if type(path_planner) == types.FunctionType: controlLoop = partial( diff --git a/python/smc/multiprocessing/networking/client.py b/python/smc/multiprocessing/networking/client.py index 1c25cf54e927487b85123365a8bc0b1db2531ab2..1d617d261e81013308a472da618554153eb9f620 100644 --- a/python/smc/multiprocessing/networking/client.py +++ b/python/smc/multiprocessing/networking/client.py @@ -1,13 +1,16 @@ -import socket -from multiprocessing import shared_memory +from typing import Any +from smc.multiprocessing.networking.util import DictPb2EncoderDecoder + from google.protobuf.internal.encoder import _VarintBytes from google.protobuf.internal.decoder import _DecodeVarint32 -from ur_simple_control.networking.util import DictPb2EncoderDecoder +from multiprocessing import shared_memory, Queue +import socket import pickle import time +from argparse import Namespace -def client_receiver(args, init_command, shm_name, lock): +def client_receiver(args: Namespace, init_command, shm_name: str, lock): """ client ------- @@ -113,7 +116,7 @@ def client_receiver(args, init_command, shm_name, lock): print("NETWORKING_CLIENT: caught KeyboardInterrupt, i'm out") -def client_sender(args, init_command, queue): +def client_sender(args: Namespace, init_command: dict[str, Any], queue: Queue): """ server ------- diff --git a/python/smc/multiprocessing/networking/server.py b/python/smc/multiprocessing/networking/server.py index dac395797282cab1efdb93058197710075e1f2de..a81f093ef21414f1d87fd5d2479b3cd8b84a3e12 100644 --- a/python/smc/multiprocessing/networking/server.py +++ b/python/smc/multiprocessing/networking/server.py @@ -1,6 +1,7 @@ +from smc.multiprocessing.networking.util import DictPb2EncoderDecoder + import socket from google.protobuf.internal.encoder import _VarintBytes -from ur_simple_control.networking.util import DictPb2EncoderDecoder def server_sender(args, init_command, queue): diff --git a/python/smc/multiprocessing/networking/util.py b/python/smc/multiprocessing/networking/util.py index 4b3bf8b00e23653740fa4e0aadf0e9918ebd55ca..828cabdd8c43e3a949f5991a1c393a657e2f9191 100644 --- a/python/smc/multiprocessing/networking/util.py +++ b/python/smc/multiprocessing/networking/util.py @@ -1,6 +1,7 @@ # TODO: make protobuf an optional import # then if it's not there use pickling as default -import ur_simple_control.networking.message_specs_pb2 as message_specs_pb2 +import smc.multiprocessing.networking.message_specs_pb2 as message_specs_pb2 + from google.protobuf.internal.encoder import _VarintBytes from google.protobuf.internal.decoder import _DecodeVarint32 import numpy as np @@ -188,9 +189,9 @@ class DictPickleWithHeaderEncoderDecoder: self.HEADERSIZE = 10 self.buffer = b"" - def dictToSerializedMsg(self, dict_msg : dict): + def dictToSerializedMsg(self, dict_msg: dict): msg = pickle.dumps(dict_msg) - return bytes(f"{len(msg)}:<{self.HEADERSIZE}", 'utf-8')+msg + return bytes(f"{len(msg)}:<{self.HEADERSIZE}", "utf-8") + msg def what(self): pass diff --git a/python/smc/multiprocessing/process_manager.py b/python/smc/multiprocessing/process_manager.py index 89757bc882fa50764a05aef12b5daae4b7217e93..315587b082242461a417c6722b4c2571aed17309 100644 --- a/python/smc/multiprocessing/process_manager.py +++ b/python/smc/multiprocessing/process_manager.py @@ -150,7 +150,7 @@ class ProcessManager: # the key should be a string containing the command, # and the value should be the data associated with the command, # just to have some consistency - def sendCommand(self, command: typing.Union[dict, np.ndarray]): + def sendCommand(self, command: typing.Union[dict, np.ndarray]) -> None: """ sendCommand ------------ @@ -182,7 +182,7 @@ class ProcessManager: self.shared_command[:] = command[:] self.shared_command_lock.release() - def getData(self): + def getData(self) -> dict[str, typing.Any]: if self.comm_direction < 3: if not self.data_queue.empty(): self.latest_data = self.data_queue.get_nowait() @@ -208,7 +208,7 @@ class ProcessManager: # self.latest_data = self.encoder_decoder.serializedPb2MsgToDict(data_copy, self.msg_code) return copy.deepcopy(self.latest_data) - def terminateProcess(self): + def terminateProcess(self) -> None: if self.comm_direction == 3: self.shm_cmd.close() self.shm_cmd.unlink() diff --git a/python/smc/path_generation/path_math/cart_pulling_path_math.py b/python/smc/path_generation/path_math/cart_pulling_path_math.py index bedff3a280b5637668c749a5ebd910ec48ea2ce5..499fc63baa86c3ea7ce00da1f31a6e8ac79a2a15 100644 --- a/python/smc/path_generation/path_math/cart_pulling_path_math.py +++ b/python/smc/path_generation/path_math/cart_pulling_path_math.py @@ -9,6 +9,13 @@ from argparse import Namespace from collections import deque +# NOTE: extremely inefficient. +# there should be no copy-pasting of the whole path at every single point in time, +# instead all the computations should be cached. +# ideally you don't even cast the whole past_path into an array, but work on the queue, +# and just do the smallest update. +# this shouldn't be too difficult, it's just annoying. first we fix the logic, +# then we improve efficiency. def getCurrentPositionHandlebarInPastBasePath( args: Namespace, p_base_current: np.ndarray, past_path2D_untimed: np.ndarray ) -> int: diff --git a/python/smc/path_generation/path_math/path_to_trajectory.py b/python/smc/path_generation/path_math/path_to_trajectory.py index dace0769317a4bd7b436e8702fd3529ee26559e4..15d9fdd5e5193d93aea0212cb6a312cb839adefc 100644 --- a/python/smc/path_generation/path_math/path_to_trajectory.py +++ b/python/smc/path_generation/path_math/path_to_trajectory.py @@ -53,7 +53,9 @@ def path2D_timed(args, path2D_untimed, max_base_v): y_diff = y_i_plus_1 - y_i y_diff = y_diff.reshape((-1, 1)) path_length = np.sum(np.linalg.norm(np.hstack((x_diff, y_diff)), axis=1)) + print(path_length) total_time = path_length / base_v + print(total_time) # 2) we find the correspondence between s and time # TODO: read from where it should be, but seba checked that it's 5 for some reason # TODO THIS IS N IN PATH PLANNING, MAKE THIS A SHARED ARGUMENT diff --git a/python/smc/path_generation/star_navigation/robot/bicycle.py b/python/smc/path_generation/star_navigation/robot/bicycle.py index a2f4ec607e5633486bcd32eb54b3b93995e52545..19272209697c320b32fb7b5dabe47463debc8818 100644 --- a/python/smc/path_generation/star_navigation/robot/bicycle.py +++ b/python/smc/path_generation/star_navigation/robot/bicycle.py @@ -1,14 +1,23 @@ import numpy as np -from robot import MobileRobot +from ..robot import MobileRobot class Bicycle(MobileRobot): - def __init__(self, width, vel_min=None, vel_max=None, steer_max=None, name='robot'): + def __init__(self, width, vel_min=None, vel_max=None, steer_max=None, name="robot"): self.vmax = vel_max[0] x_min = [-np.inf] * 3 + [-steer_max] x_max = [np.inf] * 3 + [steer_max] - super().__init__(nu=2, nx=4, width=width, name=name, u_min=vel_min, u_max=vel_max, x_min=x_min, x_max=x_max) + super().__init__( + nu=2, + nx=4, + width=width, + name=name, + u_min=vel_min, + u_max=vel_max, + x_min=x_min, + x_max=x_max, + ) # [x,y of backwheel, orientation, steering angle] # def f(self, x, u): @@ -16,10 +25,13 @@ class Bicycle(MobileRobot): # u[0] * np.sin(x[2]), # u[0] * np.tan(u[1]) / self.width] def f(self, x, u): - return [u[0] * np.cos(x[2]), - u[0] * np.sin(x[2]), - u[0] * np.tan(u[1]) / self.width, - u[1]] + return [ + u[0] * np.cos(x[2]), + u[0] * np.sin(x[2]), + u[0] * np.tan(u[1]) / self.width, + u[1], + ] + # def f(self, x, u): # return [u[0] * np.cos(x[2]) * np.cos(x[3]), # u[0] * np.sin(x[2]) * np.cos(x[3]), @@ -27,8 +39,10 @@ class Bicycle(MobileRobot): # u[1]] def h(self, x): - return [x[0] + self.width/2 * np.cos(x[2]), - x[1] + self.width/2 * np.sin(x[2])] + return [ + x[0] + self.width / 2 * np.cos(x[2]), + x[1] + self.width / 2 * np.sin(x[2]), + ] def vel_min(self): return self.u_min @@ -36,20 +50,27 @@ class Bicycle(MobileRobot): def vel_max(self): return self.u_max - def init_plot(self, ax=None, color='b', alpha=0.7, markersize=10, **kwargs): + def init_plot(self, ax=None, color="b", alpha=0.7, markersize=10, **kwargs): h = super(Bicycle, self).init_plot(ax=ax, color=color, alpha=alpha) - h += ax.plot(0, 0, marker=(3, 0, np.rad2deg(0)), markersize=markersize, color=color) - h += ax.plot(0, 0, marker=(2, 0, np.rad2deg(0)), markersize=0.5*markersize, color='w') + h += ax.plot( + 0, 0, marker=(3, 0, np.rad2deg(0)), markersize=markersize, color=color + ) + h += ax.plot( + 0, 0, marker=(2, 0, np.rad2deg(0)), markersize=0.5 * markersize, color="w" + ) h += ax.plot(0, 0, color=color, alpha=alpha) return h def update_plot(self, x, handles): super(Bicycle, self).update_plot(x, handles) handles[1].set_data(self.h(x)) - handles[1].set_marker((3, 0, np.rad2deg(x[2]-np.pi/2))) + handles[1].set_marker((3, 0, np.rad2deg(x[2] - np.pi / 2))) handles[1].set_markersize(handles[1].get_markersize()) handles[2].set_data(x[0], x[1]) - handles[2].set_marker((2, 0, np.rad2deg(x[2]-np.pi/2))) + handles[2].set_marker((2, 0, np.rad2deg(x[2] - np.pi / 2))) handles[2].set_markersize(handles[2].get_markersize()) - handles[3].set_data([x[0], x[0] + self.width * np.cos(x[2])], - [x[1], x[1] + self.width * np.sin(x[2])]) \ No newline at end of file + handles[3].set_data( + [x[0], x[0] + self.width * np.cos(x[2])], + [x[1], x[1] + self.width * np.sin(x[2])], + ) + diff --git a/python/smc/path_generation/star_navigation/robot/omnidirectional.py b/python/smc/path_generation/star_navigation/robot/omnidirectional.py index f476facda106f46a8d81a2aaef6a0ab8de1f113e..72e4970b001242e9710e49d9af056d6d10e7ea9e 100644 --- a/python/smc/path_generation/star_navigation/robot/omnidirectional.py +++ b/python/smc/path_generation/star_navigation/robot/omnidirectional.py @@ -1,17 +1,23 @@ import numpy as np -from robot import MobileRobot +from ..robot import MobileRobot class Omnidirectional(MobileRobot): - def __init__(self, radius, vel_max, name='robot'): + def __init__(self, radius, vel_max, name="robot"): vel_max = vel_max * np.ones(2) self.vmax = float(np.linalg.norm(vel_max)) - super().__init__(nu=2, nx=2, radius=radius, name=name, u_min=(-vel_max).tolist(), u_max=(vel_max).tolist()) + super().__init__( + nu=2, + nx=2, + radius=radius, + name=name, + u_min=(-vel_max).tolist(), + u_max=(vel_max).tolist(), + ) def f(self, x, u): - return [u[0], - u[1]] + return [u[0], u[1]] def h(self, x): return x[:2] diff --git a/python/smc/path_generation/star_navigation/robot/unicycle.py b/python/smc/path_generation/star_navigation/robot/unicycle.py index 5ae12267a93a733816c54fae8204b1b45128afc8..30aff50ae67b184fab838da2340c4c254a860712 100644 --- a/python/smc/path_generation/star_navigation/robot/unicycle.py +++ b/python/smc/path_generation/star_navigation/robot/unicycle.py @@ -1,5 +1,5 @@ import numpy as np -from robot import MobileRobot +from ..robot import MobileRobot import matplotlib.pyplot as plt @@ -13,38 +13,49 @@ def get_triangle_vertices(center, orientation, side_length): # calculate the three vertices vertex1 = (center[0] + x_offset, center[1] + y_offset) - vertex2 = (center[0] + x_offset * np.cos(np.radians(120)) - y_offset * np.sin(np.radians(120)), - center[1] + x_offset * np.sin(np.radians(120)) + y_offset * np.cos(np.radians(120))) - vertex3 = (center[0] + x_offset * np.cos(np.radians(240)) - y_offset * np.sin(np.radians(240)), - center[1] + x_offset * np.sin(np.radians(240)) + y_offset * np.cos(np.radians(240))) + vertex2 = ( + center[0] + + x_offset * np.cos(np.radians(120)) + - y_offset * np.sin(np.radians(120)), + center[1] + + x_offset * np.sin(np.radians(120)) + + y_offset * np.cos(np.radians(120)), + ) + vertex3 = ( + center[0] + + x_offset * np.cos(np.radians(240)) + - y_offset * np.sin(np.radians(240)), + center[1] + + x_offset * np.sin(np.radians(240)) + + y_offset * np.cos(np.radians(240)), + ) return (vertex1, vertex2, vertex3) + class Unicycle(MobileRobot): - def __init__(self, width, vel_min=None, vel_max=None, name='robot'): + def __init__(self, width, vel_min=None, vel_max=None, name="robot"): self.vmax = vel_max[0] - super().__init__(nu=2, nx=3, width=width, name=name, u_min=vel_min, u_max=vel_max) + super().__init__( + nu=2, nx=3, width=width, name=name, u_min=vel_min, u_max=vel_max + ) def f(self, x, u): - return [u[0] * np.cos(x[2]), # vx - u[0] * np.sin(x[2]), # vy - u[1]] # wz - + return [u[0] * np.cos(x[2]), u[0] * np.sin(x[2]), u[1]] # vx # vy # wz def move(self, x, u, dt): u_sat = np.clip(u, self.u_min, self.u_max) x_next = x + np.array(self.f(x, u_sat)) * dt x_next = np.clip(x_next, self.x_min, self.x_max) - while x_next[2] > 2*np.pi: + while x_next[2] > 2 * np.pi: x_next[2] -= 2 * np.pi - while x_next[2] <= -0*np.pi: + while x_next[2] <= -0 * np.pi: x_next[2] += 2 * np.pi return x_next, u_sat - def h(self, x): - return x[:2] # x, y + return x[:2] # x, y def vel_min(self): return self.u_min @@ -52,17 +63,21 @@ class Unicycle(MobileRobot): def vel_max(self): return self.u_max - def init_plot(self, ax=None, color='b', alpha=0.7, markersize=10): + def init_plot(self, ax=None, color="b", alpha=0.7, markersize=10): handles, ax = super(Unicycle, self).init_plot(ax=ax, color=color, alpha=alpha) - handles += ax.plot(0, 0, marker=(3, 0, np.rad2deg(0)), markersize=markersize, color=color) - handles += ax.plot(0, 0, marker=(2, 0, np.rad2deg(0)), markersize=0.5*markersize, color='w') + handles += ax.plot( + 0, 0, marker=(3, 0, np.rad2deg(0)), markersize=markersize, color=color + ) + handles += ax.plot( + 0, 0, marker=(2, 0, np.rad2deg(0)), markersize=0.5 * markersize, color="w" + ) return handles, ax def update_plot(self, x, handles): super(Unicycle, self).update_plot(x, handles) handles[1].set_data([x[0]], [x[1]]) - handles[1].set_marker((3, 0, np.rad2deg(x[2]-np.pi/2))) + handles[1].set_marker((3, 0, np.rad2deg(x[2] - np.pi / 2))) handles[1].set_markersize(handles[1].get_markersize()) handles[2].set_data([x[0]], [x[1]]) - handles[2].set_marker((2, 0, np.rad2deg(x[2]-np.pi/2))) + handles[2].set_marker((2, 0, np.rad2deg(x[2] - np.pi / 2))) handles[2].set_markersize(handles[2].get_markersize()) diff --git a/python/smc/path_generation/starworlds/obstacles/ellipse.py b/python/smc/path_generation/starworlds/obstacles/ellipse.py index 17f216ea08bfd56748b3be73dbb0ffe8d9155481..ce09821eeaec2c0bf252f28231db8247c63a0a60 100644 --- a/python/smc/path_generation/starworlds/obstacles/ellipse.py +++ b/python/smc/path_generation/starworlds/obstacles/ellipse.py @@ -1,8 +1,8 @@ -from obstacles import StarshapedObstacle, Frame +from ..obstacles import StarshapedObstacle, Frame import numpy as np import matplotlib.pyplot as plt import matplotlib.patches as patches -from utils import is_ccw, tic, toc +from ..utils import is_ccw, tic, toc import shapely @@ -15,12 +15,19 @@ class Ellipse(StarshapedObstacle): if xr is None: xr = np.zeros(2) super().__init__(xr=xr, **kwargs) - self.enclosing_ball_diameter = max(2*self._a[0], 2*self._a[1]) + self.enclosing_ball_diameter = max(2 * self._a[0], 2 * self._a[1]) def copy(self, id, name): - if (id == 'duplicate' or id == 'd'): + if id == "duplicate" or id == "d": id = self.id() - return Ellipse(id=id, name=name, a=self._a, xr=self._xr, n_pol=self._n_pol, motion_model=self._motion_model) + return Ellipse( + id=id, + name=name, + a=self._a, + xr=self._xr, + n_pol=self._n_pol, + motion_model=self._motion_model, + ) def dilated_obstacle(self, padding, id="new", name=None): cp = self.copy(id, name) @@ -36,16 +43,24 @@ class Ellipse(StarshapedObstacle): def init_plot(self, ax=None, show_reference=True, show_name=False, **kwargs): if ax is None: - _, ax = plt.subplots(subplot_kw={'aspect': 'equal'}) + _, ax = plt.subplots(subplot_kw={"aspect": "equal"}) # Default facecolor if "fc" not in kwargs and "facecolor" not in kwargs: - kwargs["fc"] = 'lightgrey' + kwargs["fc"] = "lightgrey" line_handles = [] # Boundary - line_handles += [patches.Ellipse(xy=[0, 0], width=2*self._a[0], height=2*self._a[1], angle=0, **kwargs)] + line_handles += [ + patches.Ellipse( + xy=[0, 0], + width=2 * self._a[0], + height=2 * self._a[1], + angle=0, + **kwargs + ) + ] ax.add_patch(line_handles[-1]) # Reference point - line_handles += ax.plot(*self._xr, '+', color='k') if show_reference else [None] + line_handles += ax.plot(*self._xr, "+", color="k") if show_reference else [None] # Name line_handles += [ax.text(*self._xr, self._name)] if show_name else [None] return line_handles, ax @@ -67,23 +82,50 @@ class Ellipse(StarshapedObstacle): def boundary_mapping(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): x_obstacle = self.transform(x, input_frame, Frame.OBSTACLE) - intersect_obstacle = self.line_intersection([self._xr, self._xr+1.1*self.enclosing_ball_diameter*self.reference_direction(x_obstacle, Frame.OBSTACLE, Frame.OBSTACLE)], - input_frame=Frame.OBSTACLE, output_frame=Frame.OBSTACLE) + intersect_obstacle = self.line_intersection( + [ + self._xr, + self._xr + + 1.1 + * self.enclosing_ball_diameter + * self.reference_direction(x_obstacle, Frame.OBSTACLE, Frame.OBSTACLE), + ], + input_frame=Frame.OBSTACLE, + output_frame=Frame.OBSTACLE, + ) if not intersect_obstacle: return None if len(intersect_obstacle) == 1: return self.transform(intersect_obstacle[0], Frame.OBSTACLE, output_frame) else: - if np.linalg.norm(intersect_obstacle[0]-x_obstacle) < np.linalg.norm(intersect_obstacle[1]-x_obstacle): - return self.transform(intersect_obstacle[0], Frame.OBSTACLE, output_frame) + if np.linalg.norm(intersect_obstacle[0] - x_obstacle) < np.linalg.norm( + intersect_obstacle[1] - x_obstacle + ): + return self.transform( + intersect_obstacle[0], Frame.OBSTACLE, output_frame + ) else: - return self.transform(intersect_obstacle[1], Frame.OBSTACLE, output_frame) + return self.transform( + intersect_obstacle[1], Frame.OBSTACLE, output_frame + ) - def normal(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL, x_is_boundary=False): - b_obstacle = self.transform(x, input_frame, Frame.OBSTACLE) if x_is_boundary else self.boundary_mapping(x, input_frame, Frame.OBSTACLE) + def normal( + self, + x, + input_frame=Frame.GLOBAL, + output_frame=Frame.GLOBAL, + x_is_boundary=False, + ): + b_obstacle = ( + self.transform(x, input_frame, Frame.OBSTACLE) + if x_is_boundary + else self.boundary_mapping(x, input_frame, Frame.OBSTACLE) + ) if b_obstacle is None: return None - n_obstacle = np.array([self._a2[1] * b_obstacle[0], self._a2[0] * b_obstacle[1]]) + n_obstacle = np.array( + [self._a2[1] * b_obstacle[0], self._a2[0] * b_obstacle[1]] + ) n_obstacle = n_obstacle / np.linalg.norm(n_obstacle) return self.rotate(n_obstacle, Frame.OBSTACLE, output_frame) @@ -92,18 +134,25 @@ class Ellipse(StarshapedObstacle): loc = (x_obstacle[0] / self._a[0]) ** 2 + (x_obstacle[1] / self._a[1]) ** 2 - 1 return loc - def line_intersection(self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): + def line_intersection( + self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ): # Transform line points to left/right points in obstacle ellipse coordinates l0_obstacle = self.transform(line[0], input_frame, Frame.OBSTACLE) l1_obstacle = self.transform(line[1], input_frame, Frame.OBSTACLE) - l_left_obstacle = l0_obstacle if l0_obstacle[0] < l1_obstacle[0] else l1_obstacle - l_right_obstacle = l1_obstacle if l0_obstacle[0] < l1_obstacle[0] else l0_obstacle + l_left_obstacle = ( + l0_obstacle if l0_obstacle[0] < l1_obstacle[0] else l1_obstacle + ) + l_right_obstacle = ( + l1_obstacle if l0_obstacle[0] < l1_obstacle[0] else l0_obstacle + ) - - vertical_line = abs(l_right_obstacle[0]-l_left_obstacle[0]) < 1e-4 + vertical_line = abs(l_right_obstacle[0] - l_left_obstacle[0]) < 1e-4 if not vertical_line: # Line parameters - m = (l_right_obstacle[1] - l_left_obstacle[1]) / (l_right_obstacle[0] - l_left_obstacle[0]) + m = (l_right_obstacle[1] - l_left_obstacle[1]) / ( + l_right_obstacle[0] - l_left_obstacle[0] + ) c = l_left_obstacle[1] - m * l_left_obstacle[0] vertical_line = abs(m) > 100 @@ -112,16 +161,32 @@ class Ellipse(StarshapedObstacle): if l_right_obstacle[0] < -self._a[0] or l_right_obstacle[0] > self._a[0]: return [] - l_top_obstacle = l_right_obstacle if l_right_obstacle[1] > l_left_obstacle[1] else l_left_obstacle - l_bottom_obstacle = l_left_obstacle if l_right_obstacle[1] > l_left_obstacle[1] else l_right_obstacle - x_intersect_top_obstacle, x_intersect_bottom_obstacle = np.array([0, self._a[1]]), np.array([0, -self._a[1]]) - x_intersect_top = self.transform(x_intersect_top_obstacle, Frame.OBSTACLE, output_frame) - x_intersect_bottom = self.transform(x_intersect_bottom_obstacle, Frame.OBSTACLE, output_frame) + l_top_obstacle = ( + l_right_obstacle + if l_right_obstacle[1] > l_left_obstacle[1] + else l_left_obstacle + ) + l_bottom_obstacle = ( + l_left_obstacle + if l_right_obstacle[1] > l_left_obstacle[1] + else l_right_obstacle + ) + x_intersect_top_obstacle, x_intersect_bottom_obstacle = np.array( + [0, self._a[1]] + ), np.array([0, -self._a[1]]) + x_intersect_top = self.transform( + x_intersect_top_obstacle, Frame.OBSTACLE, output_frame + ) + x_intersect_bottom = self.transform( + x_intersect_bottom_obstacle, Frame.OBSTACLE, output_frame + ) if l_top_obstacle[1] >= self._a[1] and l_bottom_obstacle[1] <= -self._a[1]: return [x_intersect_top, x_intersect_bottom] elif l_top_obstacle[1] >= self._a[1] and l_bottom_obstacle[1] <= self._a[1]: return [x_intersect_top] - elif l_top_obstacle[1] >= -self._a[1] and l_bottom_obstacle[1] <= -self._a[1]: + elif ( + l_top_obstacle[1] >= -self._a[1] and l_bottom_obstacle[1] <= -self._a[1] + ): return [x_intersect_bottom] else: return [] @@ -140,18 +205,28 @@ class Ellipse(StarshapedObstacle): x_intersect_obstacle = np.array([tmp_x, m * tmp_x + c]) return [self.transform(x_intersect_obstacle, Frame.OBSTACLE, output_frame)] else: - in_sqrt = kx ** 2 / (4 * kx2 ** 2) - k1 / kx2 + in_sqrt = kx**2 / (4 * kx2**2) - k1 / kx2 if np.isclose(in_sqrt, 0): in_sqrt = 0 tmp_x = -kx / (2 * kx2) - np.sqrt(in_sqrt) x_intersect_left_obstacle = np.array([tmp_x, m * tmp_x + c]) tmp_x = -kx / (2 * kx2) + np.sqrt(in_sqrt) x_intersect_right_obstacle = np.array([tmp_x, m * tmp_x + c]) - x_intersect_left = self.transform(x_intersect_left_obstacle, Frame.OBSTACLE, output_frame) - x_intersect_right = self.transform(x_intersect_right_obstacle, Frame.OBSTACLE, output_frame) + x_intersect_left = self.transform( + x_intersect_left_obstacle, Frame.OBSTACLE, output_frame + ) + x_intersect_right = self.transform( + x_intersect_right_obstacle, Frame.OBSTACLE, output_frame + ) - if l_right_obstacle[0] < x_intersect_left_obstacle[0] or x_intersect_right_obstacle[0] < l_left_obstacle[0] or \ - x_intersect_left_obstacle[0] < l_left_obstacle[0] < l_right_obstacle[0] < x_intersect_right_obstacle[0]: + if ( + l_right_obstacle[0] < x_intersect_left_obstacle[0] + or x_intersect_right_obstacle[0] < l_left_obstacle[0] + or x_intersect_left_obstacle[0] + < l_left_obstacle[0] + < l_right_obstacle[0] + < x_intersect_right_obstacle[0] + ): return [] elif x_intersect_left_obstacle[0] < l_left_obstacle[0]: return [x_intersect_right] @@ -170,8 +245,8 @@ class Ellipse(StarshapedObstacle): a2 = self._a**2 vertical_tangent = abs(a2[0] - px**2) < 1e-5 if vertical_tangent: - m2 = (py**2-a2[1]) / (2*px*py) - x2 = (px * m2 ** 2 - py * m2) / (a2[1] / a2[0] + m2 ** 2) + m2 = (py**2 - a2[1]) / (2 * px * py) + x2 = (px * m2**2 - py * m2) / (a2[1] / a2[0] + m2**2) y2 = m2 * (x2 - px) + py tp1_obstacle = np.array([px, 0]) tp2_obstacle = np.array([x2, y2]) @@ -179,7 +254,7 @@ class Ellipse(StarshapedObstacle): tmp = px**2 - a2[0] c1 = (px * py) / tmp c2 = (a2[1] - py**2) / tmp - tmp = np.sqrt(c1**2+c2) + tmp = np.sqrt(c1**2 + c2) m1, m2 = c1 + tmp, c1 - tmp tmp = a2[1] / a2[0] m1_sqr = m1**2 @@ -212,6 +287,6 @@ class Ellipse(StarshapedObstacle): def _compute_polygon_representation(self): # logprint(str(self) + ": " + str(self._polygon), 0) t = np.linspace(0, 2 * np.pi, self._n_pol, endpoint=False) - a = self._a + 1e-3 # Add offset to adjust for polygon approximation + a = self._a + 1e-3 # Add offset to adjust for polygon approximation polygon = np.vstack((a[0] * np.cos(t), a[1] * np.sin(t))).T self._polygon = shapely.geometry.Polygon(polygon) diff --git a/python/smc/path_generation/starworlds/obstacles/obstacle.py b/python/smc/path_generation/starworlds/obstacles/obstacle.py index 7789611537fe4a9621377a6521a8c1d6ae239f7d..262fb1b7fca1c8de9e48013754e68c5693a68f12 100644 --- a/python/smc/path_generation/starworlds/obstacles/obstacle.py +++ b/python/smc/path_generation/starworlds/obstacles/obstacle.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod import numpy as np import shapely from shapely import affinity as sh_affinity -from utils import affine_transform +from ..utils import affine_transform from copy import deepcopy from enum import Enum @@ -16,30 +16,43 @@ class Frame(Enum): class Obstacle(ABC): - """ Abstract base class of obstacles - """ + """Abstract base class of obstacles""" + id_counter = 0 # obs_id <0: temp object, obs_id=0: new object, obs_id>0: existing object with id #obs_id - def __init__(self, motion_model=None, is_convex=None, is_starshaped=None, id='new', name=None, compute_polygon=False): + def __init__( + self, + motion_model=None, + is_convex=None, + is_starshaped=None, + id="new", + name=None, + compute_polygon=False, + ): self._id = None self._is_convex = is_convex self._is_starshaped = is_starshaped # Pose of local frame in global frame - self._motion_model = motion_model # if motion_model is not None else mm.Static([0., 0.], 0.) + self._motion_model = ( + motion_model # if motion_model is not None else mm.Static([0., 0.], 0.) + ) # Initialize id and name self._set_id_name(id, name) self._polygon = None # Polygon in obstacle frame self._polygon_global = None # Polygon in global frame if static obstacle - self._polygon_global_pose = None # Obstacle pose corresponding to global polygon + self._polygon_global_pose = ( + None # Obstacle pose corresponding to global polygon + ) if compute_polygon: self._compute_global_polygon_representation() - def __str__(self): return self._name + def __str__(self): + return self._name - def copy(self, id='temporary', name=None): + def copy(self, id="temporary", name=None): ob = deepcopy(self) - if not (id == 'duplicate' or id == 'd'): + if not (id == "duplicate" or id == "d"): ob._set_id_name(id, name) return ob @@ -51,7 +64,7 @@ class Obstacle(ABC): def rot(self, output_frame=Frame.GLOBAL): if output_frame == Frame.OBSTACLE or self._motion_model is None: - return 0. + return 0.0 if output_frame == Frame.GLOBAL: return self._motion_model.rot() @@ -62,13 +75,14 @@ class Obstacle(ABC): return True if self.point_location(x, input_frame) > 0 else False def boundary_point(self, x, input_frame=Frame.GLOBAL): - return np.isclose(self.point_location(x, input_frame), 0.) + return np.isclose(self.point_location(x, input_frame), 0.0) def move(self, dt): if self._motion_model is not None: self._motion_model.move(self, dt) - def id(self): return self._id + def id(self): + return self._id def polygon(self, output_frame=Frame.GLOBAL): if self._polygon is None: @@ -81,9 +95,20 @@ class Obstacle(ABC): if not current_pose == self._polygon_global_pose: self._polygon_global_pose = current_pose c, s = np.cos(current_pose[2]), np.sin(current_pose[2]) - trans_matrix = np.array([[c, -s, current_pose[0]], [s, c, current_pose[1]], [0, 0, 1]]) - affinity_matrix = [trans_matrix[0, 0], trans_matrix[0, 1], trans_matrix[1, 0], trans_matrix[1, 1], trans_matrix[0, 2], trans_matrix[1, 2]] - self._polygon_global = sh_affinity.affine_transform(self._polygon, affinity_matrix) + trans_matrix = np.array( + [[c, -s, current_pose[0]], [s, c, current_pose[1]], [0, 0, 1]] + ) + affinity_matrix = [ + trans_matrix[0, 0], + trans_matrix[0, 1], + trans_matrix[1, 0], + trans_matrix[1, 1], + trans_matrix[0, 2], + trans_matrix[1, 2], + ] + self._polygon_global = sh_affinity.affine_transform( + self._polygon, affinity_matrix + ) return self._polygon_global else: raise Frame.InvalidFrameError @@ -131,10 +156,10 @@ class Obstacle(ABC): # ------------ Private methods ------------ # def _set_id_name(self, id, name=None): - if id == 'new' or id == 'n': + if id == "new" or id == "n": Obstacle.id_counter += 1 self._id = Obstacle.id_counter - elif id == 'temporary' or id == 'temp' or id == 't': + elif id == "temporary" or id == "temp" or id == "t": self._id = None elif isinstance(id, int) and 0 < id <= Obstacle.id_counter: self._id = id @@ -149,7 +174,9 @@ class Obstacle(ABC): def _rotate_global2obstacle(self, x_global): rot = self._motion_model.rot() - return affine_transform(x_global, rotation=rot, translation=[0, 0], inverse=True) + return affine_transform( + x_global, rotation=rot, translation=[0, 0], inverse=True + ) def _transform_obstacle2global(self, x_obstacle): pos, rot = (self._motion_model.pos(), self._motion_model.rot()) @@ -163,13 +190,21 @@ class Obstacle(ABC): self._compute_polygon_representation() if self._motion_model is None: self._polygon_global = self._polygon - if self._motion_model.__class__.__name__ == 'Static': + if self._motion_model.__class__.__name__ == "Static": pos, rot = (self._motion_model.pos(), self._motion_model.rot()) c, s = np.cos(rot), np.sin(rot) trans_matrix = np.array([[c, -s, pos[0]], [s, c, pos[1]], [0, 0, 1]]) - affinity_matrix = [trans_matrix[0, 0], trans_matrix[0, 1], trans_matrix[1, 0], trans_matrix[1, 1], - trans_matrix[0, 2], trans_matrix[1, 2]] - self._polygon_global = shapely.affinity.affine_transform(self._polygon, affinity_matrix) + affinity_matrix = [ + trans_matrix[0, 0], + trans_matrix[0, 1], + trans_matrix[1, 0], + trans_matrix[1, 1], + trans_matrix[0, 2], + trans_matrix[1, 2], + ] + self._polygon_global = shapely.affinity.affine_transform( + self._polygon, affinity_matrix + ) # ------------ Abstract methods ------------ # @abstractmethod @@ -185,7 +220,9 @@ class Obstacle(ABC): pass @abstractmethod - def line_intersection(self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): + def line_intersection( + self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ): pass @abstractmethod diff --git a/python/smc/path_generation/starworlds/obstacles/polygon.py b/python/smc/path_generation/starworlds/obstacles/polygon.py index d8ec63a62b891136497967a50f588d08dd1b8343..97ba8d16cb2d6bf3cd46cb2095154612f8711ce3 100644 --- a/python/smc/path_generation/starworlds/obstacles/polygon.py +++ b/python/smc/path_generation/starworlds/obstacles/polygon.py @@ -1,5 +1,5 @@ -from obstacles import Obstacle, Frame -from utils import is_cw, is_ccw, is_collinear, tic, toc +from ..obstacles import Obstacle, Frame +from ..utils import is_cw, is_ccw, is_collinear, tic, toc import shapely import numpy as np import matplotlib.pyplot as plt @@ -19,11 +19,11 @@ class Polygon(Obstacle): def init_plot(self, ax=None, show_name=False, **kwargs): if ax is None: - _, ax = plt.subplots(subplot_kw={'aspect': 'equal'}) + _, ax = plt.subplots(subplot_kw={"aspect": "equal"}) if "fc" not in kwargs and "facecolor" not in kwargs: - kwargs["fc"] = 'lightgrey' - if 'show_reference' in kwargs: - del kwargs['show_reference'] + kwargs["fc"] = "lightgrey" + if "show_reference" in kwargs: + del kwargs["show_reference"] line_handles = [] # Boundary line_handles += [patches.Polygon(np.random.rand(3, 2), **kwargs)] @@ -70,29 +70,49 @@ class Polygon(Obstacle): return 0 return 1 - def line_intersection(self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): + def line_intersection( + self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ): l0_obstacle = self.transform(line[0], input_frame, Frame.OBSTACLE) l1_obstacle = self.transform(line[1], input_frame, Frame.OBSTACLE) - intersection_points_shapely = shapely.geometry.LineString([l0_obstacle, l1_obstacle]).intersection(self._polygon.exterior) + intersection_points_shapely = shapely.geometry.LineString( + [l0_obstacle, l1_obstacle] + ).intersection(self._polygon.exterior) if intersection_points_shapely.is_empty: return [] - if intersection_points_shapely.geom_type == 'Point': - intersection_points_obstacle = [np.array([intersection_points_shapely.x, intersection_points_shapely.y])] - elif intersection_points_shapely.geom_type == 'MultiPoint': - intersection_points_obstacle = [np.array([p.x, p.y]) for p in intersection_points_shapely.geoms] - elif intersection_points_shapely.geom_type == 'LineString': - intersection_points_obstacle = [np.array([ip[0], ip[1]]) for ip in intersection_points_shapely.coords] - elif intersection_points_shapely.geom_type == 'MultiLineString': - intersection_points_obstacle = [np.array([ip[0], ip[1]]) for line in intersection_points_shapely.geoms for ip in line.coords] + if intersection_points_shapely.geom_type == "Point": + intersection_points_obstacle = [ + np.array([intersection_points_shapely.x, intersection_points_shapely.y]) + ] + elif intersection_points_shapely.geom_type == "MultiPoint": + intersection_points_obstacle = [ + np.array([p.x, p.y]) for p in intersection_points_shapely.geoms + ] + elif intersection_points_shapely.geom_type == "LineString": + intersection_points_obstacle = [ + np.array([ip[0], ip[1]]) for ip in intersection_points_shapely.coords + ] + elif intersection_points_shapely.geom_type == "MultiLineString": + intersection_points_obstacle = [ + np.array([ip[0], ip[1]]) + for line in intersection_points_shapely.geoms + for ip in line.coords + ] else: print(intersection_points_shapely) - return [self.transform(ip, Frame.OBSTACLE, output_frame) for ip in intersection_points_obstacle] + return [ + self.transform(ip, Frame.OBSTACLE, output_frame) + for ip in intersection_points_obstacle + ] def tangent_points(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): x_obstacle = self.transform(x, input_frame, Frame.OBSTACLE) t0 = tic() - phi = np.arctan2(self.circular_vertices[:, 1] - x_obstacle[1], self.circular_vertices[:, 0] - x_obstacle[0]) + phi = np.arctan2( + self.circular_vertices[:, 1] - x_obstacle[1], + self.circular_vertices[:, 0] - x_obstacle[0], + ) phi[phi < 0] += 2 * np.pi t1 = toc(t0) t0 = tic() @@ -106,9 +126,9 @@ class Polygon(Obstacle): phi_decrease_idcs = np.flatnonzero(phi_decrease_idcs) phi_increase_idcs = np.flatnonzero(phi_increase_idcs) for i in phi_decrease_idcs: - phi[i+1:] -= 2*np.pi + phi[i + 1 :] -= 2 * np.pi for i in phi_increase_idcs: - phi[i+1:] += 2*np.pi + phi[i + 1 :] += 2 * np.pi t4 = toc(t0) t0 = tic() @@ -118,7 +138,7 @@ class Polygon(Obstacle): if abs(phi[0] - phi[-1]) > 0.00001: # Interior point return [] - if (phi[i_max] - phi[i_min]) >= 2*np.pi: + if (phi[i_max] - phi[i_min]) >= 2 * np.pi: # Blocked exterior point return [] t5 = toc(t0) @@ -143,15 +163,25 @@ class Polygon(Obstacle): i = 0 N = v.shape[0] # Make sure first vertice is not collinear - while is_collinear(v[i-1, :], v[i, :], v[(i+1) % N, :]): + while is_collinear(v[i - 1, :], v[i, :], v[(i + 1) % N, :]): i += 1 if i > N: raise RuntimeError("Bad polygon shape. All vertices collinear") # All vertices must be either cw or ccw when iterating through for convexity - if is_cw(v[i-1, :], v[i, :], v[i+1, :]): - self._is_convex = not any([is_ccw(v[j-1, :], v[j, :], v[(j+1) % N, :]) for j in range(v.shape[0])]) + if is_cw(v[i - 1, :], v[i, :], v[i + 1, :]): + self._is_convex = not any( + [ + is_ccw(v[j - 1, :], v[j, :], v[(j + 1) % N, :]) + for j in range(v.shape[0]) + ] + ) else: - self._is_convex = not any([is_cw(v[j-1, :], v[j, :], v[(j+1) % N, :]) for j in range(v.shape[0])]) + self._is_convex = not any( + [ + is_cw(v[j - 1, :], v[j, :], v[(j + 1) % N, :]) + for j in range(v.shape[0]) + ] + ) # Not needed def _compute_polygon_representation(self): diff --git a/python/smc/path_generation/starworlds/obstacles/starshaped_obstacle.py b/python/smc/path_generation/starworlds/obstacles/starshaped_obstacle.py index 122ab8f02c24f2b1c0d57754353c639f4d5a3fae..85cc2d8d32b7a5b9afffda815edbb061276a84df 100644 --- a/python/smc/path_generation/starworlds/obstacles/starshaped_obstacle.py +++ b/python/smc/path_generation/starworlds/obstacles/starshaped_obstacle.py @@ -1,6 +1,6 @@ from abc import abstractmethod import numpy as np -from obstacles import Obstacle, Frame +from ..obstacles import Obstacle, Frame from shapely import affinity as sh_affinity @@ -25,8 +25,12 @@ class StarshapedObstacle(Obstacle): else: self._xr = new_xr - def reference_direction(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): - dir = self.transform(x, input_frame, output_frame) - self.transform(self._xr, Frame.OBSTACLE, output_frame) + def reference_direction( + self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ): + dir = self.transform(x, input_frame, output_frame) - self.transform( + self._xr, Frame.OBSTACLE, output_frame + ) if not np.any(dir): print("reference_direction for xr is not defined") return dir / np.linalg.norm(dir, axis=x.ndim - 1) @@ -34,14 +38,25 @@ class StarshapedObstacle(Obstacle): # interior point: <1. exterior point: >1. boundary point: 1. def distance_function(self, x, input_frame=Frame.GLOBAL): x_obstacle = self.transform(x, input_frame, Frame.OBSTACLE) - dist_func = (np.linalg.norm(x_obstacle - self._xr, axis=x.ndim - 1) / ( - np.linalg.norm(self.boundary_mapping(x_obstacle, input_frame=Frame.OBSTACLE, output_frame=Frame.OBSTACLE) - - self._xr, axis=x.ndim - 1))) ** 2 + dist_func = ( + np.linalg.norm(x_obstacle - self._xr, axis=x.ndim - 1) + / ( + np.linalg.norm( + self.boundary_mapping( + x_obstacle, + input_frame=Frame.OBSTACLE, + output_frame=Frame.OBSTACLE, + ) + - self._xr, + axis=x.ndim - 1, + ) + ) + ) ** 2 return dist_func # interior point: <0. exterior point: >0. boundary point: 0. def point_location(self, x, input_frame=Frame.GLOBAL): - return np.sign(self.distance_function(x, input_frame)-1.) + return np.sign(self.distance_function(x, input_frame) - 1.0) def kernel(self, output_frame=Frame.GLOBAL): if self._kernel is None: @@ -53,9 +68,20 @@ class StarshapedObstacle(Obstacle): if not current_pose == self._kernel_global_pose: self._kernel_global_pose = current_pose c, s = np.cos(current_pose[2]), np.sin(current_pose[2]) - trans_matrix = np.array([[c, -s, current_pose[0]], [s, c, current_pose[1]], [0, 0, 1]]) - affinity_matrix = [trans_matrix[0, 0], trans_matrix[0, 1], trans_matrix[1, 0], trans_matrix[1, 1], trans_matrix[0, 2], trans_matrix[1, 2]] - self._kernel_global = sh_affinity.affine_transform(self._kernel, affinity_matrix) + trans_matrix = np.array( + [[c, -s, current_pose[0]], [s, c, current_pose[1]], [0, 0, 1]] + ) + affinity_matrix = [ + trans_matrix[0, 0], + trans_matrix[0, 1], + trans_matrix[1, 0], + trans_matrix[1, 1], + trans_matrix[0, 2], + trans_matrix[1, 2], + ] + self._kernel_global = sh_affinity.affine_transform( + self._kernel, affinity_matrix + ) return self._kernel_global else: raise Frame.InvalidFrameError @@ -64,12 +90,20 @@ class StarshapedObstacle(Obstacle): if self._motion_model is None: return np.zeros(2) omega = self._motion_model.rot_vel() - lin_vel_omega = np.cross(np.hstack(([0, 0], omega)), np.hstack((self.reference_direction(x), 0)))[:2] + lin_vel_omega = np.cross( + np.hstack(([0, 0], omega)), np.hstack((self.reference_direction(x), 0)) + )[:2] return self._motion_model.lin_vel() + lin_vel_omega # ------------ Abstract methods ------------ # @abstractmethod - def normal(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL, x_is_boundary=False): + def normal( + self, + x, + input_frame=Frame.GLOBAL, + output_frame=Frame.GLOBAL, + x_is_boundary=False, + ): pass @abstractmethod diff --git a/python/smc/path_generation/starworlds/obstacles/starshaped_polygon.py b/python/smc/path_generation/starworlds/obstacles/starshaped_polygon.py index 85eba3ce218671de85d625c612a6fa9494377efe..d17a1282c729d60cbb9e4c9f27bfbce2ae1708de 100644 --- a/python/smc/path_generation/starworlds/obstacles/starshaped_polygon.py +++ b/python/smc/path_generation/starworlds/obstacles/starshaped_polygon.py @@ -1,8 +1,8 @@ -from obstacles import Frame, StarshapedObstacle, Polygon +from ..obstacles import Frame, StarshapedObstacle, Polygon import matplotlib.pyplot as plt import numpy as np import shapely -from utils import is_cw, is_ccw, is_collinear, orientation_val, get_intersection, is_between, tic, toc +from ..utils import is_cw, is_ccw, is_collinear, orientation_val, get_intersection, is_between, tic, toc class StarshapedPolygon(Polygon, StarshapedObstacle): diff --git a/python/smc/path_generation/starworlds/obstacles/starshaped_primitive_combination.py b/python/smc/path_generation/starworlds/obstacles/starshaped_primitive_combination.py index 6fdf2cd7ba907711261851bd22c60a6ab5d1b95d..339fe235c37d363b93f46ed7be9f48287d5315ca 100644 --- a/python/smc/path_generation/starworlds/obstacles/starshaped_primitive_combination.py +++ b/python/smc/path_generation/starworlds/obstacles/starshaped_primitive_combination.py @@ -1,9 +1,10 @@ import shapely import numpy as np -from obstacles import Frame, StarshapedObstacle, StarshapedPolygon -from utils import is_ccw, is_cw, draw_shapely_polygon +from ..obstacles import Frame, StarshapedObstacle, StarshapedPolygon +from ..utils import is_ccw, is_cw, draw_shapely_polygon import matplotlib.pyplot as plt + # Note: Local == Global frame class StarshapedPrimitiveCombination(StarshapedObstacle): @@ -25,8 +26,10 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): pass def point_location(self, x, input_frame=Frame.GLOBAL): - locs = [obs.point_location(x, input_frame=Frame.GLOBAL) for obs in self._obstacle_cluster] + \ - [self._hull_cluster_point_location(x)] + locs = [ + obs.point_location(x, input_frame=Frame.GLOBAL) + for obs in self._obstacle_cluster + ] + [self._hull_cluster_point_location(x)] if any([l < 0 for l in locs]): # Interior point return -1 @@ -36,7 +39,9 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): # Exterior point return 1 - def line_intersection(self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): + def line_intersection( + self, line, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ): intersection_points = [] for o in self._obstacle_cluster: intersection_points += o.line_intersection(line, Frame.GLOBAL, Frame.GLOBAL) @@ -49,30 +54,51 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): for obs in self._obstacle_cluster: tp_candidates += obs.tangent_points(x, Frame.GLOBAL, Frame.GLOBAL) for i in range(len(tp_candidates)): - if all([is_ccw(x, tp_candidates[i], tp_candidates[j]) for j in range(len(tp_candidates)) if j is not i]) or \ - all([is_cw(x, tp_candidates[i], tp_candidates[j]) for j in range(len(tp_candidates)) if j is not i]): + if all( + [ + is_ccw(x, tp_candidates[i], tp_candidates[j]) + for j in range(len(tp_candidates)) + if j is not i + ] + ) or all( + [ + is_cw(x, tp_candidates[i], tp_candidates[j]) + for j in range(len(tp_candidates)) + if j is not i + ] + ): tp += [tp_candidates[i]] return tp def _compute_kernel(self): - self._kernel = StarshapedPolygon(self.polygon(), xr=self.xr(), id="temp").kernel() + self._kernel = StarshapedPolygon( + self.polygon(), xr=self.xr(), id="temp" + ).kernel() def _check_convexity(self): - self._is_convex = StarshapedPolygon(self.polygon(), xr=self.xr(), id="temp").is_convex() + self._is_convex = StarshapedPolygon( + self.polygon(), xr=self.xr(), id="temp" + ).is_convex() def boundary_mapping(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL): # intersection_points = [p for ps in self.line_intersection([self._xr, self._xr+10*(x-self._xr)]) for p in ps] - intersection_points = self.line_intersection([self._xr, self._xr+10*(x-self._xr)]) + intersection_points = self.line_intersection( + [self._xr, self._xr + 10 * (x - self._xr)] + ) if not intersection_points: return None - dist_intersection_points = [np.linalg.norm(ip - self._xr) for ip in intersection_points] + dist_intersection_points = [ + np.linalg.norm(ip - self._xr) for ip in intersection_points + ] return intersection_points[np.argmax(dist_intersection_points)] def vel_intertial_frame(self, x): boundary_obs_idx = 0 max_dist = -1 - for i, ps in enumerate(self.line_intersection([self._xr, self._xr+10*(x-self._xr)])): - o_intersection_dist = max([np.linalg.norm(p-self._xr) for p in ps] + [-1]) + for i, ps in enumerate( + self.line_intersection([self._xr, self._xr + 10 * (x - self._xr)]) + ): + o_intersection_dist = max([np.linalg.norm(p - self._xr) for p in ps] + [-1]) if o_intersection_dist > max_dist: boundary_obs_idx = i max_dist = o_intersection_dist @@ -80,13 +106,22 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): boundary_obs_idx -= len(self._obstacle_cluster) return self._obstacle_cluster[boundary_obs_idx].vel_intertial_frame(x) - def normal(self, x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL, x_is_boundary=False, type='weigthed_polygon_approx'): - if type == 'sub_normal': + def normal( + self, + x, + input_frame=Frame.GLOBAL, + output_frame=Frame.GLOBAL, + x_is_boundary=False, + type="weigthed_polygon_approx", + ): + if type == "sub_normal": boundary_obs_idx = 0 max_dist = -1 - line = [self._xr, self._xr+10*(x-self._xr)] + line = [self._xr, self._xr + 10 * (x - self._xr)] for i, o in enumerate(self._obstacle_cluster): - intersection_points = o.line_intersection(line, Frame.GLOBAL, Frame.GLOBAL) + intersection_points = o.line_intersection( + line, Frame.GLOBAL, Frame.GLOBAL + ) for p in intersection_points: p_dist = np.linalg.norm(p - self._xr) if p_dist > max_dist: @@ -101,11 +136,18 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): max_dist = p_dist boundary_obs_idx = len(self._obstacle_cluster) if boundary_obs_idx < len(self._obstacle_cluster): - return self._obstacle_cluster[boundary_obs_idx].normal(x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL) + return self._obstacle_cluster[boundary_obs_idx].normal( + x, input_frame=Frame.GLOBAL, output_frame=Frame.GLOBAL + ) else: boundary_obs_idx -= len(self._obstacle_cluster) hull_vertices = np.array(self._hull_cluster.exterior.coords[:-1]) - vertex_angles = np.array([np.arctan2(v[1] - self._xr[1], v[0] - self._xr[0]) for v in hull_vertices]).flatten() + vertex_angles = np.array( + [ + np.arctan2(v[1] - self._xr[1], v[0] - self._xr[0]) + for v in hull_vertices + ] + ).flatten() idcs = np.argsort(vertex_angles) vertex_angles = vertex_angles[idcs] hull_vertices = hull_vertices[idcs, :] @@ -117,11 +159,15 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): # Adjust for circular self.vertices (self.vertices[0] == self.vertices[-1]) if v_idx == 0: v_idx = -1 - n = np.array([hull_vertices[v_idx, 1] - hull_vertices[v_idx - 1, 1], - hull_vertices[v_idx - 1, 0] - hull_vertices[v_idx, 0]]) + n = np.array( + [ + hull_vertices[v_idx, 1] - hull_vertices[v_idx - 1, 1], + hull_vertices[v_idx - 1, 0] - hull_vertices[v_idx, 0], + ] + ) n /= np.linalg.norm(n) return n - elif type == 'polygon_approx' or type == 'weigthed_polygon_approx': + elif type == "polygon_approx" or type == "weigthed_polygon_approx": if self.vertices is None: self._update_vertex_angles() angle = np.arctan2(x[1] - self._xr[1], x[0] - self._xr[0]) @@ -130,17 +176,30 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): if v_idx == self.vertices.shape[0]: v_idx = 0 - if type == 'polygon_approx': - n = np.array([self.vertices[v_idx, 1] - self.vertices[v_idx - 1, 1], - self.vertices[v_idx - 1, 0] - self.vertices[v_idx, 0]]) + if type == "polygon_approx": + n = np.array( + [ + self.vertices[v_idx, 1] - self.vertices[v_idx - 1, 1], + self.vertices[v_idx - 1, 0] - self.vertices[v_idx, 0], + ] + ) else: - edge_neighbors = [(self.vertices[(v_idx - 2 + i) % self.vertices.shape[0]], - self.vertices[(v_idx - 1 + i) % self.vertices.shape[0]]) for i in range(3)] - edge_neighbors_normal = np.array([[e[1][1] - e[0][1], - e[0][0] - e[1][0]] for e in edge_neighbors]) - edge_closest = [shapely.ops.nearest_points(shapely.geometry.LineString(e), - shapely.geometry.Point(x))[0].coords[0] for e in - edge_neighbors] + edge_neighbors = [ + ( + self.vertices[(v_idx - 2 + i) % self.vertices.shape[0]], + self.vertices[(v_idx - 1 + i) % self.vertices.shape[0]], + ) + for i in range(3) + ] + edge_neighbors_normal = np.array( + [[e[1][1] - e[0][1], e[0][0] - e[1][0]] for e in edge_neighbors] + ) + edge_closest = [ + shapely.ops.nearest_points( + shapely.geometry.LineString(e), shapely.geometry.Point(x) + )[0].coords[0] + for e in edge_neighbors + ] dist = [np.linalg.norm(np.array(e) - x) for e in edge_closest] w = np.array([1 / (d + 1e-10) for d in dist]) @@ -153,12 +212,12 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): def set_xr(self, xr, input_frame=Frame.OBSTACLE, safe_set=False): super().set_xr(xr, input_frame, safe_set) self._update_vertex_angles() - + def init_plot(self, ax=None, show_reference=True, show_name=False, **kwargs): if ax is None: - _, ax = plt.subplots(subplot_kw={'aspect': 'equal'}) + _, ax = plt.subplots(subplot_kw={"aspect": "equal"}) if "fc" not in kwargs and "facecolor" not in kwargs: - kwargs["fc"] = 'lightgrey' + kwargs["fc"] = "lightgrey" line_handles = [] @@ -166,7 +225,9 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): line_handles += lh # Reference point - line_handles += ax.plot(*self.xr(), '+', color='k') if show_reference else [None] + line_handles += ( + ax.plot(*self.xr(), "+", color="k") if show_reference else [None] + ) # Name line_handles += [ax.text(*self.xr(), self._name)] if show_name else [None] return line_handles, ax @@ -196,15 +257,22 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): intersection_points_shapely = line_sh.intersection(self._hull_cluster.exterior) if intersection_points_shapely.is_empty: return [] - if intersection_points_shapely.geom_type == 'Point': - return [np.array([intersection_points_shapely.x, intersection_points_shapely.y])] - elif intersection_points_shapely.geom_type == 'MultiPoint': + if intersection_points_shapely.geom_type == "Point": + return [ + np.array([intersection_points_shapely.x, intersection_points_shapely.y]) + ] + elif intersection_points_shapely.geom_type == "MultiPoint": return [np.array([p.x, p.y]) for p in intersection_points_shapely.geoms] - elif intersection_points_shapely.geom_type == 'LineString': - return [np.array([ip[0], ip[1]]) for ip in intersection_points_shapely.coords] - elif intersection_points_shapely.geom_type == 'MultiLineString': - return [np.array([l[0], l[1]]) for line in intersection_points_shapely.geoms for - l in line.coords] + elif intersection_points_shapely.geom_type == "LineString": + return [ + np.array([ip[0], ip[1]]) for ip in intersection_points_shapely.coords + ] + elif intersection_points_shapely.geom_type == "MultiLineString": + return [ + np.array([l[0], l[1]]) + for line in intersection_points_shapely.geoms + for l in line.coords + ] else: print("[_hull_cluster_line_intersections]: Shapely geom_type not covered!") print(intersection_points_shapely) @@ -212,12 +280,16 @@ class StarshapedPrimitiveCombination(StarshapedObstacle): def _update_vertex_angles(self): self.vertices = np.array(self._polygon.exterior.coords[:-1]) self.circular_vertices = np.array(self._polygon.exterior.coords) - self.vertex_angles = np.arctan2(self.vertices[:, 1] - self._xr[1], self.vertices[:, 0] - self._xr[0]) + self.vertex_angles = np.arctan2( + self.vertices[:, 1] - self._xr[1], self.vertices[:, 0] - self._xr[0] + ) idcs = np.argsort(self.vertex_angles) self.vertex_angles = self.vertex_angles[idcs] self.vertices = self.vertices[idcs, :] self.circular_vertices = np.vstack((self.vertices, self.vertices[0, :])) - self.vertex_angles = np.hstack((self.vertex_angles, self.vertex_angles[0] + 2 * np.pi)) + self.vertex_angles = np.hstack( + (self.vertex_angles, self.vertex_angles[0] + 2 * np.pi) + ) def _compute_polygon_representation(self): obs_pol = [obs.polygon() for obs in self._obstacle_cluster] diff --git a/python/smc/path_generation/starworlds/starshaped_hull/cluster_and_starify.py b/python/smc/path_generation/starworlds/starshaped_hull/cluster_and_starify.py index 2e825e86581a3bbecb805d3ea1351a1a6a5c95ed..85ba23dce36ce6dabe1744f658edca314a2c0181 100644 --- a/python/smc/path_generation/starworlds/starshaped_hull/cluster_and_starify.py +++ b/python/smc/path_generation/starworlds/starshaped_hull/cluster_and_starify.py @@ -1,9 +1,9 @@ import shapely import numpy as np -from obstacles import Frame, StarshapedPrimitiveCombination, Ellipse, StarshapedPolygon -from utils import is_ccw, is_collinear, equilateral_triangle, Cone, tic, toc, draw_shapely_polygon +from ..obstacles import Frame, StarshapedPrimitiveCombination, Ellipse, StarshapedPolygon +from ..utils import is_ccw, is_collinear, equilateral_triangle, Cone, tic, toc, draw_shapely_polygon from scipy.spatial import ConvexHull -import starshaped_hull as sh +from ..starshaped_hull import starshaped_hull as sh import matplotlib.pyplot as plt diff --git a/python/smc/path_generation/starworlds/starshaped_hull/starshaped_hull.py b/python/smc/path_generation/starworlds/starshaped_hull/starshaped_hull.py index 8fde482f9edaf717ffcb82f170b9bacc158c3714..16e1c4b67e18f35640c58e488bcd66db1dfb0461 100644 --- a/python/smc/path_generation/starworlds/starshaped_hull/starshaped_hull.py +++ b/python/smc/path_generation/starworlds/starshaped_hull/starshaped_hull.py @@ -1,7 +1,7 @@ import shapely import numpy as np -from obstacles import Polygon -from utils import is_ccw, is_cw, line, ray, Cone, convex_hull +from ..obstacles import Polygon +from ..utils import is_ccw, is_cw, line, ray, Cone, convex_hull import matplotlib.pyplot as plt @@ -11,7 +11,7 @@ def admissible_kernel(obstacle, x): if not tps: # Interior point return None - return Cone(x, x-tps[0], x-tps[1]) + return Cone(x, x - tps[0], x - tps[1]) # Computes the starshaped hull of a list of obstacles for specified kernel points @@ -39,7 +39,7 @@ def convex_kernel_starshaped_hull(convex_obstacle, kernel_points): if not tps: return shapely.geometry.Polygon([]) - tps = np.unique(tps,axis=0) + tps = np.unique(tps, axis=0) ch_points = np.vstack((tps, kernel_points)) pol = convex_hull(ch_points) return shapely.geometry.Polygon(pol) @@ -47,7 +47,7 @@ def convex_kernel_starshaped_hull(convex_obstacle, kernel_points): # TODO: Improve computational consideration def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): - kernel_points = kernel_points.reshape((kernel_points.size//2, 2)) + kernel_points = kernel_points.reshape((kernel_points.size // 2, 2)) if kernel_points.shape[0] > 2: # NOTE: Assumes kernel points convex @@ -58,7 +58,7 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): # vertices = np.asarray(polygon_sh.exterior.coords)[:-1, :] # Vertices of polygon vertices = np.asarray(polygon.exterior.coords)[:-1, :] # Vertices of polygon star_vertices = [] # Vertices of starshaped hull polygon - v_bar = kernel_points[0].copy() # Last vertex of starshaped hull polygon + v_bar = kernel_points[0].copy() # Last vertex of starshaped hull polygon e1_idx = 0 e2_idx = 0 k_centroid = np.mean(kernel_points, axis=0) @@ -78,7 +78,9 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): # Check if no ray r(v,kv) intersects with interior of polygon if all([ray(v, k, v).disjoint(polygon) for k in kernel_points]): # Add current vertex - if kernel_points.shape[0] < 3 or not convex_kernel_subset.contains(shapely.geometry.Point(v)): + if kernel_points.shape[0] < 3 or not convex_kernel_subset.contains( + shapely.geometry.Point(v) + ): star_vertices += [v] if star_vertices: # Intersections of lines l(k,v) and l(e1,e2) @@ -86,12 +88,16 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): e1_e2 = line(e1, e2) for k in kernel_points: - kv_e1e2_intersect = line(k,v).intersection(e1_e2) + kv_e1e2_intersect = line(k, v).intersection(e1_e2) # Adjust to closest intersection to e2 if not kv_e1e2_intersect.is_empty: adjust_e1 = True - e1_candidate = np.array([kv_e1e2_intersect.x, kv_e1e2_intersect.y]) - if np.linalg.norm(e2 - e1_candidate) < np.linalg.norm(e2 - star_vertices[e1_idx]): + e1_candidate = np.array( + [kv_e1e2_intersect.x, kv_e1e2_intersect.y] + ) + if np.linalg.norm(e2 - e1_candidate) < np.linalg.norm( + e2 - star_vertices[e1_idx] + ): star_vertices[e1_idx] = e1_candidate if not adjust_e1: @@ -102,18 +108,25 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): # If l(k,v) intersects interior of P if not kv_P_intersect.is_empty: # Find last intersection of l(k,v) and polygon boundary - if kv_P_intersect.geom_type == 'LineString': - intersection_points = [np.array([ip[0], ip[1]]) for ip in kv_P_intersect.coords] - elif kv_P_intersect.geom_type == 'MultiLineString': - intersection_points = [np.array([ip[0], ip[1]]) for l in kv_P_intersect.geoms for ip in - l.coords] - elif kv_P_intersect.geom_type == 'GeometryCollection': + if kv_P_intersect.geom_type == "LineString": + intersection_points = [ + np.array([ip[0], ip[1]]) for ip in kv_P_intersect.coords + ] + elif kv_P_intersect.geom_type == "MultiLineString": + intersection_points = [ + np.array([ip[0], ip[1]]) + for l in kv_P_intersect.geoms + for ip in l.coords + ] + elif kv_P_intersect.geom_type == "GeometryCollection": intersection_points = [] for g in kv_P_intersect.geoms: - if g.geom_type == 'Point': + if g.geom_type == "Point": intersection_points += [np.array(g.coords[0])] - if kv_P_intersect.geom_type == 'LineString': - intersection_points += [np.array([ip[0], ip[1]]) for ip in g.coords] + if kv_P_intersect.geom_type == "LineString": + intersection_points += [ + np.array([ip[0], ip[1]]) for ip in g.coords + ] else: intersection_points = [] @@ -133,30 +146,46 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): for kp in kps: kpvb_uv_intersect = line(kp, v_bar).intersection(u_v) if not kpvb_uv_intersect.is_empty: - u = np.array([kpvb_uv_intersect.x, kpvb_uv_intersect.y]) + u = np.array( + [kpvb_uv_intersect.x, kpvb_uv_intersect.y] + ) # Append u to P* star_vertices += [u] # Update last augmented edge - e1_idx, e2_idx = len(star_vertices)-1, len(star_vertices)-2 + e1_idx, e2_idx = ( + len(star_vertices) - 1, + len(star_vertices) - 2, + ) # Swap last vertices if not CCW - if is_ccw(u, v, vertices[v_idx-1]): - # if is_ccw(v_bar, v, u): - # if is_cw(k_centroid, v, u): - star_vertices[-2], star_vertices[-1] = star_vertices[-1], star_vertices[-2] + if is_ccw(u, v, vertices[v_idx - 1]): + # if is_ccw(v_bar, v, u): + # if is_cw(k_centroid, v, u): + star_vertices[-2], star_vertices[-1] = ( + star_vertices[-1], + star_vertices[-2], + ) e1_idx, e2_idx = e2_idx, e1_idx adjust_e1 = True else: # Check if no ray r(k,k'v) intersect with interior of polygon - if (not k_included[k_idx]) and (not any([ray(k, kp, v).intersects(polygon) for kp in kps])): + if (not k_included[k_idx]) and ( + not any([ray(k, kp, v).intersects(polygon) for kp in kps]) + ): k_included[k_idx] = True # Append k to P* star_vertices += [k] # Update last augmented edge - e1_idx, e2_idx = len(star_vertices)-1, len(star_vertices)-2 + e1_idx, e2_idx = ( + len(star_vertices) - 1, + len(star_vertices) - 2, + ) # Swap last vertices if not CCW - if is_ccw(k, v, vertices[v_idx-1]): - # if is_cw(k_centroid, v, k): - star_vertices[-2], star_vertices[-1] = star_vertices[-1], star_vertices[-2] + if is_ccw(k, v, vertices[v_idx - 1]): + # if is_cw(k_centroid, v, k): + star_vertices[-2], star_vertices[-1] = ( + star_vertices[-1], + star_vertices[-2], + ) e1_idx, e2_idx = e2_idx, e1_idx adjust_e1 = True # Update v_bar @@ -164,13 +193,18 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): # Visualize debug information if debug == 1: - plt.plot(*k_centroid, 'ko') - plt.plot(*polygon.exterior.xy, 'k') - plt.plot([p[0] for p in star_vertices], [p[1] for p in star_vertices], 'g-o', linewidth=2) - [plt.plot(*k, 'kx') for k in kernel_points] - [plt.plot(*line(k,v).xy, 'k--') for k in kernel_points] + plt.plot(*k_centroid, "ko") + plt.plot(*polygon.exterior.xy, "k") + plt.plot( + [p[0] for p in star_vertices], + [p[1] for p in star_vertices], + "g-o", + linewidth=2, + ) + [plt.plot(*k, "kx") for k in kernel_points] + [plt.plot(*line(k, v).xy, "k--") for k in kernel_points] if adjust_e1: - plt.plot(*star_vertices[e1_idx], 'ys') + plt.plot(*star_vertices[e1_idx], "ys") plt.show() # Check not added kernel points if they should be included @@ -183,25 +217,33 @@ def polygon_kernel_starshaped_hull(polygon, kernel_points, debug=0): star_vertices = star_vertices[:j] + [k] + star_vertices[j:] # Visualize debug information if debug == 1: - plt.plot(*k_centroid, 'ko') - plt.plot(*polygon.exterior.xy, 'k') - plt.plot([p[0] for p in star_vertices], [p[1] for p in star_vertices], 'g-o', linewidth=2) - [plt.plot(*ki, 'kx') for ki in kernel_points] - plt.plot(*line(k, v).xy, 'r--*') - plt.plot(*line(k, vp).xy, 'r--*') - plt.plot(*k, 'go') + plt.plot(*k_centroid, "ko") + plt.plot(*polygon.exterior.xy, "k") + plt.plot( + [p[0] for p in star_vertices], + [p[1] for p in star_vertices], + "g-o", + linewidth=2, + ) + [plt.plot(*ki, "kx") for ki in kernel_points] + plt.plot(*line(k, v).xy, "r--*") + plt.plot(*line(k, vp).xy, "r--*") + plt.plot(*k, "go") plt.show() # print("Final kernel check: {:.1f}".format(toc(t0))) if debug: ax = plt.gca() - ax.plot(*polygon.exterior.xy, 'k') - ax.plot([p[0] for p in star_vertices] + [star_vertices[0][0]], - [p[1] for p in star_vertices] + [star_vertices[0][1]], 'g-o', linewidth=2) + ax.plot(*polygon.exterior.xy, "k") + ax.plot( + [p[0] for p in star_vertices] + [star_vertices[0][0]], + [p[1] for p in star_vertices] + [star_vertices[0][1]], + "g-o", + linewidth=2, + ) # [ax.plot(star_vertices[i][0], star_vertices[i][1], 'r*') for i in augmented_vertex_idcs] - [ax.plot(*zip(k, sv), 'y--') for sv in star_vertices for k in kernel_points] - ax.plot(*k_centroid, 'bs') + [ax.plot(*zip(k, sv), "y--") for sv in star_vertices for k in kernel_points] + ax.plot(*k_centroid, "bs") plt.show() return shapely.geometry.Polygon(star_vertices) - diff --git a/python/smc/path_generation/starworlds/utils/cg.py b/python/smc/path_generation/starworlds/utils/cg.py index bb7525d45bbaef9404d59fb15fa2c32d9e666f12..d9ae557ca4cb8c67c9ba265b33e1d033a2c29305 100644 --- a/python/smc/path_generation/starworlds/utils/cg.py +++ b/python/smc/path_generation/starworlds/utils/cg.py @@ -3,7 +3,7 @@ import shapely.geometry import shapely.ops import matplotlib.pyplot as plt from typing import List, Tuple -from utils import draw_shapely_polygon +from ..utils import draw_shapely_polygon DEFAULT_RAY_INFINITY_LENGTH = 100000. COLLINEAR_THRESHOLD = 1e-10 diff --git a/python/smc/robots/__init__.py b/python/smc/robots/__init__.py index dbe9d2fcebbbcb4240232eebf4bfda57a94166bd..a46ef63cec4e015eb2c7a7cba321df46008e2d2e 100644 --- a/python/smc/robots/__init__.py +++ b/python/smc/robots/__init__.py @@ -7,4 +7,4 @@ from .interfaces.single_arm_interface import SingleArmInterface from .interfaces.dual_arm_interface import DualArmInterface from .interfaces.force_torque_sensor_interface import ForceTorqueOnSingleArmWrist -import utils +from .utils import * diff --git a/python/smc/robots/implementations/__init__.py b/python/smc/robots/implementations/__init__.py index 78ca8f8c7c58e18b09f122a8bc5a6ed952642813..6a9cc722e3707207c452e8f44e8ef2e990e2e8be 100644 --- a/python/smc/robots/implementations/__init__.py +++ b/python/smc/robots/implementations/__init__.py @@ -1,4 +1,9 @@ +# from .heron import RobotManagerHeron, SimulatedHeronRobotManager from .heron import * from .mir import * from .mobile_yumi import * -from .ur5e import * +from .ur5e import RobotManagerUR5e, SimulatedUR5eRobotManager +from importlib.util import find_spec + +if find_spec("rtde_control"): + from .ur5e import RealUR5eRobotManager diff --git a/python/smc/robots/implementations/ur5e.py b/python/smc/robots/implementations/ur5e.py index dbbcb888cab1674ca19dee53148780db640752e2..d50ce5de8b0e343d16d427c5d9a2fd070ecf4f4d 100644 --- a/python/smc/robots/implementations/ur5e.py +++ b/python/smc/robots/implementations/ur5e.py @@ -9,12 +9,15 @@ from smc.robots.abstract_simulated_robot import AbstractSimulatedRobotManager import numpy as np import pinocchio as pin from importlib.resources import files +from importlib.util import find_spec import time import argparse from os import path -from rtde_control import RTDEControlInterface -from rtde_receive import RTDEReceiveInterface -from rtde_io import RTDEIOInterface + +if find_spec("rtde_control"): + from rtde_control import RTDEControlInterface + from rtde_receive import RTDEReceiveInterface + from rtde_io import RTDEIOInterface # NOTE: this one assumes a jaw gripper diff --git a/python/smc/robots/interfaces/mobile_base_interface.py b/python/smc/robots/interfaces/mobile_base_interface.py index 8c2e9044a0c1ce8cd67dc79b4373fb70d1c514bf..e93a7a1ab2c2f634c11cbc9c37da1f12ee78693f 100644 --- a/python/smc/robots/interfaces/mobile_base_interface.py +++ b/python/smc/robots/interfaces/mobile_base_interface.py @@ -1,4 +1,5 @@ import numpy as np + import pinocchio as pin from smc.robots.robotmanager_abstract import AbstractRobotManager diff --git a/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py b/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py index 45b02cc8a1eb6fac460e9c67b4575c52facd7648..ca2e1fe364e423735eca7434a2d83f800e918ab5 100644 --- a/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py +++ b/python/smc/visualization/meshcat_viewer_wrapper/visualizer.py @@ -106,9 +106,12 @@ class MeshcatVisualizer(PMV): 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]): + def addPath( + self, name, path: list[pin.SE3] | np.ndarray, radius=5e-3, color=[1, 0, 0, 0.8] + ): # who cares about the name name = "path" + self.n_path_points = len(path) if type(path) == np.ndarray: # complete the quartenion path = np.hstack((path, np.zeros((len(path), 3))))