5. Planification: mouvement d’une grue#
Marc BUFFAT, département mécanique, UCB Lyon 1
%matplotlib inline
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
plt.rc('font', family='serif', size='14')
from IPython.display import display, Markdown, clear_output
def printmd(string):
display(Markdown(string))
from metakernel import register_ipython_magics
register_ipython_magics()
from sympy.physics.vector import init_vprinting
init_vprinting()
5.1. Description#
repere fixe en O, \(R_O\)
Bras \(P_1P_2\) fixe en P1 (a H de O suivant Z) cylindre de longueur Lb, de masse Mb et de rayon a
repere \(R_b\) lié au bras (// a \(R_b.x\))
rotation \(\psi(t)\) autour de \(R_O.z\)
rotation de \(\theta(t)\) autour de \(R_a.y\) (attention angle <0)
masse m accroché à \(P_2\) (extrémité du bras) par un cable de longueur L (2 rotations \(\phi_y\),\(\phi_z\))
5.2. Parametres et repéres#
# parametres
from sympy.physics.mechanics import dynamicsymbols, Point, ReferenceFrame
from sympy.physics.mechanics import Particle, RigidBody, Lagrangian, LagrangesMethod
theta, psi, phiy, phiz = dynamicsymbols('theta psi phi_y phi_z')
thetap, psip, phiyp, phizp = dynamicsymbols('theta psi phi_y phi_z',level=1)
H, Lb, Mb, alpha, omega = sp.symbols('H L_b M_b alpha omega')
# rayon barre 1/10 Lb
a = Lb/10
# masse m de la masse
m = 10*Mb
# longueur du cable
l = alpha*Lb
# force de gravite
g = omega**2*l
# repêres barre
O = Point('O')
RO = ReferenceFrame('R_O')
P1 = Point('P1')
P1.set_pos(O,H*RO.z)
R1 = ReferenceFrame('R_1')
R1.orient(RO,'Axis',[psi, RO.z])
Rb = ReferenceFrame('R_b')
Rb.orient(R1,'Axis',[theta, R1.y])
P2 = Point('P2')
P2.set_pos(P1,Lb*Rb.x)
display("OP2=",P2.pos_from(O))
G = Point('G')
G.set_pos(P1,Lb/2*Rb.x)
display("OG=",G.pos_from(O))
'OP2='

'OG='

# repere masse (rotation phi)
R2 = ReferenceFrame('R_2')
R2.orient(R1,'Axis',[phiz, R1.z])
Rm = ReferenceFrame('R_m')
Rm.orient(R2,'Axis',[phiy, R2.y])
M = Point('M')
M.set_pos(P2,-l*Rm.z)
display("OM=",M.pos_from(O))
'OM='

5.3. Cinématique#
# calcul directe
from sympy.physics.vector import express,time_derivative
display("OM=",express(M.pos_from(O),RO))
display("VM=",express(time_derivative(M.pos_from(O),RO),RO).simplify())
'OM='

'VM='

# inertie
from sympy.physics.mechanics import inertia
Ix = Mb*a**2/2
Iy = Mb*a**2/4 + Mb*Lb**2/12
IG = inertia(Rb,Ix,Iy,Iy)
display("IG=",IG)
'IG='

# vitesse
O.set_vel(RO,0.)
P1.set_vel(RO,0.)
P2.set_vel(Rb,0.)
G.set_vel(Rb,0.)
# composition des vitesses
P2.v2pt_theory(P1,RO,Rb)
G.v2pt_theory(P1,RO,Rb)
display("VP2=",P2.vel(RO),"VG=",G.vel(RO))
display("dans Rb=",P2.vel(Rb),G.vel(Rb))
'VP2='

'VG='

'dans Rb='


# vitesse de M
M.set_vel(Rm,0.)
M.v2pt_theory(P2,RO,Rm)
display("VM=",M.vel(RO))
'VM='

5.4. Formalisme de Lagrange#
systeme = Barre + Masse
Masse = Particle('Masse',M,m)
Barre = RigidBody('Barre',G,Rb,Mb,(IG,G))
display("Ec Barre=",Barre.kinetic_energy(RO).simplify())
display("Ec Masse=",Masse.kinetic_energy(RO).simplify())
'Ec Barre='

'Ec Masse='

# reference en P1
Barre.potential_energy = Mb*g*G.pos_from(P1).dot(RO.z)
display("Ep Barre:",Barre.potential_energy)
Masse.potential_energy = m*g*M.pos_from(P1).dot(RO.z)
display("Ep Masse:",Masse.potential_energy)
'Ep Barre:'

'Ep Masse:'

# calcul lagrangien
La = Lagrangian(RO,Barre,Masse)
La = La/(Lb**2*Mb)
La = La.simplify()
display("La=",La)
'La='

5.5. Cas \(\theta=cste\) \(\psi=cste\) (grue immobile)#
mouvement pendule 3D
oscillation pendule simple : $\(\omega^2 = \frac{g}{l} \)$
LLa = La.subs({theta:0,thetap:0,psi:0,psip:0})/(10*alpha**2)
LLa = LLa.simplify()
display("La=",LLa)
'La='

# equation lagrange
LLM = LagrangesMethod(LLa,[phiy,phiz],frame=RO)
Eq = LLM.form_lagranges_equations()
display(Eq)

# parametres
LL = 2.0
Alpha = 1.0
Omega = np.sqrt(10./(Alpha*LL))
Tp = 2*np.pi/Omega
print("T=",Tp,"Omega=",Omega)
T= 2.8099258924162904 Omega= 2.23606797749979
5.6. Cas \(\theta=cste\) \(\dot{\psi}=cste\)#
cas grue en rotation
\(\theta = \pi/4\)
\(\psi = kp\,t \)
kp, t = sp.symbols('k_p t')
LLa = La.subs({theta:sp.pi/4,thetap:0,psi:kp*t,psip:kp})/(10)
LLa = LLa.simplify()
display("La=",LLa)
'La='

# equation lagrange
LLM = LagrangesMethod(LLa,[phiy,phiz],frame=RO)
Eq = LLM.form_lagranges_equations()
display("Lagrange:",Eq)
'Lagrange:'

5.6.1. solution particulière#
La solution \(\phi_y=cste\) et \(\phi_z=cste\) conduit forcement a \(\phi_z=0\)
\(\leadsto\) alignement de la masse avec la barre (dans le meme plan)
# solution Phiy=cste Phiz=cste
eq0=Eq[0].subs({phiy.diff(t,t):0}).subs({phiyp:0,phizp:0}).simplify()/alpha
eq1=Eq[1].subs({phiz.diff(t,t):0}).subs({phiyp:0,phizp:0}).simplify()
display(eq0,eq1)


eq0=eq0.subs({phiz:0})
display(sp.Eq(eq0,0))

5.6.2. solution numérique#
transformation du système de Lagrange $\( A \dot{Y} = B \)\( en \)\( \dot{Y} = F(Y) \)$
# resolution numérique
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
display("FY=",FY)
'FY='

# conversion en fonction python BY
smBY = sp.lambdify((phiy,phiz,phiyp,phizp,omega,alpha,kp),FY,'numpy')
# fonction F(Y)
def F(Y,t):
'''second membre de l EDO dY/dt = F(Y) avec Y=[phiy,phiz,phiyp,phizp]'''
global Omega,Alpha,Kp
FF =smBY(Y[0],Y[1],Y[2],Y[3],Omega,Alpha,Kp)
return FF[:,0]
# parametres
HH = 1.0
LL = 2.0
Alpha = 1.0
Omega = np.sqrt(10./(Alpha*LL))
Kp = 1.
Tp = 2*np.pi/Omega
print("T=",Tp,"Omega=",Omega)
T= 2.8099258924162904 Omega= 2.23606797749979
5.6.3. calcul solution particuliere phi=cste#
détermination de phiy pour phiz=0
2 racines proches de 0 et pi
# condition correspondant à l'équilibre phi=cste
Eq0=eq0.subs({alpha:Alpha,omega:Omega,kp:Kp})
display(Eq0)
EQ0=sp.lambdify(phiy,Eq0)

PHIY=np.linspace(-np.pi,np.pi,100)
YY = EQ0(PHIY)
plt.plot(PHIY,YY,label="eq0")
plt.plot(PHIY,np.zeros(PHIY.size),'--')
plt.xlabel("$\phi_y$");

from scipy.optimize import fsolve
Phiy0=fsolve(EQ0,0.)[0]
Phiy1=fsolve(EQ0,np.pi)[0]
print("Racines Phiy0={:.3f} Phiy1={:.3f}".format(Phiy0,Phiy1))
Racines Phiy0=-0.174 Phiy1=3.024
5.6.4. résolution numérique#
from scipy.integrate import odeint
# solution equilibre
Y0 = np.array([Phiy0,0.0,0.0,0.0])
# solution avec perturbation
Y0 = np.array([Phiy0-0.3,0.3,0.0,0.0])
print("F(Y0)=",F(Y0,0.))
T = 10*Tp
N = 400
tt = np.linspace(0,T,N)
sol = odeint(F,Y0,tt,atol=1.e-12,rtol=1.e-12)
PHIY = sol[:,0]
PHIZ = np.mod(sol[:,1],2*np.pi)
F(Y0)= [ 0. 0. 1.27641501 -0.45751735]
plt.figure(figsize=(12,8))
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.subplot(2,1,2)
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
<matplotlib.legend.Legend at 0x7f7f2d114820>

# position de P2
P2x = sp.lambdify((theta,psi,Lb),express(P2.pos_from(O),RO).dot(RO.x),'numpy')
P2y = sp.lambdify((theta,psi,Lb),express(P2.pos_from(O),RO).dot(RO.y),'numpy')
P2z = sp.lambdify((theta,psi,Lb,H),express(P2.pos_from(O),RO).dot(RO.z),'numpy')
P2X = P2x(0.,Kp*tt,LL)
P2Y = P2y(0.,Kp*tt,LL)
P2Z = P2z(0.,Kp*tt,LL,HH)*np.ones(tt.size)
# et position de M
Mx = sp.lambdify((theta,psi,phiy,phiz,Lb,alpha),express(M.pos_from(O),RO).dot(RO.x),'numpy')
My = sp.lambdify((theta,psi,phiy,phiz,Lb,alpha),express(M.pos_from(O),RO).dot(RO.y),'numpy')
Mz = sp.lambdify((theta,psi,phiy,phiz,Lb,H,alpha),express(M.pos_from(O),RO).dot(RO.z),'numpy')
MX = Mx(0.,Kp*tt,PHIY,PHIZ,LL,Alpha)
MY = My(0.,Kp*tt,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,Kp*tt,PHIY,PHIZ,LL,HH,Alpha)
plt.title("Trajectoire dans le plan")
plt.plot(MX,MY,label="M")
plt.plot(P2X,P2Y,label="P2")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.axis('equal');

# trajectoire en 3D
from validation.Pendule3D import TrajectoireBras3D
TrajectoireBras3D(P2X,P2Y,P2Z,MX,MY,MZ,HH,LL*1.5)
5.7. Etude d’un mouvement imposé#
etude du mouvement pour déplacer une charge d’un point A à B
cas \(\theta=0\) et \(\psi(t)\) imposée (interpolation degré 3 )
5.7.1. calcul de la loi horaire#
définition d’une loi horaire \(\psi(t)\)
polynôme \(p(t)=a_0 + a_1 t + a_2 t^2 + a_3 t^3\)
durée du mouvement \(T\)
conditions \(p(0)=0, \dot{p}(0) = 0 , p(T)=\psi_f, \dot{p}(T)=0\)
Psif , Tf = sp.symbols('Psi_f Tf')
Psi = Psif*t**2*(3*Tf-2*t)/Tf**3
display("Psi=",Psi)
LLa = La.subs({theta:0,thetap:0, psi: Psi, psip : Psi.diff(t) })
display("La=",LLa.simplify())
'Psi='

'La='

5.7.2. 1ere phase: mouvement de A a B#
LLM = LagrangesMethod(LLa,[phiy,phiz])
Eq = LLM.form_lagranges_equations()
display("Lagrange:",Eq)
'Lagrange:'

# conversion en EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY=A.inv()*B
FY[2]=FY[2].simplify()
FY[3]=FY[3].simplify()
display("F(Y)=",FY)
'F(Y)='

# fonction BY
smBY = sp.lambdify((phiy,phiz,phiyp,phizp,t,alpha,omega,Psif,Tf),FY,'numpy')
# fonction F(Y)
def F(Y,t):
'''second membre EDO dY/dt = F(Y) avec Y=[phiy,phiz,phiyp,phizp]'''
global Alpha,Omega,PsiF,T
FF =smBY(Y[0],Y[1],Y[2],Y[3],t,Alpha,Omega,PsiF,T)
return FF[:,0]
# parametres
HH = 1.0
LL = 2.0
Alpha = 1.0
Omega = np.sqrt(10./(Alpha*LL))
Tp = 2*np.pi/Omega
print("T=",Tp,"Omega=",Omega)
PsiF = np.pi
# parcours lent
T = 20.
# parcours rapide
T = 5.
# parcours tres lent
#T = 80.
T= 2.8099258924162904 Omega= 2.23606797749979
# solution numerique
Y0 = np.array([-0.01,0.,0.,0.])
print(F(Y0,0.))
N = 200
tt = np.linspace(0,T,N)
sol = odeint(F,Y0,tt)
PHIY = sol[:,0]
PHIZ = np.mod(sol[:,1],2*np.pi)
PSi = sp.lambdify(t,Psi.subs({Tf:T,Psif:PsiF}),'numpy')
PSI = PSi(tt)
[ 0.00000000e+00 0.00000000e+00 4.99991667e-02 -7.61534626e+01]
plt.figure(figsize=(12,8))
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(tt,PSI,label="$\psi$")
plt.xlabel('t')
plt.legend();

# position de P2
P2X = P2x(0.,PSI,LL)
P2Y = P2y(0.,PSI,LL)
P2Z = P2z(0.,PSI,LL,HH)*np.ones(PSI.size)
# et de M
MX = Mx(0.,PSI,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PSI,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PSI,PHIY,PHIZ,LL,HH,Alpha)
plt.title("trajectoire dans le plan")
plt.plot(MX,MY,label="M")
plt.plot(P2X,P2Y,label="P2")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.axis('equal');

# trajectoire 3D
TrajectoireBras3D(P2X,P2Y,P2Z,MX,MY,MZ,HH,LL*1.5)
5.7.3. 2ieme phase: mouvement à la position finale#
# solution apres arret (pendule)
LLa = La.subs({theta:0,thetap:0, psi: Psif, psip : 0 })
display("La=",LLa.simplify())
'La='

LLM = LagrangesMethod(LLa,[phiy,phiz])
Eq = LLM.form_lagranges_equations()
display(Eq)

# transformation EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
FY[2]=FY[2].simplify()
FY[3]=FY[3].simplify()
display("FY=",FY)
'FY='

# fonction BY
smBYf = sp.lambdify((phiy,phiz,phiyp,phizp,omega),FY,'numpy')
# fonction Ff(Y)
def Ff(Y,t):
'''2nd membre de l EDO dY/dt = F(Y)'''
global Omega
FF =smBYf(Y[0],Y[1],Y[2],Y[3],Omega)
return FF[:,0]
# resolution numérique
Y0f = sol[-1,:]
print(Ff(Y0,0.))
ttf = np.linspace(T,2*T,N)
solf = odeint(Ff,Y0f,ttf)
PHIY = solf[:,0]
PHIZ = np.mod(solf[:,1],2*np.pi)
[0. 0. 0.04999917 0. ]
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
plt.xlabel('t');

# position de P2 et M
P2X = P2x(0.,PsiF,LL)*np.ones(PHIY.size)
P2Y = P2y(0.,PsiF,LL)*np.ones(PHIY.size)
P2Z = P2z(0.,PsiF,LL,HH)*np.ones(PHIY.size)
MX = Mx(0.,PsiF,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PsiF,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PsiF,PHIY,PHIZ,LL,HH,Alpha)
plt.plot(MX,MY)
plt.plot(MX[0],MY[0],'x')
plt.plot(P2X,P2Y,'o')
plt.title("Trajectoire plan")
plt.axis('equal');

# trajectoire 3D
TrajectoireBras3D(P2X,P2Y,P2Z,MX,MY,MZ,HH,LL*1.5)
5.8. Utilisation d’un cable anti-rotation#
un câble anti-giratoire empêche la rotation autour de z. Par un système d’assemblage de torons enroullés dans des sens opposé, le cable résistera à la rotation et ainsi la charge soulevée ne tournera pas sur elle-même. Ce type de câble est systèmatiquement utilisé dans les grues à tour ou grues de chantier. $\(\dot{\phi_z} = 0\)$
LLa = (La.subs({theta:0,thetap:0, psi: Psi, psip : Psi.diff(t), phiz:0, phizp:0 })).simplify()
display("La=",LLa)
'La='

5.8.1. premiere phase A vers B#
LLM = LagrangesMethod(LLa,[phiy])
Eq = LLM.form_lagranges_equations()
display(Eq)

# transformation EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
FY[1] = FY[1].simplify()
display("FY=",FY)
'FY='

# fonction BY
smBY = sp.lambdify((phiy,phiyp,t,alpha,omega,Psif,Tf),FY,'numpy')
# fonction F(Y)
def F(Y,t):
'''second membre EDO dY/dt = F(Y) avec Y=[phiy,phiyp]'''
global Alpha,Omega,PsiF,T
FF =smBY(Y[0],Y[1],t,Alpha,Omega,PsiF,T)
return FF[:,0]
# solution numerique
print("parametres:",Alpha,Omega,PsiF,T)
Y0 = np.array([-0.01,0.])
print(F(Y0,0.))
N = 200
tt = np.linspace(0,T,N)
sol = odeint(F,Y0,tt)
PHIY = sol[:,0]
PHIZ = np.zeros(tt.size)
PSi = sp.lambdify(t,Psi.subs({Tf:T,Psif:PsiF}),'numpy')
PSI = PSi(tt)
parametres: 1.0 2.23606797749979 3.141592653589793 5.0
[0. 0.04999917]
plt.figure(figsize=(12,8))
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(tt,PSI,label="$\psi$")
plt.xlabel('t')
plt.legend();

# position de P2
P2X = P2x(0.,PSI,LL)
P2Y = P2y(0.,PSI,LL)
P2Z = P2z(0.,PSI,LL,HH)*np.ones(PSI.size)
# et de M
MX = Mx(0.,PSI,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PSI,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PSI,PHIY,PHIZ,LL,HH,Alpha)
plt.title("trajectoire dans le plan")
plt.plot(MX,MY,label="M")
plt.plot(P2X,P2Y,label="P2")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.axis('equal');

# trajectoire 3D
TrajectoireBras3D(P2X,P2Y,P2Z,MX,MY,MZ,HH,LL*1.5)
5.8.2. seconde phase#
# solution apres arret (pendule)
LLa = La.subs({theta:0,thetap:0, psi: Psif, psip : 0, phiz:0, phizp:0})
display("La=",LLa.simplify())
'La='

LLM = LagrangesMethod(LLa,[phiy])
Eq = LLM.form_lagranges_equations()
display(Eq)

# transformation EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
FY[1]=FY[1].simplify()
display("FY=",FY)
'FY='

# fonction BY
smBYf = sp.lambdify((phiy,phiyp,omega),FY,'numpy')
# fonction Ff(Y)
def Ff(Y,t):
'''2nd membre de l EDO dY/dt = F(Y)'''
global Omega
FF =smBYf(Y[0],Y[1],Omega)
return FF[:,0]
# resolution numérique
Y0f = sol[-1,:]
print(Ff(Y0,0.))
ttf = np.linspace(T,2*T,N)
solf = odeint(Ff,Y0f,ttf)
PHIY = solf[:,0]
PHIZ = np.zeros(ttf.size)
[0. 0.04999917]
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
plt.xlabel('t');

# position de P2 et M
P2X = P2x(0.,PsiF,LL)*np.ones(PHIY.size)
P2Y = P2y(0.,PsiF,LL)*np.ones(PHIY.size)
P2Z = P2z(0.,PsiF,LL,HH)*np.ones(PHIY.size)
MX = Mx(0.,PsiF,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PsiF,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PsiF,PHIY,PHIZ,LL,HH,Alpha)
plt.plot(MX,MY)
plt.plot(MX[0],MY[0],'x')
plt.plot(P2X,P2Y,'o')
plt.title("Trajectoire plan")
plt.axis('equal');

# trajectoire 3D
TrajectoireBras3D(P2X,P2Y,P2Z,MX,MY,MZ,HH,LL*1.5)
5.9. Contrôle avec cable anti-rotation#
On veut finaliser le contrôle du mouvement en contrôlant le couple \(C\) qui impose la rotation du bras
attention La est adimensionnalisée par \(L_b^2 M_b\)
LLa = La.subs({theta:0,thetap:0, phiz:0, phizp:0}).simplify()
display("La=",LLa)
'La='

C = sp.symbols('C')
LLM = LagrangesMethod(LLa,[psi,phiy],forcelist=[(Rb,C*RO.z)],frame=RO)
Eq = LLM.form_lagranges_equations()
display("Equations de Lagrange:",Eq)
'Equations de Lagrange:'

eq1 = Eq[1].subs([(sp.sin(phiy),phiy),(sp.cos(phiy),1)])
eq0 = Eq[0].subs([(sp.sin(phiy),phiy),(sp.cos(phiy),1),(phiy**2,0),(phiy*phiyp,0)])
print("Parametres Omega={:.3f} Alpha={:.3f} :".format(Omega,Alpha))
display("Equations:",sp.Eq(eq1,0),sp.Eq(eq0,0))
Parametres Omega=2.236 Alpha=1.000 :
'Equations:'


rel1 = sp.solve(eq1,psip**2)[0]
display(sp.Eq(psip**2,rel1))

5.9.1. trajectoire optimale#
on veut choisir \(\Psi(t)\) qui assure l’oscillation la plus faible
On détermine le polynôme de degré 5 sans dimension tq: $\(\Xi(0)= 0, \frac{d\Xi}{dt}(0)=0, \frac{d^2\Xi}{dt^2}(0)=0\)\( \)\(\Xi(1)= 1, \frac{d\Xi}{dt}(1)=\beta, \frac{d^2\Xi}{dt^2}(1)=0\)$
a0,a1,a2,a3,a4,a5 = sp.symbols("a_0 a_1 a_2 a_3 a_4 a_5")
Poly = sp.Lambda(t, a3*t**3 + a4*t**4 + a5*t**5)
Poly(0),Poly(t).diff(t,1).subs(t,0),Poly(t).diff(t,2).subs(t,0)

# equations
beta = sp.symbols('beta')
eqs = [Poly(1)-1, Poly(t).diff(t,1).subs(t,1) - beta, Poly(t).diff(t,2).subs(t,1)]
eqs

# solution
coeff = list(sp.linsolve(eqs,[a3,a4,a5]))[0]
coeff

Xi = sp.Lambda(t, coeff[0]*t**3 + coeff[1]*t**4 + coeff[2]*t**5)
display("Xi(t)=",Xi(t))
display("cdts a t=1:",(Xi(1),Xi(t).diff(t,1).subs(t,1),Xi(t).diff(t,2).subs(t,1)))
'Xi(t)='

'cdts a t=1:'

Beta = 1
sp.plot(Xi(t).diff(t).subs(beta,Beta),(t,0,1),title="$\dot{\psi}/\psi_f$",xlabel="t/Tf")
sp.plot(Xi(t).subs(beta,Beta),(t,0,1),title="$\psi/\psi_f$",xlabel="t/Tf");


5.9.2. Simulation avec psi imposé#
pour déterminer la valeur optimale de \(\beta\)
définition d’une fonction qui calcule la solution numérique fct de beta
calcul d’un critère: en fin de trajectoire valeur \(\phi_y(T)\) et \(\dot{\phi_y}(T)\)
oscillation: $\( \phi(t) = A \cos(\omega t + \Psi) \mbox{ avec } A cos\psi = \phi_y(T) , -A\omega\sin\psi = \dot{\phi_y}(T)\)\( d'où l'amplitude A: \)\( A^2 \omega^2 = \omega^2 (\phi_y(T))^2 + (\dot{\phi_y}(T))^2 \)\( et l'ordre de grandeur du deplacement max \)\approx L A$
Err = lambda Phiy, Phiyp : LL*np.sqrt(Phiy**2 + Phiyp**2/Omega**2)
def solution(Beta,debug=False):
# calcul Psi
Psi = Psif*Xi(t/Tf).subs(beta,Beta)
if debug: display("Psi=",Psi)
# calcul lagrangien
LLa = (La.subs({theta:0,thetap:0, psi: Psi, psip : Psi.diff(t), phiz:0, phizp:0 })).simplify()
if debug: display("La=",LLa)
# equation de Lagrange
LLM = LagrangesMethod(LLa,[phiy])
Eq = LLM.form_lagranges_equations()
if debug: display(Eq)
# transformation EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
FY[1] = FY[1].simplify()
if debug: display("FY=",FY)
# fonction python BY
smBY = sp.lambdify((phiy,phiyp,t,alpha,omega,Psif,Tf),FY,'numpy')
# fonction F(Y)
def F(Y,t):
'''second membre EDO dY/dt = F(Y) avec Y=[phiy,phiyp]'''
global Alpha,Omega,PsiF,T
FF =smBY(Y[0],Y[1],t,Alpha,Omega,PsiF,T)
return FF[:,0]
# solution numerique
if debug: print("parametres numerique:",Alpha,Omega,PsiF,T)
Y0 = np.array([0.,0.])
N = 200
tt = np.linspace(0,T,N)
sol = odeint(F,Y0,tt)
PHIY = sol[:,0]
PHIZ = np.zeros(tt.size)
PSi = sp.lambdify(t,Psi.subs({Tf:T,Psif:PsiF}),'numpy')
PSI = PSi(tt)
err = Err(sol[-1,0],sol[-1,1])
if debug: print("Erreur: ",err)
return tt,PSI,PHIY,PHIZ,err
# simulation (val opt 1.14)
Beta = 1.0
tt, PSI, PHIY, PHIZ, err = solution(Beta,True)
'Psi='

'La='


'FY='

parametres numerique: 1.0 2.23606797749979 3.141592653589793 5.0
Erreur: 0.1224537525041114
plt.figure(figsize=(12,8))
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.plot(tt,PHIZ,label='$\\phi_z$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(tt,PSI,label="$\psi$")
plt.xlabel('t')
plt.legend();

# position de P2
P2X = P2x(0.,PSI,LL)
P2Y = P2y(0.,PSI,LL)
P2Z = P2z(0.,PSI,LL,HH)*np.ones(PSI.size)
# et de M
MX = Mx(0.,PSI,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PSI,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PSI,PHIY,PHIZ,LL,HH,Alpha)
print("Ecart final:",MX[-1]-P2X[-1])
Ecart final: 0.10747021546826074
plt.title("trajectoire dans le plan")
plt.plot(MX,MY,label="M")
plt.plot(P2X,P2Y,label="P2")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.axis('equal');

# etude de l'ecart en fct de beta
BETA = np.linspace(1,1.2,11)
ECART = np.zeros(BETA.size)
for k in range(BETA.size):
tt, PSI, PHIY, PHIZ, err = solution(BETA[k])
ECART[k]=err
print("beta={:.3f} Ecart final={:.3f}".format(BETA[k],ECART[k]))
beta=1.000 Ecart final=0.122
beta=1.020 Ecart final=0.111
beta=1.040 Ecart final=0.101
beta=1.060 Ecart final=0.093
beta=1.080 Ecart final=0.087
beta=1.100 Ecart final=0.083
beta=1.120 Ecart final=0.083
beta=1.140 Ecart final=0.086
beta=1.160 Ecart final=0.092
beta=1.180 Ecart final=0.100
beta=1.200 Ecart final=0.111
plt.plot(BETA,ECART,'-o')
plt.plot(BETA,np.zeros(BETA.size),'--')
plt.xlabel("$\\beta$")
plt.title("Ecart en fin de trajectoire");

# valeur optimale (minimum)
Bopt = 1.112
print("Bopt={:.4f}".format(Bopt))
# calcul Psi opt
Psi = Psif*Xi(t/Tf).subs(beta,Bopt)
display("Psi opt=",Psi)
Bopt=1.1120
'Psi opt='

5.9.3. Controle avec le couple#
On impose donc un couple \(C\) basé sur un régulateur simple pour obtenir la trajectoire \(\psi_i(t)\) imposée
Kc, Tc = sp.symbols('K_c T_c')
Cc = -Kc*((psi-Psi)+(psip-Psi.diff(t,1))*Tc)
display("Couple C=",Cc)
'Couple C='

C = sp.symbols('C')
LLa = La.subs({theta:0,thetap:0, phiz:0, phizp:0 }).simplify()
display("Lagrangien:",LLa)
LLM = LagrangesMethod(LLa,[phiy,psi],forcelist=[(Rb,C*RO.z)],frame=RO)
Eq = LLM.form_lagranges_equations()
display("Equations",Eq)
'Lagrangien:'

'Equations'

# transformation EDO dY/dt = F(Y)
A=LLM.mass_matrix_full
B=LLM.forcing_full
FY = A.inv()*B
FY[2]=FY[2].simplify()
FY[3]=FY[3].simplify()
display("FY=",FY)
'FY='

# fonction BY
smBY = sp.lambdify([phiy,psi,phiyp,psip,alpha,omega,C],FY,'numpy')
# et couple
CC = sp.lambdify([psi,psip,t,Psif,Tf,Kc,Tc],Cc,'numpy')
# fonction F(Y)
def F(Y,t):
'''second membre EDO dY/dt = F(Y) avec Y=[phiy,psi,phiyp,psip]'''
global Alpha,Omega,T,PsiF,KC,TC
Ci = CC(Y[1],Y[3],t,PsiF,T,KC,TC)
FF =smBY(Y[0],Y[1],Y[2],Y[3],Alpha,Omega,Ci)
return FF[:,0]
# solution numerique
KC = 100
TC = 800./KC
print("parametres:",Alpha,Omega,PsiF,T,KC,TC)
Y0 = np.array([0.0,0.0,0.,0.])
# avec perturbation en psi
#Y0 = np.array([0.0,0.1,0.,0.])
N = 200
tt = np.linspace(0,T,N)
sol = odeint(F,Y0,tt)
PHIY = sol[:,0]
PSI = sol[:,1]
err = Err(sol[-1,0],sol[-1,2])
print("Erreur:",err)
parametres: 1.0 2.23606797749979 3.141592653589793 5.0 100 8.0
Erreur: 0.09357936449364572
plt.figure(figsize=(12,8))
plt.subplot(2,1,1)
plt.plot(tt,PHIY,label='$\\phi_y$')
plt.legend()
plt.subplot(2,1,2)
plt.plot(tt,PSI,label="$\psi$")
plt.xlabel('t')
plt.legend();

# position de P2
P2X = P2x(0.,PSI,LL)
P2Y = P2y(0.,PSI,LL)
P2Z = P2z(0.,PSI,LL,HH)*np.ones(PSI.size)
# et de M
MX = Mx(0.,PSI,PHIY,PHIZ,LL,Alpha)
MY = My(0.,PSI,PHIY,PHIZ,LL,Alpha)
MZ = Mz(0.,PSI,PHIY,PHIZ,LL,HH,Alpha)
print("Ecart final:",MX[-1]-P2X[-1])
Ecart final: -0.003938349868875868
plt.title("trajectoire dans le plan")
plt.plot(MX,MY,label="M")
plt.plot(P2X,P2Y,label="P2")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.axis('equal');

5.10. oscillation en fin de trajectoire#
# resolution numérique
Y0f = sol[-1,::2]
print(Y0f)
ttf = np.linspace(T,2*T,N)
solf = odeint(Ff,Y0f,ttf)
PHIYf = solf[:,0]
PHIZf = np.zeros(ttf.size)
[-0.00196919 0.10453221]
plt.plot(tt,PHIYf,label='$\\phi_y$')
plt.legend()
plt.xlabel('t');

# position de P2 et M
P2X = P2x(0.,PsiF,LL)*np.ones(PHIYf.size)
P2Y = P2y(0.,PsiF,LL)*np.ones(PHIYf.size)
P2Z = P2z(0.,PsiF,LL,HH)*np.ones(PHIYf.size)
MX = Mx(0.,PsiF,PHIYf,PHIZf,LL,Alpha)
MY = My(0.,PsiF,PHIYf,PHIZf,LL,Alpha)
MZ = Mz(0.,PsiF,PHIYf,PHIZf,LL,HH,Alpha)
plt.plot(MX,MY)
plt.plot(MX[0],MY[0],'x')
plt.plot(P2X,P2Y,'o')
plt.title("Trajectoire plan")
plt.axis('equal');
