[SOLVED] Delay elongation problem while activating relay wirelessly

Hey guys!
I am new to this forum and needed help with my project. My aim is to switch On/Off 2 DC motors and change their direction on command wirelessly. I don’t need speed control, hence using relays.

Parts used on TX side:

  • Arduino Nano
  • XBee S2C module
  • 9V Battery
  • Matrix style button module for inputs.

Parts used on RX side:

  • Arduino Uno
  • XBee S2C module
  • 4 channel relay board (5V activated, fires on LOW)
  • 2 x 12V DC Motors
  • 12V, 5Ah battery

Here is the code, it uses the Button library (https://github.com/JChristensen/Button).

Transmitter side code:

#include <Button.h> //https://github.com/JChristensen/Button
const int BTN_EXTENDCLUTCH = 4;// CLUTCH MOTOR // A signal  
const int BTN_RETRACTCLUTCH = 5;// CLUTCH MOTOR // B signal
const int BTN_EXTEND1 = 6; // // BRAKE MOTOR
const int BTN_EXTEND2 = 7;   //INITIALIZATION
const int BTN_EXTEND3 = 8;
const int BTN_EXTEND4 = 9;
const int BTN_RETRACTBRAKE = 10;
#define DEBOUNCE_MS 20
#define PULLUP true
#define INVERT true
Button btnExtendclutch(BTN_EXTENDCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);
Button btnRetractclutch(BTN_RETRACTCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend1(BTN_EXTEND1, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend2(BTN_EXTEND2, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend3(BTN_EXTEND3, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend4(BTN_EXTEND4, PULLUP, INVERT, DEBOUNCE_MS);
Button btnRetractbrake(BTN_RETRACTBRAKE, PULLUP, INVERT, DEBOUNCE_MS);

void setup() {
Serial.begin(9600);
}

void loop() {
btnExtendclutch.read();
btnRetractclutch.read();
btnExtend1.read();
btnExtend2.read();
btnExtend3.read();
btnExtend4.read(); 
btnRetractbrake.read();

if (btnExtendclutch.isPressed()) {  // Pin 4
Serial.print("A");
}
//if (digitalRead(BTN_RETRACTCLUTCH) == LOW) { // Pin 5
if (btnRetractclutch.isPressed()) {
Serial.print("B");
}
if (btnExtend1.isPressed()) {//Pin 6
Serial.print("C");
}
if (btnExtend2.isPressed()) {  // Pin 7
Serial.print("D");
}
if (btnExtend3.isPressed()) {  // Pin 8
Serial.print("E");
}
if (btnExtend4.isPressed()){  // Pin 9
Serial.print("F");
}
if (btnRetractbrake.isPressed()) {  // Pin 10
Serial.print("G");
}
}

Receiver side code:

const int RELAY[] = {5,6,7,8};

void setup() {
pinMode(RELAY[0], OUTPUT);
pinMode(RELAY[1], OUTPUT);
pinMode(RELAY[2], OUTPUT);
pinMode(RELAY[3], OUTPUT);
Serial.begin(9600);
}

void loop() 
{
if(Serial.available() > 0)
    {
    char ltr = Serial.read();
    if(ltr == 'A')// Clutch motor, coming from Pin 4
   {
        extendActuator1();
}
    if(ltr == 'B')// Clutch Motor, coming from Pin 5
   {
        retractActuator1();
        
}
    if(ltr == 'C')  // Brake Motor, coming from Pin 6
    {
        digitalWrite(RELAY[1], LOW);// LOW = ON
        digitalWrite(RELAY[0], HIGH); // HIGH = OFF
        delay(1000);
        digitalWrite(RELAY[1], HIGH);
       
    }
    if(ltr == 'D')  // Brake Motor, coming from Pin 7
    {
        digitalWrite(RELAY[1], LOW);// ON
        digitalWrite(RELAY[0], HIGH);// OFF
        delay(1200);
        digitalWrite(RELAY[0], HIGH);// OFF
        digitalWrite(RELAY[1], HIGH);// ON
    }
    if(ltr == 'E')  // Brake Motor, coming from Pin 8
        {
        digitalWrite(RELAY[1], LOW);// ON
        digitalWrite(RELAY[0], HIGH);// OFF
        delay(1500);
        digitalWrite(RELAY[0], HIGH);// OFF
        digitalWrite(RELAY[1], HIGH);// ON
    }
   if(ltr == 'F')  // 
        {
        extendActuator();//
        }
   if(ltr == 'G')// 
        {
        retractActuator();
        }
}
}
void extendActuator() {
  //Serial.println("extendActuator");
  digitalWrite(RELAY[1], LOW);
  digitalWrite(RELAY[0], HIGH);
}
void retractActuator() {
  //Serial.println("retractActuator");
  digitalWrite(RELAY[0], LOW);
  digitalWrite(RELAY[1], HIGH);
}
void extendActuator1() {
  //Serial.println("extendActuator");
  digitalWrite(RELAY[2], LOW);
  digitalWrite(RELAY[3], HIGH);
}
void retractActuator1() {
  //Serial.println("retractActuator");
  digitalWrite(RELAY[3], LOW);
  digitalWrite(RELAY[2], HIGH);
}

I have checked that:

  • The code itself works well and the relays work perfectly.
  • Both XBee modules are configured in AT mode, one as Coordinator, other as End Device(X-CTU chat was successful). Xbees are sending and receiving well.

Problems:
When I test this code with both Uno and Nano circuits attached to PC via USB and send A,B,C commands etc. via keyboard the delay time is accurate (1000, 1200 and 1500 ms). But if I do the same with the buttons on my button module, each delay is AMPLIFIED.
I have tried this 5-6 times. Still, this problem persists.

What could be the reason? Is the code itself correct? And if not that, then does it have to be with debounce time ?

Thanks for your consideration.

P.S. I have tried very short delays too (20,30 and 40 ms). Still they are amplified by 4-6 times(when using buttons), NOT with PC keys.

I have no experience with XBee but I guess you have these modules connect to RX/TX on the Arduino.
The only thing I'd say there is that that limits the use of Serial.print for debug purposes. You could use SoftwareSerial for these instead.

Anyway, my first instinct would be to suspect the button debounce routine. To test this, I'd modify your Receiver code by adding one line to drop the contents of the serial buffer after receiving one character:

if(Serial.available() > 0)
    {
    char ltr = Serial.read();
    while ( Serial.available() > 0 ) { char dumpThis = Serial.read() };  // dump remaining serial buffer contents
    if(ltr == 'A')// Clutch motor, coming from Pin 4
    . . .

Hi 6v6gt, thanks for taking the time out for this issue. Currently, I am trying without XBees to simplify the circuit. Using a single wire attached from TX of Nano to RX of Uno. I tried your code:

void loop() 
{
if(Serial.available() > 0)
    {
    char ltr = Serial.read();
    while ( Serial.available() > 0 )
    {
      char dumpThis = Serial.read();
      }
    if(ltr == 'C')  // Brake Motor, coming from Pin 6
        {
        digitalWrite(RELAY[1], LOW);// LOW = ON
        digitalWrite(RELAY[0], HIGH); // HIGH = OFF
        delay(1000);
        digitalWrite(RELAY[1], HIGH);
        }

I tried this, but still the problem persists.
I have tried changing the delay to various values - as low as 1ms, till 2000ms.

For example, I tried the following code(with dumpThis):

{
        digitalWrite(RELAY[1], LOW);// LOW = ON
        digitalWrite(RELAY[0], HIGH); // HIGH = OFF
        delay(5000);
        digitalWrite(RELAY[1], HIGH);
        }

I tried this with different debounce times (20,10 ,5 and 2 ms). With PC, the delay is absolutely accurate. With button it is amplified by twice, as you can see.

debounce 20
delay(5000);
With PC: 5 seconds
With Button: 10 seconds

debounce 10
delay(5000);
With PC: 5 seconds
With Button: 10 seconds

debounce 5
delay(5000);
With PC: 5 seconds
With Button: 10 seconds

debounce 2
delay(5000);
With PC: 5 seconds
With Button: 10 seconds

Same results.
Is there something wrong with the way I am transmitting characters?

I suspect you should not be using delay() anywhere in your program because it blocks the Arduino from doing other things. Have a look at how millis() is used to manage timing without blocking in Several things at a time

Also have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

...R

Delays are generally unhealthy in code so, as Robin2 says, you should eliminate these. It is entirely plausible that these could, for example, be interfering with the debounce library functions, because these have their own time period ( defined as 20mS in your code) which, because of the delay statements, is broken up.

How are you testing the two Arduinos then if you are not using Xbee ? With connections between RX and TX ?

Hey!
Robin2: Okay, As you suggested, I am working on replacing all the delays in my code with millis() function. I will have a look at Serial Input Basics soon.
6v6gt: I am testing the Arduinos using a simple wire with connections b/w TX of Nano to RX of Uno. Working on removing the delays now.

Hey! I tried a different code snippet I found on this link(Activate a DC motor for a fixed amount of time - Arduino Stack Exchange) - 3rd code from the top, just for testing.
This is my code:

const int RELAY = {5};
long int currentMillis;
long int relayon;
void setup() {
pinMode(RELAY[0], OUTPUT);
Serial.begin(9600);
}
void loop() {
if(Serial.available() > 0)
{
char ltr = Serial.read();
if(ltr=='C'){
relayon = millis();
while(millis() != (relayon+3000)){
digitalWrite(RELAY[0], HIGH);
}
digitalWrite(RELAY[0], LOW);
}
}
}

Now the problem is: the Relay doesn't turn back on when I press the button. The button command is supposed to turn it off(HIGH) for 3 seconds and back on. It is not(with button)! But with PC, it works as usual.
Please help with this. What could be the problem? I am not using any delays, etc. I am not running any other task simultaneously...

Basically I want to run a motor for X amount of seconds when I press a button using millis(), instead of delay().

I've hacked your original receiver code to eliminate the delay statements. It was easier to change it than to explain how to change it. Here it is (untested and without guarantees) but ask if you have any questions:

const int RELAY[] = {5, 6, 7, 8};

unsigned long inWaitAtMs = 0 ;
bool inWaitC = false ;
bool inWaitD = false ;
bool inWaitE = false ;

void setup() {
  pinMode(RELAY[0], OUTPUT);
  pinMode(RELAY[1], OUTPUT);
  pinMode(RELAY[2], OUTPUT);
  pinMode(RELAY[3], OUTPUT);
  Serial.begin(9600);
}

void loop()
{


  if ( inWaitC || inWaitD || inWaitE ) {

    if ( inWaitC && millis() - inWaitAtMs > 1000 ) {
      inWaitC = false ;
      digitalWrite(RELAY[1], HIGH);
    }
    else if ( inWaitD && millis() - inWaitAtMs > 1200 ) {
      inWaitD = false ;
      digitalWrite(RELAY[0], HIGH);// OFF
      digitalWrite(RELAY[1], HIGH);// ON
    }
    else if ( inWaitE && millis() - inWaitAtMs > 1500 ) {
      inWaitE = false ;
      digitalWrite(RELAY[0], HIGH);// OFF
      digitalWrite(RELAY[1], HIGH);// ON
    }
  }

  else if (Serial.available() > 0)
  {
    char ltr = Serial.read();
    if (ltr == 'A') // Clutch motor, coming from Pin 4
    {
      extendActuator1();
    }
    if (ltr == 'B') // Clutch Motor, coming from Pin 5
    {
      retractActuator1();

    }
    if (ltr == 'C') // Brake Motor, coming from Pin 6
    {
      digitalWrite(RELAY[1], LOW);// LOW = ON
      digitalWrite(RELAY[0], HIGH); // HIGH = OFF
      // delay(1000);
      // digitalWrite(RELAY[1], HIGH);
      inWaitC = true ;
      inWaitAtMs = millis() ;

    }
    if (ltr == 'D') // Brake Motor, coming from Pin 7
    {
      digitalWrite(RELAY[1], LOW);// ON
      digitalWrite(RELAY[0], HIGH);// OFF
      // delay(1200);
      // digitalWrite(RELAY[0], HIGH);// OFF
      // digitalWrite(RELAY[1], HIGH);// ON
      inWaitD = true ;
      inWaitAtMs = millis() ;
    }
    if (ltr == 'E') // Brake Motor, coming from Pin 8
    {
      digitalWrite(RELAY[1], LOW);// ON
      digitalWrite(RELAY[0], HIGH);// OFF
      // delay(1500);
      // digitalWrite(RELAY[0], HIGH);// OFF
      // digitalWrite(RELAY[1], HIGH);// ON
      inWaitE = true ;
      inWaitAtMs = millis() ;
    }
    if (ltr == 'F') //
    {
      extendActuator();//
    }
    if (ltr == 'G') //
    {
      retractActuator();
    }
  }
}
void extendActuator() {
  //Serial.println("extendActuator");
  digitalWrite(RELAY[1], LOW);
  digitalWrite(RELAY[0], HIGH);
}
void retractActuator() {
  //Serial.println("retractActuator");
  digitalWrite(RELAY[0], LOW);
  digitalWrite(RELAY[1], HIGH);
}
void extendActuator1() {
  //Serial.println("extendActuator");
  digitalWrite(RELAY[2], LOW);
  digitalWrite(RELAY[3], HIGH);
}
void retractActuator1() {
  //Serial.println("retractActuator");
  digitalWrite(RELAY[3], LOW);
  digitalWrite(RELAY[2], HIGH);
}

Hey ! I am trying out your receiver code, but the debouncing issue still exists. The relay once on, turns off much later than 1000, 1200 or 1500ms. What to do? Should I change the button library? Or should I replace the button module with something else?
PC inputs are absolutely accurate still.
Now, I have noticed that this may be an issue of debouncing. I noticed that in my relay board (https://www.google.co.in/search?q=4+relay+board&source=lnms&tbm=isch&sa=X&ved=0ahUKEwiplPGMq9TTAhUHOo8KHTUXBFYQ_AUICigB&biw=1366&bih=662#imgrc=YJDdSJvQv3aYfM:), once I press and release the button, the IN1 light on the relay keeps pulsing till the bouncing stops.

Try modifying your transmitter code to complete the actions for buttons D to G like the example for buttons A and B and see if it is any better.

#include <Button.h> //https://github.com/JChristensen/Button
const int BTN_EXTENDCLUTCH = 4;// CLUTCH MOTOR // A signal
const int BTN_RETRACTCLUTCH = 5;// CLUTCH MOTOR // B signal
const int BTN_EXTEND1 = 6; // // BRAKE MOTOR
const int BTN_EXTEND2 = 7;   //INITIALIZATION
const int BTN_EXTEND3 = 8;
const int BTN_EXTEND4 = 9;
const int BTN_RETRACTBRAKE = 10;

void setup() {
  Serial.begin(9600);
}

void loop() {
  delay ( 100 ) ;  // crude debounce
  if (digitalRead(BTN_EXTENDCLUTCH) == LOW) { // Pin 5
  // if (btnExtendclutch.isPressed()) {  // Pin 4
    Serial.print("A");
  }
  if (digitalRead(BTN_RETRACTCLUTCH) == LOW) { // Pin 5
    // if (btnRetractclutch.isPressed()) {
    Serial.print("B");
  }
  if (btnExtend1.isPressed()) {//Pin 6
    Serial.print("C");
  }
  if (btnExtend2.isPressed()) {  // Pin 7
    Serial.print("D");
  }
  if (btnExtend3.isPressed()) {  // Pin 8
    Serial.print("E");
  }
  if (btnExtend4.isPressed()) { // Pin 9
    Serial.print("F");
  }
  if (btnRetractbrake.isPressed()) {  // Pin 10
    Serial.print("G");
  }
}

Okay, I am trying out your code. Will update you about the output. Thanks!

Hey, I have tried your method. Still the same...
Should I consider some other input method?

Forget the receiver part for the moment and disconnect it. Look at what happens on the transmitter part on the serial console when you press the buttons to see if you get multiple responses for each button press. Also post a link to your keypad. Sometimes there are special libraries for these.

Hi 6v6gt. As you suggested, I disconnected the receiver part. Worked with the transmitter part to check for button presses.

Button module link http://robokits.co.in/control-boards/interface-boards/4x4-matrix-keypad-module-16-button-for-arduino

Here is the code:

#include <Button.h>
const int BTN_EXTENDCLUTCH = 2;
#define DEBOUNCE_MS 20
#define PULLUP true
#define INVERT true
Button btnExtendclutch(BTN_EXTENDCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);

void setup() {
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  int buttonState = btnExtendclutch.read();
  Serial.println(buttonState);
  delay(2);
  }

Results:
With delay(2), I get 9-10 1’s on the serial monitor.
With delay(20), I get about 5 1’s
With delay(200), I get a single 1 on each press

As you can see, with an increase in delay, number of 1’s DISPLAYED are reduced. Does this mean that, as the microprocessor works very fast, it may also be processing my single press as multiple presses? Please correct me if I am wrong.

There is not much information with that keyboard that you have connected, but it is probably similar to this schematic.

How have you got it wired ? Normally, you would a use library to interpret the key presses: example

200mS is a long time for a keyboard/keypress to stabilise but some jitter is expected, which has to be handled somewhere (debouncing). I guess if you are trying to use it as a normal keyboard and with out pullup/pulldown resistors, that could be the explanation of why it takes so long.

Yes, it is similar to the schematic you linked me to. And I will try it with the keypad library too as you suggest.
As of now I was using the Button library(https://github.com/JChristensen/Button). And I am using Pullups.

#include<Button.h>// https://github.com/JChristensen/Button
const int BTN_EXTENDCLUTCH = 4;
#define DEBOUNCE_MS 20
#define PULLUP true //PULLUPS USED
#define INVERT true
Button btnExtendclutch(BTN_EXTENDCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);

I have a question:
I am facing a lot of problem with mechanical type of buttons. I will surely try it out with the Keypad library but if that doesn’t work then can I use Capacitive type buttons like this one:

I haven’t used something like that before, though.

Thanks.

I have tried using the KeyPad library. But the delay problem is not going..

I am seriously considering this module:

It is a Capacitive module. Should I go for it?

Hey! I have solved the issue :o :slight_smile: . Looks like the problem was caused by the debounce and delay routines interrupting with each other. Nevertheless, adding a short delay on the Transmitter side commands solved my problem (C,D,E AND F commands). I honestly don’t know how this works but it is working.

I checked the delay timings multiple times with Buttons and PC, it is now absolutely accurate with both. Debounce is not causing any problems now.

I have tested the system with XBees too. It works perfectly. Thanks alot for helping me out !

Here is the code:

Transmitter Side:

#include <Button.h>

const int BTN_EXTENDCLUTCH = 4;
const int BTN_RETRACTCLUTCH = 5;
const int BTN_EXTEND1 = 6;
const int BTN_EXTEND2 = 7;
const int BTN_EXTEND3 = 8;
const int BTN_EXTEND4 = 9;
const int BTN_RETRACTBRAKE = 10;
#define DEBOUNCE_MS 20
#define PULLUP true
#define INVERT true
Button btnExtendclutch(BTN_EXTENDCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);
Button btnRetractclutch(BTN_RETRACTCLUTCH, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend1(BTN_EXTEND1, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend2(BTN_EXTEND2, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend3(BTN_EXTEND3, PULLUP, INVERT, DEBOUNCE_MS);
Button btnExtend4(BTN_EXTEND4, PULLUP, INVERT, DEBOUNCE_MS);
Button btnRetractbrake(BTN_RETRACTBRAKE, PULLUP, INVERT, DEBOUNCE_MS);

void setup() {
Serial.begin(9600);
}

void loop() {
btnExtendclutch.read();
btnRetractclutch.read();
btnExtend1.read();
btnExtend2.read();
btnExtend3.read();
btnExtend4.read();
btnRetractbrake.read();

if (btnExtendclutch.isPressed()&& flag == 0) {  // Clutch motor, Pin 4
Serial.print("A");
}
if (btnRetractclutch.isPressed()&& flag == 0) { // Clutch Motor, Pin 5
Serial.print("B");
}
if (btnExtend1.isPressed()&& flag == 0) { // Pin 6
Serial.print("C");
delay(150);
}
if (btnExtend2.isPressed()&& flag == 0) {  // Pin 7
Serial.print("D");
delay(150);
}
if (btnExtend3.isPressed()&& flag == 0) {  // Pin 8
Serial.print("E");
delay(150);
}
if (btnExtend4.isPressed()&& flag == 0){  // Pin 9, Brake Motor MANUAL MODE
Serial.print("F");
delay(100);
}
if (btnRetractbrake.isPressed()&& flag == 0) {  // Brake motor, Pin 10
Serial.print("G");
}
}

Receiver Side

const int RELAY[] = {5,6,7,8};
long int relayon;
void setup() {
pinMode(RELAY[0], OUTPUT);
pinMode(RELAY[1], OUTPUT);
pinMode(RELAY[2], OUTPUT);
pinMode(RELAY[3], OUTPUT);
Serial.begin(9600);
}

void loop() 
{
if(Serial.available() > 0)
    {
    char ltr = Serial.read();
    if(ltr == 'A')// Clutch motor, coming from Pin 4
   {
        extendActuator1();
   }
    if(ltr == 'B')// Clutch Motor, coming from Pin 5
   {
        retractActuator1();
   }
    if(ltr == 'C')  // Brake Motor, coming from Pin 6
    {
        digitalWrite(RELAY[1], LOW);
        digitalWrite(RELAY[0], HIGH);
        delay(300);
        digitalWrite(RELAY[1], HIGH);
     }
    if(ltr == 'D')  // Brake Motor, coming from Pin 7
    {
        digitalWrite(RELAY[1], LOW);
        digitalWrite(RELAY[0], HIGH);
        delay(450);
        digitalWrite(RELAY[1], HIGH);
    }
    if(ltr == 'E')  // Brake Motor, coming from Pin 8
        {
        digitalWrite(RELAY[1], LOW);
        digitalWrite(RELAY[0], HIGH);
        delay(600);
        digitalWrite(RELAY[1], HIGH);
    }
   if(ltr == 'F')  // Brake Motor Manual Mode, coming from Pin 9,
        {
        extendActuator();
        }
   if(ltr == 'G')// Brake Motor retract, coming from Pin 10
        {
        retractActuator();
        }
}
}
void extendActuator() {
  digitalWrite(RELAY[1], LOW);
  digitalWrite(RELAY[0], HIGH);
  delay(100);
  digitalWrite(RELAY[1], HIGH);
}
void retractActuator() {
  digitalWrite(RELAY[0], LOW);
  digitalWrite(RELAY[1], HIGH);
}
void extendActuator1() { 
  digitalWrite(RELAY[2], LOW);
  digitalWrite(RELAY[3], HIGH);
}
void retractActuator1() {
  digitalWrite(RELAY[3], LOW);
  digitalWrite(RELAY[2], HIGH);
}