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)