簡體   English   中英

如何在Java中實現多線程PID控制器?

[英]How can I implement a multi-threaded PID controller in 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嗎?

您已經為PIDController實現了run()方法,因此還應該實現Runnable接口:

class PIDController implements Runnable {
    ....
}

現在,您可以通過調用以下命令啟動PIDController異步:

pidControllerThread = new Thread( pidController );
pidControllerThread.start();

對於同步(如果需要),您應該查看sun 並發指南

到目前為止,將線程附加到任何對象的最佳機制是將完成工作的對象與線程對象分開。 Runnable接口可能很有吸引力,因為它允許人們將對象傳遞給Thread構造函數或Executor並運行它。 但是,如果您對對象的生命周期管理要求超出了“運行至完成”范圍,例如暫停,那么您將發現在大多數情況下管理對象中的線程更為合適,這樣您就可以知道哪個線程正在運行(是的,您可以在運行時將實例對象設置為Thread.currentThread(),但是...)。

因此,我認為您擁有一個好的開始。 您需要添加一些鎖定功能,以幫助自己管理pause()和其他線程控制。

public class PIDController {
        private final Object myLock = new Object();
        private final ControllerMethods ctrl;
        private volatile Thread thread;
        private volatile Runner runner;
        private int pidInterval = 700;
        private final double setPoint, kp, ki, kd;

        public PIDController( double setPoint, double kp, double ki, double kd, ControllerMethods inst ) {
            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+": already paused");
                }
                runner.paused = true;
            }
        }

        public void resume() {
            synchronized( myLock ) {
                if( !runner.paused ) {
                    throw new IllegalOperationException(this+": already resumed");
                }
                runner.paused = false;
            }
        }

        public bool isRunning() {
            return running;
        }

        public void start() {
            if( thread != null ) {
                throw new IllegalOperationException( this+": already running");
            }
            myThread = new Thread( runner = new Runner() );
            myThread.start();
        }

        public void stop() {
            if( runner == null ) {
                throw new IllegalOperationException( this+": PID is not running");
            }
            runner.running = false;
            if( runner.paused )
                resume();
            runner = null;
        }


        // It is important, anytime that you implement a stoppable Runnable, that
        // you include the "running" flag as a member of an innner instance class like
        // this so that when you ask this instance to stop, you can immediately restart
        // another instance and not have the two threads observing the same "running" flag
        private class Runner implements Runnable {
            volatile bool running = false, bool paused;
            public void run() {
                running = true;
                while( running ) {
                    // do this at the top of the loop so that a wake from
                    // pause will check running, before recomputing.
                    reComputePID();

                    // Use the double check idiom to 
                    if( paused ) {
                        synchronized( myLock ) {
                            while( paused ) {
                                myLock.wait();
                            }
                        }
                    }
                    Thread.sleep( pidInterval );
                }
            }
        }

        public void reComputePID() {
            ...
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM