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
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;
-
1Please use Enum instead of "magic number"Filip Franik– Filip Franik2019年03月09日 03:57:47 +00:00Commented 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.Amir Hossein Jobeiri– Amir Hossein Jobeiri2019年03月12日 09:43:48 +00:00Commented 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– Dorian2019年03月12日 10:05:10 +00:00Commented Mar 12, 2019 at 10:05