1

I want to control a servo motor in a way that

  • if you push the button, you can control it by potentiometer a
  • if you push double time, you can control servo with infrared
  • if you hold button step motor start to to rotate from one position to another

I have a problem that when I press button it goes to an infinite loop and I can not stop it . I try different button library but I still have a same problem. Here is my code :

// includes the Servo library
#include <Servo.h>
#include <IRremote.h>
#include <OneButton.h>

int state = 0;
int RECV_PIN = 12;
const char type ='W';// W for white, B for black. Must keep single quotes like 'B' or 'W'
const boolean PCB = 0;// if receiver is PCB set to 1, if not set to 0. See video for details
boolean displayCode = true;// to display remote code. if not, set to false

const int SERVO_PIN = 8;  // analog pin used to connect the potentiometer
int angle =90;    // initial angle  for servo
int angleStep =10;
const int ANGLE_CENTRE =90;// the centre/reset angle of your servo
//**** Servo settings settings ends

// remote settings 
const String RIGHT="CH+";// move servo to the right with this key on remote
const String LEFT ="CH-";// move servo to the left with this key on remote
const String CENTRE ="CH";// move servo to centre with this key on remote
// remote settings end

IRrecv irrecv(RECV_PIN);
// Defines Tirg and Echo pins of the Ultrasonic Sensor
const int trigPin = 10;
const int echoPin = 11;
const int potPin = 0;
const int pushButton = 8;
OneButton button(A1, true);  
int value;

// Variables for the duration and the distance
long duration;
int distance_cm;
Servo myServo; // Creates a servo object for controlling the servo motor

// this is array holding codes for White Remote when used with non-PCB version of receiver            
unsigned int whiteRemote[] ={
            0xFFA25D, // CH-
            0xFF629D,   // CH
            0xFFE21D,  // CH+

            0xFF22DD, // |<<
            0xFF02FD, // >>|
            0xFFC23D, // >||          

            0xFFE01F, // -
            0xFFA857, // +
            0xFF906F, // EQ

            0xFF6897, // 0
            0xFF9867, // 100+
            0xFFB04F, // 200+

            0xFF30CF, // 1
            0xFF18E7, // 2
            0xFF7A85, // 3           

            0xFF10EF, // 4 
            0xFF38C7, // 5
            0xFF5AA5,  // 6

            0xFF42BD, // 7
            0xFF4AB5, // 8
            0xFF52AD  // 9                          
            };
// key lables of white remote
 String whiteRemoteKey[] ={
            "CH-",
            "CH",
            "CH+",

            "|<<",
            ">>|",
            ">||",

            "-",
            "+",
            "EQ",

            "0",
            "100+",
            "200+",

            "1",
            "2",
            "3",

            "4",
            "5",
            "6",

            "7",
            "8",
            "9"
            };

// this is array holding codes for Black Remote when used with non-PCB version of receiver
 unsigned int blackRemote[] ={
            0xFF629D, // ^
            0x38D3975C,   // <
            0x9334F738,  // OK
            0x320412D8, // >
            0xFFA857, // v

            0xFF6897, // 1
            0xFF9867, // 2
            0xF0C41643, // 3           

            0xFF30CF, // 4 
            0xFF18E7, // 5
            0xFF7A85,  // 6

            0xFF10EF, // 7
            0xFF38C7, // 8
            0xFF5AA5,  // 9 

            0xFF42BD, // *
            0xFF4AB5, // 0
            0xFF52AD  // #                                      
            };
// Black remote key names
 String blackRemoteKey[] ={
            "^",
            "<",
            "OK",
            ">",
            "v",

            "1",
            "2",
            "3",

            "4",
            "5",
            "6",

            "7",
            "8",
            "9",

            "*",
            "0",
            "#"
            };

decode_results results;

void setup() {
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an input
  Serial. begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  myServo.attach(SERVO_PIN); // Defines on which pin is the servo motor attached

  button.attachDoubleClick(doubleClick);            // link the function to be called on a doubleClick event.
  button.attachClick(singleClick);                  // link the function to be called on a singleClick event.
  button.attachLongPressStop(longClick);            // link the function to be called on a longpress event.

}
void loop() { 
  button.tick();                                    // check the status of the button
  delay(10);                                        // a short wait between checking the button
}

// Function for calculating the distance measured by the Ultrasonic sensor
int calculateDistance(){ 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  // Sets the trigPin on HiGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
  //Comment by me!
  //distance= duration*0.034/2;
  //
  distance_cm = (duration/2) / 29.1;
  return distance_cm;
}
void doubleClick() {                                // what happens when button is double-clicked
  while(1) {
    if (irrecv.decode(&results)) {
      if(displayCode)Serial.println(results.value, HEX);
      validateCode(results.value);// used the "robojaxValidateCode" bellow
      irrecv.resume(); // Receive the next value
    }
    delay(50);// 50 melisecond delay
    break;
  }
}

void singleClick(){                                 // what happens when the button is clicked
  while(1) {
    value = analogRead(potPin);
    value = map(value, 0, 1023, 15, 165);
    myServo.write(value);
    delay(30);
    distance_cm = calculateDistance();

    Serial.print(value); // Sends the current degree into the Serial Port
    Serial.print(","); // Sends addition character right next to the previous value needed later in the Processing iDE for indexing
    Serial.print(distance_cm); // Sends the distance value into the Serial Port
    Serial.print("."); // Sends addition character right next to the previous value needed later in the Processing iDE for indexin
  }
}

void longClick(){                                   // what happens when buton is long-pressed
  for(int i=15;i<=165;i++){ 
    myServo.write(i);
    delay(30);
    distance_cm = calculateDistance();// Calls a function for calculating the distance measured by the Ultrasonic sensor for each degree

    Serial.print(i); // Sends the current degree into the Serial Port
    Serial.print(","); // Sends addition character right next to the previous value needed later in the Processing iDE for indexing
    Serial.print(distance_cm); // Sends the distance value into the Serial Port
    Serial.print("."); // Sends addition character right next to the previous value needed later in the Processing iDE for indexin
  }
  // Repeats the previous lines from 165 to 15 degrees
  for(int i=165;i>15;i--){
    myServo.write(i);
    delay(30);
    distance_cm = calculateDistance();

    Serial.print(i);
    Serial.print(",");
    Serial.print(distance_cm);
    Serial.print("."); 
  }
}
/*
 * function: validateCode
 * validates the remote code and prints correct key name
 * cd is code poassed from the loop
 * Written by A. S. for Robojax
 */
void validateCode(int cd)
{

  // Robojax IR Remote decoder
  int found=0;

 if(type =='W' && !PCB)
 {
    // Robojax IR White Remote decoder
    // if tyepe is set to 'W' (white remote) and PCB=0 then check Black remote code
      for(int i=0; i< sizeof(whiteRemote)/sizeof(int); i++)
      {
        if(whiteRemote[i] ==cd)
        {

          Serial.print("Key pressed:");
          Serial.println(whiteRemoteKey[i]);
          servoAction(whiteRemoteKey[i]);// take action
          found=1;
        }// if matched
      }// for
 }else{

      // if tyepe is set to 'B' (black remote) and PCB =0 then check Black remote code
       for(int i=0; i< sizeof(blackRemote)/sizeof(int); i++)
      {
        // Robojax IR black Remote decoder
        if(blackRemote[i] ==cd)
        {

          Serial.print("Key pressed:");
          Serial.println(blackRemoteKey[i]);
          servoAction(blackRemoteKey[i]);// take action          

          found=1;
        }// if matched
      }// for  
 }// else
  if(!found){
    if(cd !=0xFFFFFFFF)
      {
    Serial.println("Key unkown");
      }
  }// found
}// validateCode end

/*
 * 
 * servoAction()
 * receives string "value" as input and based on the settings, 
 * sends translates it to servo value and controls servo
 * either 
 * rotates servo to right
 * rotates servo to left
 * moves the servo to middle
 * 
 */
void servoAction(String value){
  // Servo button demo with IR remote by Robojax.com
  while(value == RIGHT){

    if (angle > 0 && angle <= 180) {
      angle = angle - angleStep;
       if(angle < 0){
        angle = 0;
       }else{
      myServo.write(angle); // move the servo to desired angle
      Serial.print("Moved to: ");
      Serial.print(angle);   // print the angle
      Serial.println(" degree");
       }
    }// if
    value =".";
    delay(100);
  }// while for RIGHT
  while(value == LEFT){

    // Servo button demo with IR remote by Robojax.com
    if (angle >= 0 && angle <= 180) {
      angle = angle + angleStep;
      if(angle >180){
        angle =180;
       }else{
      myServo.write(angle); // move the servo to desired angle
      Serial.print("Moved to: ");
      Serial.print(angle);   // print the angle
      Serial.println(" degree");
       }
    }
    value =".";
    delay(100);
  }// while for LEFT

  if(value == CENTRE)
  {
    angle = ANGLE_CENTRE;
    myServo.write(angle); // move the servo to centre at 90 degree angle
  }
    // Robojax IR Servo control
}//relayAction end

sorry about my English. I hope someone help me.

1 Answer 1

0

You have infinite loops in the click event call functions, after a button event you never return to the main loop.

Use the event functions just to set a status variable then, in the main loop use switch case case to select the code used by the servo control like this:

 ....
 unsigned int status = 0;
 ....
 void doubleClick(){
    status = 0;
 }
 void singleClick(){
    status = 1;
 }
 void longClick(){
    status = 2;
 }
 void setup() {
 ....
 }
 void loop {
   button.tick();                                    // check the status of the button
   //delay(10); // this is not needed.    
   switch (status){
     case 0:{
       //action for double click 
     } 
     case 1:{
       //action for single click 
     } 
     case 2:{
       //action for long click 
     } 
 }

Inside each case insert the corresponding code code you have in the while(1) loops of the button event functions.

Another option is to insert inside the forever loops a return when the button is pressed like this:

if (button pressed) return;

3
  • 1
    Please use Enum instead of "magic number" Mar 9, 2019 at 3:57
  • Thanks for your answer.But I need that action happen infinitely until the status of the button change from for example single push to double push .when I use if statement It does not work properly. Mar 12, 2019 at 9:43
  • @AmirHosseinJobeiri The while(1) loop is replaced by the main loop so it is happening forever until you press the button and change the status variable. Or just use return on button pressed inside while(1) loop but it is quite difficult to extend your code further.
    – Dorian
    Mar 12, 2019 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.