-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
differential_ik.py
99 lines (84 loc) · 4.08 KB
/
differential_ik.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import numpy as np
from pydrake.common.eigen_geometry import AngleAxis
from pydrake.manipulation.planner import DoDifferentialInverseKinematics
from pydrake.math import RigidTransform, RollPitchYaw
from pydrake.systems.framework import BasicVector, LeafSystem, PortDataType
# TODO(russt): Clean this up and move it to C++.
class DifferentialIK(LeafSystem):
"""
A simple system that wraps calls to the DifferentialInverseKinematics API.
It is highly recommended that the user calls SetPosition() once to
initialize the initial position commands to match the initial
configuration of the robot.
.. pydrake_system::
name: DifferentialIK
input_ports:
- X_WE_desired
output_ports:
- joint_position_desired
"""
def __init__(self, robot, frame_E, parameters, time_step):
"""
@param robot is a reference to a MultibodyPlant.
@param frame_E is a multibody::Frame on the robot.
@param params is a DifferentialIKParams.
@params time_step This system updates its state/outputs at discrete
periodic intervals defined with period @p time_step.
"""
LeafSystem.__init__(self)
self.robot = robot
self.frame_E = frame_E
self.parameters = parameters
self.parameters.set_timestep(time_step)
self.time_step = time_step
# Note that this context is NOT the context of the DifferentialIK
# system, but rather a context for the multibody plant that is used
# to pass the configuration into the DifferentialInverseKinematics
# methods.
self.robot_context = robot.CreateDefaultContext()
# Confirm that all velocities are zero (they will not be reset below).
assert not self.robot.GetPositionsAndVelocities(
self.robot_context)[-robot.num_velocities():].any()
# Store the robot positions as state.
position_state_index = self.DeclareDiscreteState(robot.num_positions())
self.DeclarePeriodicDiscreteUpdate(time_step)
# Desired pose of frame E in world frame.
self.DeclareInputPort("rpy_xyz_desired",
PortDataType.kVectorValued, 6)
# Provide the output as desired positions.
self.DeclareStateOutputPort("joint_position_desired",
position_state_index)
def SetPositions(self, context, q):
context.SetDiscreteState(0, q)
def ForwardKinematics(self, q):
x = self.robot.GetMutablePositionsAndVelocities(
self.robot_context)
x[:self.robot.num_positions()] = q
return self.robot.EvalBodyPoseInWorld(
self.robot_context, self.frame_E.body())
def CalcPoseError(self, X_WE_desired, q):
pose = self.ForwardKinematics(q)
err_vec = np.zeros(6)
err_vec[-3:] = X_WE_desired.translation() - pose.translation()
rot_err = AngleAxis(X_WE_desired.rotation()
* pose.rotation().transpose())
err_vec[:3] = rot_err.axis() * rot_err.angle()
def DoCalcDiscreteVariableUpdates(
self, context, events, discrete_state):
rpy_xyz_desired = self.EvalVectorInput(context, 0).get_value()
X_WE_desired = RigidTransform(RollPitchYaw(rpy_xyz_desired[:3]),
rpy_xyz_desired[-3:])
q_last = context.get_discrete_state_vector().get_value()
x = self.robot.GetMutablePositionsAndVelocities(
self.robot_context)
x[:self.robot.num_positions()] = q_last
result = DoDifferentialInverseKinematics(self.robot,
self.robot_context,
X_WE_desired, self.frame_E,
self.parameters)
if (result.status != result.status.kSolutionFound):
print("Differential IK could not find a solution.")
discrete_state.set_value(q_last)
else:
discrete_state.set_value(
q_last + self.time_step * result.joint_velocities)