Boat autopilot - PID not centralizing rudder.

*** The original issue with PID not centralizing rudder is solved, as stated in a later post in this thread. The thread has become more of a discussion about the implementation as an autopilot in general. I will create a new thread about it to keep this clean. ***
/Tobbera, 2015-03-09

New thread is HERE.
/Tobbera, 2015-07-27

"After a couple of test runs tonight, I can now see that I was wrong in my first statement when creating this thread. The PID function does indeed actually “center” the rudder, at least a little bit. According to the graphs, the PID output decreases when error decreases, even if there still is an error. Good! :slight_smile: Thank you all for your input! "


Original post:

Hi all, hope you can bring some clarity into my life.

The project is a autopilot for a sailing boat. PID Input is wind direction, PID output is a servo connected to the rudder.

Issue: The PID controller does not centralize the rudder when closing in on the right cource.
For example, the boat is out of course by 20 degrees, the PID function increases PID Output which turns the rudder, more and more. After a while the boat is going to react to the rudder and start closing in in the desired course/setpoint (error decreasing), but the rudder angle (PID output) is not going back (PID output decreasing). Actually, its still increasing. The result is going to be the boat swinging way pass the setpoint. Not until the boat has actually swung pass the setpoint the PID start to decrease PID output.

Basically, the PID need to decrease Output when error is decreasing. Maybe PID is not the way to go here at all?

Bellow is my very first simple code I have done to try out the PID functionality.

#include <PID_v1.h>
#include <Servo.h>

// HARDWARE
const int WindVanePotPin = A5; // Analog input pin that the potentiometer in the Wind Vane is attached to
const int RudderServoPin = 9; // Digital output to the Rudder Servo.
Servo RudderServo; // Create servo object to control a servo

// PID
double Setpoint, Input, Output;   // Define Variables we'll be connecting to
double varKp=4, varKi=0.2, varKd=1;   // Define the Default Tuning Parameters
PID myPID(&Input, &Output, &Setpoint, varKp, varKi, varKd, DIRECT); 

// Work vars
long PreviousSerialWriteMillis = 0;      // will store last time LED was updated
long SerialWritInterval = 500;           // interval at which to blink (milliseconds)

void setup()
{
Setpoint = 500;                                            // Example
myPID.SetMode(AUTOMATIC);   // Turn the PID on
myPID.SetOutputLimits(1, 179); // min: Low end of the range. must be < max (double). max: High end of the range. must be > min (double) 
RudderServo.attach(RudderServoPin);
RudderServo.write(90);             // sets starting servo position to Center.
Serial.begin(9600); // Debug logging
}

void loop()
{

/*
Kp: Determines how aggressively the PID reacts to the current amount of error (Proportional) (double >=0)
Ki: Determines how aggressively the PID reacts to error over time (Integral) (double>=0)
Kd: Determines how aggressively the PID reacts to the change in error (Derivative) (double>=0) 
*/

// Read Wind Vane
Input = analogRead(WindVanePotPin);

// Input = map(Input, 0, 1023, 0, 360);  // Commented out because PID compute expect 0-1023 value.

// DEBUG LOGGING
unsigned long currentMillis = millis();
if(currentMillis - PreviousSerialWriteMillis > SerialWritInterval) {
PreviousSerialWriteMillis = currentMillis;   
Serial.print("Wind Vane Value: ");
Serial.println(Input);
Serial.print("Setpoint Value: ");
Serial.println(Setpoint);
Serial.print("Servo Write Value: ");
Serial.println(Output);
  }

myPID.Compute();

RudderServo.write(Output);  
}

Re-tune your PID. Sounds like one of the parameters is way off.

My understanding is that you start with all parameters 0 and the crank up the P parameter until you get a fast response with minimal overshoot. Then increase D to eliminate the overshoot without slowing the response too much. Then increase I to eliminate offset (where it settles close to but not on the desired setpoint).

There is also a PID auto-tune library that might help.

I have a little experience of full sized sailing boats. It would be rare for the rudder to be exactly centred.

The issue is whether the boat is going in the required direction, NOT what angle the rudder is at.

If your PID system is focused on rudder angle I doubt if your project will work.

Does your boat also have computer controlled sail movements? Potentially a very very complex feedback system.

...R

From the symptoms I would guess you have too much gain on the integral term and not enough on the derivative term.

i am no PID expert by any stretch, but am curious if this statement is true

PID compute expect 0-1023 value.

It seems to me that if the Setpoint is in the range of 0 to 360 the Input should be as well.

Thanks for your comments, could definitely try to tweak my PID values. However, I'm in doubt that it will actually do what I'm looking for.

The rudder will not be completely centered when going straight on course (error 0), there will always be a bit of offset because of sail trim etc. But when the PID starts to move the rudder (PID Output) because of error from setpoint, it also need to counter-compensate (PID Output) when the error stops increasing and eventually starts to decrease. This is where I'm worried that PID is not the way to go at all. Looking at the PID library and how its used, seems that Output keeps increasing as long as there is a error, not matter if the error increase or decrease.

No, no auto sail trim. Just steering on wind angle.

I think this is not a programming question, but a boat control question.

You seem to be assuming, that when the boat is on the correct course, the rudder should be centralised. This is, in general, not a valid assumption. For a sailing boat, or a motor boat, any effect such as wind or even currents will cause the boat's course to change. To maintain the desired course, even in the absense of transient disturbance, may require some rudder condition that is not "central". You can minimise this requirement by correct boat design, but you cannot eliminate it.

Basically, the PID need to decrease Output when error is decreasing. Maybe PID is not the way to go here at all?

If this is really your problem, then you need to reduce the value of the gain for the "D" component in the P-I-D formula. That's what it is there for.

Yes, I'm very aware of this. With "centralize" I don't mean dead center, zero rudder angle. I mean counter-react on decrease in Error. I'm not a native English speaker so I might not use the correct terms.

But when I manually steer my boat (keeping it on a certain angle to the wind, or compass course), I make a rudder adjustment until boat starts to close in on the desired course, then I "centralize" the rudder (decrease rudder angle), before the boat has actually reached the desired course, to avoid overshoot.

On the other hand, what my PID example is doing is keep increasing Output (rudder angle) as long as there is an error. No matter if the error is increasing, stable, or decreasing. Where I would need the PID to start decrease Output ("centralize" the rudder) to avoid overshoot.

michinyon: I think this is not a programming question, but a boat control question.

You seem to be assuming, that when the boat is on the correct course, the rudder should be centralised. This is, in general, not a valid assumption. For a sailing boat, or a motor boat, any effect such as wind or even currents will cause the boat's course to change. To maintain the desired course, even in the absense of transient disturbance, may require some rudder condition that is not "central". You can minimise this requirement by correct boat design, but you cannot eliminate it.

michinyon:

Basically, the PID need to decrease Output when error is decreasing. Maybe PID is not the way to go here at all?

If this is really your problem, then you need to reduce the value of the gain for the "D" component in the P-I-D formula. That's what it is there for.

I will try this out tonight. I actually read somewhere about an example where they went with negative numbers on D. Is that sane?

It would depend on whether your error was expressed as a positive or negative number. And the format of your equation. "Negative feedback" is perfectly normal, in fact it is the only useful kind of feedback.

You haven't given any indication of what is the source of information about the course the boat is supposed to be following, or how the system would know when it is approaching the correct course and should reduce the steering input. Also, has the system sensors to detect all the disturbing forces on a sailboat - wind strength and direction, sail settings, current etc?

I suspect it will be easier to program for small (and decreasing) overshoots rather than trying to get the correct course at first attempt.

...R

Tobbera: Hi all, hope you can bring some clarity into my life.

The project is a autopilot for a sailing boat. PID Input is wind direction, PID output is a servo connected to the rudder.

What hardware part did you use to receive the "wind direction" as input ?!!.

Input The main input is wind direction. Hardware is a encoder with wind vane outputting 0-5v (1-360 degrees) to a analog port. The analog readings is then going to be filtered thru a standard deviation algorithm that I have started looking at as well. This will give a stable wind direction without short term oscillation. During my experiments I'm using a simple potentiometer with my thumb to get the feeling of how to use the PID library to do something that's sane. Also looking at incorporating a tilt compensated compass to be able to steer the boat to a compass angle rather than wind angle. Ontop of this some buttons and pots to trim the the pilot. No other input is planned.

michinyon:

Basically, the PID need to decrease Output when error is decreasing. Maybe PID is not the way to go here at all?

If this is really your problem, then you need to reduce the value of the gain for the "D" component in the P-I-D formula. That's what it is there for.

Yesterday evening I tried to fiddle with the PID values, mostly the D one, as you told me. And yes, I can get some kind of "bounce back" when using a rather high D value. That is, when I induce error by altering the Input, and then rapidly decrease error by un-altering the Input again, the servo "bounces" in the counter direction a bit, but then goes back to where it were again. This sounds confusing, and that is how I experience it as well. Tonight I'm going to try to make a datalog of a couple of runs and post here.

The problem might be with the integral portion. What update interval is the PID running at? If it is a very short interval then the error sum will have gotten quite large before correction starts (due to the latency of the response loop). That would explain why the output does not lessen as the absolute error lessens. Actually I would think in your particular case you do not want the integral response at all.

I'm pretty sure you will want the integral term - it is the only way you will eliminate steady state errors. But you need to make sure the PID algorithm does not give it excessive authority and does not integrate it over too long a term.

I'm sure there are much clearer tutorials out there, but my naive approach to PID tuning is to disable everything except the proportional element and make sure that roughly the right amount of feedback is being applied at the correct sense in both directions relative to the set point. This ought to work-ish but oscillate like mad. Then gradually turn up the derivative feedback term to damp down the oscillation. Once that works, add in enough of the integral term to eliminate the steady state error.

If PID doesn’t work for you there are undoubtedly one or more errors in the program or the implementation. It is worth noting that the PID algorithm is intended to bring the system to the setpoint, which in your case would (SHOULD) be the desired course, with the input being the actual course, and the error being the deviation from the desired course. PID was never intended to make the system respond to a rapidly changing variable like the wind direction.

Maybe PID is not the way to go here at all?

You may be amused to learn that PID controllers were originally developed to steer ships. Here is a short quote from the Wikipedia entry on PID controllers: PID controller - Wikipedia

PID controllers date to 1890s governor design.[2][3] PID controllers were subsequently developed in automatic ship steering. One of the earliest examples of a PID-type controller was developed by Elmer Sperry in 1911,[4] while the first published theoretical analysis of a PID controller was by Russian American engineer Nicolas Minorsky, in (Minorsky 1922). Minorsky was designing automatic steering systems for the US Navy, and based his analysis on observations of a helmsman, noting the helmsman controlled the ship based not only on the current error, but also on past error as well as the current rate of change;[5] this was then made mathematical by Minorsky.

After a couple of test runs tonight, I can now see that I was wrong in my first statement when creating this thread. The PID function does indeed actually "center" the rudder, at least a little bit. According to the graphs, the PID output decreases when error decreases, even if there still is an error. Good! :) Thank you all for your input!

What I have been thinking about is that I might give the autopilot a lot less authority over the rudder than what was initially my idea. Maybe just +/- 20 degrees of rudder angle or so. That should make it easier for the PID to narrow in on the desired course, without overshooting all over the place.

Another thing, very visible in Test run 2 & 3, is that the PID output value starts off way out of centre. Its starts at 16,62 and keeps that value until there is a error to correct. The problem is that if it is starting off with a value like that (full rudder port) there is definitely going to be an error to correct, and the boat is going to take a proper detour before its on the right course again. I need to wind up the PID controller output to about 90 degrees before the PID Output is somewhat centered and can be mechanically connected to the rudder tiller. Is there anyway of making the Output start off in the middle of its extremes. Or I might need a wrapper around it to wind it up.

Wind direction is notoriously fickle - just look at a Met Office graph from one of their expensive anemometers. On small low interia wind vanes it will be much worse.

Mechanical wind vane steering has been used by sailing boats for a very long time. The mechanisms are expensive. I suspect they rely on the existence of a lot of inertia in the system - the forces on the rudder, the mass of the boat etc. There is probably also an interaction between the effect on the boat direction of gusts and the effect of the same gusts on the steering.

In my personal experience the little flag thing at the top of the mast is no use to the helmsman, a much better indicator of average wind direction is obtained from the sound of the breeze in my ears. (By the way I have never raced a sailboat and those who can do so successfully may have a different view, but I suspect they won't).

What about building a purely mechanical wind vane steering system and when it works properly try disconnecting the wind vane from the steering and interposing an Arduino between them?

...R