Examples¶
A first script¶
Let us go through examples/ur3_end_effector_tracking.py, where a UR3 arm
tracks a target moving back and forth. We first load the robot model:
import pinker
robot = pinker.load_robot_description("ur3_official_description")
We define the two tasks of this inverse kinematics: track the target with the end effector, and stay close to a reference posture. The posture task has a much lower cost, so that it only regularizes the redundancy left by the first task:
from pinker.tasks import FrameTask, PostureTask
end_effector_task = FrameTask(
"tool0",
position_cost=1.0, # [cost] / [m]
orientation_cost=1.0, # [cost] / [rad]
lm_damping=1.0, # tuned for this setup
)
posture_task = PostureTask(
cost=1e-3, # [cost] / [rad]
)
tasks = [end_effector_task, posture_task]
Tasks are defined by their cost and by their target. Here we initialize all targets from the initial configuration of the robot, so that the robot starts at rest with a zero task error:
import pinker
from pinker.kinematics import custom_configuration
q_ref = custom_configuration(
robot.model,
elbow_joint=1.0,
shoulder_lift_joint=1.0,
shoulder_pan_joint=1.0,
)
configuration = pinker.Configuration(robot.model, robot.data, q_ref)
for task in tasks:
task.set_target_from_configuration(configuration)
We can now run the closed-loop inverse kinematics. Each cycle updates the target of the end-effector task, computes a velocity that steers the robot towards all its tasks, and integrates that velocity into the next configuration:
import numpy as np
from loop_rate_limiters import RateLimiter
from pinker import solve_ik
rate = RateLimiter(frequency=200.0, warn=False)
dt = rate.period
t = 0.0 # [s]
while True:
end_effector_target = end_effector_task.transform_target_to_world
end_effector_target.translation[1] = 0.5 + 0.1 * np.sin(2.0 * t)
end_effector_target.translation[2] = 0.2
velocity = solve_ik(configuration, tasks, dt, solver="daqp")
configuration.integrate_inplace(velocity, dt)
rate.sleep()
t += dt
The configuration is thus the state carried from one cycle to the next. The full example wraps this loop with a Viser visualizer:
from pinker.visualizer import start_viser_visualizer
viz = start_viser_visualizer(robot)
viz.display(configuration.q) # in the loop, after integration
Running the examples¶
Examples live in the examples/ directory and carry their own dependencies
in an inline script metadata block (PEP 723), so that uv can run them standalone:
uv run examples/ur3_end_effector_tracking.py
Most examples start a Viser server and open the visualization in a new browser tab.
What the examples cover¶
Example |
Illustrates |
|---|---|
|
Displaying a robot description in Viser |
|
Closed kinematic chains with |
|
Center-of-mass tracking with |
|
End-effector tracking with a posture regularization |
|
Control barrier functions (Barriers) |
|
Whole-body inverse kinematics, with the feet in contact |
|
Maximizing manipulability with |
|
Iterating differential IK to reach a prescribed end-effector pose |
|
Mobile manipulation, with world and mobile-base targets |
|
Clamping base velocities with |
|
Rolling without slipping, with |
|
Selecting a sparse QP solver |
|
Smoothing velocities with a task gain, a |
|
Tracking joint velocities with |
Examples are named <robot>_<task>.py, after the robot description they load
and what they do with it. Their README.md has videos of the resulting
motions.