1

I'm building a project that has 2 motors. What I want to do is: When button is pressed (hold down through RF controller) then:

  1. Run motor A on pwm at 50 for 1 second
  2. Run motor B on pwm at 255 for 1 second

After that first second

  1. Run motor A on pwm at 255 until button is released
  2. Stop motor B.

And when I hit the button again the whole thing repeats. Here is my rough code but it doesn't work that way. What it does is if I pressed the button in the first second since start up off the Arduino it does the first task. If I press it again it does the second task.

I have looked and tried through a lot of examples of blink without delay and multitasking. But I still can't get it working.

Here is my code:

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <elapsedMillis.h>


// Motor 1
int dir1PinA = 4;
int dir2PinA = 5;
int speedPinA = 3; // Needs to be a PWM pin to be able to control motor speed

// Motor 2
int dir1PinB = 7;
int dir2PinB = 8;
int speedPinB = 6; // Needs to be a PWM pin to be able to control motor speed

int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;

unsigned long previousMillis = 0;
long OnTime1 = 500;
long OnTime2 = 10000;


void setup(){
 Serial.begin(9600);
 radio.begin();
 radio.openReadingPipe(1,pipe);
 radio.startListening();

 pinMode(dir1PinA,OUTPUT);
 pinMode(dir2PinA,OUTPUT);
 pinMode(speedPinA,OUTPUT);

 pinMode(dir1PinB,OUTPUT);
 pinMode(dir2PinB,OUTPUT);
 pinMode(speedPinB,OUTPUT);

 }
 void CandPush()
 {
          analogWrite(speedPinA, 50);//Sets speed variable via PWM 
          digitalWrite(dir1PinA, HIGH);
          digitalWrite(dir2PinA, LOW);
          analogWrite(speedPinB, 255);//Sets speed variable via PWM 
          digitalWrite(dir1PinB, LOW);
          digitalWrite(dir2PinB, HIGH);

 }
 void CandStop()
 {
          analogWrite(speedPinA, 255);//Sets speed variable via PWM 
          digitalWrite(dir1PinA, HIGH);
          digitalWrite(dir2PinA, LOW);
          analogWrite(speedPinB, 0);//Sets speed variable via PWM 
          digitalWrite(dir1PinB, LOW);
          digitalWrite(dir2PinB, LOW);


 }
 void Home()
 {
          analogWrite(speedPinA, 0);//Sets speed variable via PWM 
          digitalWrite(dir1PinA, LOW);
          digitalWrite(dir2PinA, LOW);
          analogWrite(speedPinB, 255);//Sets speed variable via PWM 
          digitalWrite(dir1PinB, HIGH);
          digitalWrite(dir2PinB, LOW);


 }
 void loop(){

 if (radio.available()){
    bool done = false;    
    while (!done){
    done = radio.read(msg, 1);      
    Serial.println(msg[0]);
    if (msg[0] == 111)
    {
      unsigned long currentMillis = millis();
      CandPush();
      if(currentMillis - previousMillis >= OnTime1)
      {
        CandStop();
        previousMillis = currentMillis;
      }


    }
 }
 }

 else
 {
  Home();
  Serial.println("Nothing");
 }
 }

migrated from electronics.stackexchange.com Feb 17 '17 at 22:50

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

1

I assume pressing the button results in msg[0] == 111 every time you do the radio.read (i.e. it will continue sending that while the button is held). If so, the first issue I see is that after 500ms has elapsed, you will call CandStop(), and then it will loop back and immediately call CandPush(), essentially cancelling the second state.

I think you should create a state variable and state machine, so for example it does a different operation when/while the button is pressed depending on whether it is in the 'home', 'push', or 'stop' state. In the first ('home') state it is waiting for the button to be pressed, in the second ('push') state it is waiting for the time to elapse, and in the third ('stop') state it is only waiting for the button to be released. It would also allow you to avoid repeatedly calling CandPush() and Home() when it only needs to be called once (when the button is pressed).

EDIT: I am adding the code below. This hasn't been tested so there may be some bugs but it should give an idea of what I mean. It could probably also be optimized somewhat, but I tried to make it do what I think you wanted it to do based on the code you attached.

There are parts in there that I doubt work as you wanted, aside from the button handling, for example how Home() is called whenever there is no radio available and how nothing appears to happen when the button is released.

Should the Home() call really set B to full output? I added a call to StopAll which I assumed you would use to stop A and B when the button is released.

Also radio.read doesn't return anything, so done = radio.read(...) is pointless.

// State machine states
enum {
    STATE_INIT, 
    STATE_HOME,
    STATE_PUSH,
    STATE_STOP
};

unsigned long previousMillis;
bool buttonPressed = false;
bool radioAvailable = false;
int state = STATE_INIT;

void loop()
{
    //Check for new radio input every cycle
    if (radio.available()) {
        radio.read(msg, 1);
        buttonPressed = (bool) (msg[0] == 111);
        radioAvailable = true;
    } else {
        radioAvailable = false;
    }

    //State machine
    switch (state) {
    case STATE_INIT:
        //first cycle after boot-up, add any desired initialization
        //wait here until the first time the radio is available
        if (radioAvailable) {
            state = STATE_HOME;
        }
        break;

    case STATE_HOME:        //Wait for button to be pressed
        if (radioAvailable) {
            if (buttonPressed) {
                //button was pressed, reset timer and move to PUSH state
                previousMillis = millis();
                CandPush();
                Serial.println("STATE_PUSH");
                state = STATE_PUSH;
            }
        } else {
            //no radio input, go to HOME state
            Home();
            Serial.println("STATE_HOME");           
            state = STATE_HOME;
        }
        break;

    case STATE_PUSH:        //Wait for timer to elapse
        if (millis() - previousMillis >= OnTime1) {
            //OnTime1 has elapsed, move to STOP state
            CandStop();
            Serial.println("STATE_STOP");
            state = STATE_STOP;
        }
        break;

    case STATE_STOP:        //Wait for button to be released
        if (radioAvailable) {
            if (!buttonPressed) {
                //button was released, stop all motors?
                StopAll();
                state = STATE_HOME;
            }   //else still waiting for button to be released
        } else {
            //no radio input, go to HOME state
            Home();
            Serial.println("STATE_HOME");           
            state = STATE_HOME;
        }
        break;
    }
}
  • Can you give me a code example? – zuzu Feb 17 '17 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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