1

I'm kinda new to Java, so haven't yet fully grasped the concept of multithreading.I would like to create a PIDController class that allows me to do this:

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();
}

I've worked out how to calculate the standard PID argorithms, but I can't work out how to provide the asynchronous functionality.

Can anybody tell me how I can achieve a similar API?

2 Answers 2

1

You already implemented a run() method for PIDController so you should also implement the Runnable interface:

class PIDController implements Runnable {
    ....
}

Now you can start your PIDController asynchonous, by calling:

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

For synchronization (if needed) you should have a look at the sun concurrency guide.

Sign up to request clarification or add additional context in comments.

3 Comments

If you want better control, then let an Executor (many in the ExecutorService) manage it instead of having a loose Thread running around. java.sun.com/javase/6/docs/api/java/util/concurrent/…
At present, my PIDController class has an instance of an inner class derived from Thread. I can't really decide whether the controller shoud be a Thread or contain a Thread
I'd recommend moving the multithreading code out of your PIDController class, and into a PIDManager or something, which is in charge of setting up PIDControllers in separate threads.
0

By far, the best mechanism for attaching threads to anything is to separate the object which does the work from the object which is the thread. The Runnable interface can be attractive, because it allows people to pass the object to a Thread constructor or Executor, and run it. However, if you have lifecycle management requirements for your object which are out side of "running to completion", such as pausing, then you will find it more appropriate in most cases, to manage the Thread within your object so that you know which thread is running (yes you can set an instance object to Thread.currentThread() on entry to run, but...).

So, I think what you have is a good start. You need to add the use of some locking to help yourself manage pause() and other thread control.

    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() {
            ...
        }
    }

4 Comments

'attaching threads to anything' - this verbage is not meaningful. May be this SO post might add some value to your own understanding - stackoverflow.com/questions/23414744/…
I am not sure what you are suggesting here? Based on that post, it seems you may have had some problems with how threading works. Do you need further explanation here about what is happening above?
np, i thought you are on the same page where i was once, when you wrote 'attach threads'.. pls ignore
I said "the object which is the thread" meaning the literal java "Thread" object only. That is, of course as you now probably know, the "wrapper" object used by Java to provide you access to the operating system resources associated with the real thread implementation. Subclassing Thread is never the right answer because it can create some other issues with the SecurityManage implementation which happens to check to see if the Thread that is executing is actually a subclass of java.lang.Thread instead of an actual instance of java.lang.Thread.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.