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