Default state not working in Switch-case sketch

The project: Two motors controlled by H-Bridge and Pro Micro, using HC12 communication.
The hardware: Receiver: Two motors controlled by H-Bridge and Pro Micro, using HC12 communication. Transmitter: Nano, joystick, and HC12
Expected results: Moving the joystick to any of the 4 quadrants, on X and Y axes should more the motors (for a robot) in particular way.
What happens: Motors react as they should- for the most part - but I cannot get them to stop when the joystick is a idle (center).
Software: For this version, I'm trying create a state machine, using Switch-case statements. Each of the 4 conditions, Forward, Reverse, Left and Right is a case. At the end is a default case if none of the 4 conditions are valid. I'm expecting the motors to stop when none of the cases are valid, ie at idle position, but they continue to run and will change direction at my command.
What I've tried: I tried putting some While and Do-While commands and also the motor stop commands inside the cases but this did not work. In another version I use IF conditionals also with limited success.


   //   ****Good speed and control but cannot make motors stop 

#define Left_PWM 5     // pin 5 Left Motor   A1A  //recommended is 1A=speed (PWM)
#define LeftDir 3      // pin 3              A1B  // 1B=direction
#define Right_PWM 9    // pin 9 Right motor  B1A  //recommended is 1A=speed (PWM)
#define RightDir 6     // pin 6              B1B  // 1B=direction
#define DIR_DELAY 250  // brief delay for abrupt motor changes
//#define SetHC12 8      // HC12 configuration pin  low to activate

#include "SerialTransfer.h"
SerialTransfer myTransfer;

struct STRUCT {
  int x;
  int y;
} testStruct;

int xAxis = 0;
int yAxis = 0;
int c = 0;                     //case number
int PWM_Slow = 50;             //min PWM value that moves motors
int PWM_Fast = 200;            //max PWM value  max is 255
int deadband = 20;             //deadband for around center stick
int XCenter = 514;             //these are idle values   514 for Joy on Nano
int YCenter = 499;             // 499 for joy on Nano
int Xlo = XCenter - deadband;  //20 is deadband, amount off center
int Xhi = XCenter + deadband;
int Ylo = YCenter - deadband;  //i.e. 498-30=468
int Yhi = YCenter + deadband;

//************************** Setup ********************************************
void setup() {
  pinMode(Left_PWM, OUTPUT);
  pinMode(LeftDir, OUTPUT);
  pinMode(Right_PWM, OUTPUT);
  pinMode(RightDir, OUTPUT);
  Serial1.begin(19200);
  Serial.begin(19200);
  myTransfer.begin(Serial1);
}
//*************************** Loop ********************************************
void loop() {

  if (myTransfer.available()) {
    // keeps track of how many bytes processed from the receive buffer
    uint16_t recSize = 0;
    recSize = myTransfer.rxObj(testStruct, recSize);

    Serial.print(testStruct.x);
    Serial.print(" | ");
    Serial.println(testStruct.y);
    xAxis = testStruct.x;
    yAxis = testStruct.y;
  }
  

   if(yAxis >= Yhi) { // Stick down= 1022
    c = 1;
  }
   if (yAxis <= Ylo) { // Stick up= 0
    c = 2;
  }
  if (xAxis <= Xlo) { // X Left= 0
    c = 3;
  }
  if (xAxis >= Xhi) { //X Right=1022
    c = 4;
  }

  
  switch (c) {
    case 1:  //Motors Reverse   Stick down=1022
      digitalWrite(LeftDir, LOW);
      digitalWrite(RightDir, LOW);
      analogWrite(Left_PWM, PWM_Fast);
      analogWrite(Right_PWM, PWM_Fast);
       break;
    
      //******************Forward*********************  Stick up Y=0
    case 2:  // Motors Forward
      digitalWrite(LeftDir, HIGH);
      digitalWrite(RightDir, HIGH);
      analogWrite(Left_PWM, PWM_Fast);   //
      analogWrite(Right_PWM, PWM_Fast);  //
      break;

    // X-axis used for left and right control
    //*******************turn LEFT*******************  X left=0
    case 3:
      digitalWrite(LeftDir, HIGH);
      digitalWrite(RightDir, HIGH);
      analogWrite(Left_PWM, PWM_Slow);
      analogWrite(Right_PWM, PWM_Fast);
      break;

      //*******************turn Right******************** x right=1022
    case 4:
      digitalWrite(LeftDir, HIGH);
      digitalWrite(RightDir, HIGH);
      analogWrite(Left_PWM, PWM_Fast);
      analogWrite(Right_PWM, PWM_Slow);
      break;

    default:
      digitalWrite(LeftDir, LOW);
      digitalWrite(Left_PWM, LOW);
      digitalWrite(RightDir, LOW);
      digitalWrite(Right_PWM, LOW);
      break;
  } //end switch
}  //end loop

Once you assign a number from 1-4 to variable 'c', there exists no code to set it to any other value. Thus there is nothing to "default" to...

suggest

  c = something_else;
  if(yAxis >= Yhi) { // Stick down= 1022
    c = 1;
  }
   if (yAxis <= Ylo) { // Stick up= 0
    c = 2;
  }
  if (xAxis <= Xlo) { // X Left= 0
    c = 3;
  }
  if (xAxis >= Xhi) { //X Right=1022
    c = 4;
  }

You have to reset the variable to a value that will be in default.

Otherwise, it retains the value from the last time any of your if statements set it.

Just do that after you switch/case, before the next pass through the loop.

a7

In order for the default case to be activated then the value of c has to be outside of the range 1 to 4.

Where in the sketch, other than when it is declared, is c set to such a value ?

Also, I see you've programmed some dead bands, that is good.

You may find in practice that using an analog joystick as essentially four switches it woukd operate a bit better if those no-action regions were somewhat larger.

a7

The diagonal corners may not behave as users expect.

Also also, the addition of one Serial.println() just before the switch/case statement

  Serial.println(c);

would have instantly shown you the sticky nature of that variable and solve, or at least hand you a huge clue to solving, your problem.

a7

1 Like

I thought it was "automatic", that if none of the cases were valid, it would automatically go to the default case. No?

Yes, but you are continuously feeding the switch statement only numbers from 1-4. Print it out, as suggested.

But it doesn't...I think. Here's a screen print of the values coming in from the transmitter while the joystick is at center. (X on left, Y on right)
image
So I'm checking above and below those values with the IF statements. If it doesn't fit, it goes to default. Do I need a 5th state? Will try the print statement.

Yes, you do. I posted it.

I started with the analog resistor type joystick when I had a previous sketch that varied the speed according to the resistance, but I realized that was overkill for this little jobbie, so I elected to go with on-off (max speed or off), but keep the joystick.

Wow! Thanks Arrg. I made c=5, ran it and everything is working exactly as I planned. Thanks other guys too, knowledge is never wasted.
This entry can be closed.
I wrote about 500 words, but it was only one word to fix the problem. What irony!

I've done that. With return-to-center springs maybe that relatively short throw to action is OK. I know I'd find it a bit too prone to action with my thumbs on the sticks.

Always just sayin'.

a7

I was using one of those Arduino-type 5-pin joysticks for testing but the final result has to work with my wireless Nunchuk. I junked the Nunchuk innards and replaced with components to talk to my robot. I like the Nunchuk because it is one-hand operation. Resistor values slightly different but the code will compensate for that.

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