Как я могу реализовать многопоточный ПИД-контроллер в Java?
Я немного новичок в Java, поэтому еще не полностью понял концепцию многопоточности. Я хотел бы создать класс PIDController, который позволит мне сделать это:
ControllerMethods methods = new ControllerMethods()
{
public long getError(long setpoint)
{
//get an input
}
public void setOutput(long value)
{
//do something
}
public void isComplete(long setpoint)
{
return getError() == 0;
}
};
PIDController motorPID = new PIDController(setpoint, kp, ki, kd, methods);
motorPID.run();
//runs the PID controller to completion (methods.isComplete() == true)
motorPID.run(false);
//starts the PID controller in a separate thread, allowing
//continual monitoring in the current thread
while(motorPID.isRunning())
{
//do something else
if(condition1)
motorPID.pause();
//pause the PID controller, preventing the integral from increasing
else if(condition2)
motorPID.stop();
}
Я разработал способ вычисления стандартных алгоритмов PID, но я не могу понять, как обеспечить асинхронную функциональность.
Кто-нибудь может сказать мне, как я могу добиться аналогичного API?
2 ответа
Вы уже реализовали run()
метод для PIDController
поэтому вы должны также реализовать Runnable
интерфейс:
class PIDController implements Runnable {
....
}
Теперь вы можете запустить свой PIDController асинхронно, вызвав:
pidControllerThread = new Thread( pidController );
pidControllerThread.start();
Для синхронизации (при необходимости) вы должны взглянуть на руководство по параллельности солнца.
Безусловно, лучший механизм для прикрепления потоков к чему-либо - это отделение объекта, который выполняет работу, от объекта, который является потоком. Интерфейс Runnable может быть привлекательным, поскольку он позволяет людям передавать объект в конструктор Thread или Executor и запускать его. Однако, если у вас есть требования к управлению жизненным циклом для вашего объекта, которые выходят за рамки "запуска до завершения", например, приостановки, то в большинстве случаев вы найдете более подходящим управление потоком внутри вашего объекта, чтобы вы знали, какой поток работает (да, вы можете установить объект экземпляра в Thread.currentThread () на входе для запуска, но...).
Итак, я думаю, что у вас есть хорошее начало. Вы должны добавить использование некоторой блокировки, чтобы помочь себе управлять pause () и другими средствами управления потоками.
открытый класс PIDController { private final Object myLock = new Object(); приватный финал ControllerMethods ctrl; частная летучая нить; частный летучий раннер; private int pidInterval = 700; закрытый финал двойной setPoint, кп, ки, кд; public PIDController(двойной setPoint, двойной kp, двойной ki, двойной kd, экземпляр ControllerMethods) { this.ctrl = inst; this.setPoint = setPoint; this.kp = kp; this.ki = ki; this.kd = kd; } public void pause() { synchronized( myLock) { if( runner.paused) { throw new IllegalOperationException(this+": уже приостановлено"); } runner.paused = true; } } public void resume() { synchronized( myLock) { if(!runner.paused) { throw new IllegalOperationException(this+": уже возобновлено"); } runner.paused = false; } } public bool isRunning() { return running; } public void start() { if( thread!= null) { throw new IllegalOperationException( this+": уже запущен"); } myThread = new Thread( runner = new Runner()); myThread.start(); } public void stop() { if( runner == null) { throw new IllegalOperationException( this+": PID не запущен"); } runner.running = false; if( runner.paused) resume(); бегун = ноль; } // Важно, чтобы в любое время, когда вы реализуете Runnable, который можно остановить, // вы включаете флаг "running" в качестве члена класса экземпляра innner, такого как // this, чтобы при запросе остановки этого экземпляра вы могли немедленно перезапустить // другой экземпляр и не иметь двух потоков, наблюдающих один и тот же флаг "бег" частного класса Runner реализует Runnable { volatile bool running = false, bool paused; public void run() { running = true; while( running) { // сделать это в верхней части цикла, чтобы при пробуждении из // pause проверялось выполнение перед повторным вычислением. reComputePID(); // Используем идиому двойной проверки для if( paused) { synchronized( myLock) { while( paused) { myLock.wait(); } } } Thread.sleep( pidInterval); } } } public void reComputePID() { ... } }