Multiple IF and multiple blink without delay in loop

Hi,

In firmware for Arduino Mega for my trolling motor autopilot for small boat

I’m using multiple IF statement/conditions and multiple millis "blink without delay".

in the main while (true) loop for go home procedure I set few conditions how my trolling motor should operate to keep me close to my home position (GPS based positioning).

The first condition is that boat (GPS position) must be between 1.5 and 2500 m from home (stored GPS position).

When that is true the program set other conditions based on angle difference of trolling motor (compass) heading and GPS bearing


(calculated from home GPS coordinates and current GPS coordinates) named "error" absolute value.

I set two maximum angle "error" differences T and Tx

T is maximum "error" when trolling motor propeller is ON "if (abs(error) <= 30 motor is ON; else is OFF"

Tx is maximum "error" difference when stepper motor that rotate trolling motor shaft CW or CCW is OFF "if (error < 0 && abs(error) > Tx); if (error > 0 && abs(error) > Tx)

Now my questions are:

  1. are this IF statements/conditions properly written

  2. are all this millis "blink without delay" (mostly used for acceleration and deceleration of propeller and stepper motor timing) properly written (don’t conflict between each other)

Basically everything seams to work but some time I think that rotation of shaft and activation of prop is little bit off from given conditions.

 if (Distance_To_Home > 1.50 && Distance_To_Home <= 2500){      // If the boat is between 1.5 and 2500 m from the home spot, run 
        
//*******************************************************
//turning ON/OFF trolling motor proppeler      
        
       if (abs(error) <= T){      //  T = 30°
          unsigned long currentMillis = millis();
          if (((unsigned long)(currentMillis - previousMillis) >= interval_a) && (pwm < run_Speed))  {
             pwm = pwm + b;
             analogWrite(runPin, pwm);         // turn on trolling motor and accelerate to pwm walue
             previousMillis = currentMillis;
             //Serial.println(pwm);
             }
             else if (((unsigned long)(currentMillis - previousMillis) >= interval_d) && (run_Speed < pwm)){
             pwm = pwm - b;
             analogWrite(runPin, pwm);         // turn on trolling motor and decelerate to pwm walue
             previousMillis = currentMillis;
             //Serial.println(pwm);
             }   
         }
         else {
          digitalWrite(runPin, LOW);
          pwm = 0;
         }
//***************************************************
//rotating trolling motor CCW

          if (error < 0 && abs(error) > Tx){   //  Tx = maximum allowed angle between compass and gps heading (set to 10 degree)
          digitalWrite(enablePin, LOW); //enable A4988 stepper motor driver who is rotating compass and trolling motor bar
          delay(5);
          digitalWrite(dirPin, HIGH);// Stepper motor rotate CCW; LOW/HIGH (check on hardware!!!)

          unsigned long currentMillis = millis();
          if (((unsigned long)(currentMillis - previousMillis) >= M) && (stepAcc < Puls))  {
            stepAcc = stepAcc + 300;
            previousMillis = currentMillis;
            }
          tone(stepPin,stepAcc);
          }
//*************************************** 
//rotating trolling motor CW
  
          if (error > 0 && abs(error) > Tx){    //  Tx = maximum allowed angle diference between compass and gps heading (set to 10 degree)
          digitalWrite(enablePin, LOW); //enable A4988 stepper motor driver who is rotating compassand trolling motor bar
          delay(5);
          digitalWrite(dirPin, LOW);// Stepper motor rotate CW; LOW/HIGH (check on hardware!!!)

          unsigned long currentMillis = millis();
          if (((unsigned long)(currentMillis - previousMillis) >= M) && (stepAcc < Puls))  {
            stepAcc = stepAcc + 300;
            previousMillis = currentMillis;
            }
          tone(stepPin,stepAcc);
          }
//**********************************************************
//stop rotating trolling motor shaft

          if (abs(error) <= Tx){  
          //digitalWrite(stepPin, LOW);
          digitalWrite(enablePin, HIGH); //deactivation of stepper motor driver A4988 
          noTone(stepPin);
          stepAcc = 0;
          }

          
            
          Serial.print("kut=");
          Serial.print(error); 
          Serial.print("  D=");
          Serial.print(Distance_To_Home);
          Serial.print("m   heading=");
          Serial.print(headingct);
          Serial.print("    GPS_Course=");
          Serial.print(GPS_Course); 
          Serial.println("");  

          unsigned long cMillis = millis();
          if ((unsigned long)(cMillis - pMillis) >= 500){
            
          Serial1.print("Er:");
          Serial1.print(error);
          Serial1.print("° D=");
          Serial1.print(Distance_To_Home);
          Serial1.println("m ");
          pMillis = cMillis;
          
          }
          
          
     }                                                         //End of Distance_To_Home >1.5m Loop

might be easier to understand your requirements if you explained what you want to do rather how you think the code needs to implement your requirements

why would the error affect the run speed

if this code is implemented in a sub-function, why not just return if this condition is not met

not clear (to me) is this saying the error is 30 if the motor is ON but something else when the motor is OFF? what if it is OFF?

can you explain this without logic. what is the value of TxError? what is the condition for the error.

what if the conditions for both error values are true, which error takes priority

seems there should be a test when the error exceeds some threshold which is either T or Tx and there should be some conditional that determines either the error or "mode" of operation

why not less repetitiously

       unsigned long currentMillis = millis ();
       if ( (currentMillis - previousMillis) >= interval_a)  {
            previousMillis = currentMillis;
            if (pwm < run_Speed)
                pwm = pwm + b;
            else
                pwm = pwm - b;

            analogWrite(runPin, pwm);  
            //Serial.println(pwm);
        }

similar for other case, Tx


    if (abs(error) > Tx) {
        digitalWrite(enablePin, LOW); //enable A4988 stepper motor driver who is rotating compass and trolling motor bar
        delay(5);
        if (error < 0)
            digitalWrite(dirPin, HIGH);
        else
            digitalWrite(dirPin, LOW);

        unsigned long currentMillis = millis();
        if ((currentMillis - previousMillis) >= M) && (stepAcc < Puls))  {
            stepAcc = stepAcc + 300;
            previousMillis = currentMillis;
        }

        tone(stepPin,stepAcc);
    }

not clear what stepAcc means? how does it correct an angle error

could there be a common currentMillis

If motor is inside yellow area (+30° right from bearing; +30°left from bearing; thats T) than propeller is running "ON" . I dont want that my boat goes in circle 90°angle, or zig zag. So first he must rotate with stepper motor aid to get into yellow zone and then start the propeller.
Also I use PWM for acceleration (soft start of propeller) and I can also remotely change PWM value.

Also I dont wan that my stepper motor go constantly left right so i stop it when is in green area (+10° right from bearing; +10°left from bearing; thats Tx)

Error is, as I explained calculated angle between bearing and heading, and that works fine!
T and Tx are just limit angle where propeller or stepper is OFF or ON
(error < Tx = stepper OFF; error> Tx = stepper ON )
(error < T = propeller ON; error > T = propeller OFF)

why not less repetitiously

       unsigned long currentMillis = millis ();
       if ( (currentMillis - previousMillis) >= interval_a)  {
            previousMillis = currentMillis;
            if (pwm < run_Speed)
                pwm = pwm + b;
            else
                pwm = pwm - b;

            analogWrite(runPin, pwm);  
            //Serial.println(pwm);
        }

I have two different speeds, one is for acceleration (much slower) and other is for deceleration (faster)

Regarding
similar for other case, Tx

 if (abs(error) > Tx) {
        digitalWrite(enablePin, LOW); //enable A4988 stepper motor driver who is rotating compass and trolling motor bar
        delay(5);
        if (error < 0)
            digitalWrite(dirPin, HIGH);
        else
            digitalWrite(dirPin, LOW);

        unsigned long currentMillis = millis();
        if ((currentMillis - previousMillis) >= M) && (stepAcc < Puls))  {
            stepAcc = stepAcc + 300;
            previousMillis = currentMillis;
        }

        tone(stepPin,stepAcc);
    }

How in this case system will know on what direction shall he rotate CW or CCW,?
Stepper motor must choose the direction of rotation (shaft and trolling motor rotation), he must take the shortest side to get to targeted angle.

not clear what stepAcc means? how does it correct an angle error

could there be a common currentMillis

Stepper motor also have acceleration (soft start) , that is why stepAcc is there.

Im more concerned of multiple currentMillis and previouseMillis.
Shall i separate them for each function, one for stepper and one for propeller motor?
I did that for serial1 print of data that are sent to my MIT App android app via BLE.
I noticed that data were not sent every half second so i change it to cMillis and pMillis, and it work.

i wish you could explain without coding statements what your trying to do.

doesn't the propeller always need to be on to reach the waypoint? what does "tone()" do?

your diagram suggests that there is a target, the waypoint. in other words, the goal isn't to maintain a bearing, it is to reach a specific position knowing the bearing to that position. And that bearing is constantly changing due to accumulated position error.

doesn't any change in the servo to correct a directional error need to be undone to maintain the correct bearing and to avoid zig-zagging between the two error boundaries

why not more conventionally use the error to continuously correct the direction (using a servo) rather than only make a correction beyond a specific error threshold?

i'm asking these suggestive questions not because i think you're doing it wrong, but because it's not clear to me what you're trying to do.

Independent separate timers need unique time stamps.

I didn't look closely to be sure you are OK using just previuosMillis everywhere.

Take one currentMillis from millis() at the very top of your free running, non blocking loop().

Use a unique unsigned long variable to note the time of action like you use previuosMillis now.

a7

Hi,

I’m tiring to do simple DP (dynamic positioning) system for my boat to keep me on my fishing spot.

Something like Minn Kota trolling motors with Spot lock.

https://www.minnkotamotors.com/learn/technology/trolling-motors/spot-lock

System should work in way that first you save position where your boat needs to be (waypoint) and than trolling motor connected to Arduino and gearbox with stepper motor should continuously taking me to way point position. If boat is inside 1.5 m radius circle around way point than everything stops, and starts again when boat goes out of that circle.

I just put 2500 m limit so that cant go around the globe :slight_smile: so first condition to start keeping position is that Arduino have all data and that boat is between 1,5 and 2500 m from waypoint.

You are right, since trolling motor is taking me back to waypoint, heading and bearing constantly change and according to new values of heading and bearing that Arduino is constantly calculating (from GPS data and compass (tilt compensated) data), Arduino is doing constantly calculation in what direction he should rotate the trolling motor.

So this is inside while () loop and it goes forever unless I send command to STOP.

I hope is more clear now what I’m doing J

millis() are set outside, no problem with that.

I agree that would be much better to separate the millis like acurentMillis, bcurentMillis, and so on...

Same for previous millis apreviuoseMillis, bpreviuoseMillis, ....

Or something similar.

That way I don’t need to think are some of those millis in conflict.

That's not agreeing with me. In a free running loop, loop() takes, to a first approximation, no time at all.

Thus one currentMillis would suffice, and ensure that everyone is taking about now. In my loop(), I use that very name

 unsinged long now = millis();

A local variable declared and initialised as the first statement.

The other part you got, even if you could demonstrate logically that there was no conflicting use of one time stamp previuosMills, it would help the reader and avoid something you may have missed, or subsequently introduced, that would interfere.

The names could be better then a, b, cPreviuosMillis, like previuosButtonCheck, relayStartTime, &c.

I've never been good at naming anything, so.

a7

what is "error"? a bearing or a distance rom a waypoint?

sound like a position error is needed, as well as a bearing and an orientation of the boat relative to the bearing

I don't see that you have posted a complete compilable we-can-play-with-it sketch. And said what is or isn't wrong with it.

Please do! Or show me where you did.

a7

error is calculated value between current bearing and trolling motor heading
Bearing change constantly since boat is moving its calculated between two GPS coordinates, stored one as home, and current one where boat is.
Example
The bearing between two GPS points is 250° and trolling motor (compass) is oriented at that particular moment toward 130° so the the error is 120 (250-180= 120).
In that case propeller want start rotating before stepper motor rotate the trolling motor and reduce that error below 30°.
And stepper motor will stop rotating when the error drops below 10.

Hope is clear now?
I dont know how to explain it better.

You can see the video of my test at sea.
https://www.youtube.com/watch?v=Y-7gwGw0Bqk

i think this is the first time this has been explained

and there's still the question about distance from the waypoint

and there's the issue of neutralizing the corrective action so that the boat does zig-zag from one extreme to the other

Distance from waypoint is easy, its calculated between two GPS coordinates, stored one as home, and current one where boat is.
Zig-Zag is not so problematic, its more limitation by precision of GPS signal (GPS drifting), so maybe 1.5 m radius circle is too strong, usually precision of GPS is 2,5 m diameter under open sky (on the sea).
But that is easy to change in the code.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.