Pages: 1 [2]   Go Down
Author Topic: Serial Communication and Blocking vs NonBlocking Functions  (Read 1989 times)
0 Members and 1 Guest are viewing this topic.
Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Does this mean I need to check whether the boolean is true/false before telling the motor to run?
No.

Code:
    while(1)
    {
      moving_1 = stepper1.run();
      moving_2 = stepper2.run();
      moving_3 = stepper3.run();
      moving_4 = stepper4.run();

      if(!moving_1 || !moving_2 || !moving_3 || !moving_4)
      {
         motorRun = -1;
         break;

What are moving_1, etc. initialized to?
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

All the moving variables are initialized as true.  What exactly does the MotorRun variable do?  You're setting it to -1, but I don't currently have a MotorRun variable in my code... so I'm not sure what it's referring to.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry... my fault.  I see where you were going with that (I forgot that I do have a MotorRun variable).  Let me try it out and get back to you.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok... getting better (but still not perfect).  I now have:

Quote
  if (motorRun == 1) {
    while(1)
    {
      moving_1 = stepper1.run();
      moving_2 = stepper2.run();
      moving_3 = stepper3.run();
      moving_4 = stepper4.run();

      if(!moving_1 && !moving_2 && !moving_3 && !moving_4){
        motorRun = -1;            //reset the MotorRun variable
        Serial.println("next");   //send character for the next line from Firefly
        break;
      }
    }
  }

This basically starts out by printing "waiting" every 200ms (from the establishContact() function).  Then, once I enter in a string via the Serial Monitor: 500,400,300,200,1000,100,1,0 then it prints the word next... which is what I would expect.  The thing is... I would expect it to wait some amount of time for it to complete all the motor moves (the longest one in the string above is 500 steps) and then to print the word next.  What happens now is that it prints the word 'next' immediately after I click send on the serial monitor.  Then, it waits some amount of time and prints 'next' again.  That waiting period is what I would expect... I'm just not sure why it's sending the first 'next' command.  Also, once it returns the second print statement... it just waits there until I send another command (which is what I would expect since we set the MotorRun variable to -1).  However, when I send the same string again, it prints the word 'next' again immediately after I click the send button (just like before)... but this time it never prints the second 'next' statement.  It just sort of sits there.  You would think it would display pretty much the same behavior, but it doesn't.  It's kind of like it works once, but not again.  Any suggestions?  Thanks again.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ahhh... I actually realize my mistake.  I was sending the same string over and over... but the position values are in absolute units... not relative... so it was basically telling it to move to the position it was already in, which is why it was never returning the second string.  If I tell it to use this string first: 500,400,300,200,1000,100,1,0 and then this string second: 0,0,0,0,1000,100,1,0... then it will basically move all the motors to one position, and then back to their original position (sending the 'next' command after each time they're all done). 
So, it seems like it's working properly... all except for that pesky extra 'next' statement.  For some reason it always prints a 'next' statement each time I click the send button on the Serial Monitor.  It then waits some amount of time and prints the word 'next' again when the motors are done.  I expect the second statement, just not the first one.  Do you have any ideas as to why this would be happening?
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So, I've tested everything out (now with my application sending the data to the Arduino instead of just entering in a string in the serial monitor)... and it seems to be working well.  There's still an issue with it sending an extra 'next' statement every time it receives a message.  I could keep a counter and only send when the counter mod 2 returns zero... but this seems like it's putting a bandaid on the initial problem.  I can't seem to figure out why it's sending the extra 'next' statement.  The code I'm using is:

Quote
  if (motorRun == 1) {
    while(1)
    {
      moving_1 = stepper1.run();  //tell the motors to move to their positions
      moving_2 = stepper2.run();
      moving_3 = stepper3.run();
      moving_4 = stepper4.run();

      if(!moving_1 && !moving_2 && !moving_3 && !moving_4){
        motorRun = -1;            //reset the MotorRun variable
        Serial.println("n");      //send character for the next line from Firefly
        moving_1 = true;          //reset the moving flags
        moving_2 = true;
        moving_3 = true;
        moving_4 = true;
        break;
      }
    }
  }


The moving variables are all initialized as true and they're all reset after the if statement... so it should never jump out of the while loop unless all motors are at their final position.  Since it's sending two 'next' statements, I think I'm actually asking for the next string of data from my application immediately... so I don't think I'm actually losing data, it's just making the movement jerky.  Do you have any thoughts?
Thanks,
Andy
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The code I'm using is:
Some of the code...

It is not necessary to set moving_n flags to true, They are not checked before being set, so it doesn't matter if they get set somewhere else to Tuesday.

Quote
so it should never jump out of the while loop unless all motors are at their final position.
So, we need to look at the rest of the code. One possibility that might be causing issues would be sending the string followed by \n\r or two \n's.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Fair enough.  Here's the whole code.

Quote
 
#include <AccelStepper.h>
#define BAUDRATE 115200     //Set the Baud Rate to an appropriate speed
#define BUFFSIZE  256       // buffer one command at a time, 12 bytes is longer than the max length
#define DIR_PIN_A 2         //Set Direction Pin for Stepper A to Digital Pin 2
#define STEP_PIN_A 3        //Set Step Pin for Stepper A to Digital Pin 3
#define DIR_PIN_B 4         //Set Direction Pin for Stepper B to Digital Pin 4
#define STEP_PIN_B 5        //Set Step Pin for Stepper B to Digital Pin 5
#define DIR_PIN_C 6         //Set Direction Pin for Stepper C to Digital Pin 6
#define STEP_PIN_C 7        //Set Step Pin for Stepper C to Digital Pin 7
#define DIR_PIN_D 8         //Set Direction Pin for Stepper D to Digital Pin 8
#define STEP_PIN_D 9        //Set Step Pin for Stepper D to Digital Pin 9

long motorPos[4] = {0,0,0,0};
int motorSpeed = 2000;     //Set default speed value
int motorAcc = 1000;       //Set default acceleration value
int motorRun = 1;          //Set default run value
int motorReset = 0;        //Set default reset value

boolean moving_1 = true;
boolean moving_2 = true;
boolean moving_3 = true;
boolean moving_4 = true;

//unsigned long timer = 0;
String msg_char = "";

char *parseptr;
char buffidx;

char buffer[BUFFSIZE];    // this is the double buffer
uint16_t bufferidx = 0;   // a type of unsigned integer of length 16 bits
uint16_t p1, s1;   

// Define some steppers and the pins they will use: Ex: Accelstepper stepper1(1, 3, 4) <- STEP PIN 3, DIR PIN 4.
AccelStepper stepper1(1, STEP_PIN_A, DIR_PIN_A);
AccelStepper stepper2(1, STEP_PIN_B, DIR_PIN_B);
AccelStepper stepper3(1, STEP_PIN_C, DIR_PIN_C);
AccelStepper stepper4(1, STEP_PIN_D, DIR_PIN_D);

/*==============================================================================
 * SETUP() This code runs once
 *============================================================================*/
 
void setup()
{  
  stepper1.setCurrentPosition(0);  //Move steppers to default position
  stepper2.setCurrentPosition(0);
  stepper3.setCurrentPosition(0);
  stepper4.setCurrentPosition(0);  
  setStepperSpeeds();

  Serial.begin(BAUDRATE);         // Start serial communication
  establishContact();             // send a byte to establish contact until receiver responds
}

/*==============================================================================
 * LOOP() This code loops continuously
 *============================================================================*/
 
void loop()
{
  UpdateStepperValues();  //Get all the incoming values from Firefly

  if (motorReset == 1) {
    stepper1.setCurrentPosition(motorPos[0]);
    stepper2.setCurrentPosition(motorPos[1]);
    stepper3.setCurrentPosition(motorPos[2]);
    stepper4.setCurrentPosition(motorPos[3]);
  }
  
  if (motorRun == 1) {
    while(1)
    {
      moving_1 = stepper1.run();  //tell the motors to move to their positions
      moving_2 = stepper2.run();
      moving_3 = stepper3.run();
      moving_4 = stepper4.run();

      if(!moving_1 && !moving_2 && !moving_3 && !moving_4){
        motorRun = -1;            //reset the MotorRun variable
        Serial.println("n");      //send character for the next line from Firefly
        break;
      }
    }
  }
}


/*==============================================================================
 * UPDATE STEPPER VALUES FUNCTION()
 *============================================================================*/

void UpdateStepperValues(){

  char c;    // holds one character from the serial port
  if (Serial.available() > 0) {
    c = Serial.read();      // read one character
    buffer[bufferidx] = c;  // add to buffer

    if (c == '\n') { 
      buffer[bufferidx+1] = 0; // terminate it
      parseptr = buffer;       // offload the buffer into temp variable

      //********************************************************

      motorPos[0] = parsedecimal(parseptr);    // parse the first number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorPos[1] = parsedecimal(parseptr);    // parse the next number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorPos[2] = parsedecimal(parseptr);    // parse the next number
      parseptr = strchr(parseptr, ',')+1;       // move past the ","

      motorPos[3] = parsedecimal(parseptr);    // parse the next number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorSpeed = parsedecimal(parseptr);     // parse the next number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorAcc = parsedecimal(parseptr);       // parse the next number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorRun = parsedecimal(parseptr);       // parse the next number
      parseptr = strchr(parseptr, ',')+1;      // move past the ","

      motorReset = parsedecimal(parseptr);     // parse the next number

      setStepperSpeeds();
      stepper1.moveTo(motorPos[0]);            //set new absolute target position
      stepper2.moveTo(motorPos[1]);            //set new absolute target position
      stepper3.moveTo(motorPos[2]);            //set new absolute target position
      stepper4.moveTo(motorPos[3]);            //set new absolute target position

      bufferidx = 0;       // reset the buffer for the next read
      return;              //return so that we don't trigger the index increment below
    }
    // didn't get newline, need to read more from the buffer
    bufferidx++;    // increment the index for the next character
    if (bufferidx == BUFFSIZE-1) {  //if we get to the end of the buffer reset for safety
      bufferidx = 0;
    }
  }
}

double parsedecimal(char *str)
{
  return atof(str);
}

void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("waiting...");   // send an initial string
    delay(200);
  }
}

void setStepperSpeeds() {

  stepper1.setMaxSpeed(motorSpeed);
  stepper1.setAcceleration(motorAcc);

  stepper2.setMaxSpeed(motorSpeed);
  stepper2.setAcceleration(motorAcc);

  stepper3.setMaxSpeed(motorSpeed);
  stepper3.setAcceleration(motorAcc);

  stepper4.setMaxSpeed(motorSpeed);
  stepper4.setAcceleration(motorAcc);
}

Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My application (written in C#) does indeed call the Console.WriteLine method... which by default adds a "\r\n" characater at the end of the line (http://msdn.microsoft.com/en-us/library/zdf6yhx5.aspx).  I think the Serial Monitor send function also adds these characters.  My code does look for the '\n' character as the terminator and then flushes the buffer... But, I don't think this would cause it to update all the values twice would it?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  while (Serial.available() <= 0) {
Serial.available() can never return a value less than 0. There is data, or there isn't. There can not be a negative amount.

What does the code on the sending end expect before it sends new data? A specific character, or any character? Is the Serial.println("n") causing it to send just one batch of data or three?

Is it sending data followed by one carriage return, or is it sending data followed by carriage return and line feed? Or something else?
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the clarification about Serial.available().  The code on the sending end is looking for the 'n' character coming over the serial port.  When it receives this character it sets a flag to issue another position command and then resets the incoming buffer to null (or empty).  Once the flag has been set, it basically removes the first item from the list (as that was the one that was sent last) and then formats another string getting the next position values for each of the four motors (as well as the current state of the run, speed, acceleration, and reset values).  Then, assuming the port is open, it then sends the formatted string back over to the Arduino using the WriteLine(message) command.  Looking at this command on the msdn website, it looks like the default behavior of this function automatically adds a '\r\n' character to the end of the line.  I'm not adding it on myself... but the command automatically does it.  So, then once that command is issued, the Arduino reads in the string and goes through the while loop again.  It shouldn't be sending three batches of data ever...  Hopefully this helps clarify it a bit.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48556
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Does your sender show you all the serial data it gets? Can you send debug information to it?

If so, it would be interesting to know when a complete record is received, relative to when the n's are sent.
Logged

Pages: 1 [2]   Go Up
Jump to: