Serial stops returning data. java.io.IOException: Device not configured in write

I have Processing set up to talk with an Arduino every 4 seconds to move two stepper motors. A0 and A1 are both set up with a circuit containing two open switches and a 10k pulldown resistor. These two pairs of switches act to let the motors know when they reach their respective limits (the machine is basically a big XY plotter). Processing sends out a string like "#-1,100,1,200" every 4 seconds telling (in this example) the X motor to move 100 steps in the negative direction, and the Y motor to move 200 steps in the positive direction. The Arduino replies that it received the data with a string (again using the previous example) "Received:#-1,100,1,200" then "Moving:-1,100,1,200" (this just confirms the received string was successfully broken into an int array). The Arduino also sends a serial string letting processing know when a boundary is hit (this is of the form:"XHit:1,-1,100,1,200,0.44"). The whole system was working fine on an Arduino Uno. I switched this out for a Mega while debugging some power supply issues for the stepper. Having left the Mega in, I now have been getting a "java.io.IOException: Device not configured in writeArray" error (sorry, I'm not at the actual machine, so don't have a full stack trace) in Processing after between 3 and 10 exchanges with the Mega. I'm fine with swapping back to the Uno, but I'd like to know why the Mega is failing. I've read about this happening when the Arduino has a massive voltage drop and the usb gets reset poorly, which I can't see occurring in my case (the steppers are powered from an external supply) unless having two open analog pins is causing a voltage drop the board can't handle? Thoughts?

Thoughts?

I think I can't see your Processing code.
I think I can't see your Arduino code.
I think you haven't told us which versions of Processing and Arduino you are using.

haha, Mr. PaulS, you took my question very literally. Also, I'm from Seattle, which makes this a real community affair. First: Processing 1.5.1. Arduino 1.0.1.

Serial parts of Processing code:

Serial arduino;
int updateInterval = 5000;

void setup(){
  //Serial setups *******************************************************  
  println(Serial.list());
  arduino = new Serial(this, Serial.list()[4], 9600);
  arduino.bufferUntil('\n');
}

void draw(){
  if (millis() - timeLastSendCoordinates > updateInterval) {
    logData("Sending off for coordinates and sending to Arduino", true);
    sendCoordinates();
  }
}

void sendCoordinates() {
  timeLastSendCoordinates = millis();
  arduinoData.update(heartbeat.xNext, heartbeat.yNext);
  arduino.write("#" + arduinoData.xDir + "," + arduinoData.xSpeed + "," + arduinoData.yDir + "," + arduinoData.ySpeed + "\n");
  logData("Sending Arduino more coordinates. Moving to: " + arduinoData.x + ", " + arduinoData.y + " From: " + arduinoData.xPrev + ", " + arduinoData.yPrev, true);
}

And the Arduino code:

#include <AccelStepper.h>

// Define a stepper and the pins it will use

AccelStepper xStepper(1, 2, 22);
AccelStepper yStepper(1, 3, 23);

unsigned long time;
unsigned long lastUpdateTime;
float incompleteStepsRatio;

const int updateInterval = 5000; //interval in milliseconds to ask for new coordinates. MUST BE SAME IN PROCESSING.

int xBoundaryData = 100;
int yBoundaryData = 100;

int xDir = 1;
int yDir = 1;
int xSpeed = 200;
int ySpeed = 200;

boolean xHit = false;
boolean yHit = false;
const int xStepsNeededAfterHit = 150;
const int yStepsNeededAfterHit = 350;
int xStepsAfterHit = 0;
int yStepsAfterHit = 0;
unsigned long xHitTimeCounter = 0;
unsigned long yHitTimeCounter = 0;

boolean stringComplete = false;
int inputStringIndex = 0;
char inputString[25]; //allows for a serial input of 25 chars  
int dataStringIndex = 0;
char dataString[8]; //this gives us a buffer of 5 numbers
int dataIndex = 0;
int data[4]; //xDir, xSpeed, yDir, ySpeed

void setup() {  
  Serial.begin(9600);
  
  memset(inputString, 0, sizeof(inputString));
  memset(dataString, 0, sizeof(dataString));
  
  time = 0;
  lastUpdateTime = 0;
  
  xStepper.setSpeed(xDir * xSpeed);
  yStepper.setSpeed(yDir * ySpeed);
}

void loop() {
  checkBoundaries();
  processData();
  updateSteppers();
}
/******

Receive serial data from processing forms:
#xDir,xSteps,yDir,ySteps\n

******/ 
void serialEvent() {
    while (Serial.available()) {
      checkBoundaries();
      char inChar = (char)Serial.read(); 
      //check that we have startred reading a string and it started at the begining
      if (inputString[0] != 0 || inChar == '#') {
        inputString[inputStringIndex] = inChar;
        inputStringIndex++;
        if (inChar != '#' && inChar != ',' && inChar != '\n') {
          dataString[dataStringIndex] = inChar;
          dataStringIndex++;
        }
        if (inChar == '#') {
          memset(dataString, 0, sizeof(dataString));
          dataStringIndex = 0;
          dataIndex = 0;
        }
        if (inChar == ',' || inChar == '\n') {
          dataString[dataStringIndex] = '\0';
          data[dataIndex] = atoi(dataString);
          memset(dataString, 0, sizeof(dataString)); //clear out the dataString
          dataStringIndex = 0;
          dataIndex++;
          if (dataIndex > 3) {
            //this is just to make sure we don't overflow the index
            dataIndex = 0;
          }
        }
        if (inChar == '\n' ) {
          inputString[inputStringIndex] = '\0';
          stringComplete = true;
        } //if newline
      } //if # or such
    } //while loop
}
/******

Checks boundary data streams for a hit

******/ 
void checkBoundaries() {
  xBoundaryData = analogRead(A0);
  yBoundaryData = analogRead(A1);
  time = millis();
  
  if (xHit == true && xBoundaryData > 10) {
    if (xStepsAfterHit >= xStepsNeededAfterHit) {
      xHit = false;
    }
    xStepsAfterHit = round((float)((time - xHitTimeCounter) / 1000.0) * (float)xSpeed);
  }
  if (yHit == true && yBoundaryData > 10) {
    if (yStepsAfterHit >= yStepsNeededAfterHit) {
      yHit = false;
    }
    yStepsAfterHit = round((float)((time - yHitTimeCounter) / 1000.0) * (float)ySpeed);
  }
  
  if (xHit == false && xBoundaryData < 10) {
    xStepsAfterHit = 0;
    xHitTimeCounter = time;
    xHit = true;
    xDir = -xDir;
    xStepper.setSpeed(xSpeed * xDir);
    sendSerialHitData(0);
  }
  if (yHit == false && yBoundaryData < 10) {
    yStepsAfterHit = 0;
    yHitTimeCounter = time;
    yHit = true;
    yDir = -yDir;
    yStepper.setSpeed(ySpeed * yDir);
    sendSerialHitData(1);
  }
}
/******

Process the serial data if available.

******/ 
void processData() {
  if (stringComplete == true) { 
    lastUpdateTime = millis();
    Serial.print("Received:");
    Serial.println(inputString);
    
    if (xHit == false) {
      xDir = (abs(data[0]) == 1 ? data[0] : 1);
    }
    if (yHit == false) {
      yDir = (abs(data[2]) == 1 ? data[2] : 1);
    }
    
    xSpeed = data[1];
    ySpeed = data[3];

    xStepper.setSpeed(xDir * xSpeed);
    yStepper.setSpeed(yDir * ySpeed);    
    
    Serial.print("moving:");
    Serial.print(xDir);
    Serial.print(",");
    Serial.print(xSpeed);
    Serial.print(",");
    Serial.print(yDir);
    Serial.print(",");
    Serial.println(ySpeed); 
   
    memset(inputString, 0, sizeof(inputString));
    inputStringIndex = 0;
    stringComplete = false; 
  }
}
/******

runs steppers. Checks for hits to reset

******/ 
void updateSteppers() {
  xStepper.runSpeed();
  yStepper.runSpeed();
}
/******

Sends debug info about boundary conditions
dir -> x=0, y=1 this is just so when it gets passed to processing we can create an integer array.

******/
void sendSerialHitData(int dir) {
  //the reason dir is an int, is so that when Processing receives it we don't have to worry about its type being different than the other variables.
  incompleteStepsRatio = (float)((lastUpdateTime + updateInterval) - millis()) / (float)updateInterval;
  incompleteStepsRatio = ((int)(incompleteStepsRatio * 100)) / 100.0;
  
  Serial.print("hit:");
  Serial.print(dir);
  Serial.print(",");
  
  Serial.print(xDir);
  Serial.print(",");
  Serial.print(xSpeed);
  Serial.print(",");
  
  Serial.print(yDir);
  Serial.print(",");
  Serial.print(ySpeed);
  Serial.print(",");
  
  Serial.println(incompleteStepsRatio);
}

In the Processing app, arduinoData and heartbeat are not defined.

        if (inChar != '#' && inChar != ',' && inChar != '\n') {
          dataString[dataStringIndex] = inChar;
          dataStringIndex++;
        }

I guess it doesn't matter that there might not be room.

          if (dataIndex > 3) {
            //this is just to make sure we don't overflow the index
            dataIndex = 0;
          }

It would probably be a good idea to break out of the while loop, if this happens.
Breaking out when you find the \n would be good, too.

void checkBoundaries() {
  xBoundaryData = analogRead(A0);
  yBoundaryData = analogRead(A1);

What kind of sensors are you reading? I was visualizing limit switches, but, apparently not.

    xSpeed = data[1];
    ySpeed = data[3];

You said that the 2nd and 4th values represented number of steps. Why are the variables called xSpeed and ySpeed?

Thanks for the quick reply.

In the Processing app, arduinoData and heartbeat are not defined.

I was just showing parts of the Processing app that had anything to do with the Serial. Both of those classes are defined.

It would probably be a good idea to break out of the while loop, if this happens.
Breaking out when you find the \n would be good, too.

So after it reads a \n charcter to put a "break" in the code? Otherwise does it just keep flying around inside of the while loop of the serial read thinking that the serial is available?

What kind of sensors are you reading?

They are just temporary switches. Or whatever you call a switch that closes when its pressed down, and is open when its not pressed. I had a lot of false readings trying to read a HIGH/LOW signal from digital pins in the past, so I just hook them up to an analog pin now and wait for the signal to drop below 10, meaning the switch was hit.

Why are the variables called xSpeed and ySpeed?

Sorry for the confusion. On the Processing end it finds out how many steps should be taken, then sends over a speed value which for the AccelStepper library is the number of steps each motor takes per second.

Thank you for reading the code over so thoroughly.

So after it reads a \n charcter to put a "break" in the code?

You need to put a break; in the if(char == '\n') block. Otherwise, the program will keep reading any serial data that has been buffered. While there may not be any, it's still good practice to anticipate all possible conditions where adverse behavior could be introduced.

They are just temporary switches. Or whatever you call a switch that closes when its pressed down, and is open when its not pressed.

Momentary contact. Or, digital switches. So, why are you using analogRead() to read them?

I had a lot of false readings trying to read a HIGH/LOW signal from digital pins in the past

You need to debounce them, AND detect when the switch goes from pressed to released or released to pressed. Using analogRead() is NOT the answer. The reason that it appears to work is because it takes a lot longer to read a digital switch when pretending it is an analog device than it takes to read a digital switch, thereby doing the debouncing for you.

Post all of your Processing code, if you really want help.

You need to debounce them

What does that mean?

I attached all the code as a text file. Was too big for the textarea.

code.txt (23.8 KB)

Re: Debounce. Nevermind: found this http://arduino.cc/en/Tutorial/Debounce.

I'm (obviously) not super well versed in circuit building, but for creating a hookup that has two closed switches connected to a digital pin that would register when one of the switches opens, would this work ("C" is a switch that is closed):

5V -----C------C-------(10K resistor)----Ground
|
|
digital pin

No, that probably won't work. I don't know why you want to read two switches with one input.
Are you trying to read if both switches are in a particular state, or one of them is ?
I guess you know the difference between AND and OR.

Anyway, make sure you think that through.

So you are saying, that everything in your scenario is exactly the same, when you try
it with the UNO and the MEGA ?

My next useless suggestion..... if in doubt, read the error message.

what is "writeArray" ? Does it occur anywhere in your code, including other classes ?

If not, then it is something in Java. I find that google is your friend when it comes
to java errors.

Google "java writeArray" and the first item I see is the description of the java scheme,
which often provides a "clue" as to where your program is failing.

And the third item I see, suggests that this issue has come up on the arduino forum before....

And my next useless suggestion, is that the java crash list usually has some sort of trace through
the classes of where the exception occured. So I suggest that you take out the Uno and put the
Mega back and try and reproduce the condition, and this time you take note of all the error
messages when it fails.

As is reported in the other forums about this issue, it doesn't happen with the Uno, but does happen with the Mega. The same is happening for me. I'm just curious why. I'm going to go ahead and switch back to the Uno, but I hate not knowing why just switching the boards can cause the given problem.

For the switches they register hits to boundaries. So the far left and far right switch just reverse a motor detection and therefore can be registered to the same pin. The pin detects if one of the two switches closes. Given this, does that circuit work?

Just had a look at the previous threads on this issue. They seemed to be concerned about issues in the arduino sketch code.

Unless java is running on the arduino ( does it ? ), then the java errors obviously come from code which is executing on the
PC, be it the serial monitor, arduino ide, Processing, something running ON THE PC. This basic fact seems to have eluded
the people with a similar problem 2 years ago.

I'm going to go ahead and switch back to the Uno,

Before you do that, try again with the Mega, and this time write down ( or cut and paste ) all the error messages.

So the far left and far right switch just reverse a motor detection and therefore can be registered to the same pin. The pin detects if one of the two switches closes. Given this, does that circuit work?

As far as the circuit is concerned, yes, it should work. If the switches are normally closed, and open when the device reaches the end, then the pin should go low when either switch is opened.

You'd need to consider debouncing issues anyway.

It seems to me, unless you are very short of pins, you are opening yourself up to extra debouncing grief by doing it this way.

if you just had one switch on the pin, then when you get to the left end, the only way to go next is right. And that would be true,
no matter how many times the switch bounced. Bounce bounce bounce, go right, go right, go right.

With your arrangement, you would hit the left end, and if you had bounces, you would go right, go left, go right, go left, which would
just make the bouncing last forever......

Now the Mega and the Uno have different schemes for creating the "serial" connection to the PC through the USB connection, and this hardware
difference is something I don't really understand or care about but it does have some implications.

If there is some aspect of that difference which is causing some low-level nastiness in how the serial communication is being handled by java at the PC end, then that is really a nasty problem which is not going to be easy to fix. And if you do figure it out, you'll be acclaimed.

Had another look at that writeArray() stuff and it is kind of low-level and obscure.

Here's another bad idea. Instead of using the USB interface which is on the Mega, try using a USB-to-serial interface cable and try connecting it directly to the serial connection which is on pins 14-19 on the Mega. And even better, use one of the Serial2, Serial3 etc on the Mega chip which has nothing to do with the on-board USB converter chip.

See if you still get the problem.

And one final bad suggestion. See if you can pinpoint if it crashes, when you are trying to send data to , or from, the PC. Try slowing down your messaging process, so you can observe when it happens.

Good (though stomach turning) advice. Here is the (overdue) error message in its entirety:

java.io.IOException: Device not configured in writeArray
at gnu.io.RXTXPort.writeArray(Native Method)
at gnu.io.RXTXPort$SerialOutputStream.write(RXTXPort.java:1171)
at processing.serial.Serial.write(Serial.java:521)
at processing.serial.Serial.write(Serial.java:544)
at this_time_we_feel.sendCoordinates(this_time_we_feel.java:210)
at this_time_we_feel.draw(this_time_we_feel.java:203)
at processing.core.PApplet.handleDraw(PApplet.java:1631)
at processing.core.PApplet.run(PApplet.java:1530)
at java.lang.Thread.run(Thread.java:637)

I've been able to get rid of this issue by switching to an Uno and using a Mac with OSX 10.8.2. Was using OSX 10.6.8. Anywho. No more IOException.