Pages: [1] 2   Go Down
Author Topic: Serial stops returning data. java.io.IOException: Device not configured in write  (Read 2190 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50923
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

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:

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);
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50923
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
        if (inChar != '#' && inChar != ',' && inChar != '\n') {
          dataString[dataStringIndex] = inChar;
          dataStringIndex++;
        }
I guess it doesn't matter that there might not be room.

Code:
          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.

Code:
void checkBoundaries() {
  xBoundaryData = analogRead(A0);
  yBoundaryData = analogRead(A1);
What kind of sensors are you reading? I was visualizing limit switches, but, apparently not.

Code:
    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?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the quick reply.

Quote
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.

Quote
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?

Quote
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.

Quote
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. 

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50923
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.

Quote
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?

Quote
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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.79 KB - downloaded 32 times.)
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: February 12, 2013, 12:10:05 am by markvonrose » Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ?
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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......


Logged

Pages: [1] 2   Go Up
Jump to: