Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Análisis Dinámico:
Este artículo presenta un estudio sobre el control de un péndulo invertido en un carro móvil
sobre una viga. El péndulo invertido, un sistema clásico ampliamente utilizado en laboratorios
de control, presenta desafíos significativos debido a su falta de estabilidad. En este trabajo, se
aborda el problema mediante el diseño e implementación de un Control Proporcional-Integral-
Derivativo (PID) discreto. Se analiza el sistema utilizando técnicas de control no lineal y se
linealiza el sistema para derivar las ecuaciones de movimiento. Se discuten los resultados
obtenidos, que muestran la eficacia del controlador PID discreto en estabilizar el péndulo
invertido durante el movimiento del carro sobre la viga. Este trabajo proporciona una
contribución significativa al campo del control de sistemas no lineales, especialmente en
aplicaciones que requieren estabilidad dinámica.
Asumiendo fricción=0:
∑ F x =m ẍ
F−R x =M ẍ
Ry
Rx
a f = ẍ
'
F 1=m ẍ cos θ
'
F 2=m ẍ sin θ
Tenemos:
R y sin θ−R x cos θ−mg sin θ+ m ẍ cos θ=−mL θ̈
I θ̈
R y sin θ−R x cos θ=
L
Reemplazando las dos últimas ecuaciones:
I θ̈
−mg sin θ=−mL θ̈−m ẍ cos θ
L
2
I θ̈−Lmg sin θ=−L m θ̈−Lm ẍ cos θ
( I +m L2 ) θ̈−mgL sin θ=−mL ẍ cos θ …(2)
Por linealización tenemos:
sin θ ≈ θ
cos θ ≈ 1
2
θ̇ ≈ 0
Sustituimos en (1) y (2):
( I +m L2 ) θ̈−mgLθ=−mL ẍ …(4)
Función de transferencia:
X=
[ − ( I + m L2 ) g
mL
+ 2 Θ
s ]
Sustituimos en (5):
F=( M +m )
[ −( I +m L2) g
mL
2
]
+ 2 Θ s +mL Θ s
s
2
Θ 1
=
[ ]
F −( I +m L2 ) g 2 2
( M +m ) + 2 s +mL s
mL s
Θ 1
=
F 2 ( M +m ) ( I + m L2 ) 2
mL s − s + ( M +m ) g
mL
1
Θ mL
=
( )
F ( M + m ) ( I +m L2 ) 2 ( M + m )
1− s+ g
m 2 L2 mL
−mL
Θ ( M +m ) ( I + m L2 )−m2 L2
=
F 2 ( M + m) mLg
s−
( M +m ) ( I +m L2 )−m2 L2
Para la retroalimentación tenemos:
mL
Θ ( M +m ) ( I + m L2 )−m2 L2
=
F 2 ( M + m) mLg
s−
( M +m ) ( I +m L2 )−m2 L2
mL
Θ q
=
F ( M +m ) mLg
s2−
q
( I +m L2 ) Θ s 2−mgL Θ=−mLX s2
2
−mLX s
Θ=
( I +m L2 ) s 2−mgL
Sustituyendo:
2 2 4
2 m L Xs
F=( M +m ) X s −
( I +m L2) s2−mgL
X 1
=
F 2
m L s
2 4
( M + m) s2−
( I + m L2 ) s 2−mgL
X ( I +m L2) s2−mgL
=
F ( M + m) ( ( I +m L2) s2 −mgL ) s2 −m2 L2 s 4
X ( I +m L2) s2 −mgL
=
F ( M + m) ( I +m L2 ) s 4 −( M + m ) mgL s 2−m2 L2 s 4
X ( I +m L2 ) s2 −mgL
=
F [ ( M + m ) ( I +m L2 ) −m2 L2 ] s 4− ( M + m) mgL s2
( I + m L2 ) 2 mgL
s−
X ( M +m ) ( I + m L )−m L
2 2 2
( M +m ) ( I + m L2 )−m2 L2
=
F 4 ( M +m ) mgL 2
s− s
( M +m ) ( I + m L )−m L
2 2 2
q=( M +m ) ( I +m L2 )−m2 L2
( I +m L2 )mgL 2
s−
X q q
=
F 4 ( M +m ) mgL 2
s− s
q
G=tf(1,[-3 0 19.62]);
E_R=1/(1+G);
p=pole(G);
t=linspace(0,15,150);
r=zeros(length(t),1);
r(t>=2)=1;
lsim(E_R,r,t)
Θ 1
G= =
F −3 s +19.62
2
2
X 2 s −1
G= =
F 3 s 4 +19.62 s2
ESPACIO DE ESTADOS:
De las ecuaciones:
( I +m L2 ) θ̈−mgLθ=−mL ẍ …(4)
De (4):
mgLθ −mL ẍ
θ̈= 2
I +m L
Reemplazando en (3):
F=( M +m ) ẍ +mL θ̈
F=( M +m ) ẍ +mL
( mgLθ−mL ẍ
I+m L
2 )
( )
2 2 2 2
m L −m g L θ
ẍ ( M +m )− 2
= 2
+F
I+m L I +m L
−m2 g L2 F
ẍ= θ+
( ) m 2 L2
2 2
( I + m L2 ) M +m− m L M +m−
I + m L2 I + m L2
2 2 2
−m g L I +m L
ẍ= θ+ F
( m+ M ) ( I +m L ) −m L
2 2 2
( I +m L ) ( M + m )−m2 L2
2
2 2 2
−m g L I +m L
ẍ= 2
θ+ F
( M + m ) I + Mm L ( M +m ) I + Mm L2
De (4):
mgLθ−( I +m L2 ) θ̈
ẍ=
mL
Reemplazando en (3):
F=( M +m ) ẍ +mL θ̈
F=( M +m ) ( mgLθ−( I + m L2 ) θ̈
mL )
+mL θ̈
( M +m ) ( I + m L2 )
F=( M +m ) gθ− θ̈+ mL θ̈
mL
( m+ M ) gmL mL
θ̈= θ− F
( m+ M ) ( I + m L )−m L
2 2 2
( m+ M ) ( I +m L2) −m2 L2
mgL (M + m) mL
θ̈= 2
θ− F
( M +m ) I + Mm L ( M +m ) I + Mm L2
[]
x
X = ẋ
θ
θ̇
[]
ẋ
Ẋ = ẍ
θ̇
θ̈
ẋ= ẋ
2 2 2
−m g L I +m L
ẍ= 2
θ+ F
( M + m ) I + Mm L ( M +m ) I + Mm L2
θ̇=θ̇
mgL (M + m) mL
θ̈= 2
θ− F
( M +m ) I + Mm L ( M +m ) I + Mm L2
[ ][] [ ][]
x1 x ẋ 1 ẋ
x2 ẋ 2 = ẍ
Construimos nuestra ecuación matricial: X = = ẋ , Ẋ=
x3 θ ẋ 3 θ̇
x4 θ̇ x˙ 4 θ̈
[ ][ ] [ ]
0 1 0 0 0
[]
ẋ 0 0 −m2 g L2 I +m L
2
0 x
ẍ ( M +m ) I + Mm L2 ẋ ( M +m ) I + Mm L2
= + F
θ̇ 0 0 0 1 θ 0
θ̈ mgL (M + m) θ̇ −mL
0 0 0
( M +m ) I + Mm L2 ( M +m ) I + Mm L2
Ẋ =AX + BF
Ẋ =B ( r −KX )+ AX
Ẋ =( A−BK ) X +rB
'
Ẋ =A X +rB
'
A = A−BK
K=¿
Al resolver esta ecuación obtendremos las raíces o polos del sistema. De este modo al
asumir las raíces del sistema podemos obtener una ecuación característica que luego
puede ser comparada con esta ecuación para obtener los valores de K.
Código de Matlab:
clc
clear
syms s
syms K1 K2 K3 K4
%G=tf([1],[1 0 -1])
%ng=s+3
%dg=expand(s*(s+1)*(s+2)*(s+4))
%G=tf(-1,[-3 0 19.62])
%p=pole(G)
%rlocus(G)
m=0.04;
M=0.043;
L=0.9;
I=1/3*m*L^2
g=9.81;
b=0;
a=m*L/((M+m)*(I+m*L^2)-m^2*L^2)
G=tf(a,[1 0 a])
figure
rlocus(G)
q=(M+m)*(I+m*L^2)-m^2*L^2;
G2=tf([(I+m*L^2)/q 0 -m*g*L/q],[1 0 -(M+m)*m*g*L/q 0 0])
%----------Espacio de estados:
a23=(m^2*g*L^2)/q
a44=m*g*L*(M+m)/q
A = [0 1 0 0;
0 0 -(m^2*g*L^2)/q 0;
0 0 0 1;
0 0 m*g*L*(M+m)/q 0];
B = [ 0;
(I+m*L^2)/q;
0;
-m*L/q];
C = [1 0 0 0;
0 0 1 0];
D = [0;
0];
Im=[1 0 0 0;
0 1 0 0;
0 0 1 0;
0 0 0 1]
K=[K1 K2 K3 K4]
polcar=s*Im-A+B*K
determinante=det(polcar)
%simplify(determinante)
Deseamos que dos de los polos se encuentren muy alejados del origen para que no
tengan mucho efecto en el resultado y los otros dos sean polos complejos simétricos con
respecto al eje real.
Suponemos los siguientes polos:
%polos deseados:
p=[-100,-200,complex(-5,2),complex(-5,-2)]
k_place=place(A,B,p)
Que corresponde a:
K= [−3760.2−1353−5977.8−1643.4 ]
Para la simulación en Simulink tomamos en cuenta que el ángulo inicial es de 0°, por lo
Tenemos por lo tanto una entrada Step con un valor de 1, del cual su derivada (impulso)
δ=F
∫ δ dt=∫ F dt
m
10 N . s=10 kg =∫ F dt
s
podría aproximar a aplicar una fuerza de 20N durante 0.5s en la base del carro.
Esto corresponde a 1N.s lo que es equivalente a golpear el carro de la base con una
fuerza de 10N en un impacto de duración de 0.1s
Observamos la salida:
Graficamos la fuerza aplicada sobre el carro con respecto al tiempo:
Se genera una fuerza máxima de 11N lo que equivale a aplicar 9.62v en el motor.
Esto significa que el motor es capaz de volver a estabilizar el sistema ante un impulso
de 1N.s
Código de Arduino:
#include <math.h>
#include <Wire.h>
#include <KalmanFilter.h>
// Definición de pines
const int pinA = 3;
const int pinB = 2;
const int IN1=4;
const int IN2=5;
const int ENA=9;
const int finalCarrera=6;
int v=130;
//variable de inicio
bool inicio=1;
bool inicio2=0;
bool inicio3=0;
bool proceso=0;
// Variables
volatile int position = 0;
volatile int velocity = 0;
// Variables auxiliares
volatile boolean stateA;
volatile boolean stateB;
volatile boolean lastStateA;
float lastPosition=0;
float currentPosition=0;
float currentVelocity=0;
float pi=M_PI;
void gyro_signals(void) {
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x05);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x1C);
Wire.write(0x10);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68,6);
int16_t AccXLSB = Wire.read() << 8 | Wire.read();
int16_t AccYLSB = Wire.read() << 8 | Wire.read();
int16_t AccZLSB = Wire.read() << 8 | Wire.read();
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x8);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x43);
Wire.endTransmission();
Wire.requestFrom(0x68,6);
int16_t GyroX=Wire.read()<<8 | Wire.read();
int16_t GyroY=Wire.read()<<8 | Wire.read();
int16_t GyroZ=Wire.read()<<8 | Wire.read();
RateRoll=(float)GyroX/65.5;
RatePitch=(float)GyroY/65.5;
RateYaw=(float)GyroZ/65.5;
AccX=(float)AccXLSB/4096;
AccY=(float)AccYLSB/4096;
AccZ=(float)AccZLSB/4096;
AngleRoll=atan(AccY/sqrt(AccX*AccX+AccZ*AccZ))*1/(3.142/180);
AnglePitch=-atan(AccX/sqrt(AccY*AccY+AccZ*AccZ))*1/(3.142/180);
AngleYaw=-atan(AccY/sqrt(AccZ*AccZ+AccX*AccX))*1/(3.142/180);
}
void setup() {
//TCCR1B = TCCR1B & B11111000 | B00000001; //cambiamos frecuencia PWM a
30kHz
TCCR1B = TCCR1B & B11111000 | B00000010;
// Configuración de pines
pinMode(pinA, INPUT);
pinMode(pinB, INPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(finalCarrera, INPUT_PULLUP);
// Configuración de interrupciones
attachInterrupt(digitalPinToInterrupt(pinA), updateEncoder, CHANGE);
//attachInterrupt(digitalPinToInterrupt(pinB), updateEncoder, CHANGE);
}
if (currentTime - lastTimeBoton >= intervalBoton) {
// Actualizar última vez
lastTimeBoton = currentTime;
if (!estadoFC){
inicio=0;
inicio2=1;
}
if (inicio){
calibrarPos();
}
else if(inicio2){
detener();
position=-1833;
delay(1);
inicio2=0;
inicio3=1;
//goto0(position);
}
else if(inicio3){
if (position<0 ){
int error=-position;
//int vel=map(error,1833,0,160,40);
vel=map(error,1833,0,200,100);
goto0(vel);
}
else{
detener();
inicio3=0;
proceso=1;
}
}
else if(proceso && KalmanAngleYaw>-20 && KalmanAngleYaw<20){
if (currentPosition>-240 && currentPosition <240){
float errorAngulo=KalmanAngleYaw-0.2;
float errorVangulo=KalmanAngleV;
float errorPos=currentPosition;
float errorVel=currentVelocity;
float K1=180;
float K2=56;
float K3=200;
float K4=164;
int
velocidad=int(K1*errorAngulo+K2*errorVangulo+K3*errorPos+K4*errorVel);
int vMotor=0;
int min=18;
int med=40;
if (velocidad<=med && velocidad>min){
vMotor=med;
}
else if(velocidad>=-med && velocidad<-min){
vMotor=-med;
}
else if(velocidad>-min && velocidad<min){
vMotor=0;
}
else if(velocidad>=255){
vMotor=255;
}
else if(velocidad<=-255){
vMotor=-255;
}
else{
vMotor=velocidad;
}
controlMotor(vMotor);
}
else{
detener();
}
}
else{
detener();
}
currentVelocity = (currentPosition-lastPosition)*1000/interval_p;
lastPosition=currentPosition;
void calibrarPos(){
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, v);
}
void detener(){
analogWrite(ENA,0);
}
void goto0(int vel){
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA,vel);
void updateEncoder() {
stateA = digitalRead(pinA);
stateB = digitalRead(pinB);
if (stateB != stateA) {
position++;
} else {
position--;
}
lastStateA = stateA;
}
Fotos de la Implementación:
Link del video del funcionamiento:
https://drive.google.com/drive/folders/1aOxF4HTBp2vBs-rZwdKbs_yDRrPA4iaZ?
usp=sharing