Looping Error, need some help Please

Hey all, my lab partner and I are working on a project for class and have hit a bit of a nasty road block.

We’re building a motor system that is connected via bluetooth to an android phone application. The app consists of 5 buttons (Primary up, Primary Down, Secondary Up, Secondary Down, and home).

when the user holds one of the buttons it sends a message to the arduino which indicated the arduino to turn on a relay. We also have rotary encoders attached to the shafts of the motors to inform the arduino how much line has been fed out of the motors. This is where we’re having an issue.

In line (35-38) there is an if statement checking to see if the Primary up function is being sent by the phone and if the encoder is past 3 inches, if so then it should turn on, if not then it shouldn’t. The actual problem is that the value “distance” doesn’t update in real time during the if statement. So if we hold the up button on the phone the LED turns on, while holding the button we twist the encoder so it will go past the 3 inch mark in hopes that the LED would shut off due to the if statement no longer being valid. However this doesn’t happen, instead the LED stays on as long as we hold the UP button. But if we let go after twisting past the 3 inch mark and then try to push again, it registers that the encoder is past the limit and won’t turn on the LED.

So the issue is that the if statement isn’t updating in real time, is there a way to make this happen?

I should note that the Encoder is registering the changes in distance, they just don’t take effect until after releasing the phones “UP” button.

Thank you for any help in this issue!

Code:

  • #include <SoftwareSerial.h>
  • #include <Encoder.h>
  • int ledPin = 8;
  • String readString;
  • SoftwareSerial BTSerial(10,11);//Rx, Tx
  • long oldPosition = -999;
  • Encoder myEnc (2, 3);
  • void setup()
  • {
  • BTSerial.begin(9600);
  • pinMode (ledPin, OUTPUT);
  • }
  • void loop()
  • {
  • long newPosition = myEnc.read();
  • if (newPosition != oldPosition)
  • {
  • oldPosition = newPosition;
  • long distance = (newPosition/2400);
  • }
  • long distance = (newPosition/2400);
  • long Maxtilt = ((distance)+20); // Maxtilt check for Secondary Motor
  • while (BTSerial.available()){
  • delay(3);
  • char c = BTSerial.read();
  • readString += c;
  • }
  • if (readString.length() >0) {
  • BTSerial.println(readString);
  • if (readString == “PUP” && (distance) >3)
  • {
  • digitalWrite(ledPin, HIGH);
  • }
  • else if (readString ==“SUP”)
  • {
  • digitalWrite(ledPin, HIGH);
  • }
  • else if (readString ==“PDOWN”)
  • {
  • digitalWrite(ledPin, HIGH);
  • }
  • else if (readString ==“SDOWN”)
  • {
  • digitalWrite(ledPin, HIGH);
  • }
  • else if (readString ==“HOME”)
  • {
  • digitalWrite(ledPin, HIGH);
  • }
  • else
  • {
  • digitalWrite(ledPin, LOW);
  • }
  • readString="";
  • }
  • }

For this sort of problem I'd always build a state machine.

regards

Allan

I'm not sure how that will change the issue I'm currently having though? It's an issue within the loop itself not the structure of the program right?

Even with a State system it would still have the issue of not updating the if statement....

Hi,

Can you please post a copy of your sketch, using code tags? Please use code tags.. See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

Thanks.. Tom........ :)

SkylineMotors: I'm not sure how that will change the issue I'm currently having though? It's an issue within the loop itself not the structure of the program right?

Even with a State system it would still have the issue of not updating the if statement....

No, with a state machine, upon receiving a command you could continue with realtime updates like reading the distance. In other words, do more than one thing at a time. You can never do that with inline nested logic.

Sorry about that, I must have missed that. on the Code Tags.

And I’ll look into the State Machine set up as well, I didn’t realize it allowed for more versatility.

Code

#include <SoftwareSerial.h>
#include <Encoder.h>
int ledPin = 8;
String readString;
SoftwareSerial BTSerial(10,11);//Rx, Tx
long oldPosition  = -999;
Encoder myEnc (2, 3);
void setup()
{
  BTSerial.begin(9600);
  pinMode (ledPin, OUTPUT);
}
void loop()
{
   
long newPosition = myEnc.read();
  if (newPosition != oldPosition)
  {
    oldPosition = newPosition;
  long distance = (newPosition/2400);
}
long distance = (newPosition/2400);
long Maxtilt = ((distance)+20); // Maxtilt check for Secondary Motor
 
  while (BTSerial.available()){
   delay(3);
  char c = BTSerial.read();
readString += c;
}
  if (readString.length() >0) {
    BTSerial.println(readString);
  if (readString == "PUP" && (distance) >3)
       {
              digitalWrite(ledPin, HIGH);
           }
       
        else if (readString =="SUP")
      {
        digitalWrite(ledPin, HIGH);
      }
       else if (readString =="PDOWN")
      {
        digitalWrite(ledPin, HIGH);
      }
        else if (readString =="SDOWN")
      {
        digitalWrite(ledPin, HIGH);
      }
        else if (readString =="HOME")
      {
        digitalWrite(ledPin, HIGH);
      }
        else
      {
        digitalWrite(ledPin, LOW);
      }
      readString="";
    }
  }

I don't think a statemachine (as it's defined in my vocabulary ;) ) makes much of a difference. The problem seems (to me) that as long as the switch on the phone is active the phone is sending data. With a little bad luck you do not even get to the 'if(readString.length > 0)'. You are also executing delays in the while loop.

I also don't seem to be able to find where you clear the data that you read from BTSerial. So your read string eventually will contain PUPPUPPUPPUP............PUPPUPPUP.

Change the way you read the data and your problem should be solved; see Serial Input Basics

sterretje: I don't think a statemachine (as it's defined in my vocabulary ;) ) makes much of a difference. The problem seems (to me) that as long as the switch on the phone is active the phone is sending data. With a little bad luck you do not even get to the 'if(readString.length > 0)'. You are also executing delays in the while loop.

I also don't seem to be able to find where you clear the data that you read from BTSerial. So your read string eventually will contain PUPPUPPUPPUP............PUPPUPPUP.

Change the way you read the data and your problem should be solved; see Serial Input Basics

You're very close in your thinking. However the bad luck that you're speaking of doesn't seem to be what's truly happening. As long as the phone button is held active then the phone is sending data to the arduino. As the data is coming in it checks the conditional if statement (ONCE) and then doesn't continue to check until after the button has been released and then pressed once again. It's almost as if the code gets stuck in a loop where it just keeps the relay high and cycles through 1 line for the loop instead of checking the conditions of the if statement.

As I've said above, the encoder actually is taking in data and updating within the code...it just doesn't send that data to the if statement unless the phone button is not active. That's my problem. And I'm not sure how to address it sadly :(.

Also, could someone suggest a good library for the state machines so I could try to see if that would help or not? I really think something just needs to change within the way I call in the bluetooth signal, but I'm just not really sure what to change to accommodate my problem. I have done research on this, that's why I'm here now and asking for help from others who may have possibly had the issue. Thank you for the input that's been given so far!

I've been suggested to change my While loop for (BTSerial.available()) into an if statement to see if that will allow for better updating. Will try this and update if it's helped or not. Unfortunately Our app we created is Android based and my partner is the one with the Android phone. I am an iPhone user (As I'm greatly disappointed that it's fairly difficult to make your own apps for IOS applications and Arduino)

 if (BTSerial.available()){
   delay(3);
  char c = BTSerial.read();
 readString += c; 
}

You should read the link that I provided instead of blind-folded trying things? It shows the right approaches for serial communication.

sterretje: You should read the link that I provided instead of blind-folded trying things? It shows the right approaches for serial communication.

I have begun reading through it. Sorry, I'm working on a time frame. I have classes, meetings, and various other things I'm all trying to juggle at once. I was given the suggestion by one of my professors so I'm not blindly trying things, I'm taking an experts (in comparison to myself) suggestion and trying it while continuing to do research on the issue. Rest assured, I'm making use of the link you sent! I'm not meaning any disrespect. I'm just thankful for the suggestions and trying them as I can.

I've found a solution to my issue! I simply had to take the Distance condition from the if statement and move it up into my Encoder's if statement so it utilizes the interrupt built into the Encoder library. Everything is working perfectly now! Thank you for the suggestions from everyone.