pinocchio  3.3.1
A fast and flexible implementation of Rigid Body Dynamics algorithms and their analytical derivatives
pendulum.py
1 """
2 Create a simulation environment for a N-pendulum.
3 Example of use:
4 
5 env = Pendulum(N)
6 env.reset()
7 
8 for i in range(1000):
9  env.step(zero(env.nu))
10  env.render()
11 
12 """
13 
14 import time
15 
16 import numpy as np
17 import pinocchio as pin
18 from display import Display
19 from numpy.linalg import inv
20 from pinocchio.utils import rand
21 
22 
23 class Visual:
24  """
25  Class representing one 3D mesh of the robot, to be attached to a joint. The class
26  contains:
27  * the name of the 3D objects inside Gepetto viewer.
28  * the ID of the joint in the kinematic tree to which the body is attached.
29  * the placement of the body with respect to the joint frame.
30  This class is only used in the list Robot.visuals (see below).
31  """
32 
33  def __init__(self, name, jointParent, placement):
34  self.namename = name # Name in gepetto viewer
35  self.jointParentjointParent = jointParent # ID (int) of the joint
36  self.placementplacement = placement # placement of the body wrt joint, i.e. bodyMjoint
37 
38  def place(self, display, oMjoint):
39  oMbody = oMjoint * self.placementplacement
40  display.place(self.namename, oMbody, False)
41 
42 
43 class Pendulum:
44  """
45  Define a class Robot with 7DOF (shoulder=3 + elbow=1 + wrist=3).
46  The configuration is nq=7. The velocity is the same.
47  The members of the class are:
48  * viewer: a display encapsulating a gepetto viewer client to create 3D objects and
49  place them.
50  * model: the kinematic tree of the robot.
51  * data: the temporary variables to be used by the kinematic algorithms.
52  * visuals: the list of all the 'visual' 3D objects to render the robot, each element
53  of the list being an object Visual (see above).
54 
55  See tp1.py for an example of use.
56  """
57 
58  def __init__(self, nbJoint=1):
59  """Create a Pinocchio model of a N-pendulum, with N the argument <nbJoint>."""
60  self.viewerviewer = Display()
61  self.visualsvisuals = []
62  self.modelmodel = pin.Model()
63  self.createPendulumcreatePendulum(nbJoint)
64  self.datadata = self.modelmodel.createData()
65 
66  self.q0q0 = np.zeros(self.modelmodel.nq)
67 
68  self.DTDT = 5e-2 # Step length
69  self.NDTNDT = 2 # Number of Euler steps per integration (internal)
70  self.KfKf = 0.10 # Friction coefficient
71  self.vmaxvmax = 8.0 # Max velocity (clipped if larger)
72  self.umaxumax = 2.0 # Max torque (clipped if larger)
73  self.withSinCoswithSinCos = False # If true, state is [cos(q),sin(q),qdot], else [q,qdot]
74 
75  def createPendulum(self, nbJoint, rootId=0, prefix="", jointPlacement=None):
76  color = [red, green, blue, transparency] = [1, 1, 0.78, 1.0]
77  colorred = [1.0, 0.0, 0.0, 1.0]
78 
79  jointId = rootId
80  jointPlacement = (
81  jointPlacement if jointPlacement is not None else pin.SE3.Identity()
82  )
83  length = 1.0
84  mass = length
85  inertia = pin.Inertia(
86  mass,
87  np.array([0.0, 0.0, length / 2]),
88  mass / 5 * np.diagflat([1e-2, length**2, 1e-2]),
89  )
90 
91  for i in range(nbJoint):
92  istr = str(i)
93  name = prefix + "joint" + istr
94  jointName, _bodyName = [name + "_joint", name + "_body"]
95  jointId = self.modelmodel.addJoint(
96  jointId, pin.JointModelRY(), jointPlacement, jointName
97  )
98  self.modelmodel.appendBodyToJoint(jointId, inertia, pin.SE3.Identity())
99  try:
100  self.viewerviewer.viewer.gui.addSphere(
101  "world/" + prefix + "sphere" + istr, 0.15, colorred
102  )
103  except: # noqa: E722
104  pass
105  self.visualsvisuals.append(
106  Visual("world/" + prefix + "sphere" + istr, jointId, pin.SE3.Identity())
107  )
108  try:
109  self.viewerviewer.viewer.gui.addCapsule(
110  "world/" + prefix + "arm" + istr, 0.1, 0.8 * length, color
111  )
112  except: # noqa: E722
113  pass
114  self.visualsvisuals.append(
115  Visual(
116  "world/" + prefix + "arm" + istr,
117  jointId,
118  pin.SE3(np.eye(3), np.array([0.0, 0.0, length / 2])),
119  )
120  )
121  jointPlacement = pin.SE3(np.eye(3), np.array([0.0, 0.0, length]))
122 
123  self.modelmodel.addFrame(
124  pin.Frame("tip", jointId, 0, jointPlacement, pin.FrameType.OP_FRAME)
125  )
126 
127  def display(self, q):
128  pin.forwardKinematics(self.modelmodel, self.datadata, q)
129  for visual in self.visualsvisuals:
130  visual.place(self.viewerviewer, self.datadata.oMi[visual.jointParent])
131  self.viewerviewer.viewer.gui.refresh()
132 
133  @property
134  def nq(self):
135  return self.modelmodel.nq
136 
137  @property
138  def nv(self):
139  return self.modelmodel.nv
140 
141  @property
142  def nx(self):
143  return self.nqnq + self.nvnv
144 
145  @property
146  def nobs(self):
147  return self.nxnx + self.withSinCoswithSinCos
148 
149  @property
150  def nu(self):
151  return self.nvnv
152 
153  def reset(self, x0=None):
154  if x0 is None:
155  q0 = np.pi * (rand(self.nqnq) * 2 - 1)
156  v0 = rand(self.nvnv) * 2 - 1
157  x0 = np.vstack([q0, v0])
158  assert len(x0) == self.nxnx
159  self.xx = x0.copy()
160  self.rr = 0.0
161  return self.obsobs(self.xx)
162 
163  def step(self, u):
164  assert len(u) == self.nunu
165  _, self.rr = self.dynamicsdynamics(self.xx, u)
166  return self.obsobs(self.xx), self.rr
167 
168  def obs(self, x):
169  if self.withSinCoswithSinCos:
170  return np.vstack(
171  [np.vstack([np.cos(qi), np.sin(qi)]) for qi in x[: self.nqnq]]
172  + [x[self.nqnq :]],
173  )
174  else:
175  return x.copy()
176 
177  def tip(self, q):
178  """Return the altitude of pendulum tip"""
179  pin.framesKinematics(self.modelmodel, self.datadata, q)
180  return self.datadata.oMf[1].translation[2, 0]
181 
182  def dynamics(self, x, u, display=False):
183  """
184  Dynamic function: x,u -> xnext=f(x,y).
185  Put the result in x (the initial value is destroyed).
186  Also compute the cost of making this step.
187  Return x for convenience along with the cost.
188  """
189 
190  def modulePi(th):
191  return (th + np.pi) % (2 * np.pi) - np.pi
192 
193  def sumsq(x):
194  return np.sum(np.square(x))
195 
196  cost = 0.0
197  q = modulePi(x[: self.nqnq])
198  v = x[self.nqnq :]
199  u = np.clip(np.reshape(np.array(u), [self.nunu, 1]), -self.umaxumax, self.umaxumax)
200 
201  DT = self.DTDT / self.NDTNDT
202  for i in range(self.NDTNDT):
203  pin.computeAllTerms(self.modelmodel, self.datadata, q, v)
204  M = self.datadata.M
205  b = self.datadata.nle
206  # tau = u-self.Kf*v
207  a = inv(M) * (u - self.KfKf * v - b)
208 
209  v += a * DT
210  q += v * DT
211  cost += (sumsq(q) + 1e-1 * sumsq(v) + 1e-3 * sumsq(u)) * DT
212 
213  if display:
214  self.displaydisplay(q)
215  time.sleep(1e-4)
216 
217  x[: self.nqnq] = modulePi(q)
218  x[self.nqnq :] = np.clip(v, -self.vmaxvmax, self.vmaxvmax)
219 
220  return x, -cost
221 
222  def render(self):
223  q = self.xx[: self.nqnq]
224  self.displaydisplay(q)
225  time.sleep(self.DTDT / 10)
def obs(self, x)
Definition: pendulum.py:168
def __init__(self, nbJoint=1)
Definition: pendulum.py:58
def nx(self)
Definition: pendulum.py:142
def display(self, q)
Definition: pendulum.py:127
def dynamics(self, x, u, display=False)
Definition: pendulum.py:182
def nv(self)
Definition: pendulum.py:138
def nq(self)
Definition: pendulum.py:134
def createPendulum(self, nbJoint, rootId=0, prefix="", jointPlacement=None)
Definition: pendulum.py:75
def tip(self, q)
Definition: pendulum.py:177
def nu(self)
Definition: pendulum.py:150