PF Control
PF Control
Resumen— El presente proyecto aborda el diseño, modelado e prácticos del control en la vida real, fortaleciendo habilidades
implementación de un sistema de control PID aplicado a una de diseño, implementación y análisis de sistemas dinámicos.
rueda de reacción capaz de estabilizar la orientación de una Además, la experimentación directa con una rueda de reacción
plataforma semejante a un péndulo invertido. Se desarrolló un
facilita la conexión entre modelos matemáticos y resultados
modelo linealizado de la planta para analizar su comportamiento
experimentales, promoviendo un aprendizaje integral y
dinámico, obteniendo una función de transferencia. A partir de
este análisis, y complementándolo con datos experimentales aplicado.
obtenidos mediante un sensor inercial MPU-6050 y un motor DC
El trabajo comprende el modelado del sistema, la
con encoder, se implementó un controlador PID en una
identificación de sus parámetros dinámicos y la
Raspberry Pi Pico. La sintonización se realizó mediante una
implementación de estrategias de control que permitan regular
combinación del método de Ziegler–Nichols y ajustes empíricos,
logrando un desempeño estable ante perturbaciones. Los
la posición angular del prototipo mediante el principio de
resultados experimentales mostraron respuestas PWM estables,
conservación del momento angular. Asimismo, se evaluó el
control efectivo del motor y capacidad del sistema para mantener comportamiento del sistema bajo diferentes condiciones de
la orientación deseada, validando la viabilidad del enfoque y la operación, con el fin de comprobar la estabilidad, la respuesta
fidelidad del modelo dinámico empleado. transitoria y la robustez del controlador diseñado. Este
proyecto no solo permitió aplicar los conceptos vistos en la
Palabras clave: Péndulo invertido, rueda de reacción, asignatura, sino también comprender los desafíos asociados al
controlador PID, función de transferencia, Ziegler–Nichols, control de sistemas reales y la importancia de una correcta
estabilidad. integración entre hardware, electrónica y algoritmos de
control.
I. INTRODUCCIÓN
II. ANTECEDENTES TEÓRICOS
E
Para el mejor entendimiento sobre lo que se realizó en esta
l estudio de los sistemas de control juega un papel práctica, se mencionan algunos conceptos o palabras clave
fundamental en el diseño y operación de dispositivos utilizadas:
mecatrónicos capaces de regular su comportamiento
ante perturbaciones externas. Entre estos sistemas, las • Planta: Es el sistema o conjunto de actuadores
ruedas de reacción representan una aplicación relevante para controlados por un sistema de control. El controlador se
el control de actitud en plataformas donde no es posible encarga de llevar desde el estado actual del sistema hasta
el punto de referencia.
utilizar actuadores convencionales, como en pequeños
satélites, robots móviles o prototipos de investigación. En este Para el caso de controladores que no reutilizan la
proyecto final se desarrolló un sistema de control basado en información de salida de la planta se denominan sistemas
una rueda de reacción con el propósito de analizar su de lazo abierto. Cuando existe una retroalimentación
dinámica, diseñar un controlador adecuado y validar utilizando la información de salida, entonces estos
experimentalmente su desempeño. sistemas se conocen como de lazo cerrado. [1]
1
Control
• Función de transferencia: Una función de Este vector es perpendicular al plano formado por 𝐫 y
transferencia es una representación matemática que 𝐯, y su dirección se determina mediante la regla de la
describe la relación entre la entrada y la salida de un mano derecha. El momento angular describe la
sistema dinámico, en términos de sus variables de tendencia de una partícula o sistema a continuar en
Laplace (generalmente usando la transformada de movimiento rotacional y constituye la base para el
Laplace). Esta función se usa principalmente para análisis dinámico de cuerpos rígidos y dispositivos
como las ruedas de reacción [5].
sistemas lineales e invariantes en el tiempo (LTI, por
sus siglas en inglés: Linear Time-Invariant) [2].
2
Control
esenciales en sistemas de retroalimentación para En primer lugar, se seleccionó un material ligero pero rígido
control de motores [10]. para asegurar que la rueda mantuviera una geometría
balanceada durante el giro. Para su manufactura se
• Driver de motor TB6612FNG: El TB6612FNG es un consideraron únicamente procesos accesibles como corte láser
controlador dual de motores DC que permite manejar e impresión 3D, por lo que se eligió madera MDF de 5 mm
corrientes de hasta 1.2 A continuos por canal. como material base debido a su facilidad de corte, rigidez,
Proporciona control de dirección y velocidad mediante ligereza y adaptabilidad a geometrías bidimensionales.
señales PWM y es ampliamente utilizado en
Gracias a la precisión de la máquina láser, fue posible reducir
aplicaciones embebidas gracias a su eficiencia y
protección integrada contra sobrecorriente y significativamente las variaciones irregulares en la
sobrecalentamiento [11]. distribución de masa que podrían afectar la estabilidad de la
rueda; estas irregularidades son más probables en prototipos
• Método de Ziegler–Nichols: Es una técnica empírica impresos en 3D, además de que implican un costo de
ampliamente utilizada para sintonizar controladores manufactura mayor.
PID. Consiste en llevar al sistema al borde de la
Tras un análisis dimensional del motor, se diseñó la
estabilidad aumentando la ganancia proporcional hasta
obtener oscilaciones sostenidas. A dicho valor se le estructura mostrada en la Figura 4. El primer prototipo tomó
denomina ganancia última 𝐾𝑢 , y el período de como referencia diseños de ruedas de reacción
oscilación correspondiente se conoce como período experimentales, en los cuales se integran masas distribuidas
último 𝑇𝑢 . A partir de estos dos parámetros se calculan alrededor de la circunferencia para incrementar el momento de
las ganancias del controlador PID siguiendo reglas inercia. No obstante, se estimó que añadir peso en la periferia
establecidas por Ziegler y Nichols, las cuales podría comprometer la capacidad del motor debido a sus
proporcionan una respuesta rápida y razonablemente limitaciones de torque. Por ello, se optó por escalar la
estable sin requerir un modelo matemático exacto del geometría general de la rueda para incrementar su masa total
sistema. Este método es especialmente útil en sistemas sin sobrecargar el extremo exterior de la misma.
donde la dinámica es desconocida o difícil de modelar
[12].
III. METODOLOGÍA
En esta sección se presenta la metodología empleada para
la implementación de un controlador PID para la planta del
circuito de una rueda de reacción.
3
Control
3. Materiales utilizados
• Raspberry Pi Pico
• Sensor MPU-6050 (acelerómetro + giróscopo)
• Driver de motor TB6612FNG
• Motor de 6 V con encoder
• Protoboard
• Jumpers de conexión (macho-macho y macho-
hembra)
• Cables para protoboard
• Capacitor de 100 µF
• Fuente de voltaje externa
Figura 5. Diseño de cople implementado.
4. Implementación del sistema de control
4
Control
manera precisa y eficiente, además de proteger el circuito ante del sistema alrededor de un punto de operación. Esta
sobrecorrientes. simplificación permitió expresar la dinámica en forma de
función de transferencia y emplear técnicas clásicas de análisis
Toda la electrónica fue montada en un protoboard, de estabilidad.
empleando cables tipo jumper macho–macho y macho–
hembra para realizar las conexiones entre la Raspberry Pi Pico, A partir del modelo analítico del motor y la interacción de
el sensor, el driver y la fuente de alimentación. Se integró un momento angular entre la rueda y la plataforma, se obtuvo una
capacitor de 100 µF cercano al driver con el propósito de función de transferencia equivalente, la cual fue implementada
mitigar caídas de voltaje inducidas por los cambios bruscos de y evaluada en MATLAB. La Figura 10 (correspondiente a la
corriente del motor. Finalmente, una fuente de alimentación función de transferencia mostrada en MATLAB) presenta el
externa proporcionó la energía necesaria para el motor y los modelo del sistema. Posteriormente, se generaron las
componentes electrónicos, asegurando una operación estable respuestas al impulso y al escalón, mostradas en la Figura 11,
y aislada del consumo de la Raspberry Pi Pico. Todo el donde se observa un crecimiento exponencial de la señal; este
conjunto montado se muestra en la Figura 9. comportamiento confirma la naturaleza inestable del sistema
sin control, característica consistente con mecanismos de
orientación basados en reacción. De igual forma, el diagrama
de Bode obtenido (Figura 11) evidencia la presencia de polos
en el semiplano derecho, ratificando la necesidad de un
controlador para garantizar la estabilidad del sistema real.
Motor
Capacitor de 100 µF
La integración de todos estos elementos permitió conformar Figura 11. Respuestas del sistema ante escalón unitario e impulso.
un sistema de control funcional, capaz de interpretar la
orientación del prototipo y modificarla mediante el Este análisis previo fue indispensable para comprender la
accionamiento de la rueda de reacción en tiempo real. estructura dinámica del prototipo y para justificar el uso de un
controlador PID. Aunque el modelo linealizado no captura
Además de la implementación física del sistema, fue todas las no linealidades presentes en el sistema físico, sí
necesario comprender la dinámica del prototipo para facilitar proporciona una representación adecuada para predecir su
el diseño del controlador. La rueda de reacción, en conjunto comportamiento general en lazo abierto y orientar el proceso
con el motor, la estructura y el sensor, constituye un sistema de sintonización. El uso de MATLAB permitió visualizar de
inherentemente no lineal debido a la fricción variable, el forma clara estas tendencias, validar el modelo analítico y
acoplamiento dinámico entre la rueda y la plataforma, la establecer las bases que guiaron el ajuste de las ganancias
saturación del actuador y la cuantización del MPU-6050. Sin descrito en la siguiente sección.
embargo, para efectos de análisis y diseño de controladores
lineales, se realizó una aproximación mediante la linealización 5. Ajuste de las ganancias del controlador
5
Control
El proceso de sintonización se llevó a cabo en tres etapas: Tras completar las etapas de estimación inicial, Ziegler–
Nichols y ajuste fino, se obtuvieron los valores óptimos de las
5.1 Estimación inicial a partir del comportamiento del ganancias del controlador PID. Los valores finales
sistema seleccionados fueron:
Antes de aplicar un método formal de sintonización, se
• 𝐾𝑝 = 0.3
realizó una observación directa del comportamiento del
• 𝐾𝑖 = 1.5
prototipo ante pequeñas perturbaciones manuales. Este
análisis permitió identificar características cualitativas del • 𝐾𝑑 = 0.0001
sistema, como la inercia dominante generada por la rueda de Esta configuración permitió alcanzar un balance adecuado
reacción, el retardo entre la señal de control y la respuesta entre rapidez de respuesta, estabilidad dinámica y capacidad
física del motor, y el nivel de amortiguamiento natural. Con de corrección ante perturbaciones externas. Con estas
base en estas observaciones se propusieron valores iniciales ganancias el sistema pudo regular el ángulo de la plataforma
para las ganancias proporcional, integral y derivativa, los sin presentar oscilaciones sostenidas, saturación del actuador
cuales sirvieron como punto de partida para la sintonización o inestabilidad, logrando un desempeño satisfactorio bajo las
formal. condiciones de prueba establecidas.
5.2 Método de Ziegler–Nichols IV. RESULTADOS
Posteriormente se aplicó el método de Ziegler–Nichols en La implementación del sistema de control basado en una
lazo cerrado, una técnica empírica utilizada comúnmente rueda de reacción permitió evaluar tanto el comportamiento
cuando el modelo matemático de la planta no está dinámico del prototipo como la efectividad del controlador
completamente definido o cuando se requiere una estimación PID diseñado. En primer lugar, las pruebas iniciales del
rápida y funcional de las ganancias del controlador. Para ello, modelo linealizado mostraron que la planta presentaba
el valor de la ganancia proporcional 𝐾𝑝 se incrementó inestabilidad en lazo abierto, característica observada en la
respuesta al impulso y al escalón obtenida mediante
progresivamente mientras se desactivaban los términos
MATLAB (Figura 10). Ambas respuestas evidenciaron un
integral y derivativo, hasta que el sistema mostró oscilaciones
crecimiento exponencial de la señal, lo cual coincide con la
sostenidas. El valor de 𝐾𝑝 que generó dichas oscilaciones se
presencia de polos en el semiplano derecho identificados en el
identificó como la ganancia última 𝐾𝑢 , y el período de
análisis de Bode. Este comportamiento confirma que el
oscilación resultante como el período último 𝑇𝑢 . sistema físico, al depender del principio de conservación del
A partir de estos parámetros se calcularon las ganancias momento angular, carece de mecanismos pasivos de
preliminares del controlador PID conforme a las reglas amortiguamiento que limiten la divergencia ante
propuestas por Ziegler y Nichols. Estas ganancias perturbaciones. Esto justifica plenamente la necesidad de un
proporcionaron una primera configuración estable y sirvieron controlador robusto para mantener la plataforma en equilibrio.
como referencia para la etapa de ajuste fino. Durante la etapa experimental, se observó que la Raspberry
5.3 Ajuste por prueba y error Pi Pico generó señales PWM estables y consistentes (Figura
12), como se aprecia en la gráfica obtenida mediante
Si bien el método de Ziegler–Nichols ofrece valores osciloscopio. La señal presenta una forma rectangular bien
iniciales razonables, la dinámica real del sistema presentó definida a una frecuencia aproximada de 8.34 kHz, lo que
características no lineales y fenómenos no modelados, como indica un adecuado funcionamiento del driver TB6612FNG y
fricción variable, ruido del sensor, pequeñas desalineaciones del proceso de modulación. Esta estabilidad en la señal de
mecánicas y fluctuaciones en la velocidad del motor. Por ello control resultó esencial para garantizar que el motor
fue necesario complementar la sintonización con un proceso respondiera de forma lineal al esfuerzo solicitado por el
iterativo de prueba y error. controlador, minimizando variaciones no deseadas en la
velocidad de la rueda de reacción.
Durante esta etapa se variaron manualmente las ganancias
𝐾𝑝 , 𝐾𝑖 y 𝐾𝑑 observando en tiempo real la respuesta del sistema
ante perturbaciones. El objetivo fue reducir el sobreimpulso,
mejorar la estabilidad y minimizar las vibraciones. Este
proceso permitió adaptar el control PID directamente al
comportamiento físico del prototipo, logrando finalmente un
desempeño más robusto y suave.
6
Control
7
Control
8
Control
### tachoCount += 1
def perf_counter_ns(): def tachoB_falling(pin):
return time.time_ns()
### global tachoBValue
tachoBValue = 0
#prepare IMU sensor
#imu = MPU9250(bus=1, gfs=GFS_250, afs=AFS_2G) def irq_A(pin):
#[Link] = [0.013221153846153846, -0.030993339342948716, if [Link]() == 1:
0.004657451923076872] tachoA_rising(pin)
#[Link] = [1.3726094563802083, 1.2428309122721355, else:
0.00033772786458334] tachoA_falling(pin)
#[Link]()
i2c = I2C(0,sda=Pin(0),scl=Pin(1),freq=400000) def irq_B(pin):
imu=MPU6050(i2c) if [Link]() == 1:
#sleep(5) tachoB_rising(pin)
#mia.cal_a(5) else:
a=[ 0.009991597 , 0.013971089 , 0.05842058 ] tachoB_falling(pin)
g=[ -1.74752624 , 0.4420805 , 0.83425224 ] """
mia.offset_MPU(a,g) tachoA.when_activated = tachoA_rising
tachoA.when_deactivated = tachoA_falling
#prepare motor controller tachoB.when_activated = tachoB_rising
#my_factory = PiGPIOFactory() #hardware pwm supported tachoB.when_deactivated = tachoB_falling
#motorPWM = PWMOutputDevice(12, pin_factory=my_factory)
#motorDIR1 = DigitalOutputDevice(5) tachoA.IRQ_HIGH_LEVEL = tachoA_rising
#motorDIR2 = DigitalOutputDevice(6) tachoA.IRQ_LOW_LEVEL = tachoA_falling
#[Link] = 8000 tachoB.IRQ_HIGH_LEVEL = tachoB_rising
#[Link] = 0 tachoB.IRQ_LOW_LEVEL = tachoB_falling
motorPWM=PWM(OUT_PWM) """
[Link](8000) [Link](trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING,
motorPWM.duty_ns(0) handler=irq_A)
motorDIR1=Pin(OUT_DIR1,[Link]) #[Link](trigger=Pin.IRQ_FALLING, handler=tachoA_falling)
motorDIR2=Pin(OUT_DIR2,[Link]) [Link](trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING,
[Link](0) handler=irq_B)
[Link](0) #[Link](trigger=Pin.IRQ_FALLING, handler=tachoB_falling)
"""
#prepare tachometers #exit program when Ctrl-C is pressed
#tachoA = DigitalInputDevice(22) exitRequested = False
#tachoB = DigitalInputDevice(23) def sigintHandler(sig, frame):
tachoA = Pin(IN_TACHOA,[Link],Pin.PULL_UP) print("Ctrl-C pressed, exit program")
tachoB = Pin(IN_TACHOB,[Link],Pin.PULL_UP) global exitRequested
tachoCount = 0 exitRequested = True
tachoAValue = [Link]
tachoBValue = [Link] [Link]([Link], sigintHandler)
def tachoA_rising(pin): [Link]([Link], sigintHandler)
global tachoCount """
global tachoAValue
global tachoBValue print("program started")
tachoAValue = 1 sleep(0.1)
if tachoBValue == 0:
#A in rising edge and B in low value startTime = perf_counter_ns()
# => direction is clockwise (shaft end perspective) prevLoopTime = perf_counter_ns()
tachoCount += 1 prevTachoTime = perf_counter_ns()
else: prevPrintTime = perf_counter_ns()
tachoCount -= 1 loopCount = 0
def tachoA_falling(pin): gyroAngle = float('nan')
global tachoAValue measuredAngle = float('nan')
tachoAValue = 0
def tachoB_rising(pin): prevTachoCount = 0
wheelAV = 0
global tachoCount targetAngle = 0
global tachoAValue error = 0
global tachoBValue prevError = 0
tachoBValue = 1 integral = 0
if tachoAValue == 0: derivative = 0
tachoCount -= 1 PIDoutput = 0
else: motorCtrl = 0
9
Control
#logData =
[["secondsSinceStart","accAngle","gyroAngle","measuredAngle","target pulses = tachoCount - prevTachoCount
Angle", prevTachoCount = tachoCount
# "tachoCount","wheelAV","error","integral","derivative", cycles = pulses / CNT #360 pulses per rotation
# "PIDoutput","motorCtrl"]] wheelAV = cycles / tachoTimeDelta * 2 * [Link] #[rad/s]
#calculate arm angle (complementary filter) #compensate for motor back EMF voltage
if [Link](measuredAngle): measuredAngle = accAngle current = -PIDoutput
measuredAngle = (ANGLE_FILTER_G * (measuredAngle + voltage = MOTOR_R * current + MOTOR_Ke * wheelAV
gyroAngleDelta) +
(1-ANGLE_FILTER_G) * accAngle) #[deg] #convert voltage to pwm duty cycle
#safety check motorCtrl = voltage / SUPPLY_VOLTAGE
if abs(measuredAngle) >= ANGLE_LIMIT: motorCtrl=-PIDoutput
if secondsSinceStart < 0.001: #drive motor
print("START RISE UP SEQUENCE") motorCtrl = min(max(motorCtrl, -1), 1) #limit range to -1...1
risingUp = True #[Link] = abs(motorCtrl)
elif not risingUp: motorPWM.duty_ns(int(DUTY*abs(motorCtrl)))
print("PROGRAM STOPPED, angle is too large: %.2f" % [Link]((motorCtrl > 0))
(measuredAngle)) [Link]((motorCtrl < 0))
break
"""
#rise up sequence #log data for post analysis
if risingUp: [Link]([secondsSinceStart, accAngle, gyroAngle,
if secondsSinceStart < 1.0: measuredAngle, targetAngle,
#speed up reaction wheel to full speed tachoCount, wheelAV, error, integral, derivative,
#[Link] = 1.0 PIDoutput, motorCtrl])
motorPWM.duty_ns(int(DUTY*1.0))
[Link]((measuredAngle < 0)) #debug print
[Link]((measuredAngle > 0)) if (perf_counter_ns() - prevPrintTime) / 1e9 >= 1.0:
elif secondsSinceStart < 1.5: secondsSinceLastPrint = (perf_counter_ns() - prevPrintTime) / 1e9
#change direction using full power prevPrintTime = perf_counter_ns()
#[Link] = 1.0 loopInterval = secondsSinceLastPrint / loopCount * 1000
motorPWM.duty_ns(int(DUTY*1.0)) loopCount = 0
[Link]((measuredAngle > 0)) print("measuredAngle: %.2f, motorCtrl: %.2f, loopInterval: %.2f ms"
[Link]((measuredAngle < 0)) % (measuredAngle, motorCtrl, loopInterval))
#wait until close to top position, then start balancing """
if abs(measuredAngle) < RISEUP_END_ANGLE: sleep(SLEEP_TIME / 1000)
print("END RISE UP SEQUENCE") loopCount += 1
risingUp = False
else: #stop motor
print("RISE UP TIMEOUT") #[Link] = 0
break motorPWM.duty_ns(int(DUTY*0.0))
[Link](0)
#calculate wheel angular velocity [Link](0)
if (perf_counter_ns() - prevTachoTime) / 1e6 >=
WHEEL_AV_INTERVAL: """
tachoTimeDelta = (perf_counter_ns() - prevTachoTime) / 1e9 #[sec] #write log data to file
prevTachoTime = perf_counter_ns() print("log size", len(logData), "rows")
10
Control
if len(logData) > 0:
filename = "[Link]"
#filename = "datalog_" +
[Link]().strftime("%Y%m%d_%H%M%S") + ".dat"
print("write to file:", filename)
file = open(filename, "w")
for logLine in logData:
for value in logLine:
[Link](str(value) + ' ')
[Link]('\n')
[Link]()
"""
print("program ended")
2. FUNCIONAMIENTO
[Link]
UATR1U1TfWWMq1u/view?usp=drivesdk
11