Problem myproblem;

Hi, I've been struggling with a piece of code for a couple of days and I'm almost there but not quite. I wonder if anyone can tell me what I'm doing wrong.

first and foremost let me paste my code:

void loop() {
   while (Serial.available()) {
   delay(10);
   char c = Serial.read(); 
        string.concat(c);} // combines, or concatenates two strings into one new string. 
                           // so, 'c' is appended to the string named 'string'
        if (string.length() >0) {
	Serial.println(string);
	string.toCharArray(array, sizeof(array)); // copies the string's characters to the supplied buffer.
                                                  // in this case, the buffer is called 'array'
        int n;
	n = atoi(array); //  converts the string to an integer
                         // the motor library I am using requres an integer as input
    }
     incomingByte = Serial.read();
    if (incomingByte == 'Y') {
    string.toCharArray(array, sizeof(array)); // copies the string's characters to the supplied buffer.
                                                  // in this case, the buffer is called 'array'
        int n;
	n = atoi(array); //  converts the string to an integer
                         // the motor library I am using requres an integer as input
    Ystepper.move(n); 
    Ystepper.runToPosition();
    }
    incomingByte = Serial.read();
    if (incomingByte == 'Y') {
    string = "0";
    }
}

the problem I am having is as follows:

the data "char c = Serial.read();" is being sent from Processing. its a simple text box into which I am entering a value (distance) which instructs a motor to travel the given value. if i enter '1000' and send it to Arduino, it puts this information into the string called "string". so far all is good. the problem arises when I want to enter a new value, say '55'. What I suspect is happening is that this new value is being added on to the end of the first value, so it becomes 100055. What I would like to do is to clear the string before I enter a new value. I have attempted to achieve this via a "CLEAR" button on the processing side, which is received on the arduino side as follows:

incomingByte = Serial.read();
if (incomingByte == 'Y') {
string = "0";

In effect, the string is set to 0, and it wont allow me to enter any new values in.

This is my interpretation of the events, I may well be wrong. Perhaps you would have a look at the code and see if you agree. What can I do to reset the string before entering a new value?

I hope others find this thread useful.
Best, Arthur

You need start and end markers for your packet. You need to lose the delay in reading the serial data. You need to ditch the String class. It is completely unnecessary.

Some code to try:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Make Processing send something like and print the string in inData after the comment that says "Process the packet". When that works, actually process the packet there. That is a matter of noting the first letter, replacing that letter with a space, and then converting the rest to an int, using atoi().

Note that your code currently calls atoi twice to convert the same string, and that you have too many variables named n.

Hi Paul, thanks for you advice (on all threads I have started to solve this problem). I'm not getting much success for all the time I've put in! I had heart of the start/end packet approach but I did not know how to implement it, so I really appreciate your sample code. I've tried to integrate it into my sketch but nothing is really happening. This is what I've got:

#include <AccelStepper.h>

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;
String string;

int Xstep = 2;
int Xstepgnd = 3;
int Xdirection = 4;
int Xdirectiongnd = 5;
int Xenable = 6;
int Xenablegnd = 7;

int Ystep = 8;
int Ystepgnd = 9;
int Ydirection = 10;
int Ydirectiongnd = 11;
int Yenable = 12;
int Yenablegnd = 13;

AccelStepper Xstepper(1, Xstep, Xdirection);
AccelStepper Ystepper(1, Ystep, Ydirection);

void setup()
{
  Serial.begin(9600);
  Xstepper.setMaxSpeed(2500);
  Xstepper.setSpeed(1000);
  Xstepper.setAcceleration(1500);
  Ystepper.setMaxSpeed(2500);
  Ystepper.setSpeed(1000);
  Ystepper.setAcceleration(1500);
  
  pinMode(Xstep, OUTPUT);
  pinMode(Xstepgnd, OUTPUT);
  pinMode(Xdirection, OUTPUT);
  pinMode(Xdirectiongnd, OUTPUT);
  pinMode(Xenable, OUTPUT);
  pinMode(Xenablegnd, OUTPUT);
  
  pinMode(Ystep, OUTPUT);
  pinMode(Ystepgnd, OUTPUT);
  pinMode(Ydirection, OUTPUT);
  pinMode(Ydirectiongnd, OUTPUT);
  pinMode(Yenable, OUTPUT);
  pinMode(Yenablegnd, OUTPUT);
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }
  if(started && ended)
  {
        string.toCharArray(inData, sizeof(inData));
        string.replace('<',' ' );
        string.replace('>',' ' );
        int n;
	n = atoi(inData);
        
                     
    Ystepper.move(n); 
    Ystepper.runToPosition();
  }
}

Have I missed the point completely?

Best, Arthur

        string.toCharArray(inData, sizeof(inData));
        string.replace('<',' ' );
        string.replace('>',' ' );
        int n;
	n = atoi(inData);

You are writing over the top of the data you collected from the serial port with an empty string. Then, you are trying to remove the non-existent < and > characters from the string. Then, you are trying to convert the empty char array to an int.

Have I missed the point completely?

Just this point:

You need to ditch the String class.

At the point where that code snippet is, the inData array should contain Y1000 is the Processing application sent .

You need to do this:

char whichStepper = inData[0];
inData[0] = ' ';
int stepperPos = atoi(inData);
if(whichStepper == 'Y')
    Ystepper.move(stepperPos);

thanks Paul I'll give that a shot. Do you work for arduino or are you just a committed member of this forum?
Best, A

Do you work for arduino or are you just a committed member of this forum?

Some people think I should be committed. I work for an airplane company.

Hi Paul I tried the code and it works perfectly. Thankyou very much! I have a very heuristic approach to making things work on arduino and its really impressive that you can anticipate the outcome without testing the code at all. So, how have you applied your arduino expertise? - I bet you've done some good projects (autopilot?)

I bet you've done some good projects (autopilot?)

No, not really. What I do is to make a living programming.

HI Paul, ok I have one more question and then I will let you be! The part of your code which reads:

[code]  // Reset for the next packet
  started = false;
  ended = false;
  index = 0;
  inData[index] = '\0';

Does this mean that the string has been reset? or more specifically that a null (\O) has been sent to the end of the string at index 0 (i.e this string has no content). If so, then this poses a problem for me. I would like the incoming data from processing to define the variable (distance). But I would like Arduino to remember (distance) so that I can refer to it when other functions are called.

So, later on in the sketch there is a part which reads:

incomingByte = Serial.read();
  if (incomingByte == 'Y') {
  Xstepper.runToNewPosition(0);
  Ystepper.runToNewPosition(0);

But I'm a little concerned because I'm saying a lot of different things through the Serial. On the one hand the "inData[index] = '\0';[/code]" bit of the code is necessary or the message is looped (for ever ever), however I dont want to write of inData because I need it for when other functions are called.

I hope this makes sense, arthur

But I would like Arduino to remember (distance) so that I can refer to it when other functions are called.

So, remember the distance, not the string.

Does this mean that the string has been reset? or more specifically that a null (\O) has been sent to the end of the string at index 0 (i.e this string has no content). If so, then this poses a problem for me.

Yes, it does, and no it doesn't.

I would like the incoming data from processing to define the variable (distance). But I would like Arduino to remember (distance) so that I can refer to it when other functions are called.

There is absolutely nothing stopping you from doing that.

however I dont want to write of inData because I need it for when other functions are called.

No, you don't. You need to convert the string in inData, when it is complete, to a value, and store that value somewhere where other code can access it.

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 5)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }
  if(started && ended)
  {
    
    distance = atoi(inData);
    Xstepper.move(distance); 
    Xstepper.runToPosition();
  
  // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
   
  {
    incomingByte = Serial.read();
    if (incomingByte == 'Y') {
    Ystepper.move(50); 
    Ystepper.runToPosition();
  }
  }
  }
}

OK I agree, all of the above are possibilities, however they are not being realised in my code :frowning:

I cant persuade Arduino to receive/interpret the second signal 'Y' being sent from Processing. for this signal I dont need any of the atoi stuff. I simply want to establish the conditional that if 'Y' is received - do the following. This is basic stuff so I'm really confused as to why it isn't working. If I get rid of the first function so that only the 'if 'Y' is recieved' part remains, then it seems to work.

Best, A

I cant persuade Arduino to receive/interpret the second signal 'Y' being sent from Processing.

Chocolate and flowers, maybe?

Or post your Processing code. We can't see what Processing is sending, so there may need to be changes to the Arduino code to accommodate what Processing is sending, or changes to the Processing code to accommodate what the Arduino expects (or both).

  incomingByte = Serial.read();
    if (incomingByte == 'Y') {

You read a byte, even if you don't know there's one there to read.

I've had a bit of a tidy up before pasting, I'm quite messy!
O.K. this is the whole of the code on the Arduino side:

#include <AccelStepper.h>

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;
char inData[6];
byte index;
int incomingByte;
int distance;

int Xstep = 2;
int Xstepgnd = 3;
int Xdirection = 4;
int Xdirectiongnd = 5;
int Xenable = 6;
int Xenablegnd = 7;

int Ystep = 8;
int Ystepgnd = 9;
int Ydirection = 10;
int Ydirectiongnd = 11;
int Yenable = 12;
int Yenablegnd = 13;

AccelStepper Xstepper(1, Xstep, Xdirection);
AccelStepper Ystepper(1, Ystep, Ydirection);

void setup()
{
  Serial.begin(9600);
  Xstepper.setMaxSpeed(2500);
  Xstepper.setSpeed(1000);
  Xstepper.setAcceleration(1500);
  Ystepper.setMaxSpeed(2500);
  Ystepper.setSpeed(1000);
  Ystepper.setAcceleration(1500);
  
  pinMode(Xstep, OUTPUT);
  pinMode(Xstepgnd, OUTPUT);
  pinMode(Xdirection, OUTPUT);
  pinMode(Xdirectiongnd, OUTPUT);
  pinMode(Xenable, OUTPUT);
  pinMode(Xenablegnd, OUTPUT);
  
  pinMode(Ystep, OUTPUT);
  pinMode(Ystepgnd, OUTPUT);
  pinMode(Ydirection, OUTPUT);
  pinMode(Ydirectiongnd, OUTPUT);
  pinMode(Yenable, OUTPUT);
  pinMode(Yenablegnd, OUTPUT);
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 5)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }
  if(started && ended)
  {
    
    distance = atoi(inData);
    Xstepper.move(distance); 
    Xstepper.runToPosition();
  
  // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
   
  {
    incomingByte = Serial.read();
    if (incomingByte == 'Y') {
    Ystepper.move(50); 
    Ystepper.runToPosition();
  }
  }
  }
}

This is the code on the Processing side:

  import processing.serial.*; // serial library


  // GUI variables
  import controlP5.*; // controlP5 library
  ControlP5 controlP5; // create the handler to allow for controlP5 items
  Serial port;

  Textfield myTextfield;

  // setup
  void setup() {
  size(600,400);
  frameRate(30);

  controlP5 = new ControlP5(this); // initialize the GUI controls

  println("Available serial ports:");
  println(Serial.list());
  port = new Serial(this, "COM8", 9600);  

 
myTextfield = controlP5.addTextfield("DISTANCE",5,170,200,15); // addTextfield(name,x,y,width,height)
myTextfield.setAutoClear(false);
controlP5.addButton("X",1,5,210,40,15); // buton(name,value,x,y,width,height)
controlP5.addButton("Y",1,5,230,40,15); // buton(name,value,x,y,width,height)
controlP5.addButton("CLEAR",1,210,170,40,15); // buton(name,value,x,y,width,height)

}

  // infinite loop
  void draw() {
  background(0);
}

  // run this when there is an enter in the textfield
  public void DISTANCE(String theText) {
  port.write('<'+theText+'>'); // write the text in the field
  println(" sent "+theText); // print it to the debug screen as well
}

// run this when buttonA is triggered, send an a
  void Y(int theValue) {
  port.write('Y');
  println("sent Y"); // print it to the debug screen as well
}
  
// run this when buttonA is triggered, send an a
  void X(int theValue) {
  port.write('Y');
  println("sent X"); // print it to the debug screen as well
}

  void CLEAR(int theValue) {
  myTextfield.clear();
  println("sent CLEAR"); // print it to the debug screen as well
}

You're still reading the serial input, even when you don't know if there's something there to read (mostly, there won't be)

The code on the Arduino expects packets. Packets are bounded by start and end of packet markers. What you need to do is send "" or "" or "<1000>" in the Processing application.

Then, where it says "Process the packet", inData will contain "Y", "X", or a string representing a number. Try this:

if(strcmp(inData, "X"))
{
   // Got an X
}
else if (strcmp(inData, "Y"))
{
  // Got a Y
}
else
{
    distance = atoi(inData);
}

AHA paul no the problem with the buttons was even simpler than that. the distinction rests on whether i had told processing to port.write('Y') or ("Y"). i didnt realise that the quotation marks would be a part of my message!

thanks for your help!

Hi Paul its 'slightly' working now.

I've set up my < 's and my " 's corretly. For example from processing what I've got is:

port.write('<'+"Y"+theText+'>'); // write the text in the field

However, On the arduino side it cant distinguish X from Y. Do you think this is because the ASCII encoding is:

X = 130
Y = 131

or does it write Y as a letter to the string?

here's the code in its context:

  if(started && ended)
  {
  if(strcmp(inData, "X"))
  {
  inData[0] = ' ';
  int stepperPos = atoi(inData);
  Xstepper.move(stepperPos);
  Xstepper.runToPosition();
    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
  else if (strcmp(inData, "Y"))
  {
  inData[0] = ' ';
  int stepperPos = atoi(inData);
  Ystepper.move(stepperPos);
  Ystepper.runToPosition();
    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
  else
  {
  distance = atoi(inData);
  Xstepper.move(distance);
  Xstepper.runToPosition();
  Ystepper.move(distance);
  Ystepper.runToPosition();
    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
}
  }
}

PROCESSING CAPTURE.JPG

port.write('<'+"Y"+theText+'>'); // write the text in the field

Add a serialEvent(Serial aPort) method to the Processing application:

void serialEvent(Serial aPort)
{
  // read the serial buffer:
  String myString = aPort.readStringUntil('\n');

  // make sure you have a valid string
  if (myString != null)
  {
    // trim off the whitespace (linefeed, carriage return) characters:
    myString = trim(myString);

    println(myString);
  }
}

Then, add 3 lines to the Arduino sketch:
if(started && ended)
[
Serial.print("I got [");
Serial.print(inData);
Serial.println("]");

Is the Arduino getting what you think it is?