{ "info": { "author": "Lars Berscheid", "author_email": "lars.berscheid@kit.edu", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Programming Language :: C++", "Topic :: Scientific/Engineering" ], "description": "
\n \n

\n High-Level Motion Library for the Franka Emika Robot\n

\n
\n

\n \n \"CI\"\n \n\n \n \"Publish\"\n \n\n \n \"Issues\"\n \n\n \n \"Releases\"\n \n\n \n \"LGPL\"\n \n

\n\n\nFrankx is a high-level motion library (both C++ and Python) for the Franka Emika robot. It adds a Python wrapper around [libfranka](https://frankaemika.github.io/docs/libfranka.html), while replacing necessary real-time programming with higher-level motion commands. As frankx focuses on making real-time trajectory generation easy, it allows the robot to react to unforeseen events.\n\n\n## Installation\n\nTo start using frankx with Python and libfranka *0.9.0*, just install it via\n```bash\npip install frankx\n```\n\nFrankx is based on [libfranka](https://github.com/frankaemika/libfranka), [Eigen](https://eigen.tuxfamily.org) for transformation calculations and [pybind11](https://github.com/pybind/pybind11) for the Python bindings. Frankx uses the [Ruckig](https://ruckig.com) Community Version for Online Trajectory Generation (OTG). As the Franka is quite sensitive to acceleration discontinuities, it requires constrained jerk for all motions. After installing the dependencies (the exact versions can be found below), you can build and install frankx via\n\n```bash\ngit clone --recurse-submodules git@github.com:pantor/frankx.git\ncd frankx\nmkdir -p build\ncd build\ncmake -DBUILD_TYPE=Release ..\nmake\nmake install\n```\n\nTo use frankx, you can also include it as a subproject in your parent CMake via `add_subdirectory(frankx)` and then `target_link_libraries( libfrankx)`. If you need only the Python module, you can install frankx via\n\n```bash\npip install .\n```\n\nMake sure that the built library can be found from Python by adapting your Python Path.\n\n\n#### Using Docker\n\nTo use frankx within Docker we have supplied a [Dockerfile](docker/Dockerfile) which you currently need to build yourself:\n\n```bash\ngit clone https://github.com/pantor/frankx.git\ncd frankx/\ndocker build -t pantor/frankx --build-arg libfranka_version=0.7.0 -f docker/Dockerfile .\n```\n\nTo use another version of libfranka than the default (v.0.7.0) simply change the build argument. Then, to run the container simply:\n\n```bash\ndocker run -it --rm --network=host --privileged pantor/frankx\n```\n\nThe container requires access to the host machines network *and* elevated user rights to allow the docker user to set RT capabilities of the processes run from within it.\n\n\n## Tutorial\n\nFrankx comes with both a C++ and Python API that differ only regarding real-time capability. We will introduce both languages next to each other. In your C++ project, just include `include ` and link the library. For Python, just `import frankx`. As a first example, only four lines of code are needed for simple robotic motions.\n\n```.cpp\n#include \nusing namespace frankx;\n\n// Connect to the robot with the FCI IP address\nRobot robot(\"172.16.0.2\");\n\n// Reduce velocity and acceleration of the robot\nrobot.setDynamicRel(0.05);\n\n// Move the end-effector 20cm in positive x-direction\nauto motion = LinearRelativeMotion(Affine(0.2, 0.0, 0.0));\n\n// Finally move the robot\nrobot.move(motion);\n```\n\nThe corresponding program in Python is\n```.py\nfrom frankx import Affine, LinearRelativeMotion, Robot\n\nrobot = Robot(\"172.16.0.2\")\nrobot.set_dynamic_rel(0.05)\n\nmotion = LinearRelativeMotion(Affine(0.2, 0.0, 0.0))\nrobot.move(motion)\n```\n\nFurthermore, we will introduce methods for geometric calculations, for moving the robot according to different motion types, how to implement real-time reactions and changing waypoints in real time as well as controlling the gripper.\n\n\n### Geometry\n\n`frankx::Affine` is a thin wrapper around [Eigen::Affine3d](https://eigen.tuxfamily.org/dox/group__TutorialGeometry.html). It is used for Cartesian poses, frames and transformation. Frankx simplifies the usage of Euler angles (default ZYX-convention).\n```.cpp\n// Initiliaze a transformation with an (x, y, z, a=0.0, b=0.0, c=0.0) translation\nAffine z_translation = Affine(0.0, 0.0, 0.5);\n\n// Define a rotation transformation using the (x, y, z, a, b, c) parameter list\nAffine z_rotation = Affine(0.0, 0.0, 0.0, M_PI / 3, 0.0, 0.0);\n\n// Make use of the wonderful Eigen library\nauto combined_transformation = z_translation * z_rotation;\n\n// Get the Euler angles (a, b, c) in a vector representation\nEigen::Vector3d euler_angles = combined_transformation.angles();\n\n// Get the vector representation (x, y, z, a, b, c) of an affine transformation\nfrankx::Vector6d pose = combined_transformation.vector();\n```\n\nIn all cases, distances are in [m] and rotations in [rad]. Additionally, there are several helper functions for conversion between Eigen and libfranka's std::array objects. In python, this translates into\n```.py\nz_translation = Affine(0.0, 0.0, 0.5)\nz_rotation = Affine(0.0, 0.0, 0.0, math.pi / 3, 0.0, 0.0)\ncombined_transformation = z_translation * z_rotation\n\n# These two are now numpy arrays\neuler_angles = combined_transformation.angles()\npose = combined_transformation.vector()\n```\n\nAs the trajectory generation works in the Euler space, please make sure to have continuous Euler angles around your working point. You can adapt this by setting the flange to end-effector transformation via `setEE(...)`.\n\n\n### Robot\n\nWe wrapped most of the libfanka API (including the RobotState or ErrorMessage) for Python. Moreover, we added methods to adapt the dynamics of the robot for all motions. The `rel` name denotes that this a factor of the maximum constraints of the robot.\n```.py\nrobot = Robot(\"172.16.0.2\")\n\n# Recover from errors\nrobot.recover_from_errors()\n\n# Set velocity, acceleration and jerk to 5% of the maximum\nrobot.set_dynamic_rel(0.05)\n\n# Alternatively, you can define each constraint individually\nrobot.velocity_rel = 0.2\nrobot.acceleration_rel = 0.1\nrobot.jerk_rel = 0.01\n\n# Get the current pose\ncurrent_pose = robot.current_pose()\n```\n\n\n### Motion Types\n\nFrankx defines five different motion types. In python, you can use them as follows:\n```.py\n# A point-to-point motion in the joint space\nm1 = JointMotion([-1.81194, 1.17910, 1.75710, -2.1416, -1.14336, 1.63304, -0.43217])\n\n# A linear motion in cartesian space\nm2 = LinearMotion(Affine(0.2, -0.4, 0.3, math.pi / 2, 0.0, 0.0))\nm3 = LinearMotion(Affine(0.2, -0.4, 0.3, math.pi / 2, 0.0, 0.0), elbow=1.7) # With target elbow angle\n\n# A linear motion in cartesian space relative to the initial position\nm4 = LinearRelativeMotion(Affine(0.0, 0.1, 0.0))\n\n# A more complex motion by defining multiple waypoints\nm5 = WaypointMotion([\n Waypoint(Affine(0.2, -0.4, 0.2, 0.3, 0.2, 0.1)),\n # The following waypoint is relative to the prior one\n Waypoint(Affine(0.0, 0.1, 0.0), Waypoint.ReferenceType.Relative)\n])\n\n# Hold the position for [s]\nm6 = PositionHold(5.0)\n```\n\nThe real robot can be moved by applying a motion to the robot using `move`:\n```.py\nrobot.move(m1)\nrobot.move(m2)\n\n# To use a given frame relative to the end effector\ncamera_frame = Affine(0.1, 0.0, 0.1)\nrobot.move(camera_frame, m3)\n\n# To change the dynamics of the motion, use MotionData\ndata = MotionData(0.2) # Using a dynamic_rel of 0.2 (eventually multiplied with robot.dynamic_rel)\nrobot.move(m4, data)\n```\n\nUsing MotionData, you can adapt the dynamics (velocity, acceleration and jerk) of a specific motion.\n```.py\ndata.velocity_rel = 1.0\ndata.jerk_rel = 0.2\n```\n\n\n### Real-Time Reactions\n\nBy adding reactions to the motion data, the robot can react to unforeseen events. In the Python API, you can define conditions by using a comparison between a robot's value and a given threshold. If the threshold is exceeded, the reaction fires. Following comparisons are currently implemented\n```.py\nreaction_motion = LinearRelativeMotion(Affine(0.0, 0.0, 0.01)) # Move up for 1cm\n\n# Stop motion if the overall force is greater than 30N\nd1 = MotionData().with_reaction(Reaction(Measure.ForceXYZNorm() > 30.0))\n\n# Apply reaction motion if the force in negative z-direction is greater than 10N\nd2 = MotionData().with_reaction(Reaction(Measure.ForceZ() < -10.0), reaction_motion)\n\n# Stop motion if its duration is above 30s\nd3 = MotionData().with_reaction(Reaction(Measure.Time() >= 30.0))\n\nrobot.move(m2, d2)\n\n# Check if the reaction was triggered\nif d2.has_fired:\n robot.recover_from_errors()\n print('Force exceeded 10N!')\n```\n\nOnce a reaction has fired, it will be neglected furthermore. In C++ you can additionally use lambdas to define more complex behaviours:\n```.cpp\n// Stop motion if force is over 10N\nauto data = MotionData()\n .withReaction({\n Measure::ForceXYZNorm() > 10.0 // [N]\n })\n .withReaction({\n [](const franka::RobotState& state, double time) {\n return (state.current_errors.self_collision_avoidance_violation);\n }\n });\n\n// Hold position for 5s\nrobot.move(PositionHold(5.0), data); // [s]\n// e.g. combined with a PositionHold, the robot continues its program after pushing the end effector.\n```\n\n\n### Real-Time Waypoint Motion\n\nWhile the robot moves in a background thread, you can change the waypoints in real-time.\n```.cpp\nrobot.moveAsync(motion_hold);\n\n// Wait for key input from user\nstd::cin.get();\n\nmotion_hold.setNextWaypoint(Waypoint(Affine(0.0, 0.0, 0.1), Waypoint::ReferenceType::Relative);\n```\n\n\n### Gripper\n\nIn the `frankx::Gripper` class, the default gripper force and gripper speed can be set. Then, additionally to the libfranka commands, the following helper methods can be used:\n\n```.cpp\nauto gripper = Gripper(\"172.16.0.2\");\n\n// These are the default values\ngripper.gripper_speed = 0.02; // [m/s]\ngripper.gripper_force = 20.0; // [N]\n\n// Preshape gripper before grasp, use the given speed\ngripper.move(50.0); // [mm]\n\n// Grasp an object of unknown width\nis_grasping = gripper.clamp();\n\n// Do something\nis_grasping &= gripper.isGrasping();\n\n// Release an object and move to a given distance\nif (is_grasping) {\n gripper.release(50.0);\n}\n```\n\nThe Python API should be very straight-forward for the Gripper class.\n\n\n### Kinematics\n\nFrankx includes a rudimentary, non-realtime-capable forward and inverse kinematics.\n\n```.py\n# Some initial joint configuration\nq = [-1.45549, 1.15401, 1.50061, -2.30909, -1.3141, 1.9391, 0.02815]\n\n# Calculate the forward kinematics\nx = Affine(Kinematics.forward(q))\nprint('Current end effector position: ', x)\n\n# Define new target position\nx_new = Affine(x=0.1, y=0.0, z=0.0) * x\n\n# Franka has 7 DoFs, so what to do with the remaining Null space?\nnull_space = NullSpaceHandling(2, 1.4) # Set elbow joint to 1.4\n\n# Inverse kinematic with target, initial joint angles, and Null space configuration\nq_new = Kinematics.inverse(x_new.vector(), q, null_space)\n\nprint('New position: ', x_new)\nprint('New joints: ', q_new)\n```\n\n\n## Documentation\n\nAn auto-generated documentation can be found at [https://pantor.github.io/frankx/](https://pantor.github.io/frankx/). Moreover, there are multiple examples for both C++ and Python in the [examples](https://github.com/pantor/frankx/tree/master/examples) directory. We will add a more detailed documentation once frankx reaches v1.0.\n\n\n## Development\n\nFrankx is written in C++17 and Python3.7. It is currently tested against following versions\n\n- Eigen v3.3.7\n- Libfranka v0.9.0\n- Pybind11 v2.9.1\n- Catch2 v2.13 (only for testing)\n\n\n## License\n\nFor non-commercial applications, this software is licensed under the LGPL v3.0. If you want to use frankx within commercial applications or under a different license, please contact us for individual agreements.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pantor/frankx", "keywords": "robot,robotics,trajectory-generation,motion-control", "license": "LGPL", "maintainer": "", "maintainer_email": "", "name": "frankx", "package_url": "https://pypi.org/project/frankx/", "platform": null, "project_url": "https://pypi.org/project/frankx/", "project_urls": { "Homepage": "https://github.com/pantor/frankx" }, "release_url": "https://pypi.org/project/frankx/0.2.0/", "requires_dist": null, "requires_python": ">=3.6", "summary": "High-Level Motion Library for the Franka Panda Robot", "version": "0.2.0", "yanked": false, "yanked_reason": null }, "last_serial": 13837487, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "39245bdde4375b203d069f8456e0b158", "sha256": "ac57894c5e0912a9d71b467c3905d926d6af1277b69f4d07cc39ab6eac548990" }, "downloads": -1, "filename": "frankx-0.0.1-cp36-cp36m-manylinux2010_x86_64.whl", "has_sig": false, "md5_digest": "39245bdde4375b203d069f8456e0b158", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.6", "size": 1741708, "upload_time": "2019-10-21T17:18:36", "upload_time_iso_8601": "2019-10-21T17:18:36.253776Z", "url": "https://files.pythonhosted.org/packages/45/fe/f06c2490e8550889b32120b723a236349e2a2b66ca4a022f2a8982b3e3c7/frankx-0.0.1-cp36-cp36m-manylinux2010_x86_64.whl", "yanked": false, "yanked_reason": null } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "2a13dd9f02f43976f3acf7ed8c7fe698", "sha256": "0ca70410e8918df54cb16b9fdd069ff9111882e98c623c644fd6e7396c77b99b" }, "downloads": -1, "filename": "frankx-0.0.3-cp35-cp35m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "2a13dd9f02f43976f3acf7ed8c7fe698", "packagetype": "bdist_wheel", "python_version": "cp35", "requires_python": ">=3.5", "size": 2071060, "upload_time": "2020-10-21T21:08:00", "upload_time_iso_8601": "2020-10-21T21:08:00.492942Z", "url": "https://files.pythonhosted.org/packages/b1/45/32f99919402332e75e0f73b18e97f62dc668a020b09eb2c83f5ce870cf68/frankx-0.0.3-cp35-cp35m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "b0d74e7f00a61825259a53f1ee1fce62", "sha256": "1fac74be0d4bfd45f1946dd4ecd8a90e5eeeacd24e947011d85aa1777cbcdbd2" }, "downloads": -1, "filename": "frankx-0.0.3-cp36-cp36m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "b0d74e7f00a61825259a53f1ee1fce62", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.5", "size": 2071057, "upload_time": "2020-10-21T21:08:02", "upload_time_iso_8601": "2020-10-21T21:08:02.472703Z", "url": "https://files.pythonhosted.org/packages/eb/f1/6b6ac4248756db33dec2fc6bc28d9289ebf9c8cd49b5bdc7eec39fca8364/frankx-0.0.3-cp36-cp36m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "688ec7d5ba20d30738701c1d438c02e4", "sha256": "979d6dde752a325b2643b5a9097c3d1540537336421bb9ec5d66e1a136f222ba" }, "downloads": -1, "filename": "frankx-0.0.3-cp37-cp37m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "688ec7d5ba20d30738701c1d438c02e4", "packagetype": "bdist_wheel", "python_version": "cp37", "requires_python": ">=3.5", "size": 2071532, "upload_time": "2020-10-21T21:08:04", "upload_time_iso_8601": "2020-10-21T21:08:04.586783Z", "url": "https://files.pythonhosted.org/packages/ba/2d/0e35eb459856cad44962928c59d409f7e1cd8ac3b8700676a9978352047b/frankx-0.0.3-cp37-cp37m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "b0d29bba38596402a9180936a7232d67", "sha256": "3f5401d4da3323e903aebfd26dbc27f3b2052668570cf617926ac967d3d20085" }, "downloads": -1, "filename": "frankx-0.1.0-cp36-cp36m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "b0d29bba38596402a9180936a7232d67", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.6", "size": 2210089, "upload_time": "2021-04-06T12:06:26", "upload_time_iso_8601": "2021-04-06T12:06:26.123528Z", "url": "https://files.pythonhosted.org/packages/14/c3/55af685f4ca3db85b4fdb0438272f98130091846d730c74e39e4ff9a936e/frankx-0.1.0-cp36-cp36m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "bc5deb5cc05c5338a0d00345fd9c782f", "sha256": "99af9d56a628cb101497eff522354afdc1673f1a95f14f0c650edd4e6445264c" }, "downloads": -1, "filename": "frankx-0.1.0-cp37-cp37m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "bc5deb5cc05c5338a0d00345fd9c782f", "packagetype": "bdist_wheel", "python_version": "cp37", "requires_python": ">=3.6", "size": 2210080, "upload_time": "2021-04-06T12:06:28", "upload_time_iso_8601": "2021-04-06T12:06:28.492915Z", "url": "https://files.pythonhosted.org/packages/61/a2/f3a671b11b6e1ad214dd99393710b6cc2f735b531264755446e5ff6aaf5c/frankx-0.1.0-cp37-cp37m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "6821c0aa17f458e5f32b64d7d7d4e19f", "sha256": "a607031e26958be5d3904fa32ee2c4ba845344b0c9ca2523b1350340ea86b6df" }, "downloads": -1, "filename": "frankx-0.1.0-cp38-cp38-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "6821c0aa17f458e5f32b64d7d7d4e19f", "packagetype": "bdist_wheel", "python_version": "cp38", "requires_python": ">=3.6", "size": 2206195, "upload_time": "2021-04-06T12:06:29", "upload_time_iso_8601": "2021-04-06T12:06:29.828500Z", "url": "https://files.pythonhosted.org/packages/17/2e/0953b0a7da313c1f16295799dd48a6acd0f074140596cb64c83961c697aa/frankx-0.1.0-cp38-cp38-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "b0ef1c8a223eaed1734160ccb250fb82", "sha256": "5604b5242f208d64197008fbe5feef12f965e204a2fbe557ee65f07018762678" }, "downloads": -1, "filename": "frankx-0.1.0-cp39-cp39-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "b0ef1c8a223eaed1734160ccb250fb82", "packagetype": "bdist_wheel", "python_version": "cp39", "requires_python": ">=3.6", "size": 2205916, "upload_time": "2021-04-06T12:06:31", "upload_time_iso_8601": "2021-04-06T12:06:31.016794Z", "url": "https://files.pythonhosted.org/packages/f3/80/79c2d0da7c027e8c9b5724b9bd17748f451140d78adc95a6290ef8cdaced/frankx-0.1.0-cp39-cp39-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "2ee429fc63caec1f9e14280d638b8174", "sha256": "6d3a9a35b88da90c96fd6b9d3dd51769d1f544dc343495543c26d3f4eb3ea5fb" }, "downloads": -1, "filename": "frankx-0.1.1-cp36-cp36m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "2ee429fc63caec1f9e14280d638b8174", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.6", "size": 2311389, "upload_time": "2021-04-06T12:29:42", "upload_time_iso_8601": "2021-04-06T12:29:42.768848Z", "url": "https://files.pythonhosted.org/packages/de/1b/6aaa1d48c03ce2b10d1657d0c13a1895254513a48f62ec8eec7140767a40/frankx-0.1.1-cp36-cp36m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "beda070b8638c3831bbd1359af3432ad", "sha256": "8e7ea4ccf023ce28427333b5361523b7b11f38ec39202ab63bed10c4ca24c0c5" }, "downloads": -1, "filename": "frankx-0.1.1-cp37-cp37m-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "beda070b8638c3831bbd1359af3432ad", "packagetype": "bdist_wheel", "python_version": "cp37", "requires_python": ">=3.6", "size": 2311359, "upload_time": "2021-04-06T12:29:44", "upload_time_iso_8601": "2021-04-06T12:29:44.441669Z", "url": "https://files.pythonhosted.org/packages/13/0d/b6ed57cc26e8ab37d8b8f2d02e64e1d8cdbf64c9336dae128bafe59bc232/frankx-0.1.1-cp37-cp37m-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "de845b7744f18d2b5ecba15de1e4ff50", "sha256": "f936ba392840953dd4acd74fb7919ba2cb84c816a9bbdd680a82b374e53ff2ea" }, "downloads": -1, "filename": "frankx-0.1.1-cp38-cp38-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "de845b7744f18d2b5ecba15de1e4ff50", "packagetype": "bdist_wheel", "python_version": "cp38", "requires_python": ">=3.6", "size": 2303758, "upload_time": "2021-04-06T12:29:45", "upload_time_iso_8601": "2021-04-06T12:29:45.998606Z", "url": "https://files.pythonhosted.org/packages/1b/a4/2c4851b6c96e793bef4e2cadbcadea8be03da9b9873e6acaf7b1d3e3d3e7/frankx-0.1.1-cp38-cp38-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "ae2e3efdb31f0e3359171da0d6b2949a", "sha256": "dee3246b6e42fad5c58a0f15d4b88bcd4da18a4f65b146ccd9ad98b0c45f43a6" }, "downloads": -1, "filename": "frankx-0.1.1-cp39-cp39-manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "ae2e3efdb31f0e3359171da0d6b2949a", "packagetype": "bdist_wheel", "python_version": "cp39", "requires_python": ">=3.6", "size": 2303646, "upload_time": "2021-04-06T12:29:47", "upload_time_iso_8601": "2021-04-06T12:29:47.548948Z", "url": "https://files.pythonhosted.org/packages/14/2a/7bae2801657d5991a3a4b4499a897a75160af0b9bace1d9476d31b116635/frankx-0.1.1-cp39-cp39-manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "957a392c246dbeb82fa8d274ca8e8423", "sha256": "33eb7fa3a5c450025f7b1d8ba917a888ae777d14725e9f5c96d335fc68f6c5f5" }, "downloads": -1, "filename": "frankx-0.2.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "957a392c246dbeb82fa8d274ca8e8423", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.6", "size": 2301413, "upload_time": "2022-05-17T06:15:05", "upload_time_iso_8601": "2022-05-17T06:15:05.335080Z", "url": "https://files.pythonhosted.org/packages/9b/cd/94a7648290f09bc00484bb9ff64b657babaecb685620b0419f58ce682d9b/frankx-0.2.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "82912b786cb0b573819246b526ea88d7", "sha256": "724da3a8621c6776169b80d77fbfa0bcc7d72e662c25f7bdfde7b5c0e65378e3" }, "downloads": -1, "filename": "frankx-0.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "82912b786cb0b573819246b526ea88d7", "packagetype": "bdist_wheel", "python_version": "cp37", "requires_python": ">=3.6", "size": 2301506, "upload_time": "2022-05-17T06:15:07", "upload_time_iso_8601": "2022-05-17T06:15:07.972033Z", "url": "https://files.pythonhosted.org/packages/48/14/a494f79bd54e383fb4c68025b566c5fe2b3aa54028fed0e7ba41517a9af5/frankx-0.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "8f53d8da2f98f1aa5108105c9afe63f9", "sha256": "787bac3624c533d979fc4453c57ab1822d6b0c4a51679c969b4b2a5444c79a41" }, "downloads": -1, "filename": "frankx-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "8f53d8da2f98f1aa5108105c9afe63f9", "packagetype": "bdist_wheel", "python_version": "cp38", "requires_python": ">=3.6", "size": 2299450, "upload_time": "2022-05-17T06:15:10", "upload_time_iso_8601": "2022-05-17T06:15:10.185463Z", "url": "https://files.pythonhosted.org/packages/45/30/d101351019565a76cf85d9ac3c61d15ef6bf3b2eb7c1bc0c4547460d8692/frankx-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "32a3024a5746cffad8e9f16786362ee3", "sha256": "7d9e2da2c1a7b0f443264036394ca80117b3a42ac92e242dc03ffa4733ab48ba" }, "downloads": -1, "filename": "frankx-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "32a3024a5746cffad8e9f16786362ee3", "packagetype": "bdist_wheel", "python_version": "cp39", "requires_python": ">=3.6", "size": 2300431, "upload_time": "2022-05-17T06:15:12", "upload_time_iso_8601": "2022-05-17T06:15:12.430202Z", "url": "https://files.pythonhosted.org/packages/dc/f4/97a1a60040bf71ea1329ca7981ce620edd8a91528a205586f9b499cc787f/frankx-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "957a392c246dbeb82fa8d274ca8e8423", "sha256": "33eb7fa3a5c450025f7b1d8ba917a888ae777d14725e9f5c96d335fc68f6c5f5" }, "downloads": -1, "filename": "frankx-0.2.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "957a392c246dbeb82fa8d274ca8e8423", "packagetype": "bdist_wheel", "python_version": "cp36", "requires_python": ">=3.6", "size": 2301413, "upload_time": "2022-05-17T06:15:05", "upload_time_iso_8601": "2022-05-17T06:15:05.335080Z", "url": "https://files.pythonhosted.org/packages/9b/cd/94a7648290f09bc00484bb9ff64b657babaecb685620b0419f58ce682d9b/frankx-0.2.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "82912b786cb0b573819246b526ea88d7", "sha256": "724da3a8621c6776169b80d77fbfa0bcc7d72e662c25f7bdfde7b5c0e65378e3" }, "downloads": -1, "filename": "frankx-0.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "82912b786cb0b573819246b526ea88d7", "packagetype": "bdist_wheel", "python_version": "cp37", "requires_python": ">=3.6", "size": 2301506, "upload_time": "2022-05-17T06:15:07", "upload_time_iso_8601": "2022-05-17T06:15:07.972033Z", "url": "https://files.pythonhosted.org/packages/48/14/a494f79bd54e383fb4c68025b566c5fe2b3aa54028fed0e7ba41517a9af5/frankx-0.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "8f53d8da2f98f1aa5108105c9afe63f9", "sha256": "787bac3624c533d979fc4453c57ab1822d6b0c4a51679c969b4b2a5444c79a41" }, "downloads": -1, "filename": "frankx-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "8f53d8da2f98f1aa5108105c9afe63f9", "packagetype": "bdist_wheel", "python_version": "cp38", "requires_python": ">=3.6", "size": 2299450, "upload_time": "2022-05-17T06:15:10", "upload_time_iso_8601": "2022-05-17T06:15:10.185463Z", "url": "https://files.pythonhosted.org/packages/45/30/d101351019565a76cf85d9ac3c61d15ef6bf3b2eb7c1bc0c4547460d8692/frankx-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "32a3024a5746cffad8e9f16786362ee3", "sha256": "7d9e2da2c1a7b0f443264036394ca80117b3a42ac92e242dc03ffa4733ab48ba" }, "downloads": -1, "filename": "frankx-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "has_sig": false, "md5_digest": "32a3024a5746cffad8e9f16786362ee3", "packagetype": "bdist_wheel", "python_version": "cp39", "requires_python": ">=3.6", "size": 2300431, "upload_time": "2022-05-17T06:15:12", "upload_time_iso_8601": "2022-05-17T06:15:12.430202Z", "url": "https://files.pythonhosted.org/packages/dc/f4/97a1a60040bf71ea1329ca7981ce620edd8a91528a205586f9b499cc787f/frankx-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }