【问题标题】:How can I implement a multi-threaded PID controller in Java?如何在 Java 中实现多线程 PID 控制器?
【发布时间】:2010-12-09 20:55:57
【问题描述】:

我对 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?

【问题讨论】:

    标签: java multithreading asynchronous pid


    【解决方案1】:

    到目前为止,将线程附加到任何事物的最佳机制是将执行工作的对象与作为线程的对象分开。 Runnable 接口可能很有吸引力,因为它允许人们将对象传递给 Thread 构造函数或 Executor,并运行它。但是,如果您对对象的生命周期管理要求超出了“运行到完成”的范围,例如暂停,那么在大多数情况下,您会发现管理对象中的线程更合适,以便您知道哪个线程正在运行(是的,您可以在进入运行时将实例对象设置为 Thread.currentThread(),但是...)。

    所以,我认为你所拥有的是一个好的开始。您需要添加一些锁定来帮助自己管理 pause() 和其他线程控制。

    公共类 PIDController { 私有最终对象 myLock = new Object(); 私有最终控制器方法 ctrl; 私有 volatile Thread 线程; 私人 volatile Runner 亚军; 私人 int pidInterval = 700; 私有最终双 setPoint,kp,ki,kd; 公共PIDController(双setPoint,双kp,双ki,双kd,ControllerMethods inst){ this.ctrl = inst; this.setPoint = setPoint; 这个.kp = kp; 这个.ki = ki; 这个.kd = kd; } 公共无效暂停(){ 同步(我的锁){ 如果(跑步者。暂停){ throw new IllegalOperationException(this+": 已经暂停"); } runner.paused = true; } } 公共无效简历(){ 同步(我的锁){ 如果(!runner.paused){ throw new IllegalOperationException(this+": 已经恢复"); } runner.paused = false; } } 公共布尔isRunning(){ 返回运行; } 公共无效开始(){ 如果(线程!= null){ throw new IllegalOperationException(this+": already running"); } 我的线程 = 新线程(亚军 = 新亚军()); myThread.start(); } 公共无效停止(){ 如果(跑步者==空){ throw new IllegalOperationException(this+": PID is not running"); } runner.running = false; 如果(跑步者.暂停) 恢复(); 跑步者=空; } // 重要的是,无论何时实现可停止的 Runnable, // 您将“运行”标志作为内部实例类的成员包括在内,例如 // 这样当你要求这个实例停止时,你可以立即重启 // 另一个实例并且没有两个线程观察相同的“运行”标志 私有类 Runner 实现 Runnable { volatile bool running = false,bool 已暂停; 公共无效运行(){ 运行=真; 在跑步的时候 ) { // 在循环顶部执行此操作,以便从 // pause 将在重新计算之前检查运行。 重新计算PID(); // 使用双重检查习语 如果(暂停){ 同步(我的锁){ 而(暂停){ myLock.wait(); } } } Thread.sleep(pidInterval); } } } 公共无效重新计算PID(){ ... } }

    【讨论】:

    • '将线程附加到任何东西' - 这个措辞没有意义。也许这篇 SO 帖子可能会为您自己的理解增加一些价值 - stackoverflow.com/questions/23414744/…
    • 我不确定你在这里建议什么?根据那篇文章,您似乎对线程的工作方式有一些问题。您需要在这里进一步解释上面发生的事情吗?
    • np,当你写“附加线程”时,我以为你在同一个页面上。请忽略
    • 我说“作为线程的对象”仅指文字 java“线程”对象。当然,正如您现在可能知道的那样,Java 使用“包装器”对象为您提供对与实际线程实现相关联的操作系统资源的访问。子类化 Thread 永远不是正确的答案,因为它可能会在 SecurityManage 实现中产生一些其他问题,这恰好检查正在执行的线程是否实际上是 java.lang.Thread 的子类,而不是 java.lang 的实际实例。线程。
    【解决方案2】:

    您已经为PIDController 实现了run() 方法,因此您还应该实现Runnable 接口:

    class PIDController implements Runnable {
        ....
    }
    

    现在您可以通过以下方式启动您的 PIDController 异步:

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

    对于同步(如果需要),您应该看看太阳concurrency guide

    【讨论】:

    • 如果你想要更好的控制,那么让一个 Executor(许多在 ExecutorService 中)来管理它,而不是让一个松散的线程到处跑。 java.sun.com/javase/6/docs/api/java/util/concurrent/…
    • 目前,我的PIDController类有一个派生自Thread的内部类的实例。我真的无法决定控制器应该是 Thread 还是包含 Thread
    • 我建议将多线程代码从您的 PIDController 类中移出,并移到负责在单独线程中设置 PIDController 的 PIDManager 或其他东西中。
    猜你喜欢
    • 1970-01-01
    • 2019-10-31
    • 2023-03-03
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    相关资源
    最近更新 更多