Closed Peter230655 closed 4 months ago
It seems to be related to piecewise, since when I remove it (the simulation makes no sense then) the error disappears. I will try to replace piecewise with combinations of 'differentiable step functions' to get around this issue - but maybe still interesting on its own?
Piecewise is not differentiable.
I replaced the piecewise 'logic' using differentialble approximations of step functions $h(x,b) = \dfrac{1}{1 + e^{a(x - b)}}$ , and the error went away. I think, this should be possible in general, not 100% sure.
I am trying to apply opty to my woodpecker simulation. (The normal simulation can be found on pst-notebooks) but I am getting the error below:
When setting up the forces, I use sm.piecewise((...), (..)) which in some earlier simulation did not affect opty.
I attached the program below the error. (I do not know, why it looks so ugly. I used ``` as a first and last line, as usual)
Thanks for any help!!
-------------------------------
import sympy.physics.mechanics as me from collections import OrderedDict import time import numpy as np import sympy as sm from scipy.interpolate import CubicSpline
import opty from opty.direct_collocation import Problem from opty.utils import create_objective_function import matplotlib.pyplot as plt import matplotlib from IPython.display import HTML matplotlib.rcParams['animation.embed_limit'] = 2**128 from matplotlib.animation import FuncAnimation print('opty version: ', opty.version) print('sympy version: ', sm.version)
N, AR, AW = sm.symbols('N, AR, AW', cls = me.ReferenceFrame) O, DmcR, DmcW, P = sm.symbols('O, DmcR, DmcW, P', cls=me.Point)
t = me.dynamicsymbols._t
qR, uR, qW, uW = me.dynamicsymbols('qR, uR, qW, uW') yR, uyR = me.dynamicsymbols('yR, uyR')
mR, mW, g, iZZR, iZZW, ro, d, max_kipp, kR, kW, reibung, korrekt = sm.symbols('mR, mW, g, iZZR, iZZW, ro, d, max_kipp, kR, kW, reibung, korrekt')
set up the geometry
O.set_vel(N, 0)
AR.orient_axis(N, qR, N.z) AR.set_ang_vel(N, uR N.z) AW.orient_axis(AR, qW, AR.z) rot = AW.ang_vel_in(N) AW.set_ang_vel(AR, uW AR.z) rot1 = AW.ang_vel_in(N)
DmcR.set_pos(O, yRN.y) DmcR.set_vel(N, uyRN.y)
P.set_pos(DmcR, roAR.x - ro/5.AR.y) P.v2pt_theory(DmcR, N, AR)
DmcW.set_pos(P, d*AW.x) DmcW.v2pt_theory(P, N, AW)
iR = me.inertia(AR, 0., 0., iZZR) iW = me.inertia(AW, 0., 0., iZZW) Ring = me.RigidBody('Ring', DmcR, AR, mR, (iR, DmcR)) Woodpecker = me.RigidBody('Woodpecker', DmcW, AW, mW, (iW, DmcW)) BODY = [Ring, Woodpecker]
FG = [(DmcR, -mRgN.y), (DmcW, -mWgN.y)] # gravity FT1 = [(AW, -kW (qW-korrekt) N.z), (AR, kW (qW-korrekt) N.z)] # torque if woodpecker is not 'in line' with the ring
When - max_kipp > qR or qR > max_kipp, the ring touches the peg
faktor1 = sm.Piecewise((1., -max_kipp > qR), (1., qR >= max_kipp), (0., True))
the 'penetration' is qR - max_kipp if qR > max_kipp, and -(qR + max_kipp) if qR < -max_kipp
eindring = sm.Piecewise((qR - max_kipp, qR > max_kipp), (-qR - max_kipp, qR < -max_kipp), (0., True))
This penetration will create a torque on AR. I must determine the direction of this torque
faktor2 = sm.Piecewise((-1., max_kipp < qR), (1., True)) kraft = kR eindring faktor1 faktor2 FT2 = [(AR, kraft N.z)]
friction acting on DmcR to stop the sliding. I made it speed dependent to avoid that the ring might be driven upward.
kraft2 = sm.tanh(5 kraft) FR = [(DmcR, -uyR reibung kraft2 N.y)]
FL = FG + FT1 + FT2 + FR hilfs = [kraft, -uyR reibungkraft2]
set up the equations of motion
q_ind = [qR, qW, yR] u_ind = [uR, uW, uyR] kd = sm.Matrix([i - j.diff(t) for i, j in zip(u_ind, q_ind)])
KM = me.KanesMethod(N, q_ind=q_ind, u_ind=u_ind, kd_eqs=kd) (fr, frstar) = KM.kanes_equations(BODY, FL) MM = KM.mass_matrix_full force = KM.forcing_full
EOM = kd.col_join(fr + frstar)
print('EOM DS', me.find_dynamicsymbols(EOM)) print('EOM free symbols', EOM.free_symbols) print(f'EOM has {sm.count_ops(EOM)} operations, {sm.count_ops(sm.cse(EOM))} operations after cse', '\n')
state_symbols = tuple(q_ind + u_ind) laenge = len(state_symbols) constant_symbols = tuple((mR, mW, g, iZZR, iZZW, ro, d, max_kipp, korrekt)) specified_symbols = [] unknown_symbols = [kR, kW, reibung]
methode = 'backward euler'
duration = 10. # The duration of the simulation. num_nodes = 100 # The number of nodes to use in the direct collocation problem. t0, tf = 0., duration # The initial and final times interval_value = duration / (num_nodes - 1) # The interval value between nodes.
WERT = [0., 0., 0., 0., 0., 0.] initialguess = np.array([wert for wert in WERT for in range(num_nodes)] + [1.e6, 2.e3, 0.75])
Specify the known system parameters.
par_map = OrderedDict() par_map[mR] = 1.0 # Mass of the ring par_map[mW] = 15 # Mass of the woodpecker par_map[g] = 9.81 # Acceleration due to gravity par_map[iZZR] = 1. # Moment of inertia of the ring par_map[iZZW] = 10. # Moment of inertia of the woodpecker par_map[ro] = 1.0 # Distance of the mass center of the ring from DmcR par_map[d] = 1.0 # Distance of the mass center of the woodpecker from P par_map[max_kipp] = np.deg2rad(2.) # The maximum angle the ring can be tilted par_map[korrekt] = np.deg2rad(10.) # The angle the ring is tilted in the beginning
objective = sm.Integral(kR2 + kW2 + reibung**2, t) # minimal power
Specify the objective function and it's gradient.
obj, obj_grad = create_objective_function( objective, state_symbols, specified_symbols, unknown_symbols, num_nodes, interval_value, methode)
====================================================================================
initial_state_constraints = { qR: np.deg2rad(0), qW: np.deg2rad(-30), yR: 0., uR: 0., uW: 0., uyR: 0.}
final_state_constraints = {yR: -10}
instance_constraints = ( tuple(xi.subs({t: t0}) - xi_val for xi, xi_val in initial_state_constraints.items()), tuple(xi.subs({t: tf}) - xi_val for xi, xi_val in final_state_constraints.items()), )
prob = Problem( obj, obj_grad, EOM, state_symbols, num_nodes, interval_value, known_parameter_map=par_map, instance_constraints=instance_constraints, integration_method=methode)
prob.add_option('max_iter', 3000) # default is 3000
Find the optimal solution.
solution, info = prob.solve(initial_guess) print('message from optimizer:', info['status_msg']) print('Iterations needed',len(prob.obj_value)) print(f"objective value {info['obj_val']:.3e}")
print(f'kR: {solution[-3]:.3f}') print(f'kW: {solution[-2]:.3f}') print(f'reibung: {solution[-1]:.3f}')
prob.plot_constraint_violations(solution) prob.plot_trajectories(solution)