State-Space Kontrolör Rehberi

Not

Bu rehberi takip etmeden önce, okuyucuların Durum Uzayı - State-space Kontrolüne Giriş, durum-uzay kontrolüne girişi okumuş olmaları önerilir.

Bu rehberin amacı, bir volan için bir durum-uzay kontrolörünün uygulanmasına ilişkin “uçtan uca” talimatlar sağlamaktır. Bu rehberi takip ederek okuyucular aşağıdaki kazanımları edinecektir:

  1. Sistem tespiti veya CAD yazılımı kullanarak bir volanın isabetli durum-uzay modelini oluşturmak.

  2. Kodlayıcı hızı ölçümlerini gecikmesiz filtrelemek için Kalman Filtresi uygulamak

  3. Bir LQR geri besleme denetleyicisi uygulayın; bu, model tabanlı ileri besleme ile birleştirildiğinde, çarkı a reference “referans” a sürmek için voltaj inputs oluşturur.

Bu öğretici, çok fazla programlama uzmanlığı olmayan ekipler için ulaşılabilir olması amaçlanmıştır. WPILib kitaplığı, durum-uzay kontrol özelliklerinin uygulanma biçiminde önemli bir esneklik sunarken, bu eğitimde ana hatları verilen uygulamayı yakından takip etmek, ekiplere çeşitli durum-uzay sistemleri için yeniden kullanılabilecek temel bir yapı sağlamalıdır.

The full example is available in the state-space flywheel (Java/C++/Python) and state-space flywheel system identification (Java/C++/Python) example projects.

Neden State-Space Control-Durum Uzayı Kontrolü Kullanmalısınız?

State-Space Control-Durum-uzay kontrolü, sistemimizin doğru bir modelini oluşturmaya odaklandığından, model will respond to control inputs 1 e nasıl tepki vereceğini doğru bir şekilde tahmin edebiliriz. Bu, mekanizmalarımızı fiziksel bir robota erişim olmadan simüle etmemize ve aynı zamanda kolayca seçim yapmamıza olanak tanır gains iyi çalışacağını bildiğimiz kazançlardır. Bir modele sahip olmak, sensör okumalarını en iyi şekilde filtrelemek için Kalman Filtreleri gibi gecikmesiz filtreler oluşturmamıza da olanak tanır.

Flywheel-Volanımızın Modellenmesi

Recall that continuous state-space systems are modeled using the following system of equations:

\[\begin{split}\dot{\mathbf{x}} &= \mathbf{A}\mathbf{x} + \mathbf{B}\mathbf{u} \\ \mathbf{y} &= \mathbf{C}\mathbf{x} + \mathbf{D}\mathbf{u}\end{split}\]

Where x-dot is the rate of change of the system’s state, \(\mathbf{x}\) is the system’s current state, \(\mathbf{u}\) is the input to the system, and \(\mathbf{y}\) is the system’s output.

Let’s use this system of equations to model our flywheel in two different ways. We’ll first model it using system identification using the SysId toolsuite, and then model it based on the motor and flywheel’s moment of inertia.

Durum uzayı sistemimizi oluşturmanın ilk adımı, sistemimizin durumlarını seçmektir. Devlet olarak istediğimiz her şeyi seçebiliriz - istersek tamamen ilgisiz durumları seçebiliriz - ama önemli olan durumları seçmeye yardımcı olur. Bizim durumumuzdaki hidden states ifadesini dahil edebiliriz (sadece konumunu ölçebilseydik asansör hızı gibi) ve Kalman Filtremizin değerlerini tahmin etmesine izin verebiliriz. Seçtiğimiz durumların, geribildirim denetleyicisi tarafından ilgili references e doğru yönlendirileceğini unutmayın (tipik olarak : ref:` Doğrusal Karesel Düzenleyici <docs/software/advanced-controls/state-space/state-space-intro:The Linear-Quadratic Regulator>`, çünkü optimaldir).

Volanımız için yalnızca tek bir durumu önemsiyoruz : hızı. İvmesini de modellemeyi seçebilirken, bu durumun dahil edilmesi sistemimiz için gerekli değildir.

Daha sonra, : terimini tanımlıyoruz: `sistemimize <input> girişleri. Girdiler, durumunu değiştirmek için sistemimize “into-içine” koyabileceğimiz şeyler olarak düşünülebilir. Volan (ve FRC ® ‘deki diğer birçok tek eklemli mekanizma) durumunda, sadece bir girişimiz var: motora uygulanan voltaj. Girişimiz olarak voltajı seçerek (motor görev döngüsü gibi bir şey üzerinde), akü yükü arttıkça akü voltajındaki düşüşü telafi edebiliriz.

Sürekli zaman durum-uzay sistemi şunu yazar x-dot veya sistemin system' durumunun anlık değişim oranı, şu anki state ile orantılı olarak ve inputs<input>’. Durumumuz açısal hız olduğundan, :math:mathbf{dot{x}}` volanın açısal ivmesi olacaktır.

Daha sonra, çarkımızı sürekli zaman durum-uzay sistemi olarak modelleyeceğiz. WPILib’in LinearSystem’ sistemi bunu dahili olarak ayrık zamana dönüştürecektir. Gözden geçirme : ref: “durum uzayı gösterimi <docs/software/advanced-controls/state-space/state-space-intro:What is State-Space Notation?>``, sürekli zamanlı ve ayrık zamanlı sistemler hakkında daha fazla bilgi için.

Sistem Tanımlama ile Modelleme

To rewrite this in state-space notation using system identification, we recall from the flywheel state-space notation example, where we rewrote the following equation in terms of \(\mathbf{a}\).

\[\begin{split}V = kV \cdot \mathbf{v} + kA \cdot \mathbf{a}\\ \mathbf{a} = \mathbf{\dot{v}} = \begin{bmatrix}\frac{-kV}{kA}\end{bmatrix} v + \begin{bmatrix}\frac{1}{kA}\end{bmatrix} V\end{split}\]

Burada:math:mathbf{v} , volan hızıdır,:math:mathbf{a} ve:math:mathbf{dot{v}}, volan ivmesidir ve \(V\) voltajdır. Bunu, durum vektörü için standart \(\mathbf{x}\) ve giriş vektörü için : math:mathbf {u} standart kuralıyla yeniden yazarak şunu buluruz:

\[\mathbf{\dot{x}} = \begin{bmatrix}\frac{-kV}{kA} \end{bmatrix} \mathbf{x} + \begin{bmatrix}\frac{1}{kA} \end{bmatrix} \mathbf{u}\]

Durum uzayı notasyonunun ikinci bölümü, sistemin o anki :term:state ve girdileri ile output ile ilişkilidir. Bir volan durumunda, çıktı vektörümüz \(\mathbf{y}\) (veya sensörlerimizin ölçebildiği şeyler) volanımızın hızıdır ve bu da bizim state \(\mathbf{x}\) vektörümüzün bir unsuru olur . Bu nedenle, çıktı matrisimiz \(\mathbf{C} = \begin{bmatrix}1 \end{bmatrix}\) ve sistem besleme matrisimiz \(\mathbf{D} = \begin{bmatrix}0 \end{bmatrix}\) olur. Bunu sürekli zaman durum uzayı gösteriminde yazmak aşağıdakileri verir.

\[\begin{split}\mathbf{\dot{x}} &= \begin{bmatrix}\frac{-kV}{kA} \end{bmatrix} \mathbf{x} + \begin{bmatrix}\frac{1}{kA} \end{bmatrix} \mathbf{u} \\ \mathbf{y} &= \begin{bmatrix}1\end{bmatrix} \mathbf{x} + \begin{bmatrix}0\end{bmatrix} \mathbf{u}\end{split}\]

LinearSystem sınıfı, şu şekilde tanımlanmış durum uzayı sistemlerini kolayca oluşturmak için yöntemler içerir system identification. Bu örnek, kV değeri 0,023 ve kA değeri 0,001 olan bir volan modelini göstermektedir:

32  // Volts per (radian per second)
33  private static final double kFlywheelKv = 0.023;
34
35  // Volts per (radian per second squared)
36  private static final double kFlywheelKa = 0.001;
37
38  // The plant holds a state-space model of our flywheel. This system has the following properties:
39  //
40  // States: [velocity], in radians per second.
41  // Inputs (what we can "put in"): [voltage], in volts.
42  // Outputs (what we can measure): [velocity], in radians per second.
43  //
44  // The Kv and Ka constants are found using the FRC Characterization toolsuite.
45  private final LinearSystem<N1, N1, N1> m_flywheelPlant =
46      LinearSystemId.identifyVelocitySystem(kFlywheelKv, kFlywheelKa);
17#include <frc/system/plant/LinearSystemId.h>
30  // Volts per (radian per second)
31  static constexpr auto kFlywheelKv = 0.023_V / 1_rad_per_s;
32
33  // Volts per (radian per second squared)
34  static constexpr auto kFlywheelKa = 0.001_V / 1_rad_per_s_sq;
35
36  // The plant holds a state-space model of our flywheel. This system has the
37  // following properties:
38  //
39  // States: [velocity], in radians per second.
40  // Inputs (what we can "put in"): [voltage], in volts.
41  // Outputs (what we can measure): [velocity], in radians per second.
42  //
43  // The Kv and Ka constants are found using the FRC Characterization toolsuite.
44  frc::LinearSystem<1, 1, 1> m_flywheelPlant =
45      frc::LinearSystemId::IdentifyVelocitySystem<units::radian>(kFlywheelKv,
46                                                                 kFlywheelKa);
23# Volts per (radian per second)
24kFlywheelKv = 0.023
25
26# Volts per (radian per second squared)
27kFlywheelKa = 0.001
37        # The plant holds a state-space model of our flywheel. This system has the following properties:
38        #
39        # States: [velocity], in radians per second.
40        # Inputs (what we can "put in"): [voltage], in volts.
41        # Outputs (what we can measure): [velocity], in radians per second.
42        #
43        # The Kv and Ka constants are found using the FRC Characterization toolsuite.
44        self.flywheelPlant = (
45            wpimath.system.plant.LinearSystemId.identifyVelocitySystemRadians(
46                kFlywheelKv, kFlywheelKa
47            )
48        )

Volan Atalet Momenti ve Dişli Kullanarak Modelleme

A flywheel can also be modeled without access to a physical robot, using information about the motors, gearing, and flywheel’s moment of inertia. A full derivation of this model is presented in Section 12.3 of Controls Engineering in FRC.

The LinearSystem class contains methods to easily create a model of a flywheel from the flywheel’s motors, gearing and moment of inertia. The moment of inertia can be calculated using CAD software or using physics. The examples used here are detailed in the flywheel example project (Java/C++/Python).

Not

WPILib’in durum uzayı sınıfları için dişli, giriş üzerinden çıkış olarak yazılır - yani, volan motorlardan daha yavaş dönüyorsa, bu sayı birden büyük olmalıdır.

Not

C ++ LinearSystem sınıfı, birim karışıklıklarını önlemek ve boyutluluğu ileri sürmek için the C++ Units Library kullanır.

33  private static final double kFlywheelMomentOfInertia = 0.00032; // kg * m^2
34
35  // Reduction between motors and encoder, as output over input. If the flywheel spins slower than
36  // the motors, this number should be greater than one.
37  private static final double kFlywheelGearing = 1.0;
38
39  // The plant holds a state-space model of our flywheel. This system has the following properties:
40  //
41  // States: [velocity], in radians per second.
42  // Inputs (what we can "put in"): [voltage], in volts.
43  // Outputs (what we can measure): [velocity], in radians per second.
44  private final LinearSystem<N1, N1, N1> m_flywheelPlant =
45      LinearSystemId.createFlywheelSystem(
46          DCMotor.getNEO(2), kFlywheelMomentOfInertia, kFlywheelGearing);
17#include <frc/system/plant/LinearSystemId.h>
31  static constexpr units::kilogram_square_meter_t kFlywheelMomentOfInertia =
32      0.00032_kg_sq_m;
33
34  // Reduction between motors and encoder, as output over input. If the flywheel
35  // spins slower than the motors, this number should be greater than one.
36  static constexpr double kFlywheelGearing = 1.0;
37
38  // The plant holds a state-space model of our flywheel. This system has the
39  // following properties:
40  //
41  // States: [velocity], in radians per second.
42  // Inputs (what we can "put in"): [voltage], in volts.
43  // Outputs (what we can measure): [velocity], in radians per second.
44  frc::LinearSystem<1, 1, 1> m_flywheelPlant =
45      frc::LinearSystemId::FlywheelSystem(
46          frc::DCMotor::NEO(2), kFlywheelMomentOfInertia, kFlywheelGearing);
22kFlywheelMomentOfInertia = 0.00032  # kg/m^2
23
24# Reduction between motors and encoder, as output over input. If the flywheel spins slower than
25# the motors, this number should be greater than one.
26kFlywheelGearing = 1
38        # The plant holds a state-space model of our flywheel. This system has the following properties:
39        #
40        # States: [velocity], in radians per second.
41        # Inputs (what we can "put in"): [voltage], in volts.
42        # Outputs (what we can measure): [velocity], in radians per second.
43        self.flywheelPlant = wpimath.system.plant.LinearSystemId.flywheelSystem(
44            wpimath.system.plant.DCMotor.NEO(2),
45            kFlywheelMomentOfInertia,
46            kFlywheelGearing,
47        )

Kalman Filtreleri: Volan Durumunu Gözlemleme

Kalman filtreleri, bir durum tahmini oluşturmak için durum uzayı modelimizi kullanarak hız ölçümlerimizi filtrelemek için kullanılır : math:mathbf {hat {x}}. Volan modelimiz doğrusal olduğundan, volanın hızını tahmin etmek için bir Kalman filtresi kullanabiliriz. WPILib’in Kalman filtresi, model ve sensör ölçümlerinin standart sapmalarıyla birlikte bir LinearSystem (yukarıda bulduğumuz) alır. Bu ağırlıkları ayarlayarak durum tahminimizin ne kadar “smooth-düzgün” olduğunu ayarlayabiliriz. Daha büyük durum standart sapmaları, filtrenin durumumuza “distrust-güvenmemesine” ve yeni ölçümleri daha fazla tercih etmesine neden olurken, daha büyük ölçüm standart sapmaları bunun tersini yapacaktır.

Bir volan durumunda, 3 rad / s’lik bir durum standart sapması ve 0.01 rad / s’lik bir ölçüm standardı sapması ile başlarız. Bu değerler kullanıcının seçmesine bağlıdır - bu ağırlıklar bir miktar gürültüye toleranslı olan ancak durum tahmini a volan için dış parazitlere hızlı bir şekilde tepki veren bir filtre üretti ve aşağıdakiler için iyi davranan bir filtre oluşturmak için ayarlanmalıdır. özel volanınız. Zaman içindeki durumları, ölçümleri, girdileri, referansları ve çıktıları grafiklemek, Kalman filtrelerini ayarlamak için harika bir görsel yoldur.

The effect of a Kalman, median, and IIR filters on some flywheel data.

Yukarıdaki grafik, iki farklı şekilde ayarlanmış Kalman filtresinin yanı sıra bir:single-pole IIR filter ve Median Filtresi gösterir. Bu veriler, bir atıcı ile ~ 5 saniyede toplandı ve dört top, atıcıdan geçirildi (hızdaki dört düşüşte görüldüğü gibi). İyi durum ve ölçüm standardı sapmalarını seçme konusunda katı kurallar olmamakla birlikte, bunlar genel olarak, harici rahatsızlıklara hızlı tepki verirken gürültüyü reddedecek kadar modele güvenecek şekilde ayarlanmalıdır.

Because the feedback controller computes error using the x-hat estimated by the Kalman filter, the controller will react to disturbances only as quickly the filter’s state estimate changes. In the above chart, the upper left plot (with a state standard deviation of 3.0 and measurement standard deviation of 0.2) produced a filter that reacted quickly to disturbances while rejecting noise, while the upper right plot shows a filter that was barely affected by the velocity dips.

48  // The observer fuses our encoder data and voltage inputs to reject noise.
49  private final KalmanFilter<N1, N1, N1> m_observer =
50      new KalmanFilter<>(
51          Nat.N1(),
52          Nat.N1(),
53          m_flywheelPlant,
54          VecBuilder.fill(3.0), // How accurate we think our model is
55          VecBuilder.fill(0.01), // How accurate we think our encoder
56          // data is
57          0.020);
13#include <frc/estimator/KalmanFilter.h>
48  // The observer fuses our encoder data and voltage inputs to reject noise.
49  frc::KalmanFilter<1, 1, 1> m_observer{
50      m_flywheelPlant,
51      {3.0},   // How accurate we think our model is
52      {0.01},  // How accurate we think our encoder data is
53      20_ms};
49        # The observer fuses our encoder data and voltage inputs to reject noise.
50        self.observer = wpimath.estimator.KalmanFilter_1_1_1(
51            self.flywheelPlant,
52            (3,),  # How accurate we think our model is
53            (0.01,),  # How accurate we think our encoder data is
54            0.020,
55        )

Kalman filtreleri : ref: docs / software / advanced-controls / state-space / state-space-observers: Predict step’de durum uzayı modelimizi kullandığından, modelimizin mümkün olduğu kadar doğru olması önemlidir. Bunu doğrulamanın bir yolu, bir volanın giriş voltajını ve zaman içindeki hızını kaydetmek ve bu verileri Kalman filtresinde yalnızca predict-tahmin olarak adlandırarak yeniden yürütmektir. Daha sonra, kV ve kA kazançları (veya eylemsizlik momenti ve diğer sabitler), model kaydedilen verilerle yakından eşleşene kadar ayarlanabilir.

Doğrusal-Kuadratik Düzenleyiciler ve Plant Inversion Feedforward-İleri Besleme

Linear-Quadratic Regulator / Doğrusal-Kuadratik Düzenleyici, volanımızı system i reference a sürmek için bir geri bildirim denetleyicisi bulur . Volanımızın sadece bir durumu olduğu için, LQR’miz tarafından seçilen kontrol yasası şu biçimde olacaktır \(\mathbf{u = K (r - x)}\) burada \(\mathbf{K}\), bir 1x1 matrisdir; başka bir deyişle, LQR tarafından seçilen kontrol kuralı basitçe orantılı bir kontrolör veya sadece bir P kazancı olan bir PID kontrolörüdür. Bu kazanç, LQR’miz tarafından, geçtiğimiz durum gezi ve kontrol çabalarına göre seçilir. LQR denetleyicilerinin ayarlanması hakkında daha fazla bilgi şu adreste bulunabilir LQR uygulama örneği.

SimpleMotorFeedforward gibi, kS, kV ve kA sabitleri verilen ileri besleme voltaj girişleri oluşturmak için kullanılabilir, Plant Inversion Feedforward sınıfı, bir durum uzay sistemi verilen feedforward voltaj girişlerini üretir. `` LinearSystemLoop`` sınıfı tarafından üretilen gerilim komutları ileri besleme ve geri besleme girişlerinin toplamıdır.

59  // A LQR uses feedback to create voltage commands.
60  private final LinearQuadraticRegulator<N1, N1, N1> m_controller =
61      new LinearQuadraticRegulator<>(
62          m_flywheelPlant,
63          VecBuilder.fill(8.0), // qelms. Velocity error tolerance, in radians per second. Decrease
64          // this to more heavily penalize state excursion, or make the controller behave more
65          // aggressively.
66          VecBuilder.fill(12.0), // relms. Control effort (voltage) tolerance. Decrease this to more
67          // heavily penalize control effort, or make the controller less aggressive. 12 is a good
68          // starting point because that is the (approximate) maximum voltage of a battery.
69          0.020); // Nominal time between loops. 0.020 for TimedRobot, but can be
70  // lower if using notifiers.
11#include <frc/controller/LinearQuadraticRegulator.h>
55  // A LQR uses feedback to create voltage commands.
56  frc::LinearQuadraticRegulator<1, 1> m_controller{
57      m_flywheelPlant,
58      // qelms. Velocity error tolerance, in radians per second. Decrease this
59      // to more heavily penalize state excursion, or make the controller behave
60      // more aggressively.
61      {8.0},
62      // relms. Control effort (voltage) tolerance. Decrease this to more
63      // heavily penalize control effort, or make the controller less
64      // aggressive. 12 is a good starting point because that is the
65      // (approximate) maximum voltage of a battery.
66      {12.0},
67      // Nominal time between loops. 20ms for TimedRobot, but can be lower if
68      // using notifiers.
69      20_ms};
70
71  // The state-space loop combines a controller, observer, feedforward and plant
72  // for easy control.
73  frc::LinearSystemLoop<1, 1, 1> m_loop{m_flywheelPlant, m_controller,
74                                        m_observer, 12_V, 20_ms};
57        # A LQR uses feedback to create voltage commands.
58        self.controller = wpimath.controller.LinearQuadraticRegulator_1_1(
59            self.flywheelPlant,
60            (8,),  # qelms. Velocity error tolerance, in radians per second. Decrease
61            # this to more heavily penalize state excursion, or make the controller behave more
62            # aggressively.
63            (12,),  # relms. Control effort (voltage) tolerance. Decrease this to more
64            # heavily penalize control effort, or make the controller less aggressive. 12 is a good
65            # starting point because that is the (approximate) maximum voltage of a battery.
66            0.020,  # Nominal time between loops. 0.020 for TimedRobot, but can be lower if using notifiers.
67        )

Hepsini Bir Araya Getirin : LinearSystemLoop

LinearSystemLoop, daha önce oluşturduğumuz sistemimizi, denetleyicimizi ve gözlemcimizi birleştirir. Gösterilen kurucu ayrıca bir PlantInversionFeedforward başlatacaktır.

72  // The state-space loop combines a controller, observer, feedforward and plant for easy control.
73  private final LinearSystemLoop<N1, N1, N1> m_loop =
74      new LinearSystemLoop<>(m_flywheelPlant, m_controller, m_observer, 12.0, 0.020);
15#include <frc/system/LinearSystemLoop.h>
71  // The state-space loop combines a controller, observer, feedforward and plant
72  // for easy control.
73  frc::LinearSystemLoop<1, 1, 1> m_loop{m_flywheelPlant, m_controller,
74                                        m_observer, 12_V, 20_ms};
69        # The state-space loop combines a controller, observer, feedforward and plant for easy control.
70        self.loop = wpimath.system.LinearSystemLoop_1_1_1(
71            self.flywheelPlant, self.controller, self.observer, 12.0, 0.020
72        )

LinearSystemLoop umuza sahip olduğumuzda, geriye kalan tek şey onu çalıştırmaktır. Bunu yapmak için, Kalman filtremizi yeni enkoder hız ölçümlerimizle periyodik olarak güncelleyeceğiz ve ona yeni voltaj komutları uygulayacağız. Bunu yapmak için, önce reference yi, ardından mevcut volan hızıyla correct`, bir sonraki zaman adımına Kalman filtresini predict ve getU kullanılarak oluşturulan girdileri uyguluyoruz. .

 94  @Override
 95  public void teleopPeriodic() {
 96    // Sets the target speed of our flywheel. This is similar to setting the setpoint of a
 97    // PID controller.
 98    if (m_joystick.getTriggerPressed()) {
 99      // We just pressed the trigger, so let's set our next reference
100      m_loop.setNextR(VecBuilder.fill(kSpinupRadPerSec));
101    } else if (m_joystick.getTriggerReleased()) {
102      // We just released the trigger, so let's spin down
103      m_loop.setNextR(VecBuilder.fill(0.0));
104    }
105
106    // Correct our Kalman filter's state vector estimate with encoder data.
107    m_loop.correct(VecBuilder.fill(m_encoder.getRate()));
108
109    // Update our LQR to generate new voltage commands and use the voltages to predict the next
110    // state with out Kalman filter.
111    m_loop.predict(0.020);
112
113    // Send the new calculated voltage to the motors.
114    // voltage = duty cycle * battery voltage, so
115    // duty cycle = voltage / battery voltage
116    double nextVoltage = m_loop.getU(0);
117    m_motor.setVoltage(nextVoltage);
118  }
119}
 5#include <numbers>
 6
 7#include <frc/DriverStation.h>
 8#include <frc/Encoder.h>
 9#include <frc/TimedRobot.h>
10#include <frc/XboxController.h>
11#include <frc/controller/LinearQuadraticRegulator.h>
12#include <frc/drive/DifferentialDrive.h>
13#include <frc/estimator/KalmanFilter.h>
14#include <frc/motorcontrol/PWMSparkMax.h>
15#include <frc/system/LinearSystemLoop.h>
16#include <frc/system/plant/DCMotor.h>
17#include <frc/system/plant/LinearSystemId.h>
 92  void TeleopPeriodic() override {
 93    // Sets the target speed of our flywheel. This is similar to setting the
 94    // setpoint of a PID controller.
 95    if (m_joystick.GetRightBumperButton()) {
 96      // We pressed the bumper, so let's set our next reference
 97      m_loop.SetNextR(frc::Vectord<1>{kSpinup.value()});
 98    } else {
 99      // We released the bumper, so let's spin down
100      m_loop.SetNextR(frc::Vectord<1>{0.0});
101    }
102
103    // Correct our Kalman filter's state vector estimate with encoder data.
104    m_loop.Correct(frc::Vectord<1>{m_encoder.GetRate()});
105
106    // Update our LQR to generate new voltage commands and use the voltages to
107    // predict the next state with out Kalman filter.
108    m_loop.Predict(20_ms);
109
110    // Send the new calculated voltage to the motors.
111    // voltage = duty cycle * battery voltage, so
112    // duty cycle = voltage / battery voltage
113    m_motor.SetVoltage(units::volt_t{m_loop.U(0)});
114  }
 88    def teleopPeriodic(self) -> None:
 89        # Sets the target speed of our flywheel. This is similar to setting the setpoint of a
 90        # PID controller.
 91        if self.joystick.getTriggerPressed():
 92            # We just pressed the trigger, so let's set our next reference
 93            self.loop.setNextR([kSpinUpRadPerSec])
 94
 95        elif self.joystick.getTriggerReleased():
 96            # We just released the trigger, so let's spin down
 97            self.loop.setNextR([0.0])
 98
 99        # Correct our Kalman filter's state vector estimate with encoder data.
100        self.loop.correct([self.encoder.getRate()])
101
102        # Update our LQR to generate new voltage commands and use the voltages to predict the next
103        # state with out Kalman filter.
104        self.loop.predict(0.020)
105
106        # Send the new calculated voltage to the motors.
107        # voltage = duty cycle * battery voltage, so
108        # duty cycle = voltage / battery voltage
109        nextVoltage = self.loop.U(0)
110        self.motor.setVoltage(nextVoltage)

LQR ile Açı Sarılması

Sürekli açıya sahip düzeneklerin sürekli açısı lqr.Calculate(x, r) yerine aşağıdaki kodun çağrılmasıyla sarılabilmektedir.

var error = lqr.getR().minus(x);
error.set(0, 0, MathUtil.angleModulus(error.get(0, 0)));
var u = lqr.getK().times(error);
Eigen::Vector<double, 2> error = lqr.R() - x;
error(0) = frc::AngleModulus(units::radian_t{error(0)}).value();
Eigen::Vector<double, 2> u = lqr.K() * error;
error = lqr.R() - x
error[0] = wpimath.angleModulus(error[0])
u = lqr.K() * error