Actuator Control via a Serial Monitor - Issue

I created this code with the intention of controlling the position of an actuator using only Speed and Time via the serial monitor. The serial monitor would act as an intermediate between a Arduino Mega & Raspberry-Pi later down the project.

Controller: Arduino Mega
Motor Driver: MegaMoto Motor Control Shield
Actuator: GLA200 12V DC Small Linear Actuator

Changing the speed works but I'm stilling having issues with the timing. The main issue at the moment is that even when either of the extension & retraction features have a delay(0) they still move to the ends of the actuators and would keep going if it wasn't for the limit switches when they shouldn't be moving.

Questions from this;

  1. Is there an issue with the delay() function when it comes to Serial commands.
  2. If so why is this the case.
  3. Is the Millis() function a good alternative for the delay() feature for controlling the motor timings.
  4. Is there any other options other than Millis().

When this issue is sorted, I will use a similar Case statement to the speed so I can change the timings on the go from the serial monitor.

//int EnablePin1 = 8;
int PWMPinA1 = 11;           // Timer1
int PWMPinB1 = 3;            // Timer2


long Speed = 0;            //Speed variable which allows me to change the speed later on in the code
long receivedSpeed = 0; //Speed variable coming from the Serial Monitor
char receivedCommand; //Recieved variable from Serial Monitor
bool newData = false; // booleans for new data from serial

void setup() {

  Serial.begin(9600);

  //  pinMode(EnablePin1, OUTPUT);
  pinMode(PWMPinA1, OUTPUT);
  pinMode(PWMPinB1, OUTPUT);
}//end setup

void loop() {
  checkSerial();
}

void checkSerial() //function for receiving the commands
{
  if (Serial.available() > 0)               //If something comes from the computer
  {
    receivedCommand = Serial.read();        //Pass the value to the receivedCommad variable
    newData = true;                         //Indicate that there is a new data by setting this bool to true
    if (newData == true)                    //Only enter this long switch-case statement if there is a new command from the computer
    {
      switch (receivedCommand)              //Checks what is the command
      {
        case 'A': //Move the actuator forwards
          Serial.println("Positive direction.");
          extendActuator();
          break;

        case 'B': //Move the actuator backwards
          Serial.println("Negative direction.");
          retractActuator();
          break;

        case 'Z': //Stop the actuator
          Serial.println("Stop Actuator.");
          stopActuator();
          break;

        case 'V': //Updates Speed for the actuator
          receivedSpeed = Serial.parseFloat();
          if (receivedSpeed > 0 && receivedSpeed <= 255)
            Speed = receivedSpeed;
          Serial.println("Speed Updated.");
          break;

        default:
          break;
      }
    }
    newData = false; //after we went through the above tasks, newData is set to false again, so we are ready to receive new commands again.
  }
}

void extendActuator() {
  // digitalWrite(EnablePin1, HIGH);                 //enable board
  analogWrite(PWMPinA1, Speed);                  //apply desired speed
  analogWrite(PWMPinB1, 0);                          //apply no speed 
  delay(0);                                                           //Delays the operation for x amount of time 
}

void retractActuator() {
  // digitalWrite(EnablePin1, HIGH);                        //enable board
  analogWrite(PWMPinA1, 0);                                  //apply no speed 
  analogWrite(PWMPinB1, Speed);                        //apply desired speeds
  delay(0);                                                                  //Delays the operation for x amount of time 
}

void stopActuator() {
  // digitalWrite(EnablePin1, LOW);               //disable board
  analogWrite(PWMPinA1, 0);
  analogWrite(PWMPinB1, 0);//set speeds to 0
  delay(0);                                                       //Delays the operation for x amount of time 
}

Any advice will be appreciated greatly, and I will try to respond as fast as possible, cheers.

no, but what do you expect? a delay of zero means no delay

if you want to turn something on for a limited period of time shouldn't you turn it on, delay and then turn it off?

    // turn on for 100 msec
    analogWrite (PWMPinA1, Speed);
    delay (100);
    analogWrite (PWMPinA1, 0);

Sorry should of explained it clearer.

Ignoring the serial stuff, if I wanted to move the actuator forward for 5 seconds it would look like this.

analogWrite(PWMPinA1, Speed);                  //apply desired speed
analogWrite(PWMPinB1, 0);                          //apply no speed 
delay(5000);  

Pretty simple. If I put the delay to 0, it does nothing, understandable. But when I put in the serial stuff, and type in the case A, it will extend even though it should'nt be since the delay is set to 0.

why shouldn't it extend, the motor it turned on on PWMPinA1. the delay doesn't affect whether the motor is on or not

where do you shut the motor off?

Okay I see it now. Stupid when I think about it.

The delay is meant to act as a timer for the function, but this only works (as I have been saying) when it is paired with another function straight after (Which is what I've been doing when troubleshooting). I recognise the issue now, when isolating the functions it works how you have been saying as it constantly loops.

I basically need to integrate a stop after the delay inside the extend/retract functions to tell it to actually stop after this time limit until another command comes in, i.e.

void extendActuator() {
  // digitalWrite(EnablePin1, HIGH);                 //enable board
  analogWrite(PWMPinA1, Speed);                  //apply desired speed
  analogWrite(PWMPinB1, 0);                          //apply no speed 
  delay(2000);                                                           //Delays the operation for 2 amount of time 
  analogWrite(PWMPinA1, 0);
  analogWrite(PWMPinB1, 0);        //set speeds to 0
}

there's no need to set PWMPinB1 to zero, again.

you may want to precede your commands with a delay value.

i usually add pcRead() to all my code

// pcRead - debugging using serial monitor

const char version [] = "PcRead 201114a";

int debug = 0;

// ---------------------------------------------------------
// toggle output bit
int
readString (
    char *s,
    int   maxChar )
{
    int  n = 0;

    Serial.print ("> ");
    do {
        if (Serial.available()) {
            int c    = Serial.read ();

            if ('\n' == c)
                break;

            s [n++] = c;
            if (maxChar == n)
                break;
        }
    } while (true);

    return n;
}

// -----------------------------------------------------------------------------
// process single character commands from the PC
#define MAX_CHAR  10
char s [MAX_CHAR] = {};

int  analogPin = 0;

void
pcRead (void)
{

    static int  val = 0;

    if (Serial.available()) {
        int c = Serial.read ();

        switch (c)  {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            val = c - '0' + (10 * val);
            break;

        case 'A':
            analogPin = val;
            Serial.print   ("analogPin = ");
            Serial.println (val);
            val = 0;
            break;

        case 'D':
            debug ^= 1;
            break;

        case 'I':
            pinMode (val, INPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT");
            val = 0;
            break;

        case 'O':
            pinMode (val, OUTPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" OUTPUT");
            val = 0;
            break;

        case 'P':
            pinMode (val, INPUT_PULLUP);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT_PULLUP");
            val = 0;
            break;


        case 'a':
            Serial.print   ("analogRead: ");
            Serial.println (analogRead (val));
            val = 0;
            break;

        case 'c':
            digitalWrite (val, LOW);
            Serial.print   ("digitalWrite: LOW  ");
            Serial.println (val);
            val = 0;
            break;

        case 'p':
#if !defined(ARDUINO_ARCH_ESP32)
            analogWrite (analogPin, val);
            Serial.print   ("analogWrite: pin ");
            Serial.print   (analogPin);
            Serial.print   (", ");
            Serial.println (val);
            val = 0;
#endif
            break;

        case 'r':
            Serial.print   ("digitalRead: pin ");
            Serial.print   (val);
            Serial.print   (", ");
            Serial.println (digitalRead (val));
            val = 0;
            break;

        case 's':
            digitalWrite (val, HIGH);
            Serial.print   ("digitalWrite: HIGH ");
            Serial.println (val);
            val = 0;
            break;

        case 't':
            Serial.print   ("pinToggle ");
            Serial.println (val);
            digitalWrite (val, ! digitalRead (val));
            val = 0;
            break;

        case 'v':
            Serial.print ("\nversion: ");
            Serial.println (version);
            break;

        case '\n':          // ignore
            break;

        case '"':
            while ('\n' != Serial.read ())     // discard linefeed
                ;

            readString (s, MAX_CHAR-1);
            Serial.println (s);
            break;

        case '?':
            Serial.println ("\npcRead:\n");
            Serial.println ("    [0-9] append to #");
            Serial.println ("    A # - set analog pin #");
            Serial.println ("    D # - set debug to #");
            Serial.println ("    I # - set pin # to INPUT");
            Serial.println ("    O # - set pin # to OUTPUT");
            Serial.println ("    P # - set pin # to INPUT_PULLUP");
            Serial.println ("    a # - analogRead (pin #)");
            Serial.println ("    c # - digitalWrite (pin #, LOW)");
            Serial.println ("    p # -- analogWrite (analogPin, #)");
            Serial.println ("    r # - digitalRead (pin #)");
            Serial.println ("    s   - digitalWrite (pin #, HIGH)");
            Serial.println ("    t   -- toggle pin # output");
            Serial.println ("    v   - print version");
            Serial.println ("    \"   - read string");
            Serial.println ("    ?   - list of commands");
            break;

        default:
            Serial.print ("unknown char ");
            Serial.println (c,HEX);
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    pcRead ();
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin(115200);

    Serial.println (version);
#if defined(ARDUINO_ARCH_ESP32)
    Serial.println ("esp32");
#endif
}

Noted, I changed that and going through the pcRead() now. Thanks for the help.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.