Autonomous Sail Trimming

I made a post a little while ago about the basics of having a rotary encoder and servo work together, but I feel that this is different enough to deserve a new post, so here goes!

I am 15 and with a team competing in the Sailbot competition working towards making a fully autonomous, gps guided sailboat. Part of my job is to make the sails trim themselves automatically, if anybody knows nothing about sailing, trimming the sail means to let it in or out according to the wind (say if the wind was behind you the sail would be completely let out). Our wind vane uses a rotary encoder to measure wind direction. This code interprets readings from the wind vane and autonomously trims the sails accordingly. (at least I hope it does) I'm feeling somewhat confident in it but I was just hoping that some veterans could give me an opinion on it, whether I need to change things or fix things or even add things.

#include <Servo.h>
//these pins can not be changed 2/3 are special pins
int encoderPin1 = 3;
int encoderPin2 = 2;

Servo myservo;

int servopos = 0;

volatile int lastEncoded = 0;
volatile long pos = 0;

int pos1;

int pos2;

int pos3;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  
  Serial.begin (9600);
  
  myservo.attach(11);

  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);

}









void loop(){
  
if(pos = - 360)
pos = 0;
//*************************************************************  
if(-180 < pos < -360){

pos3 = -360 - pos;

  Serial.println("pos:");
  Serial.println(pos3);
  delay(2000);
}
  
if (servopos > pos3)  
  {
    for ( ; servopos != pos3; servopos-=10)  
    {
      myservo.write(servopos - pos3 / 2);
    }
  }

if (servopos < pos3)  
  {
    for ( ; servopos != pos3; servopos+=10)  
    {
      myservo.write(servopos - pos3 / 2);
    }
  };
//*******************************************************************  

if(-180 < pos < 0){

pos1 = 0 - pos;

  Serial.println("pos:");
  Serial.println(pos1);
  delay(2000);
}

if (servopos > pos1)
  {
    for ( ; servopos != pos1; servopos-=10)  
    {
      myservo.write(servopos - pos1 / 2);
    }
  }

if (servopos < pos1)  
  {
    for ( ; servopos != pos1; servopos+=10)  
    {
      myservo.write(servopos - pos1 / 2);
    }
  }
;
//***************************************************************************************************  
if(0 < pos < 180)
  
  Serial.println("pos:");
  Serial.println(pos);
  delay(2000);
  
if (servopos > pos)  
  {
    for ( ; servopos != pos; servopos-=10)  
    {
      myservo.write(servopos - pos / 2);
    }
  }

if (servopos < pos)  
  {
    for ( ; servopos != pos; servopos+=10)  
    {
      myservo.write(servopos - pos / 2);
    }
  };
//******************************************************************************************************
if(180 < pos < 360)

pos2 = 360 - pos;

Serial.println("pos:");
  Serial.println(pos2);
  delay(2000);
  
if (servopos > pos2)  
  {
    for ( ; servopos != pos2; servopos-=10)  
    {
      myservo.write(servopos - pos2 / 2);
    }
  }

if (servopos < pos2)  
  {
    for ( ; servopos != pos2; servopos+=10) 
    {
      myservo.write(servopos - pos2 / 2);
    }
  };
 //************************************************************************************************** 
if(pos = 360)
  pos = 0;
  
  
  Serial.println("servopos:");
  Serial.println(servopos);
  delay(2000);
}







void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) pos +=10;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) pos -=10;

  lastEncoded = encoded; //store this value for next time
  
}

but I was just hoping that some veterans could give me an opinion on it, whether I need to change things or fix things or even add things.

Yes, you should fix things.

void setup() {

If you are going to put the { brace at the end of the statement, to save lines, don't put a blank line after it.

}









void loop(){

Ifyouareputtingthe{onthelinewiththestatement,tosavealine,getridofthewhitespace.

If you are going to have white space, put the { on a new line where it belongs. In either case, the { does not get jammed up against the statement.

if(pos = - 360)

Why are you assigning a value to pos?

if(-180 < pos < -360){

Show me an example where this actually works. You can only invent shortcuts IF you are on the C standards committee. At 15, I doubt that you are.

pos3 = -360 - pos;

Is that the best you can do for a name? 2 months from now, will you know what the hell pos3 is? Two months from now, would you know what desiredSailPos was?

    for ( ; servopos != pos3; servopos-=10)  
    {
      myservo.write(servopos - pos3 / 2);
    }

If you are not going to allow time for the servo to get to each position, there is no reason to take little steps.

Per PaulS, those variable names make it really hard to understand what you're trying to do.

Pos seems to be apparent wind direction. Have you confirmed that that piece works standalone? If not I'd suggest that you reduce the sketch to something that ignores the servo and ensure that your reading of the encoder works for all angles of the wind, being particularly careful to test the transition through 0 degrees from both sides for the compass.

Given that you're trying to navigate within a box, I'd expect to see some consideration of your desired course - I'm not clear what your trimming will achieve without it.

Do you have a instrument measuring apparent wind speed? If not, you may at least want an accelerometer to tell you angle of heel - without it you may well trim yourself into a broach or capsize. I'd prefer to have both sensors.

Edit: Clarity, as noted by the man from Seattle

into a broach or capsize. I'd prefer to have both.

Both a broach and a capsize? I'd vote for neither, but, hey, I'm staying on the shore.

Your other thread was about moving a servo to an angle to match that of the encoder but it now appears as though what you want to do is to trim the sails based on the angle of the encoder, which is not the same thing.

I don't know much about sailing but I believe that you will need to rotate the servo many times in order to trim the sails unless you have huge output arm on the servo and even if you do then it will almost certainly not provide enough power to trim the sails. Is the servo a conventional one, a continuous rotational one or a pukka sail winch servo which is a cross between the two ?

As others have said, there are problems with your code which need fixing but without knowing the mechanical setup it is difficult to give more advice.

I know a little about sailing, though I was never interested in racing. I did crew on one or two club boats in races though I may have been more of a liability than an asset.

Have you worked a real sailboat yourself?

Wind is a very fickle thing and you may need a very clever program to manage sails. I doubt if a wind direction sensor on its own will be sufficient. On a boat (or sailing a radio controlled boat) the helmsman will also be aware of the heel of the boat and of it's changing direction as well as the wind direction and strength. On my boat the wind direction indicator on the masthead was not as good as my own sense of wind direction. You also need to anticipate changes (rather than react to them) to avoid getting head to wind, broaching or jibing.

I found "sailing for dummies" excellent (the authors have impeccable credentials) and one piece of advice has stuck in my mind "if in doubt let it out" which may be a useful feature in your program.

...R

dukereduker,

From your OP it sounds like you plan to steer your your sailbot by the boat sailing a constant compass course given by the GPS (until the next way point).

Then with a Apparent Wind Angle Indicator (wind vane using a rotary encoder) you will trim your sails accordingly.

You could have a simple table setting the sail trim servo(s) to a certain position to each wind angle.

• A sailboat will sail best/fastest when it is flat or less than 30º heel.As wildbill pointed out you will need at least an accelerometer to know the heal of the sailbot.

Basically, when the boat heels over the sails need to be "eased" or let out quickly, then when flat, brought back in again. Otherwise one of two things will happen, the boat will blow over, capsize, etc. or it will turn into the wind. This will cause you to have to adjust the steering every time to get back on course.

• Another thing to consider is "balance" between the center of effort of the Jib, Main and the Keel. The wind pushes on the Jib and Main, the water pushes on the Keel. If they are far apart the boat will be constantly trying to turn.

• A third thing to consider is that a sailboat cannot sail higher than about 45º apparent wind angle (with 0º straight into the wind.)

Can you give us a little more information about your wind vane using a rotary encoder?

I am interested because I considered using a MLX90316 Rotary Position Sensor and a small neodymium rod magnet on a wind vane top of the mast to sense the wind direction. I am only planning to have a 1m boat, what size is your project?

If you want other people to look at your code make sure that it has been formatted before you post it. Use auto format in the IDE tools menu. Auto formatting your code will also save you time!.

Mark