Reading a sensor value only once an input is changed

Hi everyone,

I’m trying to write a function that takes care of Cruise Control in my RC car.

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : initial speed
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1600){
    s[0] = CH3; 
  }
  if (s[0] >= 1000){
    s[1] = s[0]; 
    ESC.write(s[1]);
  }
  if (s[1] != s[2]){ 
  s[2] = s[1];
  }
  
}

So, I read the channel that is serving as throttle once the function is called.

  // Drive    
     if (CH3 != deadzoneA){
      DRIVE();
     }else{
      ESC.write(108);
     }
     if(CH2 != deadzoneB && CH2 > 1400){
      cruiseControl();
     }

The problem that I’m having is: when the function is called everything stops until I push the reset button.

It’s suppoes to store the readings in s[0] and checks it against the minimum throttle that the car needs to start moving. Then that value is stored in s[1] which sends it to the ESC unit in the car. After that, it checks if the value is changed since that last time and updates s[2].

There must be something horribly wrong for this not to work.

Here is the whole code:

//Adding Servo & NewPing libraries
  #include <Servo.h>
  #include <NewPing.h>
//Pin connections to RC Receiver
  #define CH1Pin 12
  #define CH2Pin 11
  #define CH3Pin 10
  #define CH4Pin 9
  #define CH5Pin 8
  #define CH6Pin 7
//Pin connection to Ultrasonic sensor and the range
  #define TRIGGER_PIN  4
  #define ECHO_PIN     5
  #define MAX_DISTANCE 200
//Variables to store middle position of joysticks
  int deadzoneA= 0;
  int deadzoneB= 0;
// Chanel stat1 vals
  unsigned long CH1;
  unsigned long CH2;
  unsigned long CH3;
  unsigned long CH4;
  unsigned long CH5;
  unsigned long CH6;
// variable used in the "chst_cut" to store 
  int chst_1;
// creating  servo objects
  Servo servo;
  Servo ESC;
//creating sonar object
  NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
//variables used to store the value being written to Servo objects
  int x;
  int y;
//micro seconds from trig
  int uS;
//variable to hold distance in cm
  int distance;
// Function to round and stabilise the readings from receiver
float chst_cut(int b){
  chst_1 = b/100;
  chst_1 = round (chst_1);
  chst_1 = chst_1 * 100;
  return chst_1;
}
//Á variable to hold the range 
int autonomous; 

void setup() {
//Setting the pin connection types
  pinMode(CH1Pin, INPUT);
  pinMode(CH2Pin, INPUT);
  pinMode(CH3Pin, INPUT);
  pinMode(CH4Pin, INPUT);
  pinMode(CH5Pin, INPUT);
  pinMode(CH6Pin, INPUT);
// attach() is used to assign relevant pins to relevant servos
     servo.attach(2);
     ESC.attach(3);
// begining the serial communication  
Serial.begin(250000);
}

void loop() {
// pulseIn() is used to read the signals from the receiver (not the best way!!!)
     CH1 = (pulseIn (CH1Pin, HIGH));
     CH2 = (pulseIn (CH2Pin, HIGH));
     CH3 = (pulseIn (CH3Pin, HIGH));
     CH4 = (pulseIn (CH4Pin, HIGH));
     CH5 = (pulseIn (CH5Pin, HIGH));
     CH6 = (pulseIn (CH6Pin, HIGH));
// rounding 
    CH1 = chst_cut(CH1);
    CH2 = chst_cut(CH2);
    CH3 = chst_cut(CH3);
    CH4 = chst_cut(CH4);
    CH5 = chst_cut(CH5);
    CH6 = chst_cut(CH6);
//
  uS = sonar.ping_median();
  distance = uS / US_ROUNDTRIP_CM;  

// Test purposes
   x = ESC.read();   
   Serial.println(x);
   
   y = servo.read();
   Serial.println(y);  

  Serial.print("Distance = ");
  Serial.println(distance);   
  
// Printing the CH values
   Serial.print("CH1 = ");
   Serial.println(CH1);       
   Serial.print("CH2 = ");
   Serial.println(CH2);          
   Serial.print("CH3 = ");
   Serial.println(CH3);        
   Serial.print("CH4 = ");
   Serial.println(CH4);       
   Serial.print("CH5 = ");
   Serial.println(CH5);
   Serial.print("CH6 = ");
   Serial.println(CH6); 
   Serial.println();
   
// assigning values to dead zones     
  deadzoneA = 900;
  deadzoneB = 1400; 

  autonomous = 1800;
//********** DO STUFF **********\\     

/*
 * Safety feature: When transmitter is off DON'T freak out!
 */
  if (CH1 == 0 && CH2 == 0 && CH3 == 0 && CH4 == 0 && CH5 == 0 && CH6 == 0){
    ESC.write(108);
    servo.write(94);
  }else{

  // Drive    
     if (CH3 != deadzoneA){
      DRIVE();
     }else{
      ESC.write(108);
     }
     if(CH2 != deadzoneB && CH2 >= 1400){
      cruiseControl();
     }
  // Turn 
     if (CH1 != deadzoneB){
      TURN();
      }else{
      servo.write(94);
     }
  
  //Autonomous drive
    if (CH6 >= autonomous){
      AUTONOMOUS();
    }
  }
}


void DRIVE(){
//"x" is a variable tha stores the angle  
    if (CH3 != deadzoneA && CH5 == deadzoneA){
      x = map(CH3, 900, 1900, 108, 180);
      ESC.write(x);      
    } else if (CH3 != deadzoneA && CH5 != deadzoneA){
      x = map(CH3, 900, 1900, 108, 0);
      ESC.write(x);        
    }
}


void TURN(){
//"y" is a variable tha stores the angle   
    y = map(CH1, 900, 1900, 0, 180);
    servo.write(y);
}


void AUTONOMOUS(){
/*
 * This function will drive the car Autonomously
 */
//Break

 
// Drive
  /* Makes use of one Ultrasonic sensor. 
   */
  if (CH6 >= autonomous && distance <= 200 && distance > 100){
    ESC.write(180);     // 100% Throttle 
  }else if (CH6 >= autonomous && distance <= 100 && distance > 50){
    x = map(distance, 50, 100, 144, 162); 
    ESC.write(x);       // 75% Throttle
  }else if(CH6 >= autonomous && distance <= 50 && distance > 25){
    x = map(distance, 25, 50, 126, 144);
    ESC.write(x);       // 50% Throttle
  }else if (CH6 >= autonomous && distance <= 25 && distance > 10) {
    x = map(distance, 10, 25, 115, 126);
    ESC.write(x);       // 25% Throttle
  }else if (CH6 >= autonomous && distance <= 10 && distance > 5) {
    x = map(distance, 5, 10, 108, 119);
    ESC.write(x);       // 15% Throttle
  }else{
  ESC.write(108);       // 0% Throttle
  }

// Turn
  /*Makes use of two IR sensors. The sensors are placed on both sides of the car.
   *Are monitoring the set distance within the range specified.
   */
   
}

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : initial speed
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1600){
    s[0] = CH3; 
  }
  if (s[0] >= 1000){
    s[1] = s[0]; 
    ESC.write(s[1]);
  }
  if (s[1] != s[2]){ 
  s[2] = s[1];
  }
  
}

any help with this is appreciated.

  while (CH2 >= 1600)
  {
    s[0] = CH3; 
  }

Nothing in this while loop changes the value of CH2 so will the program ever exit from it ?

I thought that the CH2 is a global variable that gets written to constantly!

I've changed the function around a bit, but then i ran in the next problem: the data would not be sent to ESC constantly and if the value of CH3 changed the speed would have changed.

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : initial speed
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1600){
    s[0] = CH3; 
    CH2 = deadzoneB;
  }
  if (s[0] >= 1000){
    s[1] = s[0]; 
    ESC.write(s[1]);
  }
  if (s[1] != s[2]){ 
  s[2] = s[1];
  }
  
}

So I added the second while loop:

(Which then there is nothing to stop the while)

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : initial speed
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1600){
    s[0] = CH3; 
    CH2 = deadzoneB;
  }
  while (s[0] >= 1000){
    s[1] = s[0]; 
    ESC.write(s[1]);
  }
  if (s[1] != s[2]){ 
  s[2] = s[1];
  }
  
}

I've even gone creative and changed it to:

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : initial speed
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1600){
    s[0] = CH3; 
    CH2 = deadzoneB;
  }
  while (CH2 >= 1500){
    if (s[0] >= 1000){
      s[1] = s[0]; 
      ESC.write(s[1]);
    }
    CH2 = deadzoneB;
  } 
  if (s[1] != s[2]){ 
  s[2] = s[1];
  }
  
}

But same problem as before. By changing the CH3 value the speed sent to ESC is changed.

I feel like this function needs to return the current speed and the value must be used in the drive function or somewhere else.

I thought that the CH2 is a global variable that gets written to constantly!

Frayed knot ! Declaring a variable global means that it is available to the whole program but something still needs to change it to escape from that while loop and your program doesn't.

Stop adding while loops that the program cannot get out of.

The thread title says that you want to read a sensor value only when an input is changed. Have a look at the StateChangeDetection example in the IDE to see how to do it. Basically you save the value of an input before reading it again and compare the new reading with the previous reading. If they are different and the input is now in the state that you are interested in you take action. If not then keep going round loop() until you detect a change.

Tried to implement the example,

But the problem remains, if CH3 changes value the signal sent to ESC will change.

void cruiseControl(){
 /*where "s" is the speed variabl
  *s[0] : counter
  *s[1] : current speed
  *s[2] : previous speed
  */
  
  int s[3];
  while (CH2 >= 1500){
    s[1] = CH3;
    s[0] ++; 
    CH2 = deadzoneB;
  }  
    while (s[1] == s[2] && s[0] % 1 == 0 && CH2 == deadzoneB){
    ESC.write(s[1]);
    CH2 = (pulseIn (CH2Pin, HIGH));
    CH2 = chst_cut(CH2);
    }
    if (s[1] != s[2]){ 
    s[2] = s[1];
    CH2 = deadzoneB;
    }
  
 }

Does Arduino/C have flags that can be implemented like PLCs do? e.g If input 0 is high set flag 1 if flag 1 is on do something then reset the flag

  while (CH2 >= 1500){
    s[1] = CH3;
    s[0] ++; 
    CH2 = deadzoneB;
  }

Why use a while loop ? It looks like an if might be more useful

  if (CH2 >= 1500)
  {
    s[1] = CH3;
    s[0] ++; 
    CH2 = deadzoneB;
  }

if CH3 changes value the signal sent to ESC will change.

CH3 is not even in the code snippet that you posted.

boolean variables make good flags. Set them true or false and test them when you need to know the current state.

Can you please explain which input you want to monitor for changes and what causes the input to change value ?

I want to Set the cruise speed of the car.

CH3 is acting as the throttle in this case and CH2 is the key that sets the cruise value. In other word, when CH2 is >= 1500 the code has to read the throttle value and store it to a variable, that’s why I only want this to happen when the joystick is >= 1500. After the throttle value is read and stored in a variable the car must cruise at the set speed even if the throttle is changed. It exits the function when CH2 <= 1300.(that’s the goal!)

thanks fore the hint on bools.

Using a boolean flag would probably be the easiest way to do what you want
Something like this maybe

cruising = false
start of loop()
  read CH2
  if CH2 >= 1500 and !cruising
    read throttle value
    set speed to current throttle value
    cruising = true
  end if
  else
  if CH2 <= 1300 and cruising
    set speed to current throttle value
    cruising = false
  end if
  
  //code here to run the motor at the current speed
  
end of loop()

Thanks mate.