Exiting while loop from case with bluetooth

I have another problem with my code. I have a car controlled with bluetooth that i want to drive it manually and auto, auto runs on 4 ultrasonic sensors. The problem that i have its i cannot exit the while loop, don't know how to make it work, to return to the SWITCH commands. I need the loop to take actions based on the ultrasonic sensors.

I was thinking using if command in while but sometimes it works, sometimes it doesn't work. What can i do? Basically I want to return from the loop at serial read by sending a data from bluetooth, lets say number 5 . Thanks

void loop() {
  delay(60);

  if (Serial.available() > 0) {
    comanda = Serial.read();

    switch (comanda) { 
      case 'F':
        forward();
        perie();
        break;

      case 'B':
        back();
        perie();
        break;

      case 'L':
        stanga();
        perie();
        break;

      case 'R':
        dreapta();
        perie();
        break;

      case 'A':
        while ('A')
        {
          if (Serial.available() == 5) {
            break;
            Stop();
          }
          else {
            aut();
          }
        }
    }
  }
}

to exit a loop (while, for, case etc.) use
break;Why is the while loop in there? would if work better instead? Why start a new thread for each problem? Just keep the dialog going with those who are already familiar with your project.

Yes, i know i need to use break, but how to implement it so when i go in auto mode i can exit it using data send through arduino from my mobile device?

How could I use IF command so the aut(); commands enters in a loop? Can you give a example? thanks

Aylee:
Yes, i know i need to use break, but how to implement it so when i go in auto mode i can exit it using data send through arduino from my mobile device?

How could I use IF command so the aut(); commands enters in a loop? Can you give a example? thanks

if(btBreakCommand) break; Are you able to receive bluetooth commands while inside the while loop?

You will never ever get to Stop(); if the case is 'A'.

I'm going to weigh in here on your switch case.... I just said earlier today in another post in another thread on this forum that I personally never take an input into the switch for a switch-case. I think you would be better served to have your commands in a if-else block of code. Leave switch-case arguments specifically for state machines.

Generally speaking if you need to break out of a WHILE loop then you should not be using a WHILE loop.

Just allow loop() to do the repetition - that's what it's for.

Why not just have a CASE statement for '5' ?

...R

Robin2:
Generally speaking if you need to break out of a WHILE loop then you should not be using a WHILE loop.

Just allow loop() to do the repetition - that's what it's for.

Why not just have a CASE statement for '5' ?

...R

Could you give me an example? I'm not so advanced in Arduino, just started it.

I need to loop only the void aut(); command and i want to exit it when i want to go in manual mode againd.

Here's a rough example of what I mean by separating inputs from cases...

char btCommand;
enum RobotState : char {RobotStopped = 0, RobotForward = 1, RobotBack = 2, RobotLeft = 3, RobotRight = 4, RobotAutoPilot = 5};
RobotState robotSwitch = RobotStopped;

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:
  decodeBluetooth();
  stateMachine();
}

void decodeBluetooth() {
  //do whatever it takes to get the ASCII commands from bluetooth and validate them as a complete and valid protocol....
  // update btCommand when valid command is received.
}

void stateMachine() {
  switch (robotSwitch) {
    case RobotStopped: {
        if (btCommand == 'F') {
          //whatever you need to do "immediately"
          robotSwitch = RobotForward;
        }
        else if (btCommand == 'B') {

        }
        else if (btCommand == 'L') {

        }
        else if (btCommand == 'R') {

        }
        else if (btCommand == 'A') {

        }
        else if (btCommand == 'S');//already stopped. do nothing.
        break;
      }
    case RobotForward: {

        break;
      }
    case RobotBack: {

        break;
      }
    case RobotLeft: {

        break;
      }
    case RobotRight: {

        break;
      }
    case RobotAutoPilot: {

        break;
      }
  }
}

Ugh... it's kind hard for me to understand, it's too much for my mind xD. I will post all the code of my program, maybe someone will figure it out what could I do.

I have a Stop button too on my mobile device, so when i press it i want the car to stop completely and do nothing.

For controlling the engines i use l293d shield if it helps

It's hard to understand because english it's not my native language and it's hard to translate

L.E. I think i've understanded what you did there, separate input from cases. I will try tommorow this. And if i go to manual mode, it will stop from looping? if using separate input from cases?

#include <AFMotor.h> 
#include <NewPing.h> 


AF_DCMotor motor3(3);
AF_DCMotor motor4(4); 
AF_DCMotor motor1(1); 
AF_DCMotor motor2(2);



#define MAX_DISTANCE 10000 

NewPing sonar[4] = {
  NewPing(A0, A0, MAX_DISTANCE), //sonar 0 --- STANGA
  NewPing(A1, A1, MAX_DISTANCE), //sonar 1 --- DREAPTA
  NewPing(A2, A2, MAX_DISTANCE), //sonar 2 --- JOS
  NewPing(A3, A3, MAX_DISTANCE)  //sonar 3 --- INAINTE
};


char comanda; 



void setup() {
  Serial.begin(9600);
  delay(5000);
  motor3.setSpeed(180);
  motor3.run(RELEASE);
  motor4.setSpeed(160);
  motor4.run(RELEASE);
  motor1.setSpeed(10);
  motor1.run(RELEASE);
  motor2.setSpeed(10);
  motor2.run(RELEASE);
}


void loop() {
  delay(60);

  if (Serial.available() > 0) {
    comanda = Serial.read();
    Stop(); 

    switch (comanda) { 
      case 'F':
        forward();
        perie();
        break;

      case 'B':
        back();
        perie();
        break;

      case 'L':
        stanga();
        perie();
        break;

      case 'R':
        dreapta();
        perie();
        break;

      case 'A':
        while ('A')
        {
          if (Serial.available() == 5) {
            break;
            Stop();
          }
          else {
            aut();
          }
        }
    }
  }
}

void forward()
{
  motor3.setSpeed(180);
  motor4.setSpeed(160); // corectie pentru a putea merge cat mai drept
  motor3.run(FORWARD);
  motor4.run(FORWARD);
}

void back()
{
  motor3.setSpeed(180);
  motor4.setSpeed(160);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
}

void stanga()
{
  motor3.setSpeed(180);
  motor4.setSpeed(180);
  motor3.run(BACKWARD);
  motor4.run(FORWARD);
}

void dreapta()
{
  motor3.setSpeed(180);
  motor4.setSpeed(180);
  motor3.run(FORWARD);
  motor4.run(BACKWARD);
}

void Stop()
{
  motor3.setSpeed(0);
  motor3.run(RELEASE);
  motor4.setSpeed(0);
  motor4.run(RELEASE);
  motor1.setSpeed(0);
  motor1.run(RELEASE);
  motor2.setSpeed(0);
  motor2.run(RELEASE);
}

void perie()
{
  motor1.setSpeed(10);
  motor1.run(BACKWARD);
  motor2.setSpeed(10);
  motor2.run(FORWARD);
}

void aut()  {


  if (sonar[3].ping_cm() > 10) {
    forward();
  }
  else {
    Stop();
    back();
    delay(300);
    dreapta();
    delay(300);
  }

  if (sonar[2].ping_cm() > 20) {
    Stop();
    back();
    delay(500);
    dreapta();
    delay(500);

  }

  if (sonar[1].ping_cm() < 9) {
    Stop();
    back();
    delay(500);
    stanga();
    delay(500);
  }

  if (sonar[0].ping_cm() < 9) {
    Stop();
    back();
    delay(500);
    dreapta();
    delay(2000);
  }
}

Aylee:
Ugh... it's kind hard for me to understand, it's too much for my mind xD.

If you send 'L' from your bluetooth, do you want to do stanga() and prairie() only once? Or, do you want to do them until 'R' or 'A' is received? if only once, R, L, F and B are not really cases, and should be handled by if statements and A is the default (and only) state. If you want to do them until the next command is received, then you need to remain in the case, but you must do all your calls, receive serial included, within that case. Your headache is that you do not understand the difference between a conditional branch and a state machine.

Perehama:
If you send 'L' from your bluetooth, do you want to do stanga() and prairie() only once? Or, do you want to do them until 'R' or 'A' is received? if only once, R, L, F and B are not really cases, and should be handled by if statements and A is the default (and only) state. If you want to do them until the next command is received, then you need to remain in the case, but you must do all your calls, receive serial included, within that case. Your headache is that you do not understand the difference between a conditional branch and a state machine.

No, I want stanga() and perie() to run continously till another command it's received. I want to do the same thing with 'A' command if possible.

All commands I want them to run continously till another command is received through bluetooth.

Perehama:
Newsflash! case IS a while statement.... you have to figure out how to exit case R,L,B,F and A, and it's all going to be the same way, and you can do different things in each. But, you can't receive serial data unless you do it from within the case. Hence, you should not base your switch on data.

How it comes it only does a thing from the void aut(); if it's a while statement? I want the aut(); to loop through the IF's all the time, to get informations from sensors.

So, i cannot do anything to run as i like? Ugh...

Aylee:
No, I want stanga() and perie() to run continously till another command it's received. I want to do the same thing with 'A' command if possible.

Newsflash! case IS a while statement.... you have to figure out how to exit case R,L,B,F and A, and it's all going to be the same way, and you can do different things in each. But, you can't receive serial data unless you do it from within the case. Hence, you should not base your switch on data.

Aylee:
So, i cannot do anything to run as i like? Ugh...

Ok, give me a bit of time to fix it. i will work on it and post maybe tomorrow.

Perehama:
Ok, give me a bit of time to fix it. i will work on it and post maybe tomorrow.

Oh, thank you, hope you can do something. I need to do this as my final exam and it kinda gives me headaches, today i worked on it 10 hours. First i had problems with the ultrasonic sensors, now this ...

Perehama:
Newsflash! case IS a while statement....

NOPE.

SWITCH / CASE is a special (limited) type of IF / ELSE

...R

Robin2:
NOPE.

SWITCH / CASE is a special (limited) type of IF / ELSE

...R

I've misunderstood. Thanks, Robin.

Perehama:
Ok, give me a bit of time to fix it.

Here's what I think you are trying to do... Not sure why the delay and stop commands are in your loop, but I know I've gotten you close...

#include <AFMotor.h>
#include <NewPing.h>

enum Starea : char {MergiInainte = 0, MergetiInapoi = 1, ViratiLaStanga = 2, ViratiDreapta = 3, Autonom = 4, Opri = 5};
Starea comanda = Opri;

const unsigned int DISTANTA_MAXIMA =  10000;
unsigned long intervalDeTimp;

AF_DCMotor motor3(3);
AF_DCMotor motor4(4);
AF_DCMotor motor1(1);
AF_DCMotor motor2(2);


NewPing sonar[4] = {
  NewPing(A0, A0, DISTANTA_MAXIMA), //sonar 0 --- STANGA
  NewPing(A1, A1, DISTANTA_MAXIMA), //sonar 1 --- DREAPTA
  NewPing(A2, A2, DISTANTA_MAXIMA), //sonar 2 --- JOS
  NewPing(A3, A3, DISTANTA_MAXIMA)  //sonar 3 --- INAINTE
};

void setup() {
  Serial.begin(9600);
  delay(5000);
  motor3.setSpeed(180);
  motor3.run(RELEASE);
  motor4.setSpeed(160);
  motor4.run(RELEASE);
  motor1.setSpeed(10);
  motor1.run(RELEASE);
  motor2.setSpeed(10);
  motor2.run(RELEASE);
}


void loop() {
  primiComanda();
  if (millis() >= intervalDeTimp) {// evita utilizarea delay(60) care blocheaza primirea comanda
    intervalDeTimp += 60UL;
    stareaRobotului();
  }
}

void primiComanda() {
  if (Serial.available() > 0) {
    char c = Serial.read();
    if (c == 'F') comanda = MergiInainte;
    else if (c == 'B') comanda = MergetiInapoi;
    else if (c == 'L') comanda = ViratiLaStanga;
    else if (c == 'R') comanda = ViratiDreapta;
    else if (c == 'A') comanda = Autonom;
    else if (c == 'S') comanda = Opri;
  }
}

void stareaRobotului() {
  switch (comanda) {
    case MergiInainte: {
        forward();
        perie();
        break;
      }
    case MergetiInapoi: {
        back();
        perie();
        break;
      }
    case ViratiLaStanga: {
        stanga();
        perie();
        break;
      }
    case ViratiDreapta: {
        dreapta();
        perie();
        break;
      }
    case Autonom: {
        aut();
        break;
      }
    case Opri: {
        Stop();
        break;
      }
  }
}

void forward()
{
  motor3.setSpeed(180);
  motor4.setSpeed(160); // corectie pentru a putea merge cat mai drept
  motor3.run(FORWARD);
  motor4.run(FORWARD);
}

void back()
{
  motor3.setSpeed(180);
  motor4.setSpeed(160);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
}

void stanga()
{
  motor3.setSpeed(180);
  motor4.setSpeed(180);
  motor3.run(BACKWARD);
  motor4.run(FORWARD);
}

void dreapta()
{
  motor3.setSpeed(180);
  motor4.setSpeed(180);
  motor3.run(FORWARD);
  motor4.run(BACKWARD);
}

void Stop()
{
  motor3.setSpeed(0);
  motor3.run(RELEASE);
  motor4.setSpeed(0);
  motor4.run(RELEASE);
  motor1.setSpeed(0);
  motor1.run(RELEASE);
  motor2.setSpeed(0);
  motor2.run(RELEASE);
}

void perie()
{
  motor1.setSpeed(10);
  motor1.run(BACKWARD);
  motor2.setSpeed(10);
  motor2.run(FORWARD);
}

void aut()  {


  if (sonar[3].ping_cm() > 10) {
    forward();
  }
  else {
    Stop();
    back();
    delay(300);
    dreapta();
    delay(300);
  }

  if (sonar[2].ping_cm() > 20) {
    Stop();
    back();
    delay(500);
    dreapta();
    delay(500);

  }

  if (sonar[1].ping_cm() < 9) {
    Stop();
    back();
    delay(500);
    stanga();
    delay(500);
  }

  if (sonar[0].ping_cm() < 9) {
    Stop();
    back();
    delay(500);
    dreapta();
    delay(2000);
  }
}

Perehama:
Here's what I think you are trying to do... Not sure why the delay and stop commands are in your loop, but I know I've gotten you close...

Nice, I will try it when i get home from work.

The delay was for the ultrasonic sensors, they need at least 60ms to have a good measurment.

Hope it works. Thank you very much for your time and effort! I really, really apreciate it! And thanks for the goolge translate ^^

L.E. Whoaaaaaaa, it works like a charm, THANK YOU SO MUCH! This community is awesome. If it weren't you I probably still looking how to exit the while loop xD. thank you thank you!

Aylee:
The delay was for the ultrasonic sensors, they need at least 60ms to have a good measurment.

I know you've probably put this all behind you now, but for future reference, move the non-blocking delay code into the aut() function for the sensors, and you can use the same delay code where it's at for a speed adjustment.