A real-time robot control framework with liveliness.
Project description
Lively v1.0.0 (RC 2)
NOTE: Since Lively is still in beta, the design is subject to change and should not be considered final!
About
Lively Package
The Lively framework provides a highly configurable toolkit for commanding robots in mixed modalities while incorporating liveliness motions. It is adapted from RelaxedIK framework, and compatible with Python and Javascript/Node.
To configure a robot, the easiest method is to use the LivelyStudio interface in the LivelyStudio repository, which is a system for configuring and programming the robot visually.
Configuring
Configuring of Lively is centered on the Solver class, which you can instantiate in the following ways:
python
from lively import Solver, PositionMatchObjective, OrientationMatchObjective, SmoothnessMacroObjective, CollisionAvoidanceObjective, State, Transform, ScalarRange, BoxShape
solver = Solver(
urdf='<?xml version="1.0" ?><robot name="panda">...</robot>', # Full urdf as a string
objectives={
"PositionMatchObjective" : PositionMatchObjective(name="EE Position",link="panda_hand",weight=50),
"OrientationMatchObjective" : OrientationMatchObjective(name="EE Rotation",link="panda_hand",weight=25),
"SmoothnessMacroObjective":SmoothnessMacroObjective(name="General Smoothness",weight=10),
"CollisionAvoidanceObjective":CollisionAvoidanceObjective(name="Collision Avoidance",weight=10)
...
},
root_bounds=[
ScalarRange(value=0.0,delta=0.0),ScalarRange(value=0.0,delta=0.0),ScalarRange(value=0.0,delta=0.0), # Translational, (x, y, z)
ScalarRange(value=0.0,delta=0.0),ScalarRange(value=0.0,delta=0.0),ScalarRange(value=0.0,delta=0.0) # Rotational, (r, p, y)
],
shapes=[
BoxShape(name="Table",frame="world",physical=True,x=2,y=1,z=1.2,local_transform=Transform.isometry())
],
initial_state=State(origin=Transform.identity(),joints={"panda_joint1":0.0,"panda_joint2":0.0,...}), # Optional
only_core=False, # Only use this flag if you are not using liveliness objectives and want a slight speed-up.
max_retries=1, # Number of times the solution is attempted (default 1)
max_iterations=150, # Number of iterations per try (default 150)
collision_settings = CollisionSettingInfo(
d_max = 0.3,
r = 0.0,
a_max = 2.0,
time_budget = 100,
timed = True),
)
javascript
import {Solver} from "@people_and_robots/lively";
let solver = new Solver(
urdf = '<?xml version="1.0" ?><robot name="panda">...</robot>', // Full urdf as a string
objectives = {
"eePosition": {
type: "PositionMatch",
name: "EE Position",
link: attachmentLink,
weight: 50,
},
"eeRotation": {
type: "OrientationMatch",
name: "EE Rotation",
link: attachmentLink,
weight: 25,
},
"collision": {
type: "CollisionAvoidance",
name: "Collision Avoidance",
weight: COLLISION_WEIGHT,
},
},
root_bounds = [
{ value: basePose.position.x, delta: 0.0 },
{ value: basePose.position.y, delta: 0.0 },
{ value: basePose.position.z, delta: 0.0 }, // Translational
{ value: baseEuler[0], delta: 0.0 },
{ value: baseEuler[1], delta: 0.0 },
{ value: baseEuler[2], delta: 0.0 }, // Rotational
],
shapes = [{
type:'Box', //can be 'Cylinder', 'Capsule', or 'Sphere'
name:'camera attachment',
frame: 'panda_hand', // or 'world'
physical: true,
x:0.5,y:0.5,z:0.2,
localTransform: {translation:[0.0,0.0,0.0],rotation:[0.0,0.0,0.0,1.0]} // [x, y, z, w] ordering for quaternion
}
],
initial_state= {origin:{translation:[0,0,0],rotation:[1,0,0,0]},joints:{panda_joint1:0.0,panda_joint2:0.0,...}}, // Optional
only_core=False, # Only use this flag if you are not using liveliness objectives and want a slight speed-up.
max_retries=1, # Number of times the solution is attempted (default 1)
max_iterations=150 # Number of iterations per try (default 150)
collision_settings = {dMax : 0.3, r : 0.0, aMax : 2.0, timeBudget : 100, timed : true}
)
Objectives
The LivelyTK framework allows for a wide range of robot with which users program robot motion. These 24 properties, which serve as building blocks for defining the behavior and motion of the robot, fit into five categories:
Category | Description |
---|---|
Base |
Revolve around the fluidity of robot motion by limiting rapid changes and considering possible collisions between the links of the robot |
Bounding |
Limit the space within which joints can assume angles and links can move or be oriented |
Matching |
Specify exact positions and orientations of links or angles of joints, while bounding behavior properties set limits |
Mirroring |
Allow users to mirror the current state of a link's position or orientation in a different link, or the current angle of one joint in another |
Liveliness |
Allow adding smooth, coordinated motion to joint angles or link positions/orientations |
Forces |
Proximating the physcial forces applied to the robot |
Objective | Category | Description |
---|---|---|
Collision Avoidance | Base |
Detect and avoid collision using PROXIMA alogorithm[^1] |
Joint Limits | Base |
Applies a cost to approaching the robot’s joint limits |
Velocity Minimization | Base |
Prevent rapid joint movements |
Origin Velocity Minimization | Base |
Prevent rapid robot root movements |
Acceleration Minimization | Base |
Prevent rapid changes in joint speed |
Origin Acceleration Minimization | Base |
Prevent rapid changes in robot root speed |
Jerk Minimization | Base |
Add fluidity to robot movement along the joints |
Origin Jerk Minimization | Base |
Add fluidity to robot movement within the Cartesian space of the origin |
Smoothness Macro | Base |
Combines each of the velocity, acceleration, and jerk minimization properties with normalized weights |
Position Bounding | Bounding |
Place the position of a link within a rotated ellipsoid |
Orientation Bounding | Bounding |
A region in orientation space with some delta around an orientation |
Joint Bounding | Bounding |
Limits the maximum and minimum values of a given joint |
Position Match | Matching |
Control a link's position in space |
Orientation Match | Matching |
Control a link's orientation in space |
Joint Match | Matching |
Control a joint's value directly |
Distance Match | Matching |
Specify the distance between two links in space |
Position Mirroring | Mirroring |
Mirror the positions of two links with an optional offset |
Orientation Mirroring | Mirroring |
Mirror the rotations of two links with an optional offset |
Joint Mirrorin | Mirroring |
Mirror the values of two joints with an optional offset |
Position Liveliness | Liveliness |
Add smooth motion to the position of a link |
Orientaion Liveliness | Liveliness |
Add smooth motion to the rotation of a link |
Joint Liveliness | Liveliness |
Add smooth motion to a joint directly |
Relative Motion Liveliness | Liveliness |
Add smooth motion towards and away from |
Gravity | Forces |
Add a downward force to the position of a link |
Collision
The livelytk framework provides collision detection between the robot and environmental objects as well as within the shapes of robot parts. The collision detection functionality is implemented by a time-efficient algorithm that governs collision detection through a time-limited or error-limited routine that reduces the number of collision queries between the shapes by estimating the "pairwise relative spatial coherence", which is defined below:
"Guaranteed upper and lower bounds on signed distance are computed between each active pair of shapes in the scene. In this work, these bounds are computed by assessing how relative transforms between shapes change over time, a novel technique we call Pairwise Relative Spatial Coherence[^1]".
Collision Settings
This is a parameter collision_settings
that allows the user to customize the collision checking system while configuring a Solver
d_max
:
A lower bound distance parameter that controls the distance that queries the collision detection between shapes. The distance by default is 0.3 meteres. This means that pairwise collision queries will only happen when two shapes are within 0.3 meters. Increasing/Decreasing the distance will result in a greater/smaller distance for the collision queries which will lead to greater/smaller number of collision queries.
r
:
A scalar value between 0 and 1 that controls how cautious the collision estimate will be. The value is 0 by default which is the most cautious and accurate. The estimate will be more optimistic when the value approaches 1.
a_max
:
A upper bound distance parameter that, similar to d_max, determines if a shape pair should be included or excluded in collision checking. The value is 2.0 meters by default. Increasing/Decreasing the distance will result in a greater/smaller distance for the collision queries which will lead to greater/smaller number of collision queries.
time_budget
:
A time parameter that will be used in the collision checking. The value is 100 microseconds by default. Increase the value will result in a slower but more accurate proximity approximiation.
timed
:
A boolean parameter that determines which routine will be used for collision checking. The value is true by default. Timed-limited routine will be used if true, error-limited routine will be used if false.
python
CollisionSettingInfo(
d_max = 0.3,
r = 0.0,
a_max = 2.0,
time_budget = 100,
timed = True),
javascript
let collision_settings = {dMax : 0.3, r : 0.0, aMax : 2.0, timeBudget : 100, timed : true}
Resetting
In both the Javascript and Python interfaces, the Solver
class has a reset
method that allows the user to reset the state of the solver given some new objective weights and a new robot state. In this case, the robot state only needs to supply the joints
and origin
field, as shown in the initialization example.
python
solver.reset(state=State(origin=Transform.identity(),joints={"panda_joint1":0.0,"panda_joint2":0.0,...}),weights={})
javascript
solver.reset(
{origin:{translation:[0,0,0],rotation:[1,0,0,0]},joints:{panda_joint1:0.0,panda_joint2:0.0,...}}, // New starting state
{} // Can define new weights here
)
Solving
The Solver
class has a solve
method that represents the core functionality of the Lively interface. At a high level, it accepts the following fields:
goals
: A look-up table of goal-type objects. The key of the look-up table should match with that of the objectives to which the goals are corresponded.weights
: A look-up table of floats, order corresponding to the order of the objectives. The key of the look-up table should match with that of the objectives to which the weights are corresponded.time
: (float) The current time. If no liveliness objectives are used, this has no effect.shapes
: A list of shape objects.
The solve
method returns a fully-filled State
object
Goals
There are a variety of different "goal" types that can be provided. Think of these as settings that you would like to achieve (e.g. a PositionMatch objective accepts a Translation
goal).
Translation
The translation goal is used by the PositionMatch
, PositionMirroring
, and OriginPositionMatch
objectives.
python
goal = Translation(x:1.0,y:0.0,z:0.5)
javascript
let goal = {Translation:[1.0,0.0,0.5]}
Rotation
The rotation goal is used by the OrientationMatch
, OrientationMirroring
, and OriginOrientationMatch
objectives.
python
goal = Rotation(w:0.707,x:0.0,y:0.0,z:0.707)
javascript
let goal = {Rotation:[0.707,0.0,0.0,0.707]} // [x, y, z, w] ordering
Scalar
The scalar goal is used by the JointMatch
, JointMirroring
, DistanceMatch
, JointLiveliness
, and RelativeMotionLiveliness
objectives.
python
goal = 0.5
javascript
let goal = {Scalar:0.5}
Size
The size goal is used by the PositionLiveliness
, OrientationLiveliness
, OriginPositionLiveliness
, and OriginOrientationLiveliness
objectives.
python
goal = Size(x:1.0,y:0.1,z:0.5)
javascript
let goal = {Size:[1.0,0.1,0.5]}
Ellipse
The ellipse goal is used by the PositionBounding
objective.
python
goal = Ellipse(
translation=Translation(x:1.0,y:0.0,z:0.4),
rotation=Rotation(w:0.707,x:0.0,y:0.0,z:0.707),
size=Size(x:0.1,y:0.1,z:0.2)
)
javascript
let goal = {Ellipse: {
pose: {translation: [1.0,0.0,0.4], rotation: [0.707,0.0,0.0,0.707]}, // [x, y, z, w] ordering for quaternion
size: [0.1,0.1,0.2]
}
RotationRange
The rotation range goal is used by the RotationBounding
objective.
python
goal = RotationRange(
rotation=Rotation(w:0.707,x:0.0,y:0.0,z:0.707),
delta=0.4
)
javascript
let goal = {RotationRange: {
rotation: [0.707,0.0,0.0,0.707], // [x, y, z, w] ordering for quaternion
delta:0.4
}
ScalarRange
The scalar range goal is used by the JointBounding
objective.
python
goal = ScalarRange(value=0.0,delta=0.4)
javascript
let goal = {ScalarRange: {value:0.0,delta:0.4}
Shapes
There are 4 different Shape classes: Box, Sphere, Capsule, and Cylinder. The name
field is entirely for your own usage, and the frame
field indicates what robot link the shape is attached to (by default "world"). The physical
field indicates whether the shape presents a collision, and should be factored into collision avoidance. Otherwise, the shape is simply tracked in the state if close enough.
Box
python
shape = BoxShape(
name="camera attachment",
frame='panda_hand',
physical=True,
x=0.5,y=0.5,z=0.2,
local_transform=Transform.identity())
javascript
let shape = {
type:'Box',
name:'camera attachment',
frame: 'panda_hand',
physical: true,
x:0.5,y:0.5,z:0.2,
localTransform: {translation:[0.0,0.0,0.0],rotation:[0.0,0.0,0.0,1.0]} // [x, y, z, w] ordering for quaternion
}
Sphere
python
shape = SphereShape(
name="bouncy ball",
frame='world',
physical=True,
radius=0.1,
local_transform=Transform.identity())
javascript
let shape = {
type:'Sphere',
name:'bouncy ball',
frame: 'world',
physical: true,
radius:0.1,
localTransform: {translation:[0.0,0.0,0.0],rotation:[0.0,0.0,0.0,1.0]} // [x, y, z, w] ordering for quaternion
}
Capsule
python
shape = CapsuleShape(
name="pill",
frame='world',
physical=True,
length=0.2,
radius=0.1,
local_transform=Transform.identity())
javascript
let shape = {
type:'Capsule',
name:'pill',
frame: 'world',
physical: true,
length:0.2,
radius:0.1,
localTransform: {translation:[0.0,0.0,0.0],rotation:[1.0,0.0,0.0,0.0]} // [x, y, z, w] ordering for quaternion
}
Cylinder
python
shape = CylinderShape(
name="zone",
frame='world',
physical=False,
length=0.2,
radius=0.1,
local_transform=Transform.identity())
javascript
let shape = {
type:'Cylinder',
name:'zone',
frame: 'world',
physical: false,
length:0.2,
radius:0.1,
localTransform: {translation:[0.0,0.0,0.0],rotation:[0.0,0.0,0.0,1.0]} // [x, y, z, w] ordering for quaternion
}
State
The State
object is the response back after calling solve
. It contains the state of the robot in terms of joint and frames, as well as some diagnostic information regarding proximity of various shapes and the center-of-mass of the robot.
Origin
The transform of the root of the robot. This is useful if the root node is movable. Exported as a Transform class (python) or object containing translation
and rotation
fields (javascript).
Joints
A lookup table of the joint values for each movable joint. Exported as a dictionary (python) or object (javascript).
Frames
A lookup table of the positions/orientations for each link. Exported as a dictionary (python) or object (javascript) of transform objects keyed by the link name.
Proximity
A list of all shapes that are currently tracked and that reach close enough proximity to potentially factor into collision detection. Exported as a ProximityInfo class (python) or object (javascript) with the following attributes:
-
shape1
(string
) The name of the first shape (note, if the robot is initialized with this shape, and it is attached to a robot link, the name is the link it is attached to.) -
shape2
(string
) The name of the second shape (note, if the robot is initialized with this shape, and it is attached to a robot link, the name is the link it is attached to.) -
distance
(float
/number
/None
/null
) The distance recorded between the two shapes. May possibly beNone
ornull
if not tracked, and is zero or negative if the shapes are intersecting. -
points
(None
/set of two points
) The closest points on two different shapes that are used determined whether these two shapes are close though to cause a collision based on the distance between the points on these two shapes. -
physical
(bool
) True if both shapes are physical, otherwise False. -
If the distance between points on two different shapes is smaller than or equal to
0.0
, two shapes areintersecting
with each other. -
If the distance between points on two different shapes is bigger than
0.0
but smaller than auser defined distance
, two shapes arewith in margin
with each other withinuser defined distance
.
Center of Mass
A translation (vector) indicating the current center of mass of the robot.
Extending the system.
Extending the set of objectives involves two main steps. The first step is defining the objective itself. These are generally located within the /src/objectives/
folder. When implementing an objective, you will want to import the "Callable" trait (and possibly groove_loss) with the following:
use crate::objectives::objective::{groove_loss, Callable};
For your new objective, you will need the struct block, which defines the data it encodes. As an example, Position Match defines the following:
pub struct PositionMatchObjective {
pub name: String,
pub weight: f64,
pub link: String,
// Goal Value
#[serde(skip)]
pub goal: Vector3<f64>,
}
** Note, serde is used to assist in building web bindings. Goals are skipped for this attribute because they are defined by the user explicitly
Second is the implementation for the constructor. Here is the Position Match objective again:
impl PositionMatchObjective {
pub fn new(name: String, weight: f64, link: String) -> Self {
Self {
name,
weight,
link,
goal: vector![0.0, 0.0, 0.0], // Default to a sensible value
}
}
}
Finally, you need to define the implementation of the Callable
trait:
impl Callable<Vector3<f64>> for PositionMatchObjective {
fn call(&self, _v: &Vars, state: &State) -> f64 {
// Get the link transform from frames
let link_translation = state.get_link_transform(&self.link).translation.vector;
// Calculate the distance
let x_val = (link_translation - self.goal).norm();
// Regularize by the groove_loss function and apply the weight.
return self.weight * groove_loss(x_val, 0., 2, 0.1, 10.0, 2);
}
// Implement the set_goal method
fn set_goal(&mut self, goal: Vector3<f64>) {
self.goal = goal;
}
// Implement the set_weight method
fn set_weight(&mut self, weight: f64) {
self.weight = weight;
}
// Other methods can use the default trait version.
}
The next main step is inserting the objective into the Objective
enum, located in /src/objectives/objective.rs
.
pub enum Objective {
PositionMatch(PositionMatchObjective),
OrientationMatch(OrientationMatchObjective),
...
// ++++++ Insert your Objective here ++++++
Finally, the Objective
enum defines a number of functions, mainly aimed at supporting debugging or executing the functions defined in the objective trait. Follow the patterns and descriptoins located in the file for more detail.
Contributing
Python Instructions
To build, download and cd
to this directory. Then run:
# Install Maturin
pip3 install maturin
# If you just want to install locally or develop:
maturin develop
Javascript Instructions
To build, download and cd
to this directory. Then run:
# Build the javascript bundle
wasm-pack build --scope people_and_robots --target bundler -- --features jsbindings
# Pack
wasm-pack pack
# Publish
wasm-pack publish --access=public
References
[^1]:Rakita, Daniel, Bilge Mutlu, and Michael Gleicher. "PROXIMA: An Approach for Time or Accuracy Budgeted Collision Proximity Queries." Proceedings of Robotics: Science and Systems (RSS). 2022. http://www.roboticsproceedings.org/rss18/p043.pdf
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for lively_tk-1.0.0rc2-cp37-abi3-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1637b6b40f269c5b64ff62fcd50c5216452835568eccc6b5b68d89e874dc21f8 |
|
MD5 | 95f7593f1e00611daa8347e1795305fe |
|
BLAKE2b-256 | 12b8440bc44592f11766933152b2529370984109067ec6bcdb2e5a1b32db597a |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | fc4bcd1211d2149747d67f886ce7b61dc49620ddddf3257274813edc4ea32a50 |
|
MD5 | f1d7c8752b40dd612b284cfc50522c19 |
|
BLAKE2b-256 | 78c7e93a56360af36d57156a0e95bd86489303c21e009c9b14fd360ef5cdb72f |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-musllinux_1_2_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | db4842b1c315e8f6961569f6c0c91a70e495389171e072ba24197573ab18b6fd |
|
MD5 | 38f2c374c384ab05d84b4655c36ce046 |
|
BLAKE2b-256 | f767e6970993fbfb118095e3b59ab875e26768783795a93c52a15f8fa26d9fd1 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-musllinux_1_2_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f4c49163bb4959d392d2e6963c5f72b652d4c52e8590d1bc39419a29a08631b0 |
|
MD5 | 6e7747425d0704ea6fc0e07e3a690d6a |
|
BLAKE2b-256 | 7375d19ea8b1b4d197103cecaca4b5a8603881e7a02a3a87095207dd72830512 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-musllinux_1_2_armv7l.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f5e2496f6a8e827e7348092f98757aa83974e7eba8f0e41833232f59f4f11b6e |
|
MD5 | d61228784aaa204ad4854a12f528ee4d |
|
BLAKE2b-256 | e74e71d64520a79c569e4c2ae33253acb3305e6fb520932fb6c8892953c3cb98 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-musllinux_1_2_aarch64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 867ddd14c1bfbf442460ea9f2b810e9ccc61007ef215eeb8681a3f8e55cf0f2c |
|
MD5 | 93deb3ed45e1b457e6a636b4b449dff2 |
|
BLAKE2b-256 | 25fd7a1b0aaa49b38807b98a220ae88982275d585201da729394d57836c20185 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 100db767afda1835b8da1bccb15ddb66d0ec0d0f5bdc22e31815bb20a8b5938d |
|
MD5 | fce774a863d8adf275041a183c7b452a |
|
BLAKE2b-256 | 959c837fa55b91ad102e841199170c3511b94b06774128ff17ed0997791a0856 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9252d9b12582f8d3330b7fe83803e696c01edf8bee4de0125dc0de3559da01d0 |
|
MD5 | 8201d77949f0df0a55b69e938b08074b |
|
BLAKE2b-256 | a746f4857258407d85a2d6c8d3dbf174ef4a63c9a3c31f742e94e918b0d12676 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a744a8c006d5e6b9cbd00f19d58adb35d8186acf712c9efc3fba65acbbc567b0 |
|
MD5 | dfc1dde0771a826c94255be1359f8835 |
|
BLAKE2b-256 | ac612b54ec6d69d1aa5f366608743a90bb6f82d717e029e4bd298bcaebf9641a |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f7e486ad9e5ffa6d3fe36531cb127c24e8ccc8f9cf78494642c50efbe6189d82 |
|
MD5 | db67d4f77497c47fbf34a9bb8f8614c2 |
|
BLAKE2b-256 | ad4519c8828bd3ffd7dcd0cc01334fa77a0cdc14cc8f3e9cd13c6ebbc0bd9a40 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 497147dc437610809acd77b64ebe35d1c8528d2e35e9aea53f13e83cfed4e97a |
|
MD5 | 035d0e5e70c629c7f7d8aa29504bd6dc |
|
BLAKE2b-256 | 05887512930fe76204b96bfba9c7fbbb30c6a86bd3715dc3a37008fb5efd6260 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 004beebb16254596d70a382cf84de1b27a6d12fa7f42e8221242015cd1577a83 |
|
MD5 | 2ef4cb45efd0a56eb253020af7a051de |
|
BLAKE2b-256 | 92a159a51d32d45f64ccc08f1a89e5a7b441da8cbf725aa7deacb3dade6fc721 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | edf44c6cf81925651ee1e8edfce5f62662dc28275e47f61a1837783342636759 |
|
MD5 | 7b2d042abb82a8e40cb1c5b4649f8527 |
|
BLAKE2b-256 | de70c5b8b7dcae3ebe0ceec3cecc3d7b53b9746ee4e3731f0442f4bf86f0c6fc |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bd7ed5d74af3600960257a1d0ad64dd599f938bc75bda966adc3479f0a6cf747 |
|
MD5 | fe2041f02de7ef3838aaa0ca7ba9d9e5 |
|
BLAKE2b-256 | 7d37fe54259f46ee124351015bbfea4a6c4d31d5aa1a1e52089f87ee8ae49264 |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f732e0fe7c4415a716c3bb9ed61bd18a64561afce0e9e35caa558016c79d51c8 |
|
MD5 | 846c662741c9689b1351260afca32a46 |
|
BLAKE2b-256 | 389fbcf3876a6cdcac07dfa0e3623d52077a0bc9db96ed332698e2ae5a2b080c |
Hashes for lively_tk-1.0.0rc2-cp37-abi3-macosx_10_7_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e96daad6a1a1c2eb6c6d53e0aae48c7924d01433c9ff80dd05b7b9c353be4004 |
|
MD5 | 95c07d3cb382157ca0181aba78b1db6c |
|
BLAKE2b-256 | 18ed99b41983262965a2bceff2f528b8cae65ac4b716d010210e99e593ea77b1 |