Linear actuator reverse conflict in code

Hi, I have constructed a solar tracker with a H-bridge with mosfets and bjts to control a linear actuator. For bench testing I have set a day light threshold of 600 and night light threshold of 500, also the tracking time is set at 5 second for west and east. But I have set the run time for night east return at 10 seconds. The east and west tracking is working fine, but there is a conflict with east return which is a reverse command as is the east tracking command. When under night light threshold the actuator keeps stopping after 2-3 second and does not run for the ten seconds as I have put in the millis() function. I am new to coding, so I was wondering if anyone has any suggestions or ideas that could help me resolve this coding conflict? I have included my sketch.

int sense1Pin = A0; //west leds
int sense2Pin = A1; //east leds
int forward = 9; // use pin 9 for forward
int reverse = 10; // use pin 10 for reverse
int tolerance = 20;
unsigned long previous_F_Millis = 0;  // stores the value of millis() in each iteration of loop()
unsigned long previous_R_Millis = 0;
unsigned long previous_ER_Millis = 0; // will store last time motor was updated
const long interval_one = 5000; // constant won't change, interval motor run (milliseconds)
const long interval_two = 10000;
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  analogReference(DEFAULT);
  lcd.begin(16, 2);
  Serial.begin(9600);
  pinMode(forward, OUTPUT);
  pinMode(reverse, OUTPUT);
  delay(1000);
  digitalWrite(forward, HIGH);
  delay(1000);
  digitalWrite(forward, LOW);
  delay(1000);
  digitalWrite(reverse, HIGH);
  delay(1000);
  digitalWrite(reverse, LOW);
  delay(3000);
}

void loop() {

  int val1 = analogRead(sense1Pin);
  int val2 = analogRead(sense2Pin);
  unsigned long currentMillis = millis();


  if (val1 + val2 > 600)
    if (currentMillis - previous_F_Millis >=  interval_one) {
      previous_F_Millis = currentMillis;
      if ((val1 + val2 > 600) && (val1 > val2 + tolerance))
        digitalWrite(forward, HIGH);
      else digitalWrite(forward, LOW);
    }


  if ( val1 + val2 > 600);
  if (currentMillis - previous_R_Millis >=  interval_one) {
    previous_R_Millis = currentMillis;
    if ((val1 + val2 > 600) && (val2 > val1 + tolerance))
      digitalWrite(reverse, HIGH);
    else digitalWrite(reverse, LOW);
  }



  else (val1 + val2 < 500 );
  if (currentMillis - previous_ER_Millis >=  interval_two) {
    previous_ER_Millis = currentMillis;
    if (val1 + val2 < 500 )
      digitalWrite(reverse, HIGH);
    else digitalWrite(reverse, LOW);


  }


  lcd.setCursor(1, 0);  // set cursor to column 0, row 0 (first row)
  lcd.print("West=");
  lcd.print(val1);
  lcd.setCursor(1, 1);
  lcd.print("East=");
  lcd.print(val2);

  Serial.println(analogRead(sense1Pin));
  delay(1000);
  Serial.println(analogRead(sense2Pin));
  delay(1000);
}
// end of code.

Why do you have an empty then-part (which does nothing at all):

  if ( val1 + val2 > 600);

And why are you using an expression as a statement (which does nothing at all):

  else (val1 + val2 < 500 );

Thank you for your reply MarkT. You are right those lines of code were superfluous and I have removed them, making my sketch much cleaner. But that did not resolve the conflict, the reverse with the night time threshold still only runs for 2-3 seconds, if you have any more suggestions or ideas on that particular topic I would love to hear them. I have included the cleaned up sketch.

int sense1Pin = A0; //west leds
int sense2Pin = A1; //east leds
int forward = 9; // use pin 9 for forward
int reverse = 10; // use pin 10 for reverse
int tolerance = 20;
unsigned long previous_F_Millis = 0;  // stores the value of millis() in each iteration of loop()
unsigned long previous_R_Millis = 0;
unsigned long previous_ER_Millis = 0; // will store last time motor was updated
const long interval_one = 5000; // constant won't change, interval motor run (milliseconds)
const long interval_two = 10000;
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  analogReference(DEFAULT);
  lcd.begin(16, 2);
  Serial.begin(9600);
  pinMode(forward, OUTPUT);
  pinMode(reverse, OUTPUT);
  delay(1000);
  digitalWrite(forward, HIGH);
  delay(1000);
  digitalWrite(forward, LOW);
  delay(1000);
  digitalWrite(reverse, HIGH);
  delay(1000);
  digitalWrite(reverse, LOW);
  delay(3000);
}

void loop() {

  int val1 = analogRead(sense1Pin);
  int val2 = analogRead(sense2Pin);
  unsigned long currentMillis = millis();

  if (currentMillis - previous_F_Millis >=  interval_one) {
    previous_F_Millis = currentMillis;
    if ((val1 + val2 > 600) && (val1 > val2 + tolerance))
      digitalWrite(forward, HIGH);
    else digitalWrite(forward, LOW);
  }

  if (currentMillis - previous_R_Millis >=  interval_one) {
    previous_R_Millis = currentMillis;
    if ((val1 + val2 > 600) && (val2 > val1 + tolerance))
      digitalWrite(reverse, HIGH);
    else digitalWrite(reverse, LOW);
  }

  if (currentMillis - previous_ER_Millis >=  interval_two) {
    previous_ER_Millis = currentMillis;
    if (val1 + val2 < 500 )
      digitalWrite(reverse, HIGH);
    else digitalWrite(reverse, LOW);
  }


  lcd.setCursor(1, 0);  // set cursor to column 0, row 0 (first row)
  lcd.print("West=");
  lcd.print(val1);
  lcd.setCursor(1, 1);
  lcd.print("East=");
  lcd.print(val2);

  Serial.println(analogRead(sense1Pin));
  delay(1000);
  Serial.println(analogRead(sense2Pin));
  delay(1000);
}
// end of code.

Sounds like a problem with the motor driver or power supply.
What actuator, motor driver and actuator power supply are you using?

Thank you for your response, if the problem was mechanical, electrical or related to the power supply it would manifest it’s self in all aspects of operation. The problems lies in the coding and that’s where I am looking for some assistance.

if the problem was mechanical, electrical or related to the power supply it would manifest it's self in all aspects of operation.

That is a rather foolish assumption.

I thank you for your opinion, I assure you that I have rigorously tested all the mechanical, electrical and power sources for possible faults before I concluded that it is a coding issue. If you are able to help me in that area I would be most appreciative.

It is not possible for forum members to test your code, since they all lack the mysterious hardware.

You should apply the same rigorous approach to testing the code as you did the hardware.

jremington, I gave a description of the hardware in my original post. You are being as useful as the proverbial piranha in a hot tub. I have politely asked for some help trouble shooting my coding, if you do not wish to aid in that effort, I suggest you stop leaving unhelpful comments on this post.

Helpful comment:

a H-bridge with mosfets and bjts to control a linear actuator

is an inadequate description of the hardware.

Alright, jremington, you obviously have a lot of time on your hands. The DC linear actuator is a 18" 12 volt 5 amp model using a acme screw. The power supply is a 12 volt 9 amp hour sla battery connected to a buck voltage regulator. That power goes to the arduino through another voltage regulator that provides 9 volts and 500 m amps. The h - bridge has two p- channel mosfets and two n- channel mosfets controlled by 2 NPN bi polar transistors. I hope all this hardware information helps you in finding what is wrong with the timing issue I have in the coding.

I hope all this hardware information helps you in finding what is wrong with the timing issue I have in the coding.

Hardware should be easy to check. Take the wire attached to the arduino forward pin and connect it to the arduino 5v pin and see if the motor runs in forward direction. Take the the wire attached to the arduino reverse pin and connect it to the arduino 5v pin and see if the motor runs in reverse. If the motor does not respond as expected, then you probably have hardware, wiring, or power issues.

I do not have a hardware issue, the linear actuator goes forwards and reverse just fine it is a timing issue in the coding that is the problem.

Hi.

You have found the use of serial monitor, you are sending 2 read values at the end of every iteration.
Serial monitor is a very powerful debug tool, you can find out stuff about every step in your sketch.
Use it and use it wisely.
Send a notice whenever you’re at the start of another iteration, or evenavery time you go through setup.
That will let you know how many resets have occurred.
Send a line when you start a motor movement, and another one when you’re done with that.

After you’re done debugging, you can get rid of any serial communication you do not need any longer.

I think your problem is that there is nothing that stops the “short” timers are still running even during your “long” reverse.
Your basic logic looks like:

  if (currentMillis - previous_F_Millis >=  interval_one) {
   // maybe go forward
  }
  if (currentMillis - previous_R_Millis >=  interval_one) {
   // maybe short reverse
  }
  if (currentMillis - previous_ER_Millis >=  interval_two) {
   // maybe long reverse
  }

If the last if clause decides to turn on the motor reverse (to be turned off in 10s), the OTHER if clauses are going to continue to test their stuff every 5 seconds, and one of them is likely (?) to stop the motor before the 10s is up. I’m not sure why this would happen after 2 or 3 seconds rather than 5-ish, but the timers aren’t tightly synced, so some drift if possible.

Hi westfw,
Thanks for your reply. You are absolutely correct in diagnosing that as the problem. After some tests I confirmed that the east tracking reverse code block is turning the high command to low and interfering with the east return ten second time interval. I am going to see if I can isolate the two code blocks to stop that from happening. In the mean time if you have any suggestions or ideas on how to accomplish that I would appreciate it, as my coding abilities are very limited. Thanks again.

One way might be to set the previous_xxx_millis of the other timers into the future in the long timer code,
Pxmillis = millis() + interval two;
Or something. Be sure to add comments if you do this, because it's obscure as hell, and you won't remember why you did it two months from now.

Hi westfw,
That looks like a solution, thanks, I will try it out tomorrow and post my progress.

I have come here from this Thread at the OP’s request, although I may have nothing useful to add.

@Leodoggie, I think it is time to bring us up to date with your latest version of the program and your assessment of its operation.

…R

Hi Robin2,
I have not had time to figure out and implement westfw’s millis() idea yet. But I have isolated the problem. Under east return light conditions the actuator goes in reverse but the east tracking code block turns it to low after a few seconds. To combat this I created two while loops in my updated sketch. The effect of the while loop is that while the night light level is below the threshold, east return stays in reverse indefinitely unless the threshold goes above 500, but the coding still does not let it run for the ten seconds that it is suppose to. An improvement but still not right. I have included the updated sketch.

int sense1Pin = A0; //west leds
int sense2Pin = A1; //east leds
int forward = 9; // use pin 9 for forward
int reverse = 10; // use pin 10 for reverse
int tolerance = 20;
unsigned long previous_F_Millis = 0;  // stores the value of millis() in each iteration of loop()
unsigned long previous_R_Millis = 0;
unsigned long previous_ER_Millis = 0; // will store last time motor was updated
const long interval_one = 5000; // constant won't change, interval motor run (milliseconds)
const long interval_two = 10000;
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  analogReference(DEFAULT);
  lcd.begin(16, 2);
  Serial.begin(9600);
  pinMode(forward, OUTPUT);
  pinMode(reverse, OUTPUT);
  delay(1000);
  digitalWrite(forward, HIGH);
  delay(1000);
  digitalWrite(forward, LOW);
  delay(1000);
  digitalWrite(reverse, HIGH);
  delay(1000);
  digitalWrite(reverse, LOW);
  delay(3000);
}

void loop() {

  int val1 = analogRead(sense1Pin);
  int val2 = analogRead(sense2Pin);
  unsigned long currentMillis = millis();

  if (currentMillis - previous_F_Millis >=  interval_one) {  // west tracking code block
    previous_F_Millis = currentMillis;
    if ((val1 + val2 > 600) && (val1 > val2 + tolerance))
      digitalWrite(forward, HIGH);
    else digitalWrite(forward, LOW);
  }
  {
    while (val1 + val2 > 600) {
      if (currentMillis - previous_R_Millis >=  interval_one) {  // east tracking code block
        previous_R_Millis = currentMillis;
        if ((val1 + val2 > 600) && (val2 > val1 + tolerance))
          digitalWrite(reverse, HIGH);
        else digitalWrite(reverse, LOW);
      }
      break;
    }
  }
  {
    while (val1 + val2 < 500) {
      if (currentMillis - previous_ER_Millis >=  interval_two) {  // east return code block 
        previous_ER_Millis = currentMillis;
        if  (val1 + val2 < 500)
          digitalWrite(reverse, HIGH);
        else digitalWrite(reverse, LOW);
      }
      break;
    }
  }





  lcd.setCursor(1, 0);  // set cursor to column 0, row 0 (first row)
  lcd.print("West=");
  lcd.print(val1);
  lcd.setCursor(1, 1);
  lcd.print("East=");
  lcd.print(val2);

  Serial.println(analogRead(sense1Pin));
  delay(1000);
  Serial.println(analogRead(sense2Pin));
  delay(1000);
}
// end of code.