OpenSim Moco  0.2.0
examplePredictAndTrack.py

This example predicts the trajectory to swing a double pendulum from horizontal to vertical, and then tracks the resulting trajectory.

1 # -------------------------------------------------------------------------- #
2 # OpenSim Moco: examplePredictAndTrack.py #
3 # -------------------------------------------------------------------------- #
4 # Copyright (c) 2018 Stanford University and the Authors #
5 # #
6 # Author(s): Christopher Dembia #
7 # #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may #
9 # not use this file except in compliance with the License. You may obtain a #
10 # copy of the License at http://www.apache.org/licenses/LICENSE-2.0 #
11 # #
12 # Unless required by applicable law or agreed to in writing, software #
13 # distributed under the License is distributed on an "AS IS" BASIS, #
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15 # See the License for the specific language governing permissions and #
16 # limitations under the License. #
17 # -------------------------------------------------------------------------- #
18 
19 import os
20 import math
21 import opensim as osim
22 
23 """
24 This file performs the following problems using a
25 double pendulum model:
26 
27  1. predict an optimal trajectory (and controls),
28  2. track the states from the optimal trajectory, and
29  3. track the marker trajectories from the optimal trajectory.
30 
31 """
32 
33 visualize = True
34 if os.getenv('OPENSIM_USE_VISUALIZER') == '0':
35  visualize = False
36 
37 # Create a model of a double pendulum.
38 # ------------------------------------
39 def createDoublePendulumModel():
40  model = osim.Model()
41  model.setName("double_pendulum")
42 
43  # Create two links, each with a mass of 1 kg, center of mass at the body's
44  # origin, and moments and products of inertia of zero.
45  b0 = osim.Body("b0", 1, osim.Vec3(0), osim.Inertia(1))
46  model.addBody(b0)
47  b1 = osim.Body("b1", 1, osim.Vec3(0), osim.Inertia(1))
48  model.addBody(b1)
49 
50  # Add markers to body origin locations.
51  m0 = osim.Marker("m0", b0, osim.Vec3(0))
52  m1 = osim.Marker("m1", b1, osim.Vec3(0))
53  model.addMarker(m0)
54  model.addMarker(m1)
55 
56  # Connect the bodies with pin joints. Assume each body is 1 m long.
57  j0 = osim.PinJoint("j0", model.getGround(), osim.Vec3(0), osim.Vec3(0),
58  b0, osim.Vec3(-1, 0, 0), osim.Vec3(0))
59  q0 = j0.updCoordinate()
60  q0.setName("q0")
61  j1 = osim.PinJoint("j1",
62  b0, osim.Vec3(0), osim.Vec3(0), b1, osim.Vec3(-1, 0, 0), osim.Vec3(0))
63  q1 = j1.updCoordinate()
64  q1.setName("q1")
65  model.addJoint(j0)
66  model.addJoint(j1)
67 
68  tau0 = osim.CoordinateActuator()
69  tau0.setCoordinate(j0.updCoordinate())
70  tau0.setName("tau0")
71  tau0.setOptimalForce(1)
72  model.addComponent(tau0)
73 
74  tau1 = osim.CoordinateActuator()
75  tau1.setCoordinate(j1.updCoordinate())
76  tau1.setName("tau1")
77  tau1.setOptimalForce(1)
78  model.addComponent(tau1)
79 
80  # Add display geometry.
81  bodyGeometry = osim.Ellipsoid(0.5, 0.1, 0.1)
82  transform = osim.Transform(osim.Vec3(-0.5, 0, 0))
83  b0Center = osim.PhysicalOffsetFrame("b0_center", b0, transform)
84  b0.addComponent(b0Center)
85  b0Center.attachGeometry(bodyGeometry.clone())
86  b1Center = osim.PhysicalOffsetFrame("b1_center", b1, transform)
87  b1.addComponent(b1Center)
88  b1Center.attachGeometry(bodyGeometry.clone())
89 
90  model.finalizeConnections()
91  model.printToXML("double_pendulum.osim")
92  return model
93 
94 
95 def solvePrediction():
96  # Predict the optimal trajectory for a minimum time swing-up.
97  #
98  # o
99  # |
100  # o
101  # |
102  # +---o---o +
103  #
104  # iniital pose final pose
105  #
106  study = osim.MocoStudy()
107  study.setName("double_pendulum_predict")
108 
109  problem = study.updProblem()
110 
111  # Model (dynamics).
112  problem.setModel(createDoublePendulumModel())
113 
114  # Bounds.
115  problem.setTimeBounds(0, [0, 5])
116  # Arguments are name, [lower bound, upper bound],
117  # initial [lower bound, upper bound],
118  # final [lower bound, upper bound].
119  problem.setStateInfo("/jointset/j0/q0/value", [-10, 10], 0)
120  problem.setStateInfo("/jointset/j0/q0/speed", [-50, 50], 0, 0)
121  problem.setStateInfo("/jointset/j1/q1/value", [-10, 10], 0)
122  problem.setStateInfo("/jointset/j1/q1/speed", [-50, 50], 0, 0)
123  problem.setControlInfo("/tau0", [-100, 100])
124  problem.setControlInfo("/tau1", [-100, 100])
125 
126  # Cost: minimize final time and error from desired
127  # end effector position.
128  ftCost = osim.MocoFinalTimeGoal()
129  ftCost.setWeight(0.001)
130  problem.addGoal(ftCost)
131 
132  finalCost = osim.MocoMarkerFinalGoal()
133  finalCost.setName("final")
134  finalCost.setWeight(1000.0)
135  finalCost.setPointName("/markerset/m1")
136  finalCost.setReferenceLocation(osim.Vec3(0, 2, 0))
137  problem.addGoal(finalCost)
138 
139 
140  # Configure the solver.
141  solver = study.initTropterSolver()
142  solver.set_num_mesh_intervals(100)
143  solver.set_verbosity(2)
144  solver.set_optim_solver("ipopt")
145 
146  guess = solver.createGuess()
147  guess.setNumTimes(2)
148  guess.setTime([0, 1])
149  guess.setState("/jointset/j0/q0/value", [0, -math.pi])
150  guess.setState("/jointset/j1/q1/value", [0, 2*math.pi])
151  guess.setState("/jointset/j0/q0/speed", [0, 0])
152  guess.setState("/jointset/j1/q1/speed", [0, 0])
153  guess.setControl("/tau0", [0, 0])
154  guess.setControl("/tau1", [0, 0])
155  guess.resampleWithNumTimes(10)
156  solver.setGuess(guess)
157 
158  # Save the problem to a setup file for reference.
159  study.printToXML("examplePredictAndTrack_predict.omoco")
160 
161  # Solve the problem.
162  solution = study.solve();
163  solution.write("examplePredictAndTrack_predict_solution.sto");
164 
165  if visualize:
166  study.visualize(solution);
167  return solution
168 
169 
170 def computeMarkersReference(predictedSolution):
171  model = createDoublePendulumModel()
172  model.initSystem()
173  states = predictedSolution.exportToStatesStorage()
174 
175  # Workaround for a bug in Storage::operator=().
176  columnLabels = model.getStateVariableNames()
177  columnLabels.insert(0, "time")
178  states.setColumnLabels(columnLabels)
179 
180  statesTraj = osim.StatesTrajectory.createFromStatesStorage(model, states)
181 
182  markerTrajectories = osim.TimeSeriesTableVec3()
183  markerTrajectories.setColumnLabels(["/markerset/m0", "/markerset/m1"])
184 
185  for state in statesTraj:
186  model.realizePosition(state)
187  m0 = model.getComponent("markerset/m0")
188  m1 = model.getComponent("markerset/m1")
189  markerTrajectories.appendRow(state.getTime(),
190  osim.RowVectorVec3([m0.getLocationInGround(state),
191  m1.getLocationInGround(state)]))
192 
193  # Assign a weight to each marker.
194  markerWeights = osim.SetMarkerWeights()
195  markerWeights.cloneAndAppend(osim.MarkerWeight("/markerset/m0", 1))
196  markerWeights.cloneAndAppend(osim.MarkerWeight("/markerset/m1", 5))
197 
198  return osim.MarkersReference(markerTrajectories, markerWeights)
199 
200 
201 def solveStateTracking(stateRef):
202  # Predict the optimal trajectory for a minimum time swing-up.
203  study = osim.MocoStudy()
204  study.setName("double_pendulum_track")
205 
206  problem = study.updProblem()
207 
208  # Model (dynamics).
209  problem.setModel(createDoublePendulumModel())
210 
211  # Bounds.
212  # Arguments are name, [lower bound, upper bound],
213  # initial [lower bound, upper bound],
214  # final [lower bound, upper bound].
215  finalTime = markersRef.getMarkerTable().getIndependentColumn()[-1]
216  problem.setTimeBounds(0, finalTime)
217  problem.setStateInfo("/jointset/j0/q0/value", [-10, 10], 0)
218  problem.setStateInfo("/jointset/j0/q0/speed", [-50, 50], 0)
219  problem.setStateInfo("/jointset/j1/q1/value", [-10, 10], 0)
220  problem.setStateInfo("/jointset/j1/q1/speed", [-50, 50], 0)
221  problem.setControlInfo("/tau0", [-150, 150])
222  problem.setControlInfo("/tau1", [-150, 150])
223 
224  # Cost: track provided state data.
225  stateTracking = osim.MocoStateTrackingGoal()
226  stateTracking.setReference(osim.TableProcessor(stateRef))
227  problem.addGoal(stateTracking)
228 
229  effort = osim.MocoControlGoal()
230  effort.setName("effort")
231  effort.setWeight(0.001)
232  # TODO problem.addGoal(effort)
233 
234  # Configure the solver.
235  solver = study.initTropterSolver()
236  solver.set_num_mesh_intervals(50)
237  solver.set_verbosity(2)
238  solver.set_optim_solver("ipopt")
239  solver.set_optim_jacobian_approximation("exact")
240  solver.set_optim_hessian_approximation("exact")
241  solver.set_exact_hessian_block_sparsity_mode("dense")
242 
243  # Save the problem to a setup file for reference.
244  study.printToXML("examplePredictAndTrack_track_states.omoco")
245 
246  # Solve the problem.
247  solution = study.solve()
248 
249  solution.write("examplePredictAndTrack_track_states_solution.sto")
250 
251  if visualize:
252  study.visualize(solution)
253  return solution
254 
255 
256 def solveMarkerTracking(markersRef, guess):
257  # Predict the optimal trajectory for a minimum time swing-up.
258  study = osim.MocoStudy()
259  study.setName("double_pendulum_track")
260 
261  problem = study.updProblem()
262 
263  # Model (dynamics).
264  problem.setModel(createDoublePendulumModel())
265 
266  # Bounds.
267  # Arguments are name, [lower bound, upper bound],
268  # initial [lower bound, upper bound],
269  # final [lower bound, upper bound].
270  finalTime = markersRef.getMarkerTable().getIndependentColumn()[-1]
271  problem.setTimeBounds(0, finalTime)
272  problem.setStateInfo("/jointset/j0/q0/value", [-10, 10], 0)
273  problem.setStateInfo("/jointset/j0/q0/speed", [-50, 50], 0)
274  problem.setStateInfo("/jointset/j1/q1/value", [-10, 10], 0)
275  problem.setStateInfo("/jointset/j1/q1/speed", [-50, 50], 0)
276  problem.setControlInfo("/tau0", [-100, 100])
277  problem.setControlInfo("/tau1", [-100, 100])
278 
279  # Cost: track provided marker data.
280  markerTracking = osim.MocoMarkerTrackingGoal()
281  markerTracking.setMarkersReference(markersRef)
282  problem.addGoal(markerTracking)
283 
284  effort = osim.MocoControlGoal()
285  effort.setName("effort")
286  effort.setWeight(0.0001)
287  # problem.addGoal(effort)
288 
289  # Configure the solver.
290  solver = study.initTropterSolver()
291  solver.set_num_mesh_intervals(50)
292  solver.set_verbosity(2)
293  solver.set_optim_solver("ipopt")
294  solver.set_optim_jacobian_approximation("exact")
295  solver.set_optim_hessian_approximation("exact")
296  solver.set_exact_hessian_block_sparsity_mode("dense")
297 
298  solver.setGuess(guess)
299 
300  # Save the problem to a setup file for reference.
301  study.printToXML("examplePredictAndTrack_track_markers.omoco")
302 
303  # Solve the problem.
304  solution = study.solve()
305 
306  solution.write("examplePredictAndTrack_track_markers_solution.sto")
307 
308  if visualize:
309  study.visualize(solution)
310  return solution
311 
312 
313 
314 
315 optimalTrajectory = solvePrediction()
316 
317 markersRef = computeMarkersReference(optimalTrajectory)
318 
319 trackedSolution = solveStateTracking(optimalTrajectory.exportToStatesTable())
320 
321 trackedSolution = solveMarkerTracking(markersRef, trackedSolution)
322 
323 
324 
325 
326 
327 
328 
329 
330 
331 
332 
333 
334 
335 
336 
337 
338