WPILib’de PID Kontrolü
Not
This article focuses on in-code implementation of PID control in WPILib. For a conceptual explanation of the working of a PIDController, see PID’ye Giriş
Not
Komut Tabanlı framework aracılığıyla PID kontrolünün uygulanmasına ilişkin bir kılavuz için bkz PIDSubsystems ve PIDCommands üzerinden PID Kontrol.
WPILib supports PID control of mechanisms through the PIDController
class (Java, C++, Python
). This class handles the feedback loop calculation for the user, as well as offering methods for returning the error, setting tolerances, and checking if the control loop has reached its setpoint within the specified tolerances.
PIDController Sınıfını Kullanma
Bir PIDController Oluşturma
Not
PIDController
eşzamansız olarak kullanılabilirken, herhangi güvenlik özelliği sağlamaz - güvenli çalışmanın tamamen kullanıcıya bırakılmasını sağlar ve bu nedenle eşzamansız kullanım yalnızca gelişmiş ekipler için önerilir.
WPILib’in PID kontrol fonksiyonelliğini kullanmak için, kullanıcılar önce istenen kazançlarla bir PIDController
nesnesi oluşturmalıdır:
// Creates a PIDController with gains kP, kI, and kD
PIDController pid = new PIDController(kP, kI, kD);
// Creates a PIDController with gains kP, kI, and kD
frc::PIDController pid{kP, kI, kD};
from wpimath.controller import PIDController
# Creates a PIDController with gains kP, kI, and kD
pid = PIDController(kP, kI, kD)
Constructor’a, denetleyicinin çalıştırılacağı süreyi belirleyen isteğe bağlı dördüncü bir parametre sağlanabilir. PIDController
nesnesi, esas olarak ana robot döngüsünden senkronize kullanım için tasarlanmıştır ve bu nedenle değeri varsayılan olarak 20ms’dir.
Geri Besleme Döngüsü Çıkışını Kullanma
Not
PIDController
, calculate()
yönteminin yapılandırılan periyotla tutarlı bir aralıkta düzenli olarak çağrıldığını varsayar. Bunun yapılmaması, istenmeyen döngü davranışına neden olacaktır.
Oluşturulan PIDController
i kullanmak basittir: basitçe robotun ana döngüsünden calculate()
yöntemini çağırın (örneğin, robotun autonomousPeriodic()
yöntemi):
// Calculates the output of the PID algorithm based on the sensor reading
// and sends it to a motor
motor.set(pid.calculate(encoder.getDistance(), setpoint));
// Calculates the output of the PID algorithm based on the sensor reading
// and sends it to a motor
motor.Set(pid.Calculate(encoder.GetDistance(), setpoint));
# Calculates the output of the PID algorithm based on the sensor reading
# and sends it to a motor
motor.set(pid.calculate(encoder.getDistance(), setpoint))
Hataları Kontrol Etmek
Not
getPositionError()
ve getVelocityError()
, döngünün bir konumu kontrol ettiği varsayılarak adlandırılır - bir hızı kontrol eden bir döngü için bunlar sırasıyla hız hatasını ve hızlanma hatasını döndürür.
Ölçülen işlem değişkeninin mevcut hatası,``getPositionError()`` işlevi tarafından döndürülür, türevi ise getVelocityError()
işlevi tarafından döndürülür:
Toleransları Belirleme ve Kontrol Etme
Not
Yalnızca bir konum toleransı belirtilirse, hız toleransı varsayılan olarak sonsuzdur.
Not
Yukarıdaki gibi, position
işlem değişken ölçümünü ve velocity
bunun türevini ifade eder - dolayısıyla, bir hız döngüsü için bunlar aslında sırasıyla hız ve ivmedir.
Bazen, bir denetleyicinin ayar noktasını belirli bir tolerans dahilinde izleyip izlemediğini bilmek yararlıdır - örneğin, bir komutun sonlandırılması gerekip gerekmediğini veya (bir hareket profilini takip ederken) hareketin engellenip engellenmediğini belirlemek yada tekrar planlamak için.
Bunu yapmak için önce toleransları setTolerance()
yöntemi ile belirlemeliyiz; daha sonra atSetpoint()
metodu ile kontrol edebiliriz.
// Sets the error tolerance to 5, and the error derivative tolerance to 10 per second
pid.setTolerance(5, 10);
// Returns true if the error is less than 5 units, and the
// error derivative is less than 10 units
pid.atSetpoint();
// Sets the error tolerance to 5, and the error derivative tolerance to 10 per second
pid.SetTolerance(5, 10);
// Returns true if the error is less than 5 units, and the
// error derivative is less than 10 units
pid.AtSetpoint();
# Sets the error tolerance to 5, and the error derivative tolerance to 10 per second
pid.setTolerance(5, 10)
# Returns true if the error is less than 5 units, and the
# error derivative is less than 10 units
pid.atSetpoint()
Denetleyiciyi Sıfırlama
Artık geçerli olmayabileceğinden (örneğin, PIDController
devre dışı bırakıldığında ve ardından yeniden etkinleştirildiğinde) bir PIDController
in dahili durumunu (en önemlisi, integral akümülatörü) temizlemek istenebilir. . Bu, reset()
yöntemi çağrılarak gerçekleştirilebilir.
Max Integrator Değeri Ayarlama
Not
Entegratörler, geri besleme döngü sistemlerine kararsızlık ve histerezis getirir. Kesinlikle başka hiçbir çözüm işe yaramayacaksa ekiplerin integral kazanımı kullanmaktan kaçınmaları şiddetle tavsiye edilir - çoğu zaman, bir entegratörle çözülebilecek sorunlar daha doğru bir feedforward kullanılarak daha iyi çözülebilir.
A typical problem encountered when using integral feedback is excessive “wind-up” causing the system to wildly overshoot the setpoint. This can be alleviated in a number of ways - the WPILib PIDController
class enforces an integrator range limiter to help teams overcome this issue.
By default, the total output contribution from the integral gain is limited to be between -1.0 and 1.0.
The range limits may be increased or decreased using the setIntegratorRange()
method.
// The integral gain term will never add or subtract more than 0.5 from
// the total loop output
pid.setIntegratorRange(-0.5, 0.5);
// The integral gain term will never add or subtract more than 0.5 from
// the total loop output
pid.SetIntegratorRange(-0.5, 0.5);
# The integral gain term will never add or subtract more than 0.5 from
# the total loop output
pid.setIntegratorRange(-0.5, 0.5)
Disabling Integral Gain if the Error is Too High
Another way integral “wind-up” can be alleviated is by limiting the error range where integral gain is active. This can be achieved by setting IZone
. If the error is more than IZone
, the total accumulated error is reset, disabling integral gain. When the error is equal to or less than IZone, integral gain is enabled.
By default, IZone
is disabled.
IZone
may be set using the setIZone()
method. To disable it, set it to infinity.
// Disable IZone
pid.setIZone(Double.POSITIVE_INFINITY);
// Integral gain will not be applied if the absolute value of the error is
// more than 2
pid.setIZone(2);
// Disable IZone
pid.SetIZone(std::numeric_limits<double>::infinity());
// Integral gain will not be applied if the absolute value of the error is
// more than 2
pid.SetIZone(2);
# Disable IZone
pid.setIZone(math.inf)
# Integral gain will not be applied if the absolute value of the error is
# more than 2
pid.setIZone(2)
Sürekli Girişi - Continuous Input Ayarlama
Uyarı
Mekanizmanız tamamen sürekli dönme kabiliyetine sahip değilse (örneğin, kabloları döndükçe bükülen, kayma halkası olmayan bir turret), mekanizmanın limitlerini geçmesini önlemek için ek bir güvenlik özelliği uygulamadıysanız sürekli girişi etkinleştirmeyin !
Uyarı
Sürekli giriş işlevi, giriş değerlerinizi otomatik olarak kaydırmaz - bu özelliği kullanırken, giriş değerlerinin asla belirtilen aralığın dışında olmadığından emin olun!
Some process variables (such as the angle of a turret) are measured on a circular scale, rather than a linear one - that is, each “end” of the process variable range corresponds to the same point in reality (e.g. 360 degrees and 0 degrees). In such a configuration, there are two possible values for any given error, corresponding to which way around the circle the error is measured. It is usually best to use the smaller of these errors.
Bunu otomatik olarak yapacak bir PIDController
yapılandırmak için, enableContinuousInput()
yöntemini kullanın:
// Enables continuous input on a range from -180 to 180
pid.enableContinuousInput(-180, 180);
// Enables continuous input on a range from -180 to 180
pid.EnableContinuousInput(-180, 180);
# Enables continuous input on a range from -180 to 180
pid.enableContinuousInput(-180, 180)
Kontrol Çıkışını Bağlama
// Clamps the controller output to between -0.5 and 0.5
MathUtil.clamp(pid.calculate(encoder.getDistance(), setpoint), -0.5, 0.5);
// Clamps the controller output to between -0.5 and 0.5
std::clamp(pid.Calculate(encoder.GetDistance(), setpoint), -0.5, 0.5);
# Python doesn't have a builtin clamp function
def clamp(v, minval, maxval):
return max(min(v, maxval), minval)
# Clamps the controller output to between -0.5 and 0.5
clamp(pid.calculate(encoder.getDistance(), setpoint), -0.5, 0.5)