2

I am trying to make my Arduino micro-controller and my Mac talk together, and I have created a functional serial connection. My computer is sending data to my Arduino, and my Arduino is sending a 1 when it is ready to receive a new piece of data.

I have created an if-else statement (Python script below), which is either sending a new line of data to the Arduino or waiting for the Arduino to be ready for receiving a new line of data.

The problem is that ser.read() in the first part of the Python script always returns 1, which means that the script is sending the individual data lines faster than the Arduino connected stepper motors can possible react.

In the Arduino script you can see that I am sending the state-status in the first line of the serialEvent() function, which in my world should let the Arduino finish its job, before a new "task" is coming. However, it is for some reason not working. Can anybody help me out here?

Python script

import os
import time
import serial

# Name of csv file with drawing coordinates
csvFile = "scaled_coordinates.csv"

# Create serial connection
ser = serial.Serial(port='/dev/tty.usbserial-A9005bDh', baudrate=9600)

wd = os.getcwd()
myFile = open(wd + "/coordinates/" + csvFile)

state = '1'

while True: # Exits when there is no more lines to read
    print "test"

    if state == '0': # Wait for Arduino to be ready
        state = ser.read()

    elif state == '1': # Send one more line to Arduino
        line = myFile.readline()
        if not line:
            break
        print line
        ser.write(line)
        state = '0' # Wait for Arduino before reading next line

ser.close
myFile.close

Arduino loop function

void loop() {
  serialEvent(); // Call the serial function
  if (coord_complete) {
    // Steps to move from currrent to new point
    target1 = steps(x_current, y_current, x_new, y_new, 1);
    target2 = steps(x_current, y_current, x_new, y_new, 2);

    // Start moving
    stepper1.move(target1);
    stepper2.move(target2);

    // Update current position
    x_current = x_new;
    y_current = y_new;

    // Reset variables
    x_complete = false;
    y_complete = false;
    coord_complete = false;
  }

  // Stay in while loop until steppermotors is done
  while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0)) {
    stepper1.run();
    stepper2.run();
  }
}

Arduino serialEvent function

void serialEvent() {
  // EDIT : PUT SERIAL.WRITE INSIDE IF STATEMENT //
  if((stepper1.distanceToGo() == 0) && (stepper2.distanceToGo() == 0)){
    Serial.write('1'); // Tell Python that Arduino is ready for one more line
  }      

  while (Serial.available() && coord_complete == false) {
    char ch = Serial.read(); // Get new character
    // EDIT : REMOVE THIS LINE //
    Serial.print(ch);

    // If digit; add it to coord_string
    if (isDigit(ch)) {
      coord_string[index++] = ch;

    // Else if ch is ","; then rename to x_new
    } else if (ch == ',') {
      coord_string[index++] = NULL;  // Finish coord_string
      x_new = atoi(coord_string);    // Convert to integer
      x_complete = true;             // Change x_complete to true
      index = 0;                     // Reset index
      memset(coord_string, 0, sizeof(coord_string));  // Reset coord_string
    // Else if ch is a new line; then rename as y_new
    } else if (ch == ';') {
      //Serial.write('0');
      coord_string[index++] = NULL;
      y_new = atoi(coord_string);
      y_complete = true;
      index = 0;
      memset(coord_string, 0, sizeof(coord_string));
    }

    // Ends while-loop when true
    coord_complete = x_complete * y_complete;
  }
}

Edit

I have changed a bit in the first few lines of the serialEvent function (See comments).

Here is a sample of the text file I am reading from:

239,275;
1100,275;
300,400;
200,400;
200,300;

closed as off-topic by Chris Stratton, jfpoilpret, Dat Ha, KIIV, sa_leinad Oct 20 '16 at 14:28

  • This question does not appear to be about Arduino, within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

0

If I'm getting things right, your program fails in the above:

when you send the first message in python, you set state = 0. In arduino you enter the serialEvent function and while is triggered. You get the first char and send it through Serial.print (but this char will be send to python!!!). For the sake of example let's say the first char you get from cvs is '2'. At this point let's hold on a sec and look what happens in python. State was '0' but as you have used in arduino Serial.print(ch); now state will be updated with '2'. This will cause no more triggers of the if-else statements in python.

edit:

By now, and also as a debug, add this lines at your code:

if state == '0': # Wait for Arduino to be ready
    state = ser.read()
    if state != '1':
        print "state: " + state
        state = '0'

However if csv file contains '1's values this will also cause a problem. Do you really need that Serial.print(ch) in arduino?

EDIT The new version since comments Basically if you are trying to do things before new coordinates, you have to do things in a sequential way. You only ask for info after making all the moves. This is the code I've used to test. Note: I had to adapt your code because was missing the complete arduino code to test it. So I kinda simulated the motor moving etc with delays. Please adapt to your original code

#include <string.h>

bool coord_complete = false;
byte stepper1_disToGo = 0, stepper2_disToGo = 0;
// debug things
int led = 13;
bool led_state = true, x_complete, y_complete;
char coord_string[256];
int index = 0, x_new = 0, y_new = 0;



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  memset(&coord_string, 0, sizeof(coord_string));
}

void loop() {

  serialData(); //ask and process more data

  /*
    // Steps to move from currrent to new point
    target1 = steps(x_current, y_current, x_new, y_new, 1);
    target2 = steps(x_current, y_current, x_new, y_new, 2);

    // Start moving
    stepper1.move(target1);
    stepper2.move(target2);

    // Update current position
    x_current = x_new;
    y_current = y_new;

    // Reset variables
    x_complete = false;
    y_complete = false;
  */
  delay(2000); //replace to simulate actions
  stepper1_disToGo = 10;
  stepper2_disToGo = 10;
  coord_complete = false;

  // replaced to simulate
  /*
    // Stay in while loop until steppermotors is done
    while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0)) {
    stepper1.run();
    stepper2.run();
    }
  */
  while ((stepper1_disToGo != 0) || (stepper2_disToGo != 0)) {
    stepper1_disToGo --;
    stepper2_disToGo --;
    digitalWrite(led, led_state); // is moving!!!!
    delay(100);
    led_state = !led_state;
  }
}

/*
   you try to use the serialEvent  but the structure of
   your code and the verifications make it act like sequential.
   If you only want to make things after all steps are done there
   is no need for the serialEvent function
*/
void serialData() {
  /*
     This will never be false because you are stuck in the while

    // EDIT : PUT SERIAL.WRITE INSIDE IF STATEMENT //
    if((stepper1.distanceToGo() == 0) && (stepper2.distanceToGo() == 0)){
    Serial.write('1'); // Tell Python that Arduino is ready for one more line
    }
  */
  //EDIT: wait for info
  while (Serial.available() < 1) {
    Serial.write('1'); /// Tell Python that Arduino is ready for one more line
    delay(500);// ask for info sometimes
  }
  while (Serial.available()) {
    char ch = Serial.read(); // Get new character

    // If digit; add it to coord_string
    if (isDigit(ch)) {
      coord_string[index++] = ch;

      // Else if ch is ","; then rename to x_new
    } else if (ch == ',') {
      coord_string[index++] = NULL;                   // Finish coord_string
      x_new = atoi(coord_string);                     // Convert to integer
      x_complete = true;                              // Change x_complete to true
      index = 0;                                      // Reset index
      memset(coord_string, 0, sizeof(coord_string));  // Reset coord_string

      // Else if ch is a new line; then rename as y_new
    } else if (ch == ';') {
      coord_string[index++] = NULL;
      y_new = atoi(coord_string);
      y_complete = true;
      index = 0;
      memset(coord_string, 0, sizeof(coord_string));
    }
    //EDIT: change to AND verification
    // Ends while-loop when true
    coord_complete = x_complete && y_complete;
  }
}

The structure of your loop should be:

  1. ask for data and wait for it
  2. Read data and parse it
  3. Calculate steps needed
  4. move servos till new positions
  5. repeat

this should be your new code more or less if no mistakes were made because can't really test this version (is missing the variables declarations setup, includes etc...)

void loop() {

  serialData(); //ask and process more data
  // Steps to move from currrent to new point
  target1 = steps(x_current, y_current, x_new, y_new, 1);
  target2 = steps(x_current, y_current, x_new, y_new, 2);

  // Start moving
  stepper1.move(target1);
  stepper2.move(target2);

  // Update current position
  x_current = x_new;
  y_current = y_new;

  // Reset variables
  x_complete = false;
  y_complete = false;
  coord_complete = false;

  // Stay in while loop until steppermotors is done
  while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0)) {
    stepper1.run();
    stepper2.run();
  }
}

void serialData() {

  //EDIT: wait for info
  while (Serial.available() < 1) {
    Serial.write('1'); /// Tell Python that Arduino is ready for one more line
    delay(500);// ask for info sometimes
  }
  // we got info!!!
  while (Serial.available()) {
    char ch = Serial.read(); // Get new character

    // If digit; add it to coord_string
    if (isDigit(ch)) {
      coord_string[index++] = ch;

      // Else if ch is ","; then rename to x_new
    } else if (ch == ',') {
      coord_string[index++] = NULL;                   // Finish coord_string
      x_new = atoi(coord_string);                     // Convert to integer
      x_complete = true;                              // Change x_complete to true
      index = 0;                                      // Reset index
      memset(coord_string, 0, sizeof(coord_string));  // Reset coord_string

      // Else if ch is a new line; then rename as y_new
    } else if (ch == ';') {
      coord_string[index++] = NULL;
      y_new = atoi(coord_string);
      y_complete = true;
      index = 0;
      memset(coord_string, 0, sizeof(coord_string));
    }
    //EDIT: change to AND verification
    // Ends while-loop when true
    coord_complete = x_complete && y_complete;
  }
}
  • It makes sense to delete the Serial.print(ch) but it is still not working for me. I guess I have to clear the serial buffer or something. I can see that the my python code somehow is getting stucked in the if-statement. – Christoffer Nov 19 '15 at 22:35
  • @Christoffer can you edit your post and had a few lines of your csv file for testing? thanks. – brtiberio Nov 19 '15 at 23:05
  • sure. I have changed the post now. – Christoffer Nov 20 '15 at 7:43
  • @Christoffer Hope it helps now to achieve your goals. If it still doesn't work, supply the complete arduino code. However, i'd like to suggest you to parse the csv in python and send coordinates to arduino by using two strings or using a binary data. The easiest away should be using strings and Serial.parseInt() in arduino for each string. – brtiberio Nov 21 '15 at 0:44
  • I figured out that the solution was to clear the serial buffer and implement a minor delay. The solution is here: stackoverflow.com/questions/33805986/… – Christoffer Nov 22 '15 at 10:33

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